summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bruederli <bruederli@kolabsys.com>2015-03-26 09:35:51 (GMT)
committerThomas Bruederli <bruederli@kolabsys.com>2015-03-26 09:35:51 (GMT)
commit85974d137dd2b37a7d78bffc1d8980cb775f1386 (patch)
tree5c9c7e6139fff60c46fd38f34854137399304463
parent035978ff20b1336ec2db06e3f73a4449ea9ddb72 (diff)
downloadpykolab-85974d137dd2b37a7d78bffc1d8980cb775f1386.tar.gz
Add wrapper class for kolabformat.Note (#4908)
-rw-r--r--pykolab/xml/__init__.py9
-rw-r--r--pykolab/xml/note.py136
-rw-r--r--tests/unit/test-018-note.py95
3 files changed, 240 insertions, 0 deletions
diff --git a/pykolab/xml/__init__.py b/pykolab/xml/__init__.py
index 00edf06..20e4763 100644
--- a/pykolab/xml/__init__.py
+++ b/pykolab/xml/__init__.py
@@ -20,6 +20,11 @@ from todo import todo_from_ical
from todo import todo_from_string
from todo import todo_from_message
+from note import Note
+from note import NoteIntegrityError
+from note import note_from_string
+from note import note_from_message
+
from utils import property_label
from utils import property_to_string
from utils import compute_diff
@@ -31,6 +36,7 @@ __all__ = [
"ContactReference",
"Event",
"Todo",
+ "Note",
"RecurrenceRule",
"event_from_ical",
"event_from_string",
@@ -38,6 +44,8 @@ __all__ = [
"todo_from_ical",
"todo_from_string",
"todo_from_message",
+ "note_from_string",
+ "note_from_message",
"property_label",
"property_to_string",
"compute_diff",
@@ -49,6 +57,7 @@ errors = [
"InvalidEventDateError",
"InvalidAttendeeParticipantStatusError",
"TodoIntegrityError",
+ "NoteIntegrityError",
]
__all__.extend(errors)
diff --git a/pykolab/xml/note.py b/pykolab/xml/note.py
new file mode 100644
index 0000000..e46c41c
--- /dev/null
+++ b/pykolab/xml/note.py
@@ -0,0 +1,136 @@
+import pytz
+import datetime
+import kolabformat
+from pykolab.xml import utils as xmlutils
+from pykolab.xml.utils import ustr
+
+def note_from_string(string):
+ _xml = kolabformat.readNote(string, False)
+ return Note(_xml)
+
+def note_from_message(message):
+ note = None
+ if message.is_multipart():
+ for part in message.walk():
+ if part.get_content_type() == "application/vnd.kolab+xml":
+ payload = part.get_payload(decode=True)
+ note = note_from_string(payload)
+
+ # append attachment parts to Note object
+ elif note and part.has_key('Content-ID'):
+ note._attachment_parts.append(part)
+
+ return todo
+
+
+class Note(kolabformat.Note):
+ type = 'note'
+
+ classification_map = {
+ 'PUBLIC': kolabformat.ClassPublic,
+ 'PRIVATE': kolabformat.ClassPrivate,
+ 'CONFIDENTIAL': kolabformat.ClassConfidential,
+ }
+
+ properties_map = {
+ 'uid': 'get_uid',
+ 'summary': 'summary',
+ 'description': 'description',
+ 'created': 'get_created',
+ 'lastmodified-date': 'get_lastmodified',
+ 'classification': 'get_classification',
+ 'categories': 'categories',
+ 'color': 'color',
+ }
+
+ def __init__(self, *args, **kw):
+ self._attachment_parts = []
+ kolabformat.Note.__init__(self, *args, **kw)
+
+ def get_uid(self):
+ uid = self.uid()
+ if not uid == '':
+ return uid
+ else:
+ self.__str__()
+ return kolabformat.getSerializedUID()
+
+ def get_created(self):
+ try:
+ return xmlutils.from_cdatetime(self.created(), True)
+ except ValueError:
+ return datetime.datetime.now()
+
+ def get_lastmodified(self):
+ try:
+ _datetime = self.lastModified()
+ if _datetime == None or not _datetime.isValid():
+ self.__str__()
+ except:
+ return datetime.datetime.now(pytz.utc)
+
+ return xmlutils.from_cdatetime(self.lastModified(), True)
+
+ def set_summary(self, summary):
+ self.setSummary(ustr(summary))
+
+ def set_description(self, description):
+ self.setDescription(ustr(description))
+
+ def get_classification(self, translated=True):
+ _class = self.classification()
+ if translated:
+ return self._translate_value(_class, self.classification_map)
+ return _class
+
+ def set_classification(self, classification):
+ if classification in self.classification_map.keys():
+ self.setClassification(self.classification_map[classification])
+ elif classification in self.classification_map.values():
+ self.setClassification(status)
+ else:
+ raise ValueError, _("Invalid classification %r") % (classification)
+
+ def add_category(self, category):
+ _categories = self.categories()
+ _categories.append(ustr(category))
+ self.setCategories(_categories)
+
+ def _translate_value(self, val, map):
+ name_map = dict([(v, k) for (k, v) in map.iteritems()])
+ return name_map[val] if name_map.has_key(val) else 'UNKNOWN'
+
+ def to_dict(self):
+ if not self.isValid():
+ return None
+
+ data = dict()
+
+ for p, getter in self.properties_map.iteritems():
+ val = None
+ if hasattr(self, getter):
+ val = getattr(self, getter)()
+ if isinstance(val, kolabformat.cDateTime):
+ val = xmlutils.from_cdatetime(val, True)
+ elif isinstance(val, kolabformat.vectori):
+ val = [int(x) for x in val]
+ elif isinstance(val, kolabformat.vectors):
+ val = [str(x) for x in val]
+
+ if val is not None:
+ data[p] = val
+
+ return data
+
+ def __str__(self):
+ xml = kolabformat.writeNote(self)
+ error = kolabformat.error()
+
+ if error == None or not error:
+ return xml
+ else:
+ raise NoteIntegrityError, kolabformat.errorMessage()
+
+class NoteIntegrityError(Exception):
+ def __init__(self, message):
+ Exception.__init__(self, message)
diff --git a/tests/unit/test-018-note.py b/tests/unit/test-018-note.py
new file mode 100644
index 0000000..c4ba764
--- /dev/null
+++ b/tests/unit/test-018-note.py
@@ -0,0 +1,95 @@
+import datetime
+import pytz
+import unittest
+import kolabformat
+
+from pykolab.xml import Note
+from pykolab.xml import NoteIntegrityError
+from pykolab.xml import note_from_string
+
+xml_note = """
+<note xmlns="http://kolab.org" version="3.0">
+ <uid>d407f007-cb52-42cb-8e06-67f6132d718f</uid>
+ <prodid>Roundcube-libkolab-1.1 Libkolabxml-1.1</prodid>
+ <creation-date>2015-03-26T08:12:37Z</creation-date>
+ <last-modification-date>2015-03-26T08:12:37Z</last-modification-date>
+ <categories>One</categories>
+ <categories>Two</categories>
+ <classification>PUBLIC</classification>
+ <summary>Kolab Note</summary>
+ <description>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name="qrichtext" content="1" /&gt;&lt;meta http-equiv="Content-Type" /&gt;&lt;/head&gt;&lt;body&gt;
+&lt;p&gt;This is a HTML note&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;</description>
+ <color/>
+</note>
+"""
+
+class TestNoteXML(unittest.TestCase):
+ def assertIsInstance(self, _value, _type):
+ if hasattr(unittest.TestCase, 'assertIsInstance'):
+ return unittest.TestCase.assertIsInstance(self, _value, _type)
+ else:
+ if (type(_value)) == _type:
+ return True
+ else:
+ raise AssertionError, "%s != %s" % (type(_value), _type)
+
+ def test_001_minimal(self):
+ note = Note()
+ note.set_summary("test")
+ self.assertEqual(note.summary(), "test")
+ self.assertIsInstance(note.__str__(), str)
+
+ def test_002_full(self):
+ note = Note()
+ note.set_summary("test")
+ note.set_description("Description")
+ note.set_classification("CONFIDENTIAL")
+ note.add_category("Foo")
+ note.add_category("Bar")
+ # print str(note)
+
+ self.assertEqual(len(note.get_uid()), 36)
+ self.assertEqual(note.summary(), "test")
+ self.assertEqual(note.description(), "Description")
+ self.assertEqual(note.get_classification(), "CONFIDENTIAL")
+ self.assertEqual(note.get_classification(False), kolabformat.ClassConfidential)
+ self.assertEqual(len(note.categories()), 2)
+
+ def test_010_load_from_xml(self):
+ note = note_from_string(xml_note)
+ self.assertEqual(note.get_uid(), "d407f007-cb52-42cb-8e06-67f6132d718f")
+ self.assertEqual(note.summary(), "Kolab Note")
+ self.assertIsInstance(note.get_created(), datetime.datetime)
+ self.assertEqual(note.get_created().tzinfo, pytz.utc)
+ self.assertIsInstance(note.get_lastmodified(), datetime.datetime)
+ self.assertEqual(note.get_lastmodified().tzinfo, pytz.utc)
+
+ def test_011_to_xml(self):
+ note = Note()
+ note.setClassification(-1)
+ self.assertRaises(NoteIntegrityError, note.__str__)
+
+ # minimal
+ note = Note()
+ xml = str(note)
+ self.assertTrue('<summary/>' in xml)
+ self.assertTrue('<description/>' in xml)
+
+ def test_020_to_dict(self):
+ data = note_from_string(xml_note).to_dict()
+
+ self.assertIsInstance(data, dict)
+ self.assertTrue(data.has_key('uid'))
+ self.assertIsInstance(data.get('created', None), datetime.datetime)
+ self.assertIsInstance(data.get('lastmodified-date', None), datetime.datetime)
+ self.assertEqual(data.get('summary', None), "Kolab Note")
+ self.assertEqual(data.get('classification', None), 'PUBLIC')
+ self.assertIsInstance(data.get('categories', None), list)
+ self.assertEqual(len(data.get('categories', None)), 2)
+ self.assertTrue('<p>This is a HTML note</p>' in data.get('description', None))
+
+
+if __name__ == '__main__':
+ unittest.main() \ No newline at end of file