summaryrefslogtreecommitdiffstats
path: root/pykolab/xml/utils.py
diff options
context:
space:
mode:
authorThomas Bruederli <bruederli@kolabsys.com>2014-08-22 15:12:45 -0400
committerThomas Bruederli <bruederli@kolabsys.com>2014-08-22 15:12:45 -0400
commitfd68e0f4527f27fb406861036108d44cf500612e (patch)
treea4b7ed8a2939088c8d886635221ede79864f6eb0 /pykolab/xml/utils.py
parent3231cd8408132d3f7ddb3ac1626a049474101101 (diff)
downloadpykolab-fd68e0f4527f27fb406861036108d44cf500612e.tar.gz
List event/task properties changes in update notification mails (#3447)
Diffstat (limited to 'pykolab/xml/utils.py')
-rw-r--r--pykolab/xml/utils.py130
1 files changed, 128 insertions, 2 deletions
diff --git a/pykolab/xml/utils.py b/pykolab/xml/utils.py
index 35d7578..2fe82d2 100644
--- a/pykolab/xml/utils.py
+++ b/pykolab/xml/utils.py
@@ -4,6 +4,9 @@ import kolabformat
from dateutil.tz import tzlocal
from collections import OrderedDict
+from pykolab.translate import _
+from pykolab.translate import N_
+
def to_dt(dt):
"""
@@ -113,6 +116,113 @@ def to_cdatetime(_datetime, with_timezone=True, as_utc=False):
return _cdatetime
+property_labels = {
+ "name": N_("Name"),
+ "summary": N_("Summary"),
+ "location": N_("Location"),
+ "description": N_("Description"),
+ "url": N_("URL"),
+ "status": N_("Status"),
+ "priority": N_("Priority"),
+ "attendee": N_("Attendee"),
+ "start": N_("Start"),
+ "end": N_("End"),
+ "due": N_("Due"),
+ "rrule": N_("Repeat"),
+ "exdate": N_("Repeat Exception"),
+ "organizer": N_("Organizer"),
+ "attach": N_("Attachment"),
+ "alarm": N_("Alarm"),
+ "classification": N_("Classification"),
+ "percent-complete": N_("Progress")
+}
+
+def property_label(propname):
+ """
+ Return a localized name for the given object property
+ """
+ return _(property_labels[propname]) if property_labels.has_key(propname) else _(propname)
+
+
+def property_to_string(propname, value):
+ """
+ Render a human readable string for the given object property
+ """
+ date_format = _("%Y-%m-%d")
+ time_format = _("%H:%M (%Z)")
+ date_time_format = date_format + " " + time_format
+ maxlen = 50
+
+ if isinstance(value, datetime.datetime):
+ return value.strftime(date_time_format)
+ elif isinstance(value, datetime.date):
+ return value.strftime(date_format)
+ elif isinstance(value, int):
+ return str(value)
+ elif isinstance(value, str):
+ if len(value) > maxlen:
+ return value[:maxlen].rsplit(' ', 1)[0] + '...'
+ return value
+ elif isinstance(value, object) and hasattr(value, 'to_dict'):
+ value = value.to_dict()
+
+ if isinstance(value, dict):
+ if propname == 'attendee':
+ from . import attendee
+ name = value['name'] if value.has_key('name') and not value['name'] == '' else value['email']
+ return "%s, %s" % (name, attendee.participant_status_label(value['partstat']))
+
+ elif propname == 'organizer':
+ return value['name'] if value.has_key('name') and not value['name'] == '' else value['email']
+
+ elif propname == 'rrule':
+ from . import recurrence_rule
+ rrule = recurrence_rule.frequency_label(value['frequency']) % (value['interval'])
+ if value.has_key('count') and value['count'] > 0:
+ rrule += " " + _("for %d times") % (value['count'])
+ elif value.has_key('until') and (isinstance(value['until'], datetime.datetime) or isinstance(value['until'], datetime.date)):
+ rrule += " " + _("until %s") % (value['until'].strftime(date_format))
+ return rrule
+
+ elif propname == 'alarm':
+ alarm_type_labels = {
+ 'DISPLAY': _("Display message"),
+ 'EMAIL': _("Send email"),
+ 'AUDIO': _("Play sound")
+ }
+ alarm = alarm_type_labels.get(value['action'], "")
+ if isinstance(value['trigger'], datetime.datetime):
+ alarm += " @ " + property_to_string('trigger', value['trigger'])
+ else:
+ rel = _("%s after") if value['trigger']['related'] == 'END' else _("%s before")
+ offsets = []
+ try:
+ from icalendar import vDuration
+ duration = vDuration.from_ical(value['trigger']['value'].strip('-'))
+ except:
+ return None
+
+ if duration.days:
+ offsets.append(_("%d day(s)") % (duration.days))
+ if duration.seconds:
+ hours = duration.seconds // 3600
+ minutes = duration.seconds % 3600 // 60
+ seconds = duration.seconds % 60
+ if hours:
+ offsets.append(_("%d hour(s)") % (hours))
+ if minutes or (hours and seconds):
+ offsets.append(_("%d minute(s)") % (minutes))
+ if len(offsets):
+ alarm += " " + rel % (", ".join(offsets))
+
+ return alarm
+
+ elif propname == 'attach':
+ return value['label'] if value.has_key('label') else value['fmttype']
+
+ return None
+
+
def compute_diff(a, b, reduced=False):
"""
List the differences between two given dicts
@@ -137,7 +247,7 @@ def compute_diff(a, b, reduced=False):
while index < length:
aai = aa[index] if index < len(aa) else None
bbi = bb[index] if index < len(bb) else None
- if not aai == bbi:
+ if not compare_values(aai, bbi):
if reduced:
(old, new) = reduce_properties(aai, bbi)
else:
@@ -146,7 +256,7 @@ def compute_diff(a, b, reduced=False):
index += 1
# the two properties differ
- elif not aa.__class__ == bb.__class__ or not aa == bb:
+ elif not compare_values(aa, bb):
if reduced:
(old, new) = reduce_properties(aa, bb)
else:
@@ -156,6 +266,22 @@ def compute_diff(a, b, reduced=False):
return diff
+def compare_values(aa, bb):
+ ignore_keys = ['rsvp']
+ if not aa.__class__ == bb.__class__:
+ return False
+
+ if isinstance(aa, dict) and isinstance(bb, dict):
+ aa = dict(aa)
+ bb = dict(bb)
+ # ignore some properties for comparison
+ for k in ignore_keys:
+ aa.pop(k, None)
+ bb.pop(k, None)
+
+ return aa == bb
+
+
def reduce_properties(aa, bb):
"""
Compares two given structs and removes equal values in bb