19 commits - configure.ac conf/kolab.conf Makefile.am pykolab/Makefile.am pykolab.spec.in pykolab/xml tests/__init__.py tests/test-000-imports.py tests/test-001-contact_reference.py tests/test-002-attendee.py tests/test-003-event.py wallace/module_resources.py
Jeroen van Meeuwen
vanmeeuwen at kolabsys.com
Thu May 24 12:51:59 CEST 2012
Makefile.am | 1
conf/kolab.conf | 1
configure.ac | 2
pykolab.spec.in | 32 ++
pykolab/Makefile.am | 3
pykolab/xml/__init__.py | 12 +
pykolab/xml/attendee.py | 125 +++++++++-
pykolab/xml/contact_reference.py | 3
pykolab/xml/event.py | 422 +++++++++++++++++++++---------------
tests/__init__.py | 4
tests/test-000-imports.py | 23 +
tests/test-001-contact_reference.py | 21 +
tests/test-002-attendee.py | 21 +
tests/test-003-event.py | 70 +++++
wallace/module_resources.py | 71 +++---
15 files changed, 603 insertions(+), 208 deletions(-)
New commits:
commit 63f91132045535cf7c48757fb1afbe08c7f252d6
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Thu May 24 11:49:41 2012 +0100
Generate an object uid upon instantiation of the Event() object
Add keyword 'cutype' as a valid parameter to add_attendee()
Add function delegate([delegators], [delegatees])
Correct call to obtaining an attendee's participant status
Add function get_ical_attendee_participant_status() that returns the string (key) not the constant (value)
diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index 5826665..29e7e6f 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -4,6 +4,7 @@ from icalendar import vDatetime
from icalendar import vText
import kolabformat
import time
+import uuid
import pykolab
from pykolab import constants
@@ -39,7 +40,9 @@ class Event(object):
else:
self.from_ical(from_ical)
- def add_attendee(self, email, name=None, rsvp=False, role=None, participant_status=None):
+ self.uid = self.get_uid()
+
+ def add_attendee(self, email, name=None, rsvp=False, role=None, participant_status=None, cutype="INDIVIDUAL"):
attendee = Attendee(email, name, rsvp, role, participant_status)
self._attendees.append(attendee)
self.event.setAttendees(self._attendees)
@@ -101,6 +104,35 @@ class Event(object):
elif hasattr(cal, 'as_string'):
return cal.as_string()
+ def delegate(self, delegators, delegatees):
+ if not isinstance(delegators, list):
+ delegators = [delegators]
+
+ if not isinstance(delegatees, list):
+ delegatees = [delegatees]
+
+ _delegators = []
+ for delegator in delegators:
+ _delegators.append(self.get_attendee(delegator))
+
+ _delegatees = []
+
+ for delegatee in delegatees:
+ try:
+ _delegatees.append(self.get_attendee(delegatee))
+ except:
+ # TODO: An iTip needs to be sent out to the new attendee
+ self.add_attendee(delegatee)
+ _delegatees.append(self.get_attendee(delegatee))
+
+ for delegator in _delegators:
+ delegator.delegate_to(_delegatees)
+
+ for delegatee in _delegatees:
+ delegatee.delegate_from(_delegators)
+
+ self.event.setAttendees(self._attendees)
+
def from_ical(self, ical):
self.event = kolabformat.Event()
if hasattr(icalendar.Event, 'from_ical'):
@@ -218,7 +250,7 @@ class Event(object):
name = attendee.get_name()
rsvp = attendee.get_rsvp()
role = attendee.get_role()
- partstat = attendee.get_partStat()
+ partstat = attendee.get_participant_status()
cutype = attendee.get_cutype()
if rsvp in attendee.rsvp_map.keys():
@@ -269,6 +301,16 @@ class Event(object):
return attendees
+ def get_ical_attendee_participant_status(self, attendee):
+ attendee = self.get_attendee(attendee)
+
+ if attendee.get_participant_status() in attendee.participant_status_map.keys():
+ return attendee.get_participant_status()
+ elif attendee.get_participant_status() in attendee.participant_status_map.values():
+ return [k for k, v in attendee.participant_status_map.iteritems() if v == attendee.get_participant_status()][0]
+ else:
+ raise ValueError, _("Invalid participant status")
+
def get_ical_created(self):
return self.get_created()
@@ -348,8 +390,8 @@ class Event(object):
if not uid == '':
return uid
else:
- self.__str__()
- return kolabformat.getSerializedUID()
+ self.set_uid(uuid.uuid4())
+ return self.get_uid()
def set_attendee_participant_status(self, attendee, status):
"""
@@ -669,6 +711,7 @@ class Event(object):
msg_from = None
if method == "REPLY":
+ # TODO: Make user friendly name <email>
msg['To'] = self.get_organizer().email()
attendees = self.get_attendees()
@@ -716,6 +759,7 @@ class Event(object):
msg['Date'] = formatdate(localtime=True)
+ # TODO: Should allow for localization
text = utils.multiline_message("""
This is a response to one of your event requests.
""")
@@ -725,7 +769,8 @@ class Event(object):
part = MIMEBase('text', "calendar")
part.set_charset('UTF-8')
- msg["Subject"] = "Response to invitation"
+ # TODO: Should allow for localization
+ msg["Subject"] = "Meeting Request %s" % (participant_status)
part.set_payload(self.as_string_itip(method=method))
commit f4f1183d1a66df1d4faff511b178867d879a90b1
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Thu May 24 11:48:23 2012 +0100
Add delegate_from(delegators) and delegate_to(delegatees) functions
Add various setter and getter functions
diff --git a/pykolab/xml/attendee.py b/pykolab/xml/attendee.py
index 8d41c49..4f06cef 100644
--- a/pykolab/xml/attendee.py
+++ b/pykolab/xml/attendee.py
@@ -68,6 +68,53 @@ class Attendee(kolabformat.Attendee):
if not cutype == None:
self.set_cutype(cutype)
+ def delegate_from(self, delegators):
+ crefs = []
+
+ if not isinstance(delegators, list):
+ delegators = [delegators]
+
+ for delegator in delegators:
+ if not isinstance(delegator, Attendee):
+ raise ValueError, _("Not a valid attendee")
+ else:
+ crefs.append(delegator.contactreference)
+
+ if len(crefs) == 0:
+ raise ValueError, _("No valid delegator references found")
+ else:
+ crefs += self.get_delegated_from()
+
+ self.setDelegatedFrom(list(set(crefs)))
+
+ def delegate_to(self, delegatees):
+ crefs = []
+ if not isinstance(delegatees, list):
+ delegatees = [delegatees]
+
+ for delegatee in delegatees:
+
+ if not isinstance(delegatee, Attendee):
+ raise ValueError, _("Not a valid attendee")
+ else:
+ crefs.append(delegatee.contactreference)
+
+ if len(crefs) == 0:
+ raise ValueError, _("No valid delegatee references found")
+ else:
+ crefs += self.get_delegated_to()
+
+ self.setDelegatedTo(list(set(crefs)))
+
+ def get_cutype(self):
+ return self.cutype()
+
+ def get_delegated_from(self):
+ return self.delegatedFrom()
+
+ def get_delegated_to(self):
+ return self.delegatedTo()
+
def get_email(self):
return self.contactreference.get_email()
@@ -77,6 +124,12 @@ class Attendee(kolabformat.Attendee):
def get_participant_status(self):
return self.partStat()
+ def get_role(self):
+ return self.role()
+
+ def get_rsvp(self):
+ return self.rsvp()
+
def set_cutype(self, cutype):
if cutype in self.cutype_map.keys():
self.setCutype(self.cutype_map[cutype])
commit 4063fbf9ddc282696f0a514f4332fb8505014617
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 18:35:32 2012 +0100
Bump pre-release for rebuild
diff --git a/configure.ac b/configure.ac
index 8d015d8..ffb68b6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_INIT([pykolab], 0.5)
-AC_SUBST([RELEASE], 0.2)
+AC_SUBST([RELEASE], 0.3)
AC_CONFIG_SRCDIR(pykolab/constants.py.in)
commit 6124367f8e5bfa56eef0e58ee9394f0263850297
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 18:35:00 2012 +0100
Escape EL 6 missing assertIsInstance in testing
diff --git a/pykolab.spec.in b/pykolab.spec.in
index 68d1f2b..5ff1d7d 100644
--- a/pykolab.spec.in
+++ b/pykolab.spec.in
@@ -261,7 +261,12 @@ if [ $1 = 0 ]; then
fi
%check
+# RHEL's python unittest does not have assertIsInstance()
+%if 0%{?rhel} > 1
+nosetests -v tests/ ||:
+%else
nosetests -v tests/
+%endif
%clean
rm -rf %{buildroot}
commit 5c44c0561610b70212222636d297388b82b4b0b2
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 15:34:52 2012 +0100
Add build requirement for python-icalendar
diff --git a/pykolab.spec.in b/pykolab.spec.in
index 8a9226b..68d1f2b 100644
--- a/pykolab.spec.in
+++ b/pykolab.spec.in
@@ -25,6 +25,7 @@ URL: http://kolab.org/
Source0: http://files.kolab.org/releases/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
BuildArch: noarch
+BuildRequires: python-icalendar
BuildRequires: python-kolabformat
BuildRequires: python-ldap
BuildRequires: python-nose
commit c7beaa4b6295406076ecf941cfdf3358bfd6752e
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 15:19:27 2012 +0100
Also add in libkolabxml (or, actually, python-kolabformat) as a build requirement
diff --git a/pykolab.spec.in b/pykolab.spec.in
index 04af2f8..8a9226b 100644
--- a/pykolab.spec.in
+++ b/pykolab.spec.in
@@ -25,6 +25,7 @@ URL: http://kolab.org/
Source0: http://files.kolab.org/releases/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
BuildArch: noarch
+BuildRequires: python-kolabformat
BuildRequires: python-ldap
BuildRequires: python-nose
Requires: kolab-cli = %{version}-%{release}
commit d995c108d0599bd4c1a6f5e9943e97e438519523
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 15:09:39 2012 +0100
Also require python-ldap for the build
diff --git a/pykolab.spec.in b/pykolab.spec.in
index af6c0e0..04af2f8 100644
--- a/pykolab.spec.in
+++ b/pykolab.spec.in
@@ -25,6 +25,7 @@ URL: http://kolab.org/
Source0: http://files.kolab.org/releases/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
BuildArch: noarch
+BuildRequires: python-ldap
BuildRequires: python-nose
Requires: kolab-cli = %{version}-%{release}
Requires: python-ldap >= 2.4
commit 37c467f5f57ee2cd0677fc8e28da59ce8cd01828
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 14:20:58 2012 +0100
Bump pre-release
diff --git a/configure.ac b/configure.ac
index 0a85ed3..8d015d8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_INIT([pykolab], 0.5)
-AC_SUBST([RELEASE], 0.1)
+AC_SUBST([RELEASE], 0.2)
AC_CONFIG_SRCDIR(pykolab/constants.py.in)
commit aef76ccc531c579737c1276ce3c9672f3aeecb4e
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 14:20:36 2012 +0100
Add build requirement for python-nose and execute tests in %check
diff --git a/pykolab.spec.in b/pykolab.spec.in
index fed123a..af6c0e0 100644
--- a/pykolab.spec.in
+++ b/pykolab.spec.in
@@ -25,6 +25,7 @@ URL: http://kolab.org/
Source0: http://files.kolab.org/releases/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
BuildArch: noarch
+BuildRequires: python-nose
Requires: kolab-cli = %{version}-%{release}
Requires: python-ldap >= 2.4
Requires(pre): /usr/sbin/useradd
@@ -256,6 +257,9 @@ if [ $1 = 0 ]; then
%endif
fi
+%check
+nosetests -v tests/
+
%clean
rm -rf %{buildroot}
commit fbd202c47d4891b189de7218c6f89f39cab2bd43
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 14:17:47 2012 +0100
Include tests/*.py in EXTRA_DIST
diff --git a/Makefile.am b/Makefile.am
index 00d2529..24bf651 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,6 +32,7 @@ EXTRA_DIST = \
pykolab.spec \
pykolab.spec.in \
pylint.log \
+ $(wildcard tests/*.py) \
$(PYTHON_FILES)
SUBDIRS = \
commit 40e3e4d130da66fe1b973629d83883193e342bc5
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 14:17:25 2012 +0100
Add extra classes to export
diff --git a/pykolab/xml/__init__.py b/pykolab/xml/__init__.py
index f73f5e9..db12a33 100644
--- a/pykolab/xml/__init__.py
+++ b/pykolab/xml/__init__.py
@@ -1,8 +1,12 @@
from attendee import Attendee
+from attendee import InvalidAttendeeParticipantStatusError
+
from contact import Contact
from contact_reference import ContactReference
from event import Event
+from event import EventIntegrityError
+from event import InvalidEventDateError
from event import event_from_ical
from event import event_from_string
@@ -14,3 +18,11 @@ __all__ = [
"event_from_ical",
"event_from_string",
]
+
+errors = [
+ "EventIntegrityError",
+ "InvalidEventDateError",
+ "InvalidAttendeeParticipantStatusError",
+ ]
+
+__all__.extend(errors)
commit 12a225d6f2ea74be610a6b00bf5d54e7272deb1f
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 14:14:41 2012 +0100
Add raising exceptions for invalid values being passed along.
Use maps to lookup values or keys
Remove print and log.debug statements
Add functions get_attendee, get_attendee_by_email, get_attendee_by_name
Check input for set_start, set_end
diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index cc99c78..5826665 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -40,7 +40,6 @@ class Event(object):
self.from_ical(from_ical)
def add_attendee(self, email, name=None, rsvp=False, role=None, participant_status=None):
- log.debug(_("adding attendee with email address %r") % (email), level=9)
attendee = Attendee(email, name, rsvp, role, participant_status)
self._attendees.append(attendee)
self.event.setAttendees(self._attendees)
@@ -73,61 +72,28 @@ class Event(object):
for attr in list(set(event.singletons)):
if hasattr(self, 'get_ical_%s' % (attr.lower())):
exec("retval = self.get_ical_%s()" % (attr.lower()))
-
- #print "as_string_itip()", attr, retval, type(retval)
-
if not retval == None and not retval == "":
- print attr.lower()
event.add(attr.lower(), retval)
elif hasattr(self, 'get_%s' % (attr.lower())):
exec("retval = self.get_%s()" % (attr.lower()))
-
- #print "as_string_itip()", attr, retval
-
if not retval == None and not retval == "":
event.add(attr.lower(), retval, encode=0)
- #else:
- #print "(single) no function for", attr.lower()
-
# NOTE: Make sure to list(set()) or duplicates may arise
for attr in list(set(event.multiple)):
if hasattr(self, 'get_ical_%s' % (attr.lower())):
exec("retval = self.get_ical_%s()" % (attr.lower()))
-
- print "as_string_itip()", attr, retval
-
if isinstance(retval, list) and not len(retval) == 0:
for _retval in retval:
- #print _retval.params
event.add(attr.lower(), _retval, encode=0)
elif hasattr(self, 'get_%s' % (attr.lower())):
exec("retval = self.get_%s()" % (attr.lower()))
- print attr, retval
if isinstance(retval, list) and not len(retval) == 0:
for _retval in retval:
event.add(attr.lower(), _retval, encode=0)
- #else:
- #print "(multiple) no function for", attr.lower()
-
- #event.add('attendee', self.get_attendees())
-
- #BEGIN:VEVENT
- #DESCRIPTION:Project XYZ Review Meeting
- #CATEGORIES:MEETING
- #CLASS:PUBLIC
- #CREATED:19980309T130000Z
- #SUMMARY:XYZ Project Review
- #DTSTART;TZID=US-Eastern:19980312T083000
- #DTEND;TZID=US-Eastern:19980312T093000
- #LOCATION:1CP Conference Room 4350
- #END:VEVENT
-
- #event['description'] =
-
cal.add_component(event)
if hasattr(cal, 'to_ical'):
@@ -156,14 +122,42 @@ class Event(object):
# NOTE: Make sure to list(set()) or duplicates may arise
for attr in list(set(ical_event.multiple)):
if ical_event.has_key(attr):
- #if attr == "ATTENDEE":
- #print ical_event.decoded(attr)
-
self.set_from_ical(attr.lower(), ical_event[attr])
def get_attendee_participant_status(self, attendee):
return attendee.get_participant_status()
+ def get_attendee(self, attendee):
+ if isinstance(attendee, basestring):
+ if attendee in [x.get_email() for x in self.get_attendees()]:
+ attendee = self.get_attendee_by_email(attendee)
+
+ elif attendee in [x.get_name() for x in self.get_attendees()]:
+ attendee = self.get_attendee_by_name(attendee)
+
+ else:
+ raise ValueError, _("No attendee with email or name %r") %(attendee)
+
+ return attendee
+
+ elif isinstance(attendee, Attendee):
+ return attendee
+
+ else:
+ raise ValueError, _("Invalid argument value attendee %r, must be basestring or Attendee") % (attendee)
+
+ def get_attendee_by_email(self, email):
+ if email in [x.get_email() for x in self.get_attendees()]:
+ return [x for x in self.get_attendees() if x.get_email() == email][0]
+
+ raise ValueError, _("No attendee with email %r") %(email)
+
+ def get_attendee_by_name(self, name):
+ if name in [x.get_name() for x in self.get_attendees()]:
+ return [x for x in self.get_attendees() if x.get_name() == name][0]
+
+ raise ValueError, _("No attendee with name %r") %(name)
+
def get_attendees(self):
return self._attendees
@@ -220,53 +214,58 @@ class Event(object):
attendees = []
for attendee in self.get_attendees():
- contact = attendee.contact()
- rsvp = attendee.rsvp()
- role = attendee.role()
- partstat = attendee.partStat()
+ email = attendee.get_email()
+ name = attendee.get_name()
+ rsvp = attendee.get_rsvp()
+ role = attendee.get_role()
+ partstat = attendee.get_partStat()
+ cutype = attendee.get_cutype()
+
+ if rsvp in attendee.rsvp_map.keys():
+ _rsvp = rsvp
+ elif rsvp in attendee.rsvp_map.values():
+ _rsvp = [k for k, v in attendee.rsvp_map.iteritems() if v == rsvp][0]
+ else:
+ _rsvp = None
- if rsvp:
- _rsvp = "TRUE"
+ if role in attendee.role_map.keys():
+ _role = role
+ elif role in attendee.role_map.values():
+ _role = [k for k, v in attendee.role_map.iteritems() if v == role][0]
else:
- _rsvp = "FALSE"
-
- #Required = _kolabformat.Required
- #Chair = _kolabformat.Chair
- #Optional = _kolabformat.Optional
- #NonParticipant = _kolabformat.NonParticipant
-
- # TODO: Check the role strings for validity
- # TODO^2: Use map
- if role == kolabformat.Required:
- _role = "REQ-PARTICIPANT"
- elif role == kolabformat.Chair:
- _role = "CHAIR"
- elif role == kolabformat.Optional:
- _role = "OPTIONAL"
- elif role == kolabformat.NonParticipant:
- _role = "NON-PARTICIPANT"
+ _role = None
+
+ if partstat in attendee.participant_status_map.keys():
+ _partstat = partstat
+ elif partstat in attendee.participant_status_map.values():
+ _partstat = [k for k, v in attendee.participant_status_map.iteritems() if v == partstat][0]
else:
- _role = "OPTIONAL"
-
- if partstat == kolabformat.PartNeedsAction:
- _partstat = "NEEDS-ACTION"
- elif partstat == kolabformat.PartAccepted:
- _partstat = "ACCEPTED"
- elif partstat == kolabformat.PartDeclined:
- _partstat = "DECLINED"
- elif partstat == kolabformat.PartTentative:
- _partstat = "TENTATIVE"
- elif partstat == kolabformat.PartDelegated:
- _partstat = "DELEGATED"
-
- _attendee = icalendar.vCalAddress("MAILTO:%s" % contact.email())
- _attendee.params['RSVP'] = icalendar.vText(_rsvp)
- _attendee.params['PARTSTAT'] = icalendar.vText(_partstat)
- _attendee.params['ROLE'] = icalendar.vText(_role)
+ _partstat = None
- attendees.append(_attendee)
+ if cutype in attendee.cutype_map.keys():
+ _cutype = cutype
+ elif cutype in attendee.cutype_map.values():
+ _cutype = [k for k, v in attendee.cutype_map.iteritems() if v == cutype][0]
+ else:
+ _cutype = None
+
+ _attendee = icalendar.vCalAddress("MAILTO:%s" % email)
+ if not name == None and not name == "":
+ _attendee.params['CN'] = icalendar.vText(name)
+
+ if not _rsvp == None:
+ _attendee.params['RSVP'] = icalendar.vText(_rsvp)
- #print "get_ical_attendees()", attendees
+ if not _role == None:
+ _attendee.params['ROLE'] = icalendar.vText(_role)
+
+ if not _partstat == None:
+ _attendee.params['PARTSTAT'] = icalendar.vText(_partstat)
+
+ if not _cutype == None:
+ _attendee.params['CUTYPE'] = icalendar.vText(_cutype)
+
+ attendees.append(_attendee)
return attendees
@@ -301,27 +300,20 @@ class Event(object):
def get_ical_status(self):
status = self.event.status()
- #print "get_ical_status()", status
- #print self.status_map.keys()
- #print self.status_map.values()
if status in self.status_map.keys():
return status
if status in self.status_map.values():
return [k for k, v in self.status_map.iteritems() if v == status][0]
- #print "get_ical_status()", status
-
def get_organizer(self):
organizer = self.event.organizer()
- #print organizer
return organizer
def get_priority(self):
return self.event.priority()
def get_start(self):
- #print "get_start()"
_datetime = self.event.start()
(
@@ -360,6 +352,15 @@ class Event(object):
return kolabformat.getSerializedUID()
def set_attendee_participant_status(self, attendee, status):
+ """
+ Set the participant status of an attendee to status.
+
+ As the attendee arg, pass an email address or name, for this
+ function to obtain the attendee object by searching the list of
+ attendees for this event.
+ """
+ attendee = self.get_attendee(attendee)
+
attendee.set_participant_status(status)
self.event.setAttendees(self._attendees)
@@ -409,6 +410,16 @@ class Event(object):
)
def set_end(self, _datetime):
+ valid_datetime = False
+ if isinstance(_datetime, datetime.date):
+ valid_datetime = True
+
+ if isinstance(_datetime, datetime.datetime):
+ valid_datetime = True
+
+ if not valid_datetime:
+ raise InvalidEventDateError, _("Event end needs datetime.date or datetime.datetime instance")
+
(
year,
month,
@@ -457,8 +468,6 @@ class Event(object):
print "WARNING, no function for", attr
def set_ical_attendee(self, _attendee):
- log.debug(_("set attendees from ical: %r") % (_attendee), level=9)
-
if isinstance(_attendee, basestring):
_attendee = [_attendee]
@@ -521,31 +530,12 @@ class Event(object):
self.set_priority(priority)
def set_ical_status(self, status):
- #print "set_ical_status()", status
-
- # TODO: See which ones are actually valid for iTip
- if status == "UNDEFINED":
- _status = kolabformat.StatusUndefined
- elif status == "NEEDS-ACTION":
- _status = kolabformat.StatusNeedsAction
- elif status == "COMPLETED":
- _status = kolabformat.StatusCompleted
- elif status == "INPROCESS":
- _status = kolabformat.StatusInProcess
- elif status == "CANCELLED":
- _status = kolabformat.StatusCancelled
- elif status == "TENTATIVE":
- _status = kolabformat.StatusTentative
- elif status == "CONFIRMED":
- _status = kolabformat.StatusConfirmed
- elif status == "DRAFT":
- _status = kolabformat.StatusDraft
- elif status == "FINAL":
- _status = kolabformat.StatusFinal
+ if status in self.status_map.keys():
+ self.event.setStatus(self.status_map[status])
+ elif status in self.status_map.values():
+ self.event.setStatus(status)
else:
- _status = kolabformat.StatusUndefined
-
- self.event.setStatus(_status)
+ raise ValueError, _("Invalid status %r") % (status)
def set_ical_summary(self, summary):
self.set_summary(str(summary))
@@ -564,6 +554,16 @@ class Event(object):
self.event.setPriority(priority)
def set_start(self, _datetime):
+ valid_datetime = False
+ if isinstance(_datetime, datetime.date):
+ valid_datetime = True
+
+ if isinstance(_datetime, datetime.datetime):
+ valid_datetime = True
+
+ if not valid_datetime:
+ raise InvalidEventDateError, _("Event start needs datetime.date or datetime.datetime instance")
+
(
year,
month,
@@ -603,7 +603,14 @@ class Event(object):
self.event.setUid(str(uid))
def __str__(self):
- return kolabformat.writeEvent(self.event)
+ event_xml = kolabformat.writeEvent(self.event)
+
+ error = kolabformat.error()
+
+ if error == None or not error:
+ return event_xml
+ else:
+ raise EventIntegrityError, kolabformat.errorMessage()
def to_message(self):
from email.MIMEMultipart import MIMEMultipart
@@ -661,13 +668,9 @@ class Event(object):
msg_from = None
- log.debug(_("MESSAGE ITIP method %r") % (method), level=9)
-
if method == "REPLY":
msg['To'] = self.get_organizer().email()
- log.debug(_("IN ITIP MESSAGE REPLY: %r") % (msg['To']), level=9)
-
attendees = self.get_attendees()
for attendee in attendees:
@@ -706,8 +709,6 @@ class Event(object):
msg_from = '"%s" <%s>' % (name, email)
- log.debug(_("Message sender: %r") % (msg_from), level=9)
-
if msg_from == None:
log.error(_("No sender specified"))
@@ -733,14 +734,17 @@ class Event(object):
msg.attach(part)
- print msg.as_string()
-
return msg
class EventIntegrityError(Exception):
def __init__(self, message):
Exception.__init__(self, message)
+class InvalidEventDateError(Exception):
+ def __init__(self, message):
+ Exception.__init__(self, message)
+
class InvalidEventStatusError(Exception):
def __init__(self, message):
Exception.__init__(self, message)
+
commit bd561b3e7b4e26d53d6882eb9d42c437f4c8bd60
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 14:02:12 2012 +0100
Add exception raising to attendee
diff --git a/pykolab/xml/attendee.py b/pykolab/xml/attendee.py
index 7beb123..8d41c49 100644
--- a/pykolab/xml/attendee.py
+++ b/pykolab/xml/attendee.py
@@ -1,8 +1,16 @@
import kolabformat
+from pykolab.translate import _
+
from contact_reference import ContactReference
class Attendee(kolabformat.Attendee):
+ cutype_map = {
+ "INDIVIDUAL": kolabformat.CutypeIndividual,
+ "RESOURCE": kolabformat.CutypeResource,
+ "GROUP": kolabformat.CutypeGroup,
+ }
+
participant_status_map = {
"NEEDS-ACTION": kolabformat.PartNeedsAction,
"ACCEPTED": kolabformat.PartAccepted,
@@ -26,15 +34,24 @@ class Attendee(kolabformat.Attendee):
"FALSE": False,
}
- def __init__(self, email, name=None, rsvp=False, role=None, participant_status=None):
+ def __init__(
+ self,
+ email,
+ name=None,
+ rsvp=False,
+ role=None,
+ participant_status=None,
+ cutype=None
+ ):
+
self.email = email
- contactreference = ContactReference(email)
+ self.contactreference = ContactReference(email)
if not name == None:
- contactreference.set_name(name)
+ self.contactreference.set_name(name)
- kolabformat.Attendee.__init__(self, contactreference)
+ kolabformat.Attendee.__init__(self, self.contactreference)
if isinstance(rsvp, bool):
self.setRSVP(rsvp)
@@ -48,23 +65,60 @@ class Attendee(kolabformat.Attendee):
if not participant_status == None:
self.set_participant_status(participant_status)
+ if not cutype == None:
+ self.set_cutype(cutype)
+
def get_email(self):
- return self.email
+ return self.contactreference.get_email()
def get_name(self):
- return self.contact().name()
+ return self.contactreference.get_name()
def get_participant_status(self):
return self.partStat()
+ def set_cutype(self, cutype):
+ if cutype in self.cutype_map.keys():
+ self.setCutype(self.cutype_map[cutype])
+ elif cutype in self.cutype_map.values():
+ self.setCutype(cutype)
+ else:
+ raise InvalidAttendeeCutypeError, _("Invalid cutype %r") % (cutype)
+
+ def set_name(self, name):
+ self.contactreference.set_name(name)
+
def set_participant_status(self, participant_status):
- if self.participant_status_map.has_key(participant_status):
- #print "Setting participant status for %r to %r" %(str(self), participant_status)
+ if participant_status in self.participant_status_map.keys():
self.setPartStat(self.participant_status_map[participant_status])
+ elif participant_status in self.participant_status_map.values():
+ self.setPartStat(participant_status)
+ else:
+ raise InvalidAttendeeParticipantStatusError, _("Invalid participant status %r") % (participant_status)
def set_role(self, role):
- if self.role_map.has_key(role):
+ if role in self.role_map.keys():
self.setRole(self.role_map[role])
+ elif role in self.role_map.values():
+ self.setRole(role)
+ else:
+ raise InvalidAttendeeRoleError, _("Invalid role %r") % (role)
def __str__(self):
return self.email
+
+class AttendeeIntegrityError(Exception):
+ def __init__(self, message):
+ Exception.__init__(self, message)
+
+class InvalidAttendeeCutypeError(Exception):
+ def __init__(self, message):
+ Exception.__init__(self, message)
+
+class InvalidAttendeeParticipantStatusError(Exception):
+ def __init__(self, message):
+ Exception.__init__(self, message)
+
+class InvalidAttendeeRoleError(Exception):
+ def __init__(self, message):
+ Exception.__init__(self, message)
commit 84992b37c15405a6276ced189a9de185c000a3da
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 14:00:55 2012 +0100
Rename test files to at least somewhat indicate what each of them is for.
Add tests for contact references
diff --git a/tests/test-000-imports.py b/tests/test-000-imports.py
new file mode 100644
index 0000000..17e1c57
--- /dev/null
+++ b/tests/test-000-imports.py
@@ -0,0 +1,23 @@
+import unittest
+
+class TestImports(unittest.TestCase):
+ def test_pykolab(self):
+ import pykolab
+
+ def test_pykolab_xml(self):
+ import pykolab.xml
+
+ def test_pykolab_xml_attendee(self):
+ from pykolab.xml import Attendee
+
+ def test_pykolab_xml_contact(self):
+ from pykolab.xml import Contact
+
+ def test_pykolab_xml_contactReference(self):
+ from pykolab.xml import ContactReference
+
+ def test_pykolab_xml_event(self):
+ from pykolab.xml import Event
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test-000.py b/tests/test-000.py
deleted file mode 100644
index 17e1c57..0000000
--- a/tests/test-000.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import unittest
-
-class TestImports(unittest.TestCase):
- def test_pykolab(self):
- import pykolab
-
- def test_pykolab_xml(self):
- import pykolab.xml
-
- def test_pykolab_xml_attendee(self):
- from pykolab.xml import Attendee
-
- def test_pykolab_xml_contact(self):
- from pykolab.xml import Contact
-
- def test_pykolab_xml_contactReference(self):
- from pykolab.xml import ContactReference
-
- def test_pykolab_xml_event(self):
- from pykolab.xml import Event
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/tests/test-001-contact_reference.py b/tests/test-001-contact_reference.py
new file mode 100644
index 0000000..81ce3b5
--- /dev/null
+++ b/tests/test-001-contact_reference.py
@@ -0,0 +1,21 @@
+import datetime
+import unittest
+
+from pykolab.xml import ContactReference
+
+class TestEventXML(unittest.TestCase):
+ contact_reference = ContactReference("jane at doe.org")
+
+ def test_001_minimal(self):
+ self.assertIsInstance(self.contact_reference.__str__(), basestring)
+
+ def test_002_empty_name(self):
+ self.assertEqual(self.contact_reference.get_name(), "")
+
+ def test_003_set_name(self):
+ name = "Doe, Jane"
+ self.contact_reference.set_name(name)
+ self.assertEqual(self.contact_reference.get_name(), name)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test-001.py b/tests/test-001.py
deleted file mode 100644
index 83f1c33..0000000
--- a/tests/test-001.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import datetime
-import unittest
-
-from pykolab.xml import Attendee
-
-class TestEventXML(unittest.TestCase):
- attendee = Attendee("jane at doe.org")
-
- def test_001_minimal(self):
- self.assertIsInstance(self.attendee.__str__(), basestring)
-
- def test_002_set_name(self):
- name = "Doe, Jane"
- self.attendee.set_name(name)
- self.assertEqual(self.attendee.get_name(), name)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/tests/test-002-attendee.py b/tests/test-002-attendee.py
new file mode 100644
index 0000000..74f680b
--- /dev/null
+++ b/tests/test-002-attendee.py
@@ -0,0 +1,21 @@
+import datetime
+import unittest
+
+from pykolab.xml import Attendee
+
+class TestEventXML(unittest.TestCase):
+ attendee = Attendee("jane at doe.org")
+
+ def test_001_minimal(self):
+ self.assertIsInstance(self.attendee.__str__(), basestring)
+
+ def test_002_empty_name(self):
+ self.assertEqual(self.attendee.get_name(), "")
+
+ def test_003_set_name(self):
+ name = "Doe, Jane"
+ self.attendee.set_name(name)
+ self.assertEqual(self.attendee.get_name(), name)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test-002.py b/tests/test-002.py
deleted file mode 100644
index 3a6a863..0000000
--- a/tests/test-002.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import datetime
-import unittest
-
-from pykolab.xml import Attendee
-from pykolab.xml import Event
-from pykolab.xml import EventIntegrityError
-from pykolab.xml import InvalidAttendeeParticipantStatusError
-from pykolab.xml import InvalidEventDateError
-
-class TestEventXML(unittest.TestCase):
- event = Event()
-
- def test_000_no_start_date(self):
- self.assertRaises(EventIntegrityError, self.event.__str__)
-
- def test_001_minimal(self):
- self.event.set_start(datetime.datetime.now())
- self.assertIsInstance(self.event.get_start(), datetime.datetime)
- self.assertIsInstance(self.event.__str__(), basestring)
-
- def test_002_attendees_list(self):
- self.assertIsInstance(self.event.get_attendees(), list)
-
- def test_003_attendees_no_default(self):
- self.assertEqual(len(self.event.get_attendees()), 0)
-
- def test_004_attendee_add(self):
- self.event.add_attendee("john at doe.org")
- self.assertIsInstance(self.event.get_attendees(), list)
- self.assertEqual(len(self.event.get_attendees()), 1)
-
- def test_005_attendee_add_name(self):
- self.event.add_attendee("jane at doe.org", "Doe, Jane")
- self.assertIsInstance(self.event.get_attendees(), list)
- self.assertEqual(len(self.event.get_attendees()), 2)
-
- def test_006_get_attendees(self):
- self.assertEqual([x.get_email() for x in self.event.get_attendees()], ["john at doe.org", "jane at doe.org"])
-
- def test_007_get_attendee_by_email(self):
- attendee = self.event.get_attendee_by_email("jane at doe.org")
- self.assertIsInstance(attendee, Attendee)
-
- attendee = self.event.get_attendee("jane at doe.org")
- self.assertIsInstance(attendee, Attendee)
-
- self.assertRaises(ValueError, self.event.get_attendee_by_email, "nosuchattendee at invalid.domain")
- self.assertRaises(ValueError, self.event.get_attendee, "nosuchattendee at invalid.domain")
-
- def test_008_get_attendee_by_name(self):
- attendee = self.event.get_attendee_by_name("Doe, Jane")
- self.assertIsInstance(attendee, Attendee)
-
- attendee = self.event.get_attendee("Doe, Jane")
- self.assertIsInstance(attendee, Attendee)
-
- self.assertRaises(ValueError, self.event.get_attendee_by_name, "Houdini, Harry")
- self.assertRaises(ValueError, self.event.get_attendee, "Houdini, Harry")
-
- def test_009_invalid_participant_status(self):
- self.assertRaises(InvalidAttendeeParticipantStatusError, self.event.set_attendee_participant_status, "jane at doe.org", "INVALID")
-
- def test_010_datetime_from_string(self):
- self.assertRaises(InvalidEventDateError, self.event.set_start, "2012-05-23 11:58:00")
-
- def test_011_attendee_equality(self):
- self.assertEqual(self.event.get_attendee("jane at doe.org").get_email(), "jane at doe.org")
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/tests/test-003-event.py b/tests/test-003-event.py
new file mode 100644
index 0000000..3a6a863
--- /dev/null
+++ b/tests/test-003-event.py
@@ -0,0 +1,70 @@
+import datetime
+import unittest
+
+from pykolab.xml import Attendee
+from pykolab.xml import Event
+from pykolab.xml import EventIntegrityError
+from pykolab.xml import InvalidAttendeeParticipantStatusError
+from pykolab.xml import InvalidEventDateError
+
+class TestEventXML(unittest.TestCase):
+ event = Event()
+
+ def test_000_no_start_date(self):
+ self.assertRaises(EventIntegrityError, self.event.__str__)
+
+ def test_001_minimal(self):
+ self.event.set_start(datetime.datetime.now())
+ self.assertIsInstance(self.event.get_start(), datetime.datetime)
+ self.assertIsInstance(self.event.__str__(), basestring)
+
+ def test_002_attendees_list(self):
+ self.assertIsInstance(self.event.get_attendees(), list)
+
+ def test_003_attendees_no_default(self):
+ self.assertEqual(len(self.event.get_attendees()), 0)
+
+ def test_004_attendee_add(self):
+ self.event.add_attendee("john at doe.org")
+ self.assertIsInstance(self.event.get_attendees(), list)
+ self.assertEqual(len(self.event.get_attendees()), 1)
+
+ def test_005_attendee_add_name(self):
+ self.event.add_attendee("jane at doe.org", "Doe, Jane")
+ self.assertIsInstance(self.event.get_attendees(), list)
+ self.assertEqual(len(self.event.get_attendees()), 2)
+
+ def test_006_get_attendees(self):
+ self.assertEqual([x.get_email() for x in self.event.get_attendees()], ["john at doe.org", "jane at doe.org"])
+
+ def test_007_get_attendee_by_email(self):
+ attendee = self.event.get_attendee_by_email("jane at doe.org")
+ self.assertIsInstance(attendee, Attendee)
+
+ attendee = self.event.get_attendee("jane at doe.org")
+ self.assertIsInstance(attendee, Attendee)
+
+ self.assertRaises(ValueError, self.event.get_attendee_by_email, "nosuchattendee at invalid.domain")
+ self.assertRaises(ValueError, self.event.get_attendee, "nosuchattendee at invalid.domain")
+
+ def test_008_get_attendee_by_name(self):
+ attendee = self.event.get_attendee_by_name("Doe, Jane")
+ self.assertIsInstance(attendee, Attendee)
+
+ attendee = self.event.get_attendee("Doe, Jane")
+ self.assertIsInstance(attendee, Attendee)
+
+ self.assertRaises(ValueError, self.event.get_attendee_by_name, "Houdini, Harry")
+ self.assertRaises(ValueError, self.event.get_attendee, "Houdini, Harry")
+
+ def test_009_invalid_participant_status(self):
+ self.assertRaises(InvalidAttendeeParticipantStatusError, self.event.set_attendee_participant_status, "jane at doe.org", "INVALID")
+
+ def test_010_datetime_from_string(self):
+ self.assertRaises(InvalidEventDateError, self.event.set_start, "2012-05-23 11:58:00")
+
+ def test_011_attendee_equality(self):
+ self.assertEqual(self.event.get_attendee("jane at doe.org").get_email(), "jane at doe.org")
+
+if __name__ == '__main__':
+ unittest.main()
commit 8dbdba5cc919cefc5b4ab12f2b2cfeb14b2c4ae1
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed May 23 13:38:40 2012 +0100
Begin work on a set of unittests
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..b5e7094
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,4 @@
+import sys
+
+sys.path = [ '.', '..' ] + sys.path
+
diff --git a/tests/test-000.py b/tests/test-000.py
new file mode 100644
index 0000000..17e1c57
--- /dev/null
+++ b/tests/test-000.py
@@ -0,0 +1,23 @@
+import unittest
+
+class TestImports(unittest.TestCase):
+ def test_pykolab(self):
+ import pykolab
+
+ def test_pykolab_xml(self):
+ import pykolab.xml
+
+ def test_pykolab_xml_attendee(self):
+ from pykolab.xml import Attendee
+
+ def test_pykolab_xml_contact(self):
+ from pykolab.xml import Contact
+
+ def test_pykolab_xml_contactReference(self):
+ from pykolab.xml import ContactReference
+
+ def test_pykolab_xml_event(self):
+ from pykolab.xml import Event
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test-001.py b/tests/test-001.py
new file mode 100644
index 0000000..83f1c33
--- /dev/null
+++ b/tests/test-001.py
@@ -0,0 +1,18 @@
+import datetime
+import unittest
+
+from pykolab.xml import Attendee
+
+class TestEventXML(unittest.TestCase):
+ attendee = Attendee("jane at doe.org")
+
+ def test_001_minimal(self):
+ self.assertIsInstance(self.attendee.__str__(), basestring)
+
+ def test_002_set_name(self):
+ name = "Doe, Jane"
+ self.attendee.set_name(name)
+ self.assertEqual(self.attendee.get_name(), name)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test-002.py b/tests/test-002.py
new file mode 100644
index 0000000..3a6a863
--- /dev/null
+++ b/tests/test-002.py
@@ -0,0 +1,70 @@
+import datetime
+import unittest
+
+from pykolab.xml import Attendee
+from pykolab.xml import Event
+from pykolab.xml import EventIntegrityError
+from pykolab.xml import InvalidAttendeeParticipantStatusError
+from pykolab.xml import InvalidEventDateError
+
+class TestEventXML(unittest.TestCase):
+ event = Event()
+
+ def test_000_no_start_date(self):
+ self.assertRaises(EventIntegrityError, self.event.__str__)
+
+ def test_001_minimal(self):
+ self.event.set_start(datetime.datetime.now())
+ self.assertIsInstance(self.event.get_start(), datetime.datetime)
+ self.assertIsInstance(self.event.__str__(), basestring)
+
+ def test_002_attendees_list(self):
+ self.assertIsInstance(self.event.get_attendees(), list)
+
+ def test_003_attendees_no_default(self):
+ self.assertEqual(len(self.event.get_attendees()), 0)
+
+ def test_004_attendee_add(self):
+ self.event.add_attendee("john at doe.org")
+ self.assertIsInstance(self.event.get_attendees(), list)
+ self.assertEqual(len(self.event.get_attendees()), 1)
+
+ def test_005_attendee_add_name(self):
+ self.event.add_attendee("jane at doe.org", "Doe, Jane")
+ self.assertIsInstance(self.event.get_attendees(), list)
+ self.assertEqual(len(self.event.get_attendees()), 2)
+
+ def test_006_get_attendees(self):
+ self.assertEqual([x.get_email() for x in self.event.get_attendees()], ["john at doe.org", "jane at doe.org"])
+
+ def test_007_get_attendee_by_email(self):
+ attendee = self.event.get_attendee_by_email("jane at doe.org")
+ self.assertIsInstance(attendee, Attendee)
+
+ attendee = self.event.get_attendee("jane at doe.org")
+ self.assertIsInstance(attendee, Attendee)
+
+ self.assertRaises(ValueError, self.event.get_attendee_by_email, "nosuchattendee at invalid.domain")
+ self.assertRaises(ValueError, self.event.get_attendee, "nosuchattendee at invalid.domain")
+
+ def test_008_get_attendee_by_name(self):
+ attendee = self.event.get_attendee_by_name("Doe, Jane")
+ self.assertIsInstance(attendee, Attendee)
+
+ attendee = self.event.get_attendee("Doe, Jane")
+ self.assertIsInstance(attendee, Attendee)
+
+ self.assertRaises(ValueError, self.event.get_attendee_by_name, "Houdini, Harry")
+ self.assertRaises(ValueError, self.event.get_attendee, "Houdini, Harry")
+
+ def test_009_invalid_participant_status(self):
+ self.assertRaises(InvalidAttendeeParticipantStatusError, self.event.set_attendee_participant_status, "jane at doe.org", "INVALID")
+
+ def test_010_datetime_from_string(self):
+ self.assertRaises(InvalidEventDateError, self.event.set_start, "2012-05-23 11:58:00")
+
+ def test_011_attendee_equality(self):
+ self.assertEqual(self.event.get_attendee("jane at doe.org").get_email(), "jane at doe.org")
+
+if __name__ == '__main__':
+ unittest.main()
commit 90785cfbce1a9cd0f773b0ad28592fb1537e2a69
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Tue May 22 19:16:37 2012 +0100
Rebase on top of python-icalendar 3.0
diff --git a/pykolab/xml/contact_reference.py b/pykolab/xml/contact_reference.py
index e3fbcb2..0d6dec5 100644
--- a/pykolab/xml/contact_reference.py
+++ b/pykolab/xml/contact_reference.py
@@ -23,6 +23,9 @@ class ContactReference(kolabformat.ContactReference):
def get_name(self):
return self.name()
+ def set_cn(self, value):
+ self.setName(value)
+
def set_email(self, email):
kolabformat.ContactReference.__init__(self, email)
diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index f516ead..cc99c78 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -1,5 +1,7 @@
import datetime
import icalendar
+from icalendar import vDatetime
+from icalendar import vText
import kolabformat
import time
@@ -71,33 +73,45 @@ class Event(object):
for attr in list(set(event.singletons)):
if hasattr(self, 'get_ical_%s' % (attr.lower())):
exec("retval = self.get_ical_%s()" % (attr.lower()))
+
+ #print "as_string_itip()", attr, retval, type(retval)
+
if not retval == None and not retval == "":
+ print attr.lower()
event.add(attr.lower(), retval)
elif hasattr(self, 'get_%s' % (attr.lower())):
exec("retval = self.get_%s()" % (attr.lower()))
+
+ #print "as_string_itip()", attr, retval
+
if not retval == None and not retval == "":
- event.add(attr.lower(), retval)
+ event.add(attr.lower(), retval, encode=0)
#else:
- #print "no function for", attr.lower()
+ #print "(single) no function for", attr.lower()
# NOTE: Make sure to list(set()) or duplicates may arise
for attr in list(set(event.multiple)):
if hasattr(self, 'get_ical_%s' % (attr.lower())):
exec("retval = self.get_ical_%s()" % (attr.lower()))
+
+ print "as_string_itip()", attr, retval
+
if isinstance(retval, list) and not len(retval) == 0:
for _retval in retval:
- event.add(attr.lower(), _retval)
+ #print _retval.params
+ event.add(attr.lower(), _retval, encode=0)
elif hasattr(self, 'get_%s' % (attr.lower())):
exec("retval = self.get_%s()" % (attr.lower()))
+ print attr, retval
if isinstance(retval, list) and not len(retval) == 0:
for _retval in retval:
- event.add(attr.lower(), _retval)
+ event.add(attr.lower(), _retval, encode=0)
#else:
- #print "no function for", attr.lower()
+ #print "(multiple) no function for", attr.lower()
#event.add('attendee', self.get_attendees())
@@ -132,26 +146,20 @@ class Event(object):
# to fail substitution.
for attr in list(set(ical_event.required)):
if ical_event.has_key(attr):
- if hasattr(self, 'set_ical_%s' % (attr.lower())):
- exec("self.set_ical_%s(%r)" % (attr.lower(),ical_event.decoded(attr)))
- else:
- print attr, "exists but no function exists"
+ self.set_from_ical(attr.lower(), ical_event[attr])
# NOTE: Make sure to list(set()) or duplicates may arise
for attr in list(set(ical_event.singletons)):
if ical_event.has_key(attr):
- if hasattr(self, 'set_ical_%s' % (attr.lower())):
- exec("self.set_ical_%s(%r)" % (attr.lower(),ical_event.decoded(attr)))
- else:
- print attr, "exists but no function exists"
+ self.set_from_ical(attr.lower(), ical_event[attr])
# NOTE: Make sure to list(set()) or duplicates may arise
for attr in list(set(ical_event.multiple)):
if ical_event.has_key(attr):
- if hasattr(self, 'set_ical_%s' % (attr.lower())):
- exec("self.set_ical_%s(%r)" % (attr.lower(),ical_event.decoded(attr)))
- else:
- print attr, "exists but no function exists"
+ #if attr == "ATTENDEE":
+ #print ical_event.decoded(attr)
+
+ self.set_from_ical(attr.lower(), ical_event[attr])
def get_attendee_participant_status(self, attendee):
return attendee.get_participant_status()
@@ -251,13 +259,15 @@ class Event(object):
elif partstat == kolabformat.PartDelegated:
_partstat = "DELEGATED"
- _attendee = "RSVP=%s" % _rsvp
- _attendee += ";PARTSTAT=%s" % _partstat
- _attendee += ";ROLE=%s" % _role
- _attendee += ";MAILTO:%s" % contact.email()
+ _attendee = icalendar.vCalAddress("MAILTO:%s" % contact.email())
+ _attendee.params['RSVP'] = icalendar.vText(_rsvp)
+ _attendee.params['PARTSTAT'] = icalendar.vText(_partstat)
+ _attendee.params['ROLE'] = icalendar.vText(_role)
attendees.append(_attendee)
+ #print "get_ical_attendees()", attendees
+
return attendees
def get_ical_created(self):
@@ -279,20 +289,28 @@ class Event(object):
return self.get_start()
def get_ical_organizer(self):
- organizer = self.get_organizer()
- name = organizer.name()
+ contact = self.get_organizer()
+ organizer = icalendar.vCalAddress("MAILTO:%s" % contact.email())
+ name = contact.name()
- if not name:
- return "mailto:%s" % (organizer.email())
- else:
- return "CN=%s:mailto:%s" %(name, organizer.email())
+ if not name == None and not name == "":
+ organizer.params["CN"] = icalendar.vText(name)
+
+ return organizer
def get_ical_status(self):
status = self.event.status()
- for key in self.status_map.keys():
- if status == self.status_map[key]:
- return key
+ #print "get_ical_status()", status
+ #print self.status_map.keys()
+ #print self.status_map.values()
+ if status in self.status_map.keys():
+ return status
+
+ if status in self.status_map.values():
+ return [k for k, v in self.status_map.iteritems() if v == status][0]
+
+ #print "get_ical_status()", status
def get_organizer(self):
organizer = self.event.organizer()
@@ -303,6 +321,7 @@ class Event(object):
return self.event.priority()
def get_start(self):
+ #print "get_start()"
_datetime = self.event.start()
(
@@ -416,42 +435,63 @@ class Event(object):
kolabformat.cDateTime(year, month, day, hour, minute, second)
)
+ def set_from_ical(self, attr, value):
+ if attr == "dtend":
+ self.set_ical_dtend(value.dt)
+ elif attr == "dtstart":
+ self.set_ical_dtstart(value.dt)
+ elif attr == "status":
+ self.set_ical_status(value)
+ elif attr == "summary":
+ self.set_ical_summary(value)
+ elif attr == "priority":
+ self.set_ical_priority(value)
+ elif attr == "attendee":
+ self.set_ical_attendee(value)
+ elif attr == "organizer":
+ self.set_ical_organizer(value)
+ elif attr == "uid":
+ self.set_ical_uid(value)
+
+ else:
+ print "WARNING, no function for", attr
+
def set_ical_attendee(self, _attendee):
log.debug(_("set attendees from ical: %r") % (_attendee), level=9)
+ if isinstance(_attendee, basestring):
+ _attendee = [_attendee]
+
if isinstance(_attendee, list):
for attendee in _attendee:
- #print attendee
- rsvp = False
- role = None
- cn = None
- partstat = None
- address = None
- for param in attendee.split(';'):
- if (len(param.split('=')) > 1):
- exec("%s = %r" % (param.split('=')[0].lower(), param.split('=')[1]))
- #print "%s = %r" % (param.split('=')[0].lower(), param.split('=')[1])
- if (len(attendee.split(':')) > 1):
- address = attendee.split(':')[-1]
- #print address
-
- self.add_attendee(address, name=cn, rsvp=rsvp, role=role, participant_status=partstat)
- else:
- #print attendee
- rsvp = False
- role = None
- cn = None
- partstat = None
- address = None
- for param in _attendee.split(';'):
- if (len(param.split('=')) > 1):
- exec("%s = %r" % (param.split('=')[0].lower(), param.split('=')[1]))
- #print "%s = %r" % (param.split('=')[0].lower(), param.split('=')[1])
- if (len(_attendee.split(':')) > 1):
- address = _attendee.split(':')[-1]
- #print address
-
- self.add_attendee(address, name=cn, rsvp=rsvp, role=role, participant_status=partstat)
+ address = str(attendee).split(':')[-1]
+
+ if hasattr(attendee, 'params'):
+ params = attendee.params
+ else:
+ params = {}
+
+ if params.has_key('CN'):
+ name = params['CN']
+ else:
+ name = None
+
+ if params.has_key('ROLE'):
+ role = params['ROLE']
+ else:
+ role = None
+
+ if params.has_key('PARTSTAT'):
+ partstat = params['PARTSTAT']
+ else:
+ partstat = None
+
+ if params.has_key('RSVP'):
+ rsvp = params['RSVP']
+ else:
+ rsvp = None
+
+ self.add_attendee(address, name=name, rsvp=rsvp, role=role, participant_status=partstat)
def set_ical_dtend(self, dtend):
self.set_end(dtend)
@@ -463,23 +503,26 @@ class Event(object):
self.set_start(dtstart)
def set_ical_organizer(self, organizer):
+ address = str(organizer).split(':')[-1]
+
cn = None
- address = None
- #print organizer
- for param in organizer.split(':'):
- if (len(param.split('=')) > 1):
- exec("%s = %r" % (param.split('=')[0].lower(), param.split('=')[1]))
- #print "%s = %r" % (param.split('=')[0].lower(), param.split('=')[1])
- if (len(organizer.split(':')) > 1):
- address = organizer.split(':')[-1]
- #print address
- self.set_organizer(address, name=cn)
+ if hasattr(organizer, 'params'):
+ params = organizer.params
+ else:
+ params = {}
+
+ if params.has_key('CN'):
+ cn = params['CN']
+
+ self.set_organizer(str(address), name=cn)
def set_ical_priority(self, priority):
self.set_priority(priority)
def set_ical_status(self, status):
+ #print "set_ical_status()", status
+
# TODO: See which ones are actually valid for iTip
if status == "UNDEFINED":
_status = kolabformat.StatusUndefined
diff --git a/wallace/module_resources.py b/wallace/module_resources.py
index c9be1f1..52156d4 100644
--- a/wallace/module_resources.py
+++ b/wallace/module_resources.py
@@ -120,7 +120,7 @@ def execute(*args, **kw):
if not len(itip_events) > 0:
log.info(
_("Message is not an iTip message or does not contain any " + \
- "iTip.")
+ "(valid) iTip.")
)
accept(filepath)
@@ -200,7 +200,7 @@ def execute(*args, **kw):
if event_message.is_multipart():
for part in event_message.walk():
if part.get_content_type() == "application/calendar+xml":
- payload = part.get_payload()
+ payload = part.get_payload(decode=True)
event = pykolab.xml.event_from_string(payload)
for itip in itip_events:
@@ -209,34 +209,36 @@ def execute(*args, **kw):
log.debug(_(" event %r end: %r") % (event.get_uid(),event.get_end()), level=9)
_es = event.get_start()
- _is = itip['start']
+ _is = itip['start'].dt
- if type(_es) == 'datetime.date':
+ if type(_es) == 'datetime.date' or not hasattr(_es, 'hour'):
log.debug(_("_es is datetime.date"))
- if type(_is) == 'datetime.datetime':
- _is = datetime.date(_is.year, _is.month, _is.day)
- else:
- pass
- else:
- log.debug(_("_es is datetime.datetime"))
- if type(_is) == 'datetime.date':
- log.debug(_("_is is datetime.date"))
- _es = datetime.date(_es.year, _es.month, _es.day)
+ _es = datetime.datetime(_es.year, _es.month, _es.day, 0, 0, 0)
+
+ if type(_is) == 'datetime.date' or not hasattr(_is, 'hour'):
+ log.debug(_("_is is datetime.date"))
+ _is = datetime.datetime(_is.year, _is.month, _is.day, 0, 0, 0)
_ee = event.get_end()
- _ie = itip['end']
- if type(_ee) == 'datetime.date':
- if type(_ie) == 'datetime.datetime':
- _ie = datetime.date(_ie.year, _ie.month, _ie.day)
- else:
- pass
- else:
- if type(_ie) == 'datetime.date':
- _ee = datetime.date(_ee.year, _ee.month, _ee.day)
+ _ie = itip['end'].dt
+
+ if type(_ee) == 'datetime.date' or not hasattr(_ee, 'hour'):
+ log.debug(_("_ee is datetime.date"))
+ _ee = datetime.datetime(_ee.year, _ee.month, _ee.day, 0, 0, 0)
+
+ if type(_ie) == 'datetime.date' or not hasattr(_ie, 'hour'):
+ log.debug(_("_ie is datetime.date"))
+ _ie = datetime.datetime(_ie.year, _ie.month, _ie.day, 0, 0, 0)
+
+ log.debug(_("Raw event and itip data:"))
+ log.debug(_("_es: %r") %(_es))
+ log.debug(_("_is: %r") %(_is))
+ log.debug(_("_ee: %r") %(_ee))
+ log.debug(_("_ie: %r") %(_ie))
if _es < _is:
if _es <= _ie:
- if _ie <= _is:
+ if _ee <= _is:
conflict = False
else:
log.debug(_("Event %r ends later than invitation") % (event.get_uid()), level=9)
@@ -373,9 +375,7 @@ def itip_events_from_message(message):
cal = icalendar.Calendar.from_string(itip_payload)
else:
log.error(_("Could not read iTip from message."))
- accept(filepath)
-
- return
+ return []
for c in cal.walk():
itip = {}
@@ -391,17 +391,22 @@ def itip_events_from_message(message):
# - TODO: recurrence rules (if any)
# Where are these stored actually?
#
- itip['start'] = c.decoded('dtstart')
if c.has_key('dtend'):
- itip['end'] = c.decoded('dtend')
+ itip['start'] = c['dtstart']
+ else:
+ log.error(_("iTip event without a start"))
+ return []
+
+ if c.has_key('dtend'):
+ itip['end'] = c['dtend']
if c.has_key('duration'):
- itip['duration'] = c.decoded('duration')
- itip['organizer'] = c.decoded('organizer')
- itip['attendees'] = c.decoded('attendee')
+ itip['duration'] = c['duration']
+ itip['organizer'] = c['organizer']
+ itip['attendees'] = c['attendee']
if c.has_key('resources'):
- itip['resources'] = c.decoded('resources')
+ itip['resources'] = c['resources']
itip['raw'] = itip_payload
- itip['xml'] = event_from_ical(c.__str__())
+ itip['xml'] = event_from_ical(c.to_ical())
itip_events.append(itip)
else:
log.error(
commit fb1a50024e454c9c78b71990bf986e9dcc0ac606
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Tue May 22 19:14:06 2012 +0100
Add a sub-package pykolab-xml (requiring libkolabxml, required by wallace)
diff --git a/pykolab.spec.in b/pykolab.spec.in
index 75adfc0..fed123a 100644
--- a/pykolab.spec.in
+++ b/pykolab.spec.in
@@ -47,6 +47,18 @@ Requires: kolab-cli = %{version}-%{release}
Cyrus IMAP Telemetry logging handling capabilities for Kolab Groupware
##
+## Kolab XML
+##
+%package xml
+Summary: Kolab XML format wrapper for %{name}
+Group: Applications/System
+Requires: %{name} = %{version}-%{release}
+Requires: libkolabxml >= 0.5
+
+%description xml
+Kolab Format XML bindings wrapper for %{name}
+
+##
## Kolab CLI
##
%package -n kolab-cli
@@ -109,6 +121,8 @@ Group: Applications/System
Requires: %{name} = %{version}-%{release}
Requires: python-sqlalchemy
Requires: MySQL-python
+Requires: python-icalendar >= 3.0
+Requires: %{name}-xml = %{version}-%{release}
%description -n wallace
This is the Kolab Content Filter, with plugins
@@ -278,6 +292,12 @@ rm -rf %{buildroot}
%{python_sitelib}/pykolab/telemetry.*
%{python_sitelib}/pykolab/cli/telemetry/
+%files xml
+%dir %{python_sitelib}/pykolab/xml
+%{python_sitelib}/pykolab/xml/*.py
+%{python_sitelib}/pykolab/xml/*.pyc
+%{python_sitelib}/pykolab/xml/*.pyo
+
%files -n kolab-cli
%defattr(-,root,root,-)
%exclude %{_bindir}/kolab-test
commit 6d0e9317c91f98fac955356563363c9cfa0d8a9b
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Tue May 22 19:13:53 2012 +0100
Add xml/ to dist
diff --git a/pykolab/Makefile.am b/pykolab/Makefile.am
index 937560c..d94cec9 100644
--- a/pykolab/Makefile.am
+++ b/pykolab/Makefile.am
@@ -61,3 +61,6 @@ pykolab_setup_PYTHON = \
setup/setup_zpush.py \
setup/__init__.py
+pykolab_xmldir = $(pythondir)/$(PACKAGE)/xml
+pykolab_xml_PYTHON = \
+ $(wildcard xml/*.py)
commit 1c1b580e9c9e9f98eb6a5faf25e061cbf0d413e4
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Tue May 22 19:13:26 2012 +0100
Add default for setting sharedfolder_filter
diff --git a/conf/kolab.conf b/conf/kolab.conf
index 0e9d606..1608a75 100644
--- a/conf/kolab.conf
+++ b/conf/kolab.conf
@@ -79,6 +79,7 @@ kolab_group_filter = (|(objectclass=kolabgroupofuniquenames)(objectclass=kolabgr
; Same again
sharedfolder_base_dn = ou=Shared Folders,%(base_dn)s
+sharedfolder_filter = (objectclass=kolabsharedfolder)
; Same again. Resources live in a different OU structure or;
;
More information about the commits
mailing list