def __call__(self): term = getTermForDate(self.event.date) if term is None: return old_date = self.event.date new_date = self.event.replacement_date schoolyear = ISchoolYear(term) timetables = ITimetableContainer(schoolyear) for timetable in timetables.values(): if IScheduleExceptions.providedBy(timetable): modified = False scheduled = DateRange(timetable.first, timetable.last) meeting_exceptions = PersistentList() if old_date in scheduled: meetings = list(timetable.iterMeetings(old_date)) for meeting in meetings: meeting_exceptions.append( MeetingException( meeting.dtstart.replace(year=new_date.year, month=new_date.month, day=new_date.day), meeting.duration, period=meeting.period, meeting_id=meeting.meeting_id)) timetable.exceptions[old_date] = PersistentList() modified = True if new_date in scheduled: timetable.exceptions[new_date] = meeting_exceptions modified = True if modified: zope.lifecycleevent.modified(timetable)
def generate(self, app, seed=None): self.random = PortableRandom(seed) event_titles = self._readLines('event_titles.txt') person_ids = [person for person in app['persons'].keys() if person.startswith('student') or person.startswith('teacher')] dates = [] for term in ITermContainer(app).values(): dates.append(term.first) dates.append(term.last) first = min(dates) last = max(dates) days = DateRange(first, last) for person_id in person_ids: person = app['persons'][person_id] calendar = ISchoolToolCalendar(person) for day in days: if self.random.randrange(0, 100) < self.probability: event_title = self.random.choice(event_titles) time_hour = self.random.randint(6, 23) time_min = self.random.choice((0, 30)) event_time = datetime.datetime(day.year, day.month, day.day, time_hour, time_min, tzinfo=utc) event_duration = datetime.timedelta( minutes=self.random.randint(1, 12)*30) event = CalendarEvent(event_time, event_duration, event_title) calendar.addEvent(event)
def iterDates(self, dates): if not self.templates: for date in dates: yield None return schedule = interfaces.ISchedule(self) scheduled_dates = DateRange(schedule.first, schedule.last) schooldays = interfaces.ISchooldays(schedule) prev_index = None prev_date = None for date in dates: if (prev_date is not None and date - prev_date != date.resolution): # This is not the next day, reset day index prev_index = None if (date not in scheduled_dates or date not in schooldays): # Not a scheduled schoolday yield None else: if prev_index is None: day_index = self.getDayIndex(schedule, schooldays, date) else: day_index = (prev_index + 1) % len(self.templates) keys = self.templates.keys() yield self.templates[keys[day_index]] prev_index = day_index prev_date = date
def getDayIndex(self, schedule, schooldays, date): assert self.templates day_index = self.starting_index if date == schedule.first: return day_index if date > schedule.first: skip_dates = DateRange(schedule.first, date - date.resolution) else: skip_dates = DateRange(date + date.resolution, schedule.first) skipped_schooldays = len(list(schooldays.iterDates(skip_dates))) if date < schedule.first: skipped_schooldays = -skipped_schooldays day_index = (day_index + skipped_schooldays) % len(self.templates) return day_index
def iterMeetingsWithExceptions(meetings, exceptions, timezone, date, until_date=None): if until_date is None: until_date = date by_date = {} for d in DateRange(date, until_date): if d in exceptions: by_date[d] = list(exceptions[d]) tz = pytz.timezone(timezone) for original_meeting in meetings: meeting_date = original_meeting.dtstart.astimezone(tz).date() if meeting_date in exceptions: continue if meeting_date not in by_date: by_date[meeting_date] = list() by_date[meeting_date].append(original_meeting) for d in sorted(by_date): for meeting in sorted(by_date[d], key=lambda m: m.dtstart): yield meeting
def iterDates(self, dates): schedule = self.__parent__ scheduled_dates = DateRange(schedule.first, schedule.last) for cursor in dates: if cursor not in scheduled_dates: yield None else: yield self.default
def validateObject(self, obj): errors = super(AddTermFormValidator, self).validateObject(obj) try: dr = DateRange(obj.first, obj.last) try: validateTermsForOverlap(self.view.context, dr, None) except TermOverlapError, e: errors += (e, ) except ValueError, e: errors += (Invalid(_("Term must begin before it ends.")), )
def validateObject(self, obj): errors = super(AddSchoolYearOverlapValidator, self).validateObject(obj) try: dr = DateRange(obj.first, obj.last) try: validateScholYearsForOverlap(self.view.context, dr, None) except SchoolYearOverlapError, e: errors += (e, ) except ValueError, e: errors += (Invalid(_("School year must begin before it ends.")), )
def iterDates(self, dates): if not self.templates: for date in dates: yield None return schedule = interfaces.ISchedule(self) scheduled_dates = DateRange(schedule.first, schedule.last) for date in dates: if date not in scheduled_dates: yield None else: day = self.getDay(schedule, date) yield day
def validateObject(self, obj): errors = super(EditSchoolYearValidator, self).validateObject(obj) try: dr = DateRange(obj.first, obj.last) try: validateScholYearsForOverlap(self.view.context.__parent__, dr, self.view.context) except SchoolYearOverlapError, e: errors += (e, ) try: validateScholYearForOverflow(dr, self.view.context) except TermOverflowError, e: errors += (e, )
def iterDates(self, dates): if not self.templates: for date in dates: yield None return schedule = interfaces.ISchedule(self) schooldays = interfaces.ISchooldays(schedule) scheduled_dates = DateRange(schedule.first, schedule.last) for date in dates: if (date not in scheduled_dates or date not in schooldays): yield None else: day = self.getWeekDay(date.weekday()) yield day
def grouped_items(self): # XXX: this introduces dependency on terms. A generic grouping # would be more appropriate. items = super(CalendarOverlayView, self).items() non_term_items = [] by_term = {} current_term = removeSecurityProxy( getUtility(IDateManager).current_term) for item in items: term = ITerm(item['calendar'].__parent__, None) unsecure_term = removeSecurityProxy(term) if unsecure_term is None: non_term_items.append(item) continue term_range = DateRange(term.first, term.last) view_range = self.view.cursor_range if term_range.overlaps(view_range): if unsecure_term not in by_term: by_term[unsecure_term] = { 'group': term, 'items': [], 'expanded': unsecure_term is current_term, } by_term[unsecure_term]['items'].append(item) order = sorted(by_term, key=lambda t: t.last, reverse=True) result = [] if non_term_items: result.append({ 'group': None, 'items': non_term_items, 'expanded': True, }) for term in order: result.append(by_term[term]) return result
def grouped_items(self): # XXX: this introduces dependency on terms. A generic grouping # would be more appropriate. items = super(CalendarOverlayView, self).items() non_term_items = [] by_term = {} current_term = removeSecurityProxy( getUtility(IDateManager).current_term) for item in items: term = ITerm(item['calendar'].__parent__, None) unsecure_term = removeSecurityProxy(term) if unsecure_term is None: non_term_items.append(item) continue term_range = DateRange(term.first, term.last) view_range = self.view.cursor_range if term_range.overlaps(view_range): if unsecure_term not in by_term: by_term[unsecure_term] = { 'group': term, 'items': [], 'expanded': unsecure_term is current_term, } by_term[unsecure_term]['items'].append(item) order = sorted(by_term, key=lambda t: t.last, reverse=True) result = [] if non_term_items: result.append({ 'group': None, 'items': non_term_items, 'expanded': True, }) for term in order: result.append(by_term[term]) return result
def validate(self, value): # XXX: hack to display the overlap error next to the widget! rv = super(FlourishOverlapValidator, self).validate(value) last_widget = self.view.widgets['last'] last_value = self.request.get(last_widget.name) try: last_value = last_widget._toFieldValue(last_value) except: return try: dr = DateRange(value, last_value) except: raise FlourishInvalidDateRangeError() try: validateScholYearsForOverlap(self.container, dr, self.schoolyear) except SchoolYearOverlapError, e: raise FlourishOverlapError()
def iterOriginalMeetings(self, from_date, until_date=None): if until_date is None: until_date = from_date timezone = pytz.timezone(self.timezone) dates = DateRange(from_date, until_date) days = zip(dates, self.periods.iterDates(dates), self.time_slots.iterDates(dates)) for day_date, day_periods, day_time_slots in days: if not day_periods: continue day = combineTemplates(day_periods, day_time_slots) for n, (period, time_slot) in enumerate(day): tstart = time_slot.tstart dtstart = datetime.datetime.combine(day_date, tstart) dtstart = timezone.localize(dtstart) # Note we're using dates in timetable's timezone here meeting_id = self.periodMeetingId(day_date, period, n+1) meeting = Meeting( dtstart, time_slot.duration, period=period, meeting_id=meeting_id) yield meeting
def __iter__(self): schedule = self.schedule dates = DateRange(schedule.first, schedule.last) return self.iterDates(dates)
def __call__(self): sy = self.event.term.__parent__ dr = DateRange(*self.event.new_dates) if sy: validateTermsForOverlap(sy, dr, self.event.term)
def __call__(self): syc = self.event.schoolyear.__parent__ dr = DateRange(*self.event.new_dates) if syc: validateScholYearsForOverlap(syc, dr, self.event.schoolyear)
def __call__(self): sy = self.event.schoolyear dr = DateRange(*self.event.new_dates) validateScholYearForOverflow(dr, sy)