1.1 --- a/imiptools/client.py Sun Feb 07 23:35:20 2016 +0100
1.2 +++ b/imiptools/client.py Mon Feb 08 00:14:53 2016 +0100
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 Common calendar client utilities.
1.6
1.7 -Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This program is free software; you can redistribute it and/or modify it under
1.11 the terms of the GNU General Public License as published by the Free Software
1.12 @@ -40,17 +40,19 @@
1.13 default_window_size = 100
1.14 organiser_methods = "ADD", "CANCEL", "DECLINECOUNTER", "PUBLISH", "REQUEST"
1.15
1.16 - def __init__(self, user, messenger=None, store=None, publisher=None, preferences_dir=None):
1.17 + def __init__(self, user, messenger=None, store=None, publisher=None, journal=None,
1.18 + preferences_dir=None):
1.19
1.20 """
1.21 Initialise a calendar client with the current 'user', plus any
1.22 - 'messenger', 'store' and 'publisher' objects, indicating any specific
1.23 - 'preferences_dir'.
1.24 + 'messenger', 'store', 'publisher' and 'journal' objects, indicating any
1.25 + specific 'preferences_dir'.
1.26 """
1.27
1.28 self.user = user
1.29 self.messenger = messenger
1.30 self.store = store or imip_store.FileStore()
1.31 + self.journal = journal or imip_store.FileJournal()
1.32
1.33 try:
1.34 self.publisher = publisher or imip_store.FilePublisher()
1.35 @@ -71,6 +73,9 @@
1.36 def get_publisher(self):
1.37 return self.publisher
1.38
1.39 + def get_journal(self):
1.40 + return self.journal
1.41 +
1.42 # Store-related methods.
1.43
1.44 def acquire_lock(self):
1.45 @@ -213,23 +218,6 @@
1.46
1.47 # Common operations on calendar data.
1.48
1.49 - def update_senders(self, obj=None):
1.50 -
1.51 - """
1.52 - Update sender details in 'obj', or the current object if not indicated,
1.53 - removing SENT-BY attributes for attendees other than the current user if
1.54 - those attributes give the URI of the calendar system.
1.55 - """
1.56 -
1.57 - obj = obj or self.obj
1.58 - calendar_uri = self.messenger and get_uri(self.messenger.sender)
1.59 - for attendee, attendee_attr in uri_items(obj.get_items("ATTENDEE")):
1.60 - if attendee != self.user:
1.61 - if attendee_attr.get("SENT-BY") == calendar_uri:
1.62 - del attendee_attr["SENT-BY"]
1.63 - else:
1.64 - attendee_attr["SENT-BY"] = calendar_uri
1.65 -
1.66 def update_sender(self, attr):
1.67
1.68 "Update the SENT-BY attribute of the 'attr' sender metadata."
1.69 @@ -237,21 +225,6 @@
1.70 if self.messenger and self.messenger.sender != get_address(self.user):
1.71 attr["SENT-BY"] = get_uri(self.messenger.sender)
1.72
1.73 - def get_sending_attendee(self):
1.74 -
1.75 - "Return the attendee who sent the current object."
1.76 -
1.77 - # Search for the sender of the message or the calendar system address.
1.78 -
1.79 - senders = self.senders or self.messenger and [self.messenger.sender] or []
1.80 -
1.81 - for attendee, attendee_attr in uri_items(self.obj.get_items("ATTENDEE")):
1.82 - if get_address(attendee) in senders or \
1.83 - get_address(attendee_attr.get("SENT-BY")) in senders:
1.84 - return get_uri(attendee)
1.85 -
1.86 - return None
1.87 -
1.88 def get_periods(self, obj, explicit_only=False):
1.89
1.90 """
1.91 @@ -371,31 +344,13 @@
1.92
1.93 return methods, responses
1.94
1.95 - def get_unscheduled_parts(self, periods):
1.96 -
1.97 - "Return message parts describing unscheduled 'periods'."
1.98 -
1.99 - unscheduled_parts = []
1.100 -
1.101 - if periods:
1.102 - obj = self.obj.copy()
1.103 - obj.remove_all(["RRULE", "RDATE", "DTSTART", "DTEND", "DURATION"])
1.104 -
1.105 - for p in periods:
1.106 - if not p.origin:
1.107 - continue
1.108 - obj["RECURRENCE-ID"] = obj["DTSTART"] = [(format_datetime(p.get_start()), p.get_start_attr())]
1.109 - obj["DTEND"] = [(format_datetime(p.get_end()), p.get_end_attr())]
1.110 - unscheduled_parts.append(obj.to_part("CANCEL"))
1.111 -
1.112 - return unscheduled_parts
1.113 -
1.114 class ClientForObject(Client):
1.115
1.116 "A client maintaining a specific object."
1.117
1.118 - def __init__(self, obj, user, messenger=None, store=None, publisher=None, preferences_dir=None):
1.119 - Client.__init__(self, user, messenger, store, publisher, preferences_dir)
1.120 + def __init__(self, obj, user, messenger=None, store=None, publisher=None,
1.121 + journal=None, preferences_dir=None):
1.122 + Client.__init__(self, user, messenger, store, publisher, journal, preferences_dir)
1.123 self.set_object(obj)
1.124
1.125 def set_object(self, obj):
1.126 @@ -433,6 +388,59 @@
1.127
1.128 return get_uri(self.obj.get_value("ORGANIZER")) == self.user
1.129
1.130 + # Common operations on calendar data.
1.131 +
1.132 + def update_senders(self, obj=None):
1.133 +
1.134 + """
1.135 + Update sender details in 'obj', or the current object if not indicated,
1.136 + removing SENT-BY attributes for attendees other than the current user if
1.137 + those attributes give the URI of the calendar system.
1.138 + """
1.139 +
1.140 + obj = obj or self.obj
1.141 + calendar_uri = self.messenger and get_uri(self.messenger.sender)
1.142 + for attendee, attendee_attr in uri_items(obj.get_items("ATTENDEE")):
1.143 + if attendee != self.user:
1.144 + if attendee_attr.get("SENT-BY") == calendar_uri:
1.145 + del attendee_attr["SENT-BY"]
1.146 + else:
1.147 + attendee_attr["SENT-BY"] = calendar_uri
1.148 +
1.149 + def get_sending_attendee(self):
1.150 +
1.151 + "Return the attendee who sent the current object."
1.152 +
1.153 + # Search for the sender of the message or the calendar system address.
1.154 +
1.155 + senders = self.senders or self.messenger and [self.messenger.sender] or []
1.156 +
1.157 + for attendee, attendee_attr in uri_items(self.obj.get_items("ATTENDEE")):
1.158 + if get_address(attendee) in senders or \
1.159 + get_address(attendee_attr.get("SENT-BY")) in senders:
1.160 + return get_uri(attendee)
1.161 +
1.162 + return None
1.163 +
1.164 + def get_unscheduled_parts(self, periods):
1.165 +
1.166 + "Return message parts describing unscheduled 'periods'."
1.167 +
1.168 + unscheduled_parts = []
1.169 +
1.170 + if periods:
1.171 + obj = self.obj.copy()
1.172 + obj.remove_all(["RRULE", "RDATE", "DTSTART", "DTEND", "DURATION"])
1.173 +
1.174 + for p in periods:
1.175 + if not p.origin:
1.176 + continue
1.177 + obj["RECURRENCE-ID"] = obj["DTSTART"] = [(format_datetime(p.get_start()), p.get_start_attr())]
1.178 + obj["DTEND"] = [(format_datetime(p.get_end()), p.get_end_attr())]
1.179 + unscheduled_parts.append(obj.to_part("CANCEL"))
1.180 +
1.181 + return unscheduled_parts
1.182 +
1.183 # Object update methods.
1.184
1.185 def update_recurrenceid(self):