Beispiel #1
0
 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)
Beispiel #2
0
 def export_school_timetables(self, wb):
     self.task_progress.force('export_school_timetables', active=True)
     ws = wb.add_sheet("School Timetables")
     school_years = sorted(ISchoolYearContainer(self.context).values(),
                           key=lambda s: s.first)
     row = 0
     for ny, school_year in enumerate(sorted(school_years, key=lambda i: i.last)):
         timetables = ITimetableContainer(school_year)
         for nt, timetable in enumerate(sorted(timetables.values(), key=lambda i: i.__name__)):
             row = self.format_school_timetable(timetable, ws, row) + 1
             self.progress('export_school_timetables', normalized_progress(
                     ny, len(school_years), nt, len(timetables)))
     self.finish('export_school_timetables')
def setUpTimetables():
    app = ISchoolToolApplication(None)
    TimetableStartUp(app)()
    syc = ISchoolYearContainer(app)
    sy = syc.getActiveSchoolYear()
    timetables = ITimetableContainer(sy)
    timetables[u'rotating'] = tt_rot = Timetable(sy.first,
                                                 sy.last,
                                                 title=u"Rotating")

    tt_rot.periods = CalendarDayTemplates()
    initTemplates(tt_rot.periods)
    tt_rot.time_slots = CalendarDayTemplates()
    initTemplates(tt_rot.time_slots)
    addTimetableDays(tt_rot, [('1', 'Day 1'), ('2', 'Day 2'), ('3', 'Day 3')],
                     ['A', 'B', 'C'])

    timetables[u'weekly'] = tt_week = Timetable(sy.first,
                                                sy.last,
                                                title=u"Weekly")

    tt_week.periods = WeekDayTemplates()
    initTemplates(tt_week.periods)
    tt_week.time_slots = WeekDayTemplates()
    initTemplates(tt_week.time_slots)

    dows = [
        'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
        'Sunday'
    ]
    week_days = [(unicode(n), title) for n, title in enumerate(dows)]

    addTimetableDays(tt_week, week_days, ['A', 'B', 'C'])
Beispiel #4
0
 def export_school_timetables(self, wb):
     self.task_progress.force('export_school_timetables', active=True)
     ws = wb.add_sheet("School Timetables")
     school_years = sorted(ISchoolYearContainer(self.context).values(),
                           key=lambda s: s.first)
     row = 0
     for ny, school_year in enumerate(
             sorted(school_years, key=lambda i: i.last)):
         timetables = ITimetableContainer(school_year)
         for nt, timetable in enumerate(
                 sorted(timetables.values(), key=lambda i: i.__name__)):
             row = self.format_school_timetable(timetable, ws, row) + 1
             self.progress(
                 'export_school_timetables',
                 normalized_progress(ny, len(school_years), nt,
                                     len(timetables)))
     self.finish('export_school_timetables')
    def updateSection(self,
                      section,
                      term,
                      course,
                      instructor,
                      periods,
                      dry_run=True):
        """Create a section.

        `periods` is a list of tuples (day_id, period_id).

        A title is generated from the titles of `course` and `instructor`.
        If an existing section with the same title is found, it is used instead
        of creating a new one.

        The created section is returned, or None if dry_run is True.
        """
        if dry_run:
            return None

        # Establish links to course and to teacher
        for c in list(section.courses):
            if c is not course:
                section.remove(c)
        if course not in section.courses:
            section.courses.add(course)
        for i in list(section.instructors):
            if i is not instructor:
                section.instructor.remove(i)
        if instructor not in section.instructors:
            section.instructors.add(instructor)

        timetable_container = ITimetableContainer(self.schoolyear)
        timetables = [timetable_container[ttid] for ttid in sorted(periods)]
        schedules = IScheduleContainer(section)
        for timetable in timetables:
            selected = periods[timetable.__name__]
            schedule = None
            for s in schedules.values():
                if sameProxiedObjects(s.timetable, timetable):
                    schedule = s
                    break
            if schedule is None:
                schedule = SelectedPeriodsSchedule(timetable,
                                                   term.first,
                                                   term.last,
                                                   title=timetable.title,
                                                   timezone=timetable.timezone)
                for period in selected:
                    schedule.addPeriod(period)
                schedules[timetable.__name__] = schedule
            else:
                for period in schedule.periods:
                    if period not in selected:
                        schedule.removePeriod(period)
                for period in selected:
                    schedule.addPeriod(period)
 def importAllTimetables(self):
     if not self.shouldImportAllTimetables():
         return
     oldTimetables = ITimetableContainer(self.activeSchoolyear)
     newTimetables = ITimetableContainer(self.newSchoolyear)
     chooser = INameChooser(newTimetables)
     app = ISchoolToolApplication(None)
     tzname = IApplicationPreferences(app).timezone
     for schooltt in oldTimetables.values():
         newSchooltt = Timetable(
             self.newSchoolyear.first, self.newSchoolyear.last,
             title=schooltt.title,
             timezone=tzname)
         name = chooser.chooseName(schooltt.__name__, newSchooltt)
         newTimetables[name] = newSchooltt
         self.setUpTimetable(newSchooltt, schooltt)
         if (oldTimetables.default is not None and
             sameProxiedObjects(oldTimetables.default, schooltt)):
             newTimetables.default = newSchooltt
    def createSection(self,
                      term,
                      course,
                      instructor,
                      periods,
                      section_id=None,
                      dry_run=True):
        """Create a section.

        `periods` is a list of tuples (day_id, period_id).

        A title is generated from the titles of `course` and `instructor`.
        If an existing section with the same title is found, it is used instead
        of creating a new one.

        The created section is returned, or None if dry_run is True.
        """
        if dry_run:
            return None

        sections = ISectionContainer(term)

        section = Section()
        chooser = INameChooser(sections)
        auto_name = chooser.chooseName('', section)
        section.title = u"%s (%s)" % (course.title, auto_name)
        if section_id is None:
            section_id = auto_name
        sections[section_id] = section

        # Establish links to course and to teacher
        if course not in section.courses:
            section.courses.add(course)
        if instructor not in section.instructors:
            section.instructors.add(instructor)

        timetable_container = ITimetableContainer(self.schoolyear)
        timetables = [timetable_container[ttid] for ttid in sorted(periods)]
        schedules = IScheduleContainer(section)
        for timetable in timetables:
            selected = periods[timetable.__name__]
            schedule = SelectedPeriodsSchedule(timetable,
                                               term.first,
                                               term.last,
                                               title=timetable.title,
                                               timezone=timetable.timezone)
            for period in selected:
                schedule.addPeriod(period)
            schedules[timetable.__name__] = schedule

        return section
