1.1 --- a/imiptools/data.py Mon Apr 06 00:38:24 2015 +0200
1.2 +++ b/imiptools/data.py Mon Apr 06 00:39:51 2015 +0200
1.3 @@ -377,15 +377,17 @@
1.4
1.5 "A period with origin information from the object."
1.6
1.7 - def __init__(self, start, end, origin):
1.8 + def __init__(self, start, end, origin, start_attr=None, end_attr=None):
1.9 Period.__init__(self, start, end)
1.10 self.origin = origin
1.11 + self.start_attr = start_attr
1.12 + self.end_attr = end_attr
1.13
1.14 def as_tuple(self):
1.15 - return self.start, self.end, self.origin
1.16 + return self.start, self.end, self.origin, self.start_attr, self.end_attr
1.17
1.18 def __repr__(self):
1.19 - return "RecurringPeriod(%r, %r, %r)" % (self.start, self.end, self.origin)
1.20 + return "RecurringPeriod(%r, %r, %r, %r, %r)" % (self.start, self.end, self.origin, self.start_attr, self.end_attr)
1.21
1.22 def get_periods(obj, tzid, window_end, inclusive=False):
1.23
1.24 @@ -414,7 +416,7 @@
1.25 tzid = get_tzid(dtstart_attr, dtend_attr) or tzid
1.26
1.27 if not rrule:
1.28 - periods = [RecurringPeriod(dtstart, dtend, "DTSTART")]
1.29 + periods = [RecurringPeriod(dtstart, dtend, "DTSTART", dtstart_attr, dtend_attr)]
1.30 else:
1.31 # Recurrence rules create multiple instances to be checked.
1.32 # Conflicts may only be assessed within a period defined by policy
1.33 @@ -432,19 +434,17 @@
1.34
1.35 # Add recurrence dates.
1.36
1.37 - periods = set(periods)
1.38 - rdates = obj.get_date_values("RDATE", tzid)
1.39 + rdates = obj.get_date_value_items("RDATE", tzid)
1.40
1.41 if rdates:
1.42 - for rdate in rdates:
1.43 + for rdate, rdate_attr in rdates:
1.44 if isinstance(rdate, tuple):
1.45 - periods.add(RecurringPeriod(rdate[0], rdate[1], "RDATE"))
1.46 + periods.append(RecurringPeriod(rdate[0], rdate[1], "RDATE", rdate_attr))
1.47 else:
1.48 - periods.add(RecurringPeriod(rdate, rdate + duration, "RDATE"))
1.49 + periods.append(RecurringPeriod(rdate, rdate + duration, "RDATE", rdate_attr))
1.50
1.51 # Return a sorted list of the periods.
1.52
1.53 - periods = list(periods)
1.54 periods.sort(cmp=compare_periods(tzid))
1.55
1.56 # Exclude exception dates.
2.1 --- a/imipweb/event.py Mon Apr 06 00:38:24 2015 +0200
2.2 +++ b/imipweb/event.py Mon Apr 06 00:39:51 2015 +0200
2.3 @@ -182,16 +182,25 @@
2.4 def handle_all_period_controls(self):
2.5
2.6 """
2.7 - Handle datetime controls for a particular period, where 'index' may be
2.8 - used to indicate a recurring period, or the main start and end datetimes
2.9 - are handled.
2.10 + Handle datetime controls for all periods, including the main period for
2.11 + an event as well as any recurring periods.
2.12 """
2.13
2.14 - args = self.env.get_args()
2.15 + period, errors = self.handle_main_period_controls()
2.16 + if errors:
2.17 + return None, errors
2.18 +
2.19 + periods, errors = self.handle_recurrence_period_controls()
2.20 + if errors:
2.21 + return None, errors
2.22
2.23 - periods = []
2.24 + return ([period] + periods), None
2.25 +
2.26 + def handle_main_period_controls(self):
2.27
2.28 - # Get the main period details.
2.29 + "Return period details for the main start/end period in an event."
2.30 +
2.31 + args = self.env.get_args()
2.32
2.33 dtend_enabled = args.get("dtend-control", [None])[0]
2.34 dttimes_enabled = args.get("dttimes-control", [None])[0]
2.35 @@ -202,16 +211,22 @@
2.36
2.37 if errors:
2.38 return None, errors
2.39 + else:
2.40 + return period, errors
2.41
2.42 - periods.append(period)
2.43 + def handle_recurrence_period_controls(self):
2.44
2.45 - # Get the recurring period details.
2.46 + "Return period details for the recurrences specified for an event."
2.47 +
2.48 + args = self.env.get_args()
2.49
2.50 all_dtend_enabled = args.get("dtend-control-recur", [])
2.51 all_dttimes_enabled = args.get("dttimes-control-recur", [])
2.52 all_start_values = self.get_date_control_values("dtstart-recur", multiple=True)
2.53 all_end_values = self.get_date_control_values("dtend-recur", multiple=True, tzid_name="dtstart-recur")
2.54
2.55 + periods = []
2.56 +
2.57 for index, (start_values, end_values, dtend_enabled, dttimes_enabled) in \
2.58 enumerate(map(None, all_start_values, all_end_values, all_dtend_enabled, all_dttimes_enabled)):
2.59
2.60 @@ -467,17 +482,15 @@
2.61 if args.has_key("add"):
2.62 attendees.append("")
2.63
2.64 - # Only actually remove attendees if the event is unsent or if it is the
2.65 - # current user being removed.
2.66 + # Only actually remove attendees if the event is unsent, if the attendee
2.67 + # is new, or if it is the current user being removed.
2.68
2.69 if args.has_key("remove"):
2.70 for i in args["remove"]:
2.71 attendee = attendees[int(i)]
2.72 existing = attendee in existing_attendees
2.73
2.74 - if attendee in attendees and \
2.75 - (not existing or sequence is None or attendee == self.user):
2.76 -
2.77 + if not existing or sequence is None or attendee == self.user:
2.78 attendees.remove(attendee)
2.79
2.80 return attendees
2.81 @@ -806,12 +819,12 @@
2.82 page.tr()
2.83 error = errors and ("dtstart", index) in errors and " error" or ""
2.84 page.th("Start", class_="objectheading start%s" % error)
2.85 - self.show_recurrence_controls(obj, index, p.start, p.end, p.origin, recurrenceid, recurrenceids, True)
2.86 + self.show_recurrence_controls(obj, index, p, recurrenceid, recurrenceids, True)
2.87 page.tr.close()
2.88 page.tr()
2.89 error = errors and ("dtend", index) in errors and " error" or ""
2.90 page.th("End", class_="objectheading end%s" % error)
2.91 - self.show_recurrence_controls(obj, index, p.start, p.end, p.origin, recurrenceid, recurrenceids, False)
2.92 + self.show_recurrence_controls(obj, index, p, recurrenceid, recurrenceids, False)
2.93 page.tr.close()
2.94 page.tbody.close()
2.95 page.table.close()
2.96 @@ -836,8 +849,8 @@
2.97
2.98 for index, p in enumerate(self.is_organiser(obj) and periods[1:] or periods):
2.99 page.tr()
2.100 - self.show_recurrence_controls(obj, index, p.start, p.end, p.origin, recurrenceid, recurrenceids, True)
2.101 - self.show_recurrence_controls(obj, index, p.start, p.end, p.origin, recurrenceid, recurrenceids, False)
2.102 + self.show_recurrence_controls(obj, index, p, recurrenceid, recurrenceids, True)
2.103 + self.show_recurrence_controls(obj, index, p, recurrenceid, recurrenceids, False)
2.104 page.tr.close()
2.105
2.106 page.tbody.close()
2.107 @@ -1032,14 +1045,14 @@
2.108 else:
2.109 page.td(self.format_datetime(dt, "full"))
2.110
2.111 - def show_recurrence_controls(self, obj, index, start, end, origin, recurrenceid, recurrenceids, show_start):
2.112 + def show_recurrence_controls(self, obj, index, period, recurrenceid, recurrenceids, show_start):
2.113
2.114 """
2.115 Show datetime details from the given 'obj' for the recurrence having the
2.116 - given 'index', with the recurrence period described by the datetimes
2.117 - 'start' and 'end', indicating the 'origin' of the period from the event
2.118 - details, employing any 'recurrenceid' and 'recurrenceids' for the object
2.119 - to configure the displayed information.
2.120 + given 'index', with the recurrence period described by 'period',
2.121 + indicating a start, end and origin of the period from the event details,
2.122 + employing any 'recurrenceid' and 'recurrenceids' for the object to
2.123 + configure the displayed information.
2.124
2.125 If 'show_start' is set to a true value, the start details will be shown;
2.126 otherwise, the end details will be shown.
2.127 @@ -1048,14 +1061,15 @@
2.128 page = self.page
2.129 sn = self._suffixed_name
2.130 ssn = self._simple_suffixed_name
2.131 + p = period
2.132
2.133 # Change end dates to refer to the actual dates, not the iCalendar
2.134 # "next day" dates.
2.135
2.136 - if not isinstance(end, datetime):
2.137 - end -= timedelta(1)
2.138 + if not isinstance(p.end, datetime):
2.139 + p.end -= timedelta(1)
2.140
2.141 - start_utc = format_datetime(to_timezone(start, "UTC"))
2.142 + start_utc = format_datetime(to_timezone(p.start, "UTC"))
2.143 replaced = recurrenceids and start_utc in recurrenceids and "replaced" or ""
2.144 css = " ".join([
2.145 replaced,
2.146 @@ -1064,12 +1078,12 @@
2.147
2.148 # Show controls for editing as organiser.
2.149
2.150 - if self.is_organiser(obj) and not replaced and origin != "RRULE":
2.151 + if self.is_organiser(obj) and not replaced and p.origin != "RRULE":
2.152 page.td(class_="objectvalue dt%s" % (show_start and "start" or "end"))
2.153
2.154 if show_start:
2.155 page.div(class_="dt enabled")
2.156 - self._show_date_controls(ssn("dtstart", "recur", index), start, index=index)
2.157 + self._show_date_controls(ssn("dtstart", "recur", index), p.start, p.start_attr.get("TZID"), index=index)
2.158 page.br()
2.159 page.label("Specify times", for_=sn("dttimes-enable", index), class_="time disabled enable")
2.160 page.label("Specify dates only", for_=sn("dttimes-enable", index), class_="time enabled disable")
2.161 @@ -1080,7 +1094,7 @@
2.162 page.label("Specify end date", for_=sn("dtend-enable", index), class_="enable")
2.163 page.div.close()
2.164 page.div(class_="dt enabled")
2.165 - self._show_date_controls(ssn("dtend", "recur", index), end, index=index, show_tzid=False)
2.166 + self._show_date_controls(ssn("dtend", "recur", index), p.end, index=index, show_tzid=False)
2.167 page.br()
2.168 page.label("End on same day", for_=sn("dtend-enable", index), class_="disable")
2.169 page.div.close()
2.170 @@ -1090,7 +1104,7 @@
2.171 # Show label as attendee.
2.172
2.173 else:
2.174 - page.td(self.format_datetime(show_start and start or end, "long"), class_=css)
2.175 + page.td(self.format_datetime(show_start and p.start or p.end, "long"), class_=css)
2.176
2.177 # Full page output methods.
2.178