def occurrence(self, entryid): entryid = _bdec(entryid) pos = 2 + _utils.unpack_short(entryid, 0) basedate_val = _utils.unpack_long(entryid, pos) for exc in self.exceptions: # TODO subject etc if exc['original_start_date'] in ( basedate_val, basedate_val - self.starttime_offset): # TODO pick one start = datetime.datetime.fromtimestamp( _utils.rectime_to_unixtime(exc['start_datetime'])) start = _utils._to_gmt(start, self.tz) break else: # TODO check that date is (still) valid start = datetime.datetime.fromtimestamp( _utils.rectime_to_unixtime(basedate_val)) start = _utils._to_gmt(start, self.tz) return Occurrence( self.item, start, start + datetime.timedelta(minutes=self.endtime_offset - self.starttime_offset), basedate_val=basedate_val, )
def recurrences(self): # TODO rename to _recurrences and/or rrule? rule = rruleset() start = self.start + datetime.timedelta(minutes=self._starttime_offset) if self.range_type == u'forever': end = None else: end = self.end + datetime.timedelta(minutes=self._endtime_offset) # FIXME: add one day, so that we don't miss the last recurrence, since the end date is for example 11-3-2015 on 1:00 # But the recurrence is on 8:00 that day and we should include it. if self._pattern_type == PATTERN_WEEKLY: end += datetime.timedelta(days=1) # TODO for occurrence count? if self._pattern_type == PATTERN_DAILY: rule.rrule(rrule(DAILY, dtstart=start, until=end, interval=self._period // (24 * 60))) if self._pattern_type == PATTERN_WEEKLY: byweekday = () # Set for index, week in RRULE_WEEKDAYS.items(): if (self._pattern_type_specific[0] >> index ) & 1: byweekday += (week,) rule.rrule(rrule(WEEKLY, wkst=start.weekday(), dtstart=start, until=end, byweekday=byweekday, interval=self._period)) elif self._pattern_type == PATTERN_MONTHLY: # X Day of every Y month(s) # The Xnd Y (day) of every Z Month(s) rule.rrule(rrule(MONTHLY, dtstart=start, until=end, bymonthday=self._pattern_type_specific[0], interval=self._period)) # self._pattern_type_specific[0] is either day of month or elif self._pattern_type == PATTERN_MONTHNTH: byweekday = () # Set for index, week in RRULE_WEEKDAYS.items(): if (self._pattern_type_specific[0] >> index ) & 1: if self._pattern_type_specific[1] == 5: byweekday += (week(-1),) # last week of month else: byweekday += (week(self._pattern_type_specific[1]),) # Yearly, the last XX of YY rule.rrule(rrule(MONTHLY, dtstart=start, until=end, interval=self._period, byweekday=byweekday)) elif self._pattern_type != PATTERN_DAILY: # XXX check 0 raise NotSupportedError('Unsupported recurrence pattern: %d' % self._pattern_type) # add exceptions exc_starts = set() for exception in self._exceptions: exc_start = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(exception['start_datetime'])) rule.rdate(exc_start) exc_starts.add(exc_start) # Remove deleted ocurrences (skip added exceptions) for del_date_val in self._deleted_instance_dates: del_date = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(del_date_val)) del_date = datetime.datetime(del_date.year, del_date.month, del_date.day, self._starttime_offset//60, self._starttime_offset%60) if del_date not in exc_starts: rule.exdate(del_date) return rule
def canceled(self): if self.item.recurring: rec = self.item.recurrence basedate = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(self._basedate_val)) basedate = basedate.replace(hour=0, minute=0) message = rec._exception_message(basedate) if message: return message.canceled return self.item.canceled
def occurrence(self, entryid): entryid = _bdec(entryid) pos = 2 + _utils.unpack_short(entryid, 0) basedate_val = _utils.unpack_long(entryid, pos) start = end = subject = location = None for exc, ext in zip(self._exceptions, self._extended_exceptions): if exc['original_start_date'] in (basedate_val, basedate_val - self._starttime_offset): # TODO pick one start = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(exc['start_datetime'])) end = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(exc['end_datetime'])) if exc['override_flags'] & ARO_SUBJECT: subject = ext.get('subject') if exc['override_flags'] & ARO_LOCATION: location = ext.get('location') break else: # TODO check that date is (still) valid start = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(basedate_val)) end = start + datetime.timedelta(minutes=self._endtime_offset - self._starttime_offset) return Occurrence(self.item, start, end, subject, location, basedate_val=basedate_val)
def create_attendee(self, type_, addr): if self.item.recurring: rec = self.item.recurrence basedate = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(self._basedate_val)) basedate = basedate.replace(hour=0, minute=0) message = rec._exception_message(basedate) if message: message.create_attendee(type_, addr) _utils._save(message._attobj) return # TODO else? else: self.item.create_attendee(type_, addr)
def send(self, copy_to_sentmail=True): if self.item.recurring: basedate = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(self._basedate_val)) message = self.item.recurrence._exception_message(basedate) if message: message.store = self.store to = list(message.to) if not to: message.to = self.item.to # TODO don't change message on send message.send(copy_to_sentmail=copy_to_sentmail, _basedate=basedate, cal_item=self.item) else: self.item.send(copy_to_sentmail=copy_to_sentmail, _basedate=basedate, cal_item=self.item) else: self.item.send(copy_to_sentmail)
def attendees(self): if self.item.recurring: rec = self.item.recurrence basedate = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(self._basedate_val)) basedate = basedate.replace(hour=0, minute=0) message = rec._exception_message(basedate) if message: for row in message.table(PR_MESSAGE_RECIPIENTS): yield Attendee(self.item.server, row) return # TODO else? for attendee in self.item.attendees(): yield attendee
def _update(self, **kwargs): if self.item.recurring: rec = self.item.recurrence basedate = datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(self._basedate_val)) basedate = basedate.replace(hour=0, minute=0) if rec._is_exception(basedate): rec._modify_exception(basedate, **kwargs) # TODO does too much - only need to update kwargs! else: rec._create_exception(basedate, recips_from=self.item) rec._modify_exception(basedate, **kwargs) else: for (k, v) in kwargs.items(): setattr(self.item, k, v)
def _update(self, **kwargs): if self.item.recurring: rec = self.item.recurrence basedate = datetime.datetime.fromtimestamp( _utils.rectime_to_unixtime(self._basedate_val)) basedate = _utils._to_gmt(basedate, rec.tz) if rec.is_exception(basedate): rec.modify_exception2(basedate, **kwargs) else: rec.create_exception2(basedate) rec.modify_exception2(basedate, **kwargs) else: for (k, v) in kwargs.items(): setattr(self.item, k, v)
def end(self): """ End of recurrence range (within recurrence timezone) """ return datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(self._end_date))
def start(self): """ Start of recurrence range (within recurrence timezone) """ return datetime.datetime.utcfromtimestamp(_utils.rectime_to_unixtime(self._start_date))
def recurrences(self): rrule_weekdays = {0: SU, 1: MO, 2: TU, 3: WE, 4: TH, 5: FR, 6: SA} rule = rruleset() if self.pattern_type == PATTERN_DAILY: rule.rrule( rrule(DAILY, dtstart=self._start, until=self._end, interval=self.period // (24 * 60))) if self.pattern_type == PATTERN_WEEKLY: byweekday = () # Set for index, week in rrule_weekdays.items(): if (self.pattern_type_specific[0] >> index) & 1: byweekday += (week, ) # FIXME: add one day, so that we don't miss the last recurrence, since the end date is for example 11-3-2015 on 1:00 # But the recurrence is on 8:00 that day and we should include it. rule.rrule( rrule(WEEKLY, wkst=self._start.weekday(), dtstart=self._start, until=self._end + timedelta(days=1), byweekday=byweekday, interval=self.period)) elif self.pattern_type == PATTERN_MONTHLY: # X Day of every Y month(s) # The Xnd Y (day) of every Z Month(s) rule.rrule( rrule(MONTHLY, dtstart=self._start, until=self._end, bymonthday=self.pattern_type_specific[0], interval=self.period)) # self.pattern_type_specific[0] is either day of month or elif self.pattern_type == PATTERN_MONTHNTH: byweekday = () # Set for index, week in rrule_weekdays.items(): if (self.pattern_type_specific[0] >> index) & 1: if self.pattern_type_specific[1] == 5: byweekday += (week(-1), ) # last week of month else: byweekday += (week(self.pattern_type_specific[1]), ) # Yearly, the last XX of YY rule.rrule( rrule(MONTHLY, dtstart=self._start, until=self._end, interval=self.period, byweekday=byweekday)) elif self.pattern_type != PATTERN_DAILY: # XXX check 0 raise NotSupportedError('Unsupported recurrence pattern: %d' % self.pattern_type) # add exceptions exc_starts = set() for exception in self.exceptions: exc_start = datetime.datetime.fromtimestamp( _utils.rectime_to_unixtime(exception['start_datetime'])) rule.rdate(exc_start) exc_starts.add(exc_start) # Remove deleted ocurrences (skip added exceptions) for del_date_val in self.deleted_instance_dates: del_date = datetime.datetime.fromtimestamp( _utils.rectime_to_unixtime(del_date_val)) del_date = datetime.datetime(del_date.year, del_date.month, del_date.day, self._start.hour, self._start.minute) if del_date not in exc_starts: rule.exdate(del_date) return rule
def _end(self): return datetime.datetime.fromtimestamp( _utils.rectime_to_unixtime(self.end_date)) + datetime.timedelta( minutes=self.endtime_offset) # XXX local time..