1.1 --- a/imiptools/content.py Wed Jan 28 00:32:44 2015 +0100
1.2 +++ b/imiptools/content.py Wed Jan 28 01:04:24 2015 +0100
1.3 @@ -22,9 +22,11 @@
1.4
1.5 from datetime import datetime, timedelta
1.6 from email.mime.text import MIMEText
1.7 +from imiptools.config import MANAGER_PATH, MANAGER_URL
1.8 from imiptools.dates import *
1.9 from imiptools.period import have_conflict, insert_period, remove_period
1.10 from pytz import timezone
1.11 +from socket import gethostname
1.12 from vCalendar import parse, ParseError, to_dict
1.13 from vRecurrence import get_parameters, get_rule
1.14 import email.utils
1.15 @@ -277,14 +279,14 @@
1.16 # Dispatch to a handler and obtain any response.
1.17
1.18 handler = cls(details, senders, recipient, messenger)
1.19 - result = methods[method](handler)()
1.20 + results = methods[method](handler)()
1.21
1.22 # Aggregate responses for a single message.
1.23
1.24 - if result:
1.25 - response_method, part = result
1.26 - outgoing = method != response_method
1.27 - all_results.append((outgoing, part))
1.28 + if results:
1.29 + for result in results:
1.30 + outgoing, part = result
1.31 + all_results.append((outgoing, part))
1.32
1.33 return all_results
1.34
1.35 @@ -336,6 +338,15 @@
1.36 finally:
1.37 out.close()
1.38
1.39 +# References to the Web interface.
1.40 +
1.41 +def get_manager_url():
1.42 + url_base = MANAGER_URL or "http://%s/" % gethostname()
1.43 + return "%s/%s" % (url_base.rstrip("/"), MANAGER_PATH.lstrip("/"))
1.44 +
1.45 +def get_object_url(uid):
1.46 + return "%s/%s" % (get_manager_url().rstrip("/"), uid)
1.47 +
1.48 class Handler:
1.49
1.50 "General handler support."
1.51 @@ -363,6 +374,19 @@
1.52 except OSError:
1.53 self.publisher = None
1.54
1.55 + def wrap(self, text, link=True):
1.56 +
1.57 + "Wrap any valid message for passing to the recipient."
1.58 +
1.59 + texts = []
1.60 + texts.append(text)
1.61 + if link:
1.62 + texts.append("If your mail program cannot handle this "
1.63 + "message, you may view the details here:\n\n%s" %
1.64 + get_object_url(self.uid))
1.65 +
1.66 + return [(False, MIMEText("\n".join(texts)))]
1.67 +
1.68 # Access to calendar structures and other data.
1.69
1.70 def get_items(self, name, all=True):
2.1 --- a/imiptools/handlers/common.py Wed Jan 28 00:32:44 2015 +0100
2.2 +++ b/imiptools/handlers/common.py Wed Jan 28 01:04:24 2015 +0100
2.3 @@ -36,7 +36,7 @@
2.4
2.5 # Return the reply.
2.6
2.7 - return "REPLY", to_part("REPLY", calendar)
2.8 + return [(True, to_part("REPLY", calendar))]
2.9
2.10 def make_freebusy_to_publish(self, from_organiser=True):
2.11
2.12 @@ -50,7 +50,7 @@
2.13
2.14 # Return a published object.
2.15
2.16 - return "PUBLISH", to_part("PUBLISH", calendar)
2.17 + return [(True, to_part("PUBLISH", calendar))]
2.18
2.19 def make_freebusy(self, from_organiser=True, publish=False):
2.20
3.1 --- a/imiptools/handlers/person.py Wed Jan 28 00:32:44 2015 +0100
3.2 +++ b/imiptools/handlers/person.py Wed Jan 28 01:04:24 2015 +0100
3.3 @@ -19,21 +19,11 @@
3.4 this program. If not, see <http://www.gnu.org/licenses/>.
3.5 """
3.6
3.7 -from email.mime.text import MIMEText
3.8 -from imiptools.config import MANAGER_PATH, MANAGER_URL
3.9 from imiptools.content import Handler, get_address, get_uri, to_part, uri_dict, uri_items
3.10 from imiptools.handlers.common import CommonFreebusy
3.11 from imiptools.profile import Preferences
3.12 -from socket import gethostname
3.13 from vCalendar import to_node
3.14
3.15 -def get_manager_url():
3.16 - url_base = MANAGER_URL or "http://%s/" % gethostname()
3.17 - return "%s/%s" % (url_base.rstrip("/"), MANAGER_PATH.lstrip("/"))
3.18 -
3.19 -def get_object_url(uid):
3.20 - return "%s/%s" % (get_manager_url().rstrip("/"), uid)
3.21 -
3.22 class PersonHandler(Handler):
3.23
3.24 "Handling mechanisms specific to people."
3.25 @@ -134,19 +124,6 @@
3.26 for sender, sender_attr in uri_items(self.get_items(from_organiser and "ORGANIZER" or "ATTENDEE")):
3.27 self.store.set_freebusy_for_other(get_uri(self.recipient), freebusy, sender)
3.28
3.29 - def wrap(self, method, text, from_organiser=True, link=True):
3.30 -
3.31 - "Wrap any valid message and pass it on to the recipient."
3.32 -
3.33 - texts = []
3.34 - texts.append(text)
3.35 - if link:
3.36 - texts.append("If your mail program cannot handle this "
3.37 - "message, you may view the details here:\n\n%s" %
3.38 - get_object_url(self.uid))
3.39 -
3.40 - return method, MIMEText("\n".join(texts))
3.41 -
3.42 class Event(PersonHandler):
3.43
3.44 "An event handler."
3.45 @@ -155,63 +132,54 @@
3.46
3.47 # NOTE: Queue a suggested modification to any active event.
3.48
3.49 - # The message is now wrapped and passed on to the recipient.
3.50 -
3.51 - return "ADD", MIMEText("An addition to an event has been received.")
3.52 + return self.wrap("An addition to an event has been received.", link=False)
3.53
3.54 def cancel(self):
3.55
3.56 "Queue a cancellation of any active event."
3.57
3.58 self._record_and_deliver("VEVENT", from_organiser=True, queue=False, cancel=True)
3.59 - return self.wrap("CANCEL", "A cancellation has been received.", from_organiser=True, link=True)
3.60 + return self.wrap("A cancellation has been received.", link=False)
3.61
3.62 def counter(self):
3.63
3.64 # NOTE: Queue a suggested modification to any active event.
3.65
3.66 - # The message is now wrapped and passed on to the recipient.
3.67 -
3.68 - return "COUNTER", MIMEText("A counter proposal has been received.")
3.69 + return self.wrap("A counter proposal has been received.", link=False)
3.70
3.71 def declinecounter(self):
3.72
3.73 # NOTE: Queue a suggested modification to any active event.
3.74
3.75 - # The message is now wrapped and passed on to the recipient.
3.76 -
3.77 - return "DECLINECOUNTER", MIMEText("A declining counter proposal has been received.")
3.78 + return self.wrap("A declining counter proposal has been received.", link=False)
3.79
3.80 def publish(self):
3.81
3.82 "Register details of any relevant event."
3.83
3.84 self._record_and_deliver("VEVENT", from_organiser=True, queue=False)
3.85 - return self.wrap("PUBLISH", "Details of an event have been received.", from_organiser=True, link=True)
3.86 + return self.wrap("Details of an event have been received.")
3.87
3.88 def refresh(self):
3.89
3.90 "Update details of any active event."
3.91
3.92 self._record_and_deliver("VEVENT", from_organiser=True, queue=False)
3.93 - return self.wrap("REFRESH", "An event update has been received.", from_organiser=True, link=True)
3.94 + return self.wrap("An event update has been received.")
3.95
3.96 def reply(self):
3.97
3.98 "Record replies and notify the recipient."
3.99
3.100 self._record_and_deliver("VEVENT", from_organiser=False, queue=False)
3.101 - return self.wrap("REPLY", "A reply has been received.", from_organiser=False, link=True)
3.102 + return self.wrap("A reply has been received.")
3.103
3.104 def request(self):
3.105
3.106 "Hold requests and notify the recipient."
3.107
3.108 self._record_and_deliver("VEVENT", from_organiser=True, queue=True)
3.109 -
3.110 - # The message is now wrapped and passed on to the recipient.
3.111 -
3.112 - return "REQUEST", MIMEText("A request has been queued and can be viewed here: %s" % get_object_url(self.uid))
3.113 + return self.wrap("A request has been received.")
3.114
3.115 class Freebusy(PersonHandler, CommonFreebusy):
3.116
3.117 @@ -227,7 +195,7 @@
3.118
3.119 preferences = Preferences(get_uri(self.recipient))
3.120 if preferences.get("freebusy_messages") == "notify":
3.121 - return self.wrap("PUBLISH", "A free/busy update has been received.", from_organiser=True, link=False)
3.122 + return self.wrap("A free/busy update has been received.", link=False)
3.123
3.124 def reply(self):
3.125
3.126 @@ -239,7 +207,7 @@
3.127
3.128 preferences = Preferences(get_uri(self.recipient))
3.129 if preferences.get("freebusy_messages") == "notify":
3.130 - return self.wrap("REPLY", "A reply to a free/busy request has been received.", from_organiser=False, link=False)
3.131 + return self.wrap("A reply to a free/busy request has been received.", link=False)
3.132
3.133 def request(self):
3.134
3.135 @@ -262,26 +230,20 @@
3.136
3.137 # NOTE: Queue a suggested modification to any active entry.
3.138
3.139 - # The message is now wrapped and passed on to the recipient.
3.140 -
3.141 - return "ADD", MIMEText("An addition to a journal entry has been received.")
3.142 + return self.wrap("An addition to a journal entry has been received.", link=False)
3.143
3.144 def cancel(self):
3.145
3.146 # NOTE: Queue a suggested modification to any active entry.
3.147
3.148 - # The message is now wrapped and passed on to the recipient.
3.149 -
3.150 - return "CANCEL", MIMEText("A cancellation has been received.")
3.151 + return self.wrap("A cancellation has been received.", link=False)
3.152
3.153 def publish(self):
3.154
3.155 # NOTE: Register details of any relevant entry.
3.156
3.157 - # The message is now wrapped and passed on to the recipient.
3.158 -
3.159 self._record_and_deliver("VJOURNAL", from_organiser=True, queue=False)
3.160 - return self.wrap("PUBLISH", "Details of a journal entry have been received.", from_organiser=True, link=False)
3.161 + return self.wrap("Details of a journal entry have been received.")
3.162
3.163 class Todo(PersonHandler):
3.164
3.165 @@ -291,64 +253,53 @@
3.166
3.167 # NOTE: Queue a suggested modification to any active item.
3.168
3.169 - # The message is now wrapped and passed on to the recipient.
3.170 -
3.171 - return "ADD", MIMEText("An addition to an item has been received.")
3.172 + return self.wrap("An addition to an item has been received.", link=False)
3.173
3.174 def cancel(self):
3.175
3.176 # NOTE: Queue a suggested modification to any active item.
3.177
3.178 - # The message is now wrapped and passed on to the recipient.
3.179 -
3.180 - return "CANCEL", MIMEText("A cancellation has been received.")
3.181 + return self.wrap("A cancellation has been received.", link=False)
3.182
3.183 def counter(self):
3.184
3.185 # NOTE: Queue a suggested modification to any active item.
3.186
3.187 - # The message is now wrapped and passed on to the recipient.
3.188 -
3.189 - return "COUNTER", MIMEText("A counter proposal has been received.")
3.190 + return self.wrap("A counter proposal has been received.", link=False)
3.191
3.192 def declinecounter(self):
3.193
3.194 # NOTE: Queue a suggested modification to any active item.
3.195
3.196 - # The message is now wrapped and passed on to the recipient.
3.197 -
3.198 - return "DECLINECOUNTER", MIMEText("A declining counter proposal has been received.")
3.199 + return self.wrap("A declining counter proposal has been received.", link=False)
3.200
3.201 def publish(self):
3.202
3.203 "Register details of any relevant item."
3.204
3.205 self._record_and_deliver("VTODO", from_organiser=True, queue=False)
3.206 - return self.wrap("PUBLISH", "Details of an item have been received.", from_organiser=True, link=True)
3.207 + return self.wrap("Details of an item have been received.")
3.208
3.209 def refresh(self):
3.210
3.211 "Update details of any active item."
3.212
3.213 self._record_and_deliver("VTODO", from_organiser=True, queue=False)
3.214 - return self.wrap("REFRESH", "An item update has been received.", from_organiser=True, link=True)
3.215 + return self.wrap("An item update has been received.")
3.216
3.217 def reply(self):
3.218
3.219 "Record replies and notify the recipient."
3.220
3.221 self._record_and_deliver("VTODO", from_organiser=False, queue=False)
3.222 - return self.wrap("REPLY", "A reply has been received.", from_organiser=False, link=True)
3.223 + return self.wrap("A reply has been received.")
3.224
3.225 def request(self):
3.226
3.227 "Hold requests and notify the recipient."
3.228
3.229 self._record_and_deliver("VTODO", from_organiser=True, queue=True)
3.230 -
3.231 - # The message is now wrapped and passed on to the recipient.
3.232 -
3.233 - return "REQUEST", MIMEText("A request has been queued.")
3.234 + return self.wrap("A request has been received.")
3.235
3.236 # Handler registry.
3.237