Beispiel #8
0
    def expand(self, start, end):
        app = ISchoolToolApplication(None)

        school_timetables = ITimetableContainer(app, None)

        if school_timetables is None or school_timetables.default is None:
            return []

        calendar = ImmutableScheduleCalendar(school_timetables.default)
        events = []
        events.extend(calendar.expand(start, end))

        timetable_calendar = ImmutableCalendar(events)

        resource_calendars = getSelectedResourceCalendars(self.request)
        booking_calendar = createBookingCalendar(timetable_calendar,
                                                 resource_calendars,
                                                 event_factory=BookingTimetableEvent)
        return booking_calendar.expand(start, end)
Beispiel #9
0
 def importAllTimetables(self):
     if not self.shouldImportAllTimetables():
         return
     oldTimetables = ITimetableContainer(self.activeSchoolyear)
     newTimetables = ITimetableContainer(self.newSchoolyear)
     chooser = INameChooser(newTimetables)
     app = ISchoolToolApplication(None)
     tzname = IApplicationPreferences(app).timezone
     for schooltt in oldTimetables.values():
         newSchooltt = Timetable(self.newSchoolyear.first,
                                 self.newSchoolyear.last,
                                 title=schooltt.title,
                                 timezone=tzname)
         name = chooser.chooseName(schooltt.__name__, newSchooltt)
         newTimetables[name] = newSchooltt
         self.setUpTimetable(newSchooltt, schooltt)
         if (oldTimetables.default is not None
                 and sameProxiedObjects(oldTimetables.default, schooltt)):
             newTimetables.default = newSchooltt
Beispiel #10
0
 def container(self):
     return ITimetableContainer(self.schoolyear)
Beispiel #11
0
 def hasTimetableSchemas(self, schoolyear):
     timetables = ITimetableContainer(schoolyear)
     return bool(timetables)
Beispiel #12
0
 def schoolyear(self):
     container = ITimetableContainer(self.context)
     return ISchoolYear(IHaveTimetables(container))
Beispiel #13
0
 def actualContext(self, context):
     return ITimetableContainer(self.schoolyear)
Beispiel #14
0
 def handleApply(self, action):
     container = ITimetableContainer(self.context)
     container.default = removeSecurityProxy(self.context)
     self.ajax_settings['dialog'] = 'close'
Beispiel #15
0
 def timetables(self):
     timetables = ITimetableContainer(self.schoolyear, None)
     if timetables is not None:
         return sorted(timetables.values(), key=lambda t:t.first,
                       reverse=True)
Beispiel #16
0
 def delete(self):
     container = ITimetableContainer(self.context)
     del container[self.context.__name__]
    def importChunk(self, rows, line, dry_run=True):
        """Import a chunk of data that describes a section.

        You should run this method with dry_run=True before trying the
        real thing, or you might get in trouble.
        """
        terms = self.listTerms()
        row = rows[0]
        if len(row) not in (2, 2 + len(terms)):
            err_msg = _('Wrong section header on line ${line_no} (it should contain a'
                        ' course id, an instructor id and optional SchoolTool '
                        'section IDs for each of the terms)',
                        mapping={'line_no': line})
            return

        section_ids = None
        if len(row) == 2:
            course_id, instructor_id = row[:2]
        else:
            course_id = row[0]
            instructor_id = row[1]
            section_ids = row[2:]

        course = ICourseContainer(self.schoolyear).get(course_id, None)
        if course is None:
            self.errors.courses.append(course_id)

        instructor = self.persons.get(instructor_id, None)
        if instructor is None:
            self.errors.persons.append(instructor_id)

        line_ofs = 1
        finished = False

        timetables = ITimetableContainer(self.schoolyear)
        timetable = None
        periods = {}

        for row in rows[1:]:
            line_ofs += 1
            if row == ['***']:
                finished = True
                break

            if len(row) == 1:
                tt = timetables.get(row[0])
                if tt is None:
                    err_msg = _("Malformed line ${line_no}"
                                " (it should contain either a timetable id or"
                                " day id and a period id)",
                                mapping={'line_no': line + line_ofs - 1})
                    self.errors.generic.append(err_msg)
                    continue
                timetable = tt
                continue
            elif len(row) == 2:
                day_id, period_id = row
            else:
                err_msg = _("Malformed line ${line_no}"
                            " (it should contain either a timetable id or"
                            " day id and a period id)",
                            mapping={'line_no': line + line_ofs - 1})
                self.errors.generic.append(err_msg)
                continue

            if timetable is None:
                err_msg = _("Timetable id must be specified before"
                            " day id and a period id"
                            " at at line ${line_no}",
                            mapping={'line_no': line + line_ofs - 1})
                continue

            # check day_id
            ttday = None
            for day in timetable.periods.templates.values():
                if day.title == day_id:
                    ttday = day
                    break

            if ttday is None:
                errkey = (timetable.__name__, day_id)
                if errkey not in self.errors.day_ids:
                    self.errors.day_ids.append(errkey)
                continue

            ttperiod = None
            for period in ttday.values():
                if period.title == period_id:
                    ttperiod = period
                    break

            # check period_id
            if ttperiod is None:
                errkey = (timetable.__name__, day_id, period_id)
                if period_id not in self.errors.periods:
                    self.errors.periods.append(errkey)
                    continue

            if timetable.__name__ not in periods:
                periods[timetable.__name__] = []
            periods[timetable.__name__].append(period)

        if not finished:
            err_msg = _("Incomplete section description on line ${line}",
                        mapping = {'line': line})
            self.errors.generic.append(err_msg)
            return
        if len(rows) == line_ofs:
            err_msg = _("No students in section (line ${line})",
                        mapping = {'line': line + line_ofs})
            self.errors.generic.append(err_msg)
            return


        sections = []
        for n, term in enumerate(terms):
            section_container = ISectionContainer(term)
            section_id = None
            if section_ids is not None:
                section_id = section_ids[n]
            if (section_id is not None and
                section_id in section_container):
                section = section_container[section_id]
                self.updateSection(
                    section, term, course, instructor, periods,
                    dry_run=dry_run)
            else:
                section = self.createSection(
                    term, course, instructor, periods,
                    section_id=section_id,
                    dry_run=dry_run)
            self.importPersons(rows[line_ofs:], section, dry_run=dry_run)
            if section is not None:
                sections.append(section)
        if not self.errors.anyErrors():
            for n, section in enumerate(sections[:-1]):
                section.next = sections[n+1]
Beispiel #18
0
 def container(self):
     owner = IHaveSchedule(self.context)
     return ITimetableContainer(ISchoolYear(ITerm(owner)), {})
Beispiel #19
0
 def timetables(self):
     timetables = ITimetableContainer(self.schoolyear, None)
     if timetables is not None:
         return sorted(timetables.values(),
                       key=lambda t: t.first,
                       reverse=True)
    def importChunk(self, rows, line, dry_run=True):
        """Import a chunk of data that describes a section.

        You should run this method with dry_run=True before trying the
        real thing, or you might get in trouble.
        """
        terms = self.listTerms()
        row = rows[0]
        if len(row) not in (2, 2 + len(terms)):
            err_msg = _(
                'Wrong section header on line ${line_no} (it should contain a'
                ' course id, an instructor id and optional SchoolTool '
                'section IDs for each of the terms)',
                mapping={'line_no': line})
            return

        section_ids = None
        if len(row) == 2:
            course_id, instructor_id = row[:2]
        else:
            course_id = row[0]
            instructor_id = row[1]
            section_ids = row[2:]

        course = ICourseContainer(self.schoolyear).get(course_id, None)
        if course is None:
            self.errors.courses.append(course_id)

        instructor = self.persons.get(instructor_id, None)
        if instructor is None:
            self.errors.persons.append(instructor_id)

        line_ofs = 1
        finished = False

        timetables = ITimetableContainer(self.schoolyear)
        timetable = None
        periods = {}

        for row in rows[1:]:
            line_ofs += 1
            if row == ['***']:
                finished = True
                break

            if len(row) == 1:
                tt = timetables.get(row[0])
                if tt is None:
                    err_msg = _(
                        "Malformed line ${line_no}"
                        " (it should contain either a timetable id or"
                        " day id and a period id)",
                        mapping={'line_no': line + line_ofs - 1})
                    self.errors.generic.append(err_msg)
                    continue
                timetable = tt
                continue
            elif len(row) == 2:
                day_id, period_id = row
            else:
                err_msg = _(
                    "Malformed line ${line_no}"
                    " (it should contain either a timetable id or"
                    " day id and a period id)",
                    mapping={'line_no': line + line_ofs - 1})
                self.errors.generic.append(err_msg)
                continue

            if timetable is None:
                err_msg = _(
                    "Timetable id must be specified before"
                    " day id and a period id"
                    " at at line ${line_no}",
                    mapping={'line_no': line + line_ofs - 1})
                continue

            # check day_id
            ttday = None
            for day in timetable.periods.templates.values():
                if day.title == day_id:
                    ttday = day
                    break

            if ttday is None:
                errkey = (timetable.__name__, day_id)
                if errkey not in self.errors.day_ids:
                    self.errors.day_ids.append(errkey)
                continue

            ttperiod = None
            for period in ttday.values():
                if period.title == period_id:
                    ttperiod = period
                    break

            # check period_id
            if ttperiod is None:
                errkey = (timetable.__name__, day_id, period_id)
                if period_id not in self.errors.periods:
                    self.errors.periods.append(errkey)
                    continue

            if timetable.__name__ not in periods:
                periods[timetable.__name__] = []
            periods[timetable.__name__].append(period)

        if not finished:
            err_msg = _("Incomplete section description on line ${line}",
                        mapping={'line': line})
            self.errors.generic.append(err_msg)
            return
        if len(rows) == line_ofs:
            err_msg = _("No students in section (line ${line})",
                        mapping={'line': line + line_ofs})
            self.errors.generic.append(err_msg)
            return

        sections = []
        for n, term in enumerate(terms):
            section_container = ISectionContainer(term)
            section_id = None
            if section_ids is not None:
                section_id = section_ids[n]
            if (section_id is not None and section_id in section_container):
                section = section_container[section_id]
                self.updateSection(section,
                                   term,
                                   course,
                                   instructor,
                                   periods,
                                   dry_run=dry_run)
            else:
                section = self.createSection(term,
                                             course,
                                             instructor,
                                             periods,
                                             section_id=section_id,
                                             dry_run=dry_run)
            self.importPersons(rows[line_ofs:], section, dry_run=dry_run)
            if section is not None:
                sections.append(section)
        if not self.errors.anyErrors():
            for n, section in enumerate(sections[:-1]):
                section.next = sections[n + 1]