class ProgressReportPage(BrowserPage): render_invariant = False render_debug = False base_filename = 'export' message_title = _('export') task_progress = None overall_line_id = None def __init__(self, context, request): super(ProgressReportPage, self).__init__(context, request) self.makeProgress() def makeFileName(self, basename): if self.render_invariant: return '%s.xls' % basename timestamp = datetime.datetime.now().strftime('%y-%m-%d-%H-%M') return '%s_%s.xls' % (basename, timestamp) @property def filename(self): return self.makeFileName(self.base_filename) def makeProgress(self): task_id = getattr(self.request, 'task_id', None) self.task_progress = TaskProgress(task_id) def update(self): self.makeProgress() def updateOverall(self): if self.overall_line_id is None: return max_progress = 0.0 overall = 0.0 for lid, line in self.task_progress.lines.items(): if (line.get('progress', None) is not None and lid != self.overall_line_id): overall += line.progress max_progress += 1.0 if max_progress > 0.0: overall /= max_progress self.task_progress('overall', progress=overall) def progress(self, importer, value): self.task_progress(importer, progress=value, active=True) self.updateOverall() def finish(self, importer): self.task_progress.finish(importer) self.updateOverall()
def makeProgress(self): self.task_progress = TaskProgress(None)
class MegaExporter(SchoolTimetableExportView): overall_line_id = 'overall' def print_table(self, table, ws, row=0, col=0): for y, cells in enumerate(table): self.print_row(cells, ws, row=(row + y), col=col) return len(table) def print_row(self, cells, ws, row=0, col=0): for x, cell in enumerate(cells): self.write(ws, row, col + x, cell.data, **cell.style) def format_table(self, fields, items, importer=None, major_progress=(), sort=True): headers = [Header(header) for header, style, getter in fields] rows = [] total_items = len(removeSecurityProxy(items)) for n, item in enumerate(items): row = [style(getter(item)) for header, style, getter in fields] rows.append(row) if importer is not None: self.progress( importer, normalized_progress(*(major_progress + (n, total_items)))) if sort: rows.sort() return [headers] + rows def format_school_years(self): fields = [('ID', Text, attrgetter('__name__')), ('Title', Text, attrgetter('title')), ('Start', Date, attrgetter('first')), ('End', Date, attrgetter('last'))] items = ISchoolYearContainer(self.context).values() result = self.format_table(fields, items, importer='export_school_years') return result def export_school_years(self, wb): self.task_progress.force('export_school_years', active=True) ws = wb.add_sheet("School Years") self.print_table(self.format_school_years(), ws) self.finish('export_school_years') def calculate_holidays_and_weekdays(self): work_days = 0.0 days_of_week = {} for dow in range(7): days_of_week[dow] = [0, 0] school_years = ISchoolYearContainer(self.context).values() for school_year in school_years: terms = ITermContainer(school_year).values() for term in terms: for date in term: if term.isSchoolday(date): days_of_week[date.weekday()][0] += 1 work_days += 1 else: days_of_week[date.weekday()][1] += 1 if work_days == 0: return [[], list(range(7)), []] coefficients = [ counts[0] / work_days for day, counts in sorted(days_of_week.items()) ] # Weekends weekends = [] for n, k in enumerate(coefficients): if k < 0.1: weekends.append(n) # Weekend exceptions and holidays holidays = [] weekend_exceptions = [] for school_year in school_years: terms = ITermContainer(school_year).values() for term in terms: for date in term: if term.isSchoolday(date) and date.weekday() in weekends: weekend_exceptions.append(date) elif not term.isSchoolday(date) and date.weekday( ) not in weekends: holidays.append(date) holiday_ranges = merge_date_ranges(holidays) return [holiday_ranges, weekends, weekend_exceptions] def format_holidays(self, holidays): if not holidays: return [] table = [[], [Header("Holidays")]] table.extend([[Date(start), Date(end)] for start, end in holidays]) return table def format_weekends(self, weekends): if not weekends: return [] table = [[], [Header("Weekends")]] weekdays = map(Text, [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ]) table.append(weekdays) table.append([ weekday in weekends and Text('X') or Text('') for weekday in range(len(weekdays)) ]) return table def format_weekend_exceptions(self, working_weekends): if not working_weekends: return [] table = [[], [Header("Working weekends")]] table.extend([[Date(day)] for day in working_weekends]) return table def format_terms(self): fields = [('SchoolYear', Text, lambda t: t.__parent__.__name__), ('ID', Text, attrgetter('__name__')), ('Title', Text, attrgetter('title')), ('Start', Date, attrgetter('first')), ('End', Date, attrgetter('last'))] school_years = ISchoolYearContainer(self.context).values() items = [] for year in school_years: items.extend([term for term in ITermContainer(year).values()]) terms_table = self.format_table(fields, items, importer='export_terms') holidays, weekends, exceptions = self.calculate_holidays_and_weekdays() terms_table.extend(self.format_holidays(holidays)) terms_table.extend(self.format_weekends(weekends)) terms_table.extend(self.format_weekend_exceptions(exceptions)) return terms_table def export_terms(self, wb): self.task_progress.force('export_terms', active=True) ws = wb.add_sheet("Terms") self.print_table(self.format_terms(), ws) self.finish('export_terms') def format_persons(self): fields = [('User Name', Text, attrgetter('__name__')), ('Prefix', Text, attrgetter('prefix')), ('First Name', Text, attrgetter('first_name')), ('Middle Name', Text, attrgetter('middle_name')), ('Last Name', Text, attrgetter('last_name')), ('Suffix', Text, attrgetter('suffix')), ('Preferred Name', Text, attrgetter('preferred_name')), ('Birth Date', Date, attrgetter('birth_date')), ('Gender', Text, attrgetter('gender')), ('Password', Text, lambda p: None)] def demographics_getter(attribute): def getter(person): demographics = IDemographics(person) return demographics[attribute] return getter app = ISchoolToolApplication(None) demographics_fields = IDemographicsFields(app) for field in demographics_fields.values(): title = field.title format = Text if isinstance(field, DateFieldDescription): format = Date getter = demographics_getter(field.name) fields.append((title, format, getter)) items = self.context['persons'].values() return self.format_table(fields, items, importer='export_persons') def export_persons(self, wb): self.task_progress.force('export_persons', active=True) ws = wb.add_sheet("Persons") self.print_table(self.format_persons(), ws) self.finish('export_persons') def format_contact_persons(self): def contact_getter(attribute): def getter(contact): person = IBasicPerson(contact.__parent__, None) if person is None: return getattr(contact, attribute) if attribute == '__name__': return person.username return '' return getter fields = [('ID', Text, contact_getter('__name__')), ('Prefix', Text, contact_getter('prefix')), ('First Name', Text, contact_getter('first_name')), ('Middle Name', Text, contact_getter('middle_name')), ('Last Name', Text, contact_getter('last_name')), ('Suffix', Text, contact_getter('suffix')), ('Address line 1', Text, attrgetter('address_line_1')), ('Address line 2', Text, attrgetter('address_line_2')), ('City', Date, attrgetter('city')), ('State', Date, attrgetter('state')), ('Country', Date, attrgetter('country')), ('Postal code', Date, attrgetter('postal_code')), ('Home phone', Text, attrgetter('home_phone')), ('Work phone', Text, attrgetter('work_phone')), ('Mobile phone', Text, attrgetter('mobile_phone')), ('Email', Text, attrgetter('email')), ('Language', Text, attrgetter('language'))] items = [] for person in self.context['persons'].values(): items.append(IContact(person)) for contact in IContactContainer(self.context).values(): items.append(contact) return self.format_table(fields, items, importer='export_contacts', major_progress=(0, 2)) def format_person_contacts(self, person, major_progress=()): contacts = IContactable(person).contacts rows = [] for contact in contacts.all(): row = [] row.append(Text(person.username)) target_person = IBasicPerson(contact.__parent__, None) if target_person is None: row.append(Text(contact.__name__)) else: row.append(Text(target_person.username)) state = contacts.state(contact) for x, (date, meaning, code) in enumerate(state): row.append(Date(date)) row.append(Text(code)) rows.append(row) return rows def format_contact_relationships(self): rows = [] persons = self.context['persons'] total = len(persons) for nperson, person in enumerate(persons.values()): person = removeSecurityProxy(person) person_rows = self.format_person_contacts(person, major_progress=(1, 2, nperson, total)) rows.extend(person_rows) rows.sort() headers = [ Header('Person ID'), Header('Contact ID'), Header('Relationship') ] rows.insert(0, headers) return rows def export_contacts(self, wb): self.task_progress.force('export_contacts', active=True) ws = wb.add_sheet("Contact Persons") self.print_table(self.format_contact_persons(), ws) ws = wb.add_sheet("Contact Relationships") self.print_table(self.format_contact_relationships(), ws) self.finish('export_contacts') def format_resources(self): fields = [('ID', Text, attrgetter('__name__')), ('Type', Text, lambda r: r.__class__.__name__), ('Title', Text, attrgetter('title'))] items = self.context['resources'].values() return self.format_table(fields, items, importer='export_resources') def export_resources(self, wb): self.task_progress.force('export_resources', active=True) ws = wb.add_sheet("Resources") self.print_table(self.format_resources(), ws) self.finish('export_resources') def format_levels(self): fields = [('ID', Text, attrgetter('__name__')), ('Title', Text, attrgetter('title'))] levels = ILevelContainer(self.context) items = levels.values() return self.format_table(fields, items, importer='export_levels', sort=False) def export_levels(self, wb): self.task_progress.force('export_levels', active=True) ws = wb.add_sheet("Grade Levels") self.print_table(self.format_levels(), ws) self.finish('export_levels') def format_courses(self): def get_course_level(course): return ', '.join([l.__name__ for l in course.levels]) fields = [('School Year', Text, lambda c: ISchoolYear(c).__name__), ('ID', Text, attrgetter('__name__')), ('Title', Text, attrgetter('title')), ('Description', Text, attrgetter('description')), ('Local ID', Text, attrgetter('course_id')), ('Government ID', Text, attrgetter('government_id')), ('Credits', Text, attrgetter('credits')), ('Grade Level ID', Text, get_course_level)] school_years = ISchoolYearContainer(self.context).values() items = [] for year in school_years: items.extend([term for term in ICourseContainer(year).values()]) return self.format_table(fields, items, importer='export_courses') def export_courses(self, wb): self.task_progress.force('export_courses', active=True) ws = wb.add_sheet("Courses") self.print_table(self.format_courses(), ws) self.finish('export_courses') def format_timetables(self, section, ws, offset): schedules = IScheduleContainer(section) if not schedules: return offset schedules = list( sorted(schedules.values(), key=lambda s: s.timetable.__name__)) for schedule in schedules: timetable = schedule.timetable self.write_header(ws, offset, 0, "School Timetable") self.write(ws, offset, 1, timetable.__name__) offset += 1 self.write(ws, offset, 0, "Consecutive periods as one") self.write(ws, offset, 1, schedule.consecutive_periods_as_one and 'yes' or 'no') offset += 1 self.write_header(ws, offset, 0, "Day") self.write_header(ws, offset, 1, "Period") offset += 1 for period in schedule.periods: day = period.__parent__ self.write(ws, offset, 0, day.title) self.write(ws, offset, 1, period.title) offset += 1 offset += 1 return offset def format_section(self, year, courses, term, section, ws, row): resources = [r.__name__ for r in section.resources] self.write(ws, row, 0, year.__name__) self.write(ws, row, 1, courses) self.write(ws, row, 2, term.__name__) self.write(ws, row, 3, section.__name__) if section.previous: self.write(ws, row, 4, section.previous.__name__) if section.next: self.write(ws, row, 5, section.next.__name__) self.write(ws, row, 6, section.title) if section.description: self.write(ws, row, 7, section.description) self.write(ws, row, 8, ', '.join(resources)) def export_sections(self, wb): self.task_progress.force('export_sections', active=True) ws = wb.add_sheet("Sections") headers = [ "School Year", "Courses", "Term", "Section ID", "Previous ID", "Next ID", "Title", "Description", "Resources" ] for index, header in enumerate(headers): self.write_header(ws, 0, index, header) sections = [] for year in ISchoolYearContainer(self.context).values(): for term in year.values(): for section in ISectionContainer(term).values(): if not list(section.courses): continue courses = ', '.join([c.__name__ for c in section.courses]) sections.append((year, courses, term.first, term, section.__name__, section)) row = 1 sections.sort() n_sections = len(sections) for n, (year, courses, first, term, section_id, section) in enumerate(sections): self.format_section(year, courses, term, section, ws, row) self.progress('export_sections', normalized_progress(n, n_sections)) row += 1 self.finish('export_sections') def format_membership_block(self, relationship, headers): items = sorted(relationship.all(), key=lambda item: item.__name__) if not items: return [] table = [headers] for item in items: cells = [Text(item.__name__), Text('')] state = relationship.state(item) for x, (date, meaning, code) in enumerate(state): cells.append(Date(date)) cells.append(Text(code)) table.append(cells) table.append([]) return table def export_section_enrollment(self, ws, year, term, section, row=0): row += self.print_table([ [Header('School Year'), Header('Term'), Header('Section ID')], [Text(year.__name__), Text(term.__name__), Text(section.__name__)], [], ], ws, row=row) row += self.print_table(self.format_membership_block( section.instructors, [Header('Instructors')]), ws, row=row, col=0) row += self.print_table(self.format_membership_block( section.members, [Header('Students')]), ws, row=row, col=0) return row def export_sections_enrollment(self, wb): self.task_progress.force('export_sections_enrollment', active=True) ws = wb.add_sheet("SectionEnrollment") row = 0 years = ISchoolYearContainer(self.context) total_years = len(years) for ny, year in enumerate( sorted(years.values(), key=lambda year: year.first)): total_terms = len(year) for nt, term in enumerate( sorted(year.values(), key=lambda term: term.first)): sections = ISectionContainer(term) total_sections = len(sections) for ns, section in enumerate( sorted(sections.values(), key=lambda section: section.__name__)): row = self.export_section_enrollment(ws, year, term, section, row=row) self.progress( 'export_sections_enrollment', normalized_progress( ny, total_years, nt, total_terms, ns, total_sections, )) self.finish('export_sections_enrollment') def format_timetable_sections(self, year, timetable_sections, ws, row): headers = ["School Year", "Term", "Section ID"] for index, header in enumerate(headers): self.write_header(ws, row, index, header) row += 1 for first, term, section_id, section in sorted(timetable_sections): self.write(ws, row, 0, year.__name__) self.write(ws, row, 1, term.__name__) self.write(ws, row, 2, section.__name__) row += 1 return row + 1 def format_timetables_block(self, timetables, ws, row): for timetable in timetables: parts = timetable.split(',') self.write_header(ws, row, 0, "Timetable") self.write(ws, row, 1, parts[0]) self.write_header(ws, row, 2, "Consecutive") self.write(ws, row, 3, parts[1]) row += 2 self.write_header(ws, row, 0, "Day") self.write_header(ws, row, 1, "Period ID") row += 1 parts = parts[2:] while parts: day, period = parts[:2] self.write(ws, row, 0, day) self.write(ws, row, 1, period) parts = parts[2:] row += 1 return row + 1 def export_section_timetables(self, wb): self.task_progress.force('export_section_timetables', active=True) ws = wb.add_sheet("SectionTimetables") year_sections = {} for year in ISchoolYearContainer(self.context).values(): sections = year_sections[year] = {} for term in year.values(): for section in ISectionContainer(term).values(): if not list(section.courses): continue timetables = [] for schedule in IScheduleContainer(section).values(): if schedule.timetable.__name__ is None: # LP: #1281335 continue parts = [schedule.timetable.__name__] if schedule.consecutive_periods_as_one: parts.append('yes') else: parts.append('no') for period in schedule.periods: day = period.__parent__ parts.append(day.title) parts.append(period.title) timetables.append(','.join(parts)) if not len(timetables): continue timetables = tuple(timetables) timetable_sections = sections.setdefault(timetables, []) timetable_sections.append( (term.first, term, section.__name__, section)) row = 0 for ny, (year, sections) in enumerate(sorted(year_sections.items())): for nt, (timetables, timetable_sections) in enumerate( sorted(sections.items())): row = self.format_timetable_sections(year, timetable_sections, ws, row) row = self.format_timetables_block(timetables, ws, row) self.progress( 'export_section_timetables', normalized_progress(ny, len(year_sections), nt, len(sections))) self.finish('export_section_timetables') def format_group(self, group, ws, offset): fields = [ lambda i: ("Group Title", i.title, None), lambda i: ("ID", i.__name__, None), lambda i: ("School Year", ISchoolYear(i.__parent__).__name__, None), lambda i: ("Description", i.description, None) ] offset = self.listFields(group, fields, ws, offset) offset += self.print_table(self.format_membership_block( group.members, [Header('Members')]), ws, row=offset, col=0) offset += 1 leaders = IAsset(group).leaders offset += self.print_table(self.format_membership_block( leaders, [Header('Leaders')]), ws, row=offset, col=0) return offset def export_groups(self, wb): self.task_progress.force('export_groups', active=True) ws = wb.add_sheet("Groups") 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)): groups = IGroupContainer(school_year) for ng, group in enumerate( sorted(groups.values(), key=lambda i: i.__name__)): row = self.format_group(group, ws, row) + 1 self.progress( 'export_groups', normalized_progress(ny, len(school_years), ng, len(groups))) self.finish('export_groups') def makeProgress(self): self.task_progress = TaskProgress(None) def addImporters(self, progress): progress.add('export_school_years', active=False, title=_('School Years'), progress=0.0) progress.add('export_terms', active=False, title=_('Terms'), progress=0.0) progress.add('export_school_timetables', active=False, title=_('School Timetables'), progress=0.0) progress.add('export_resources', active=False, title=_('Resources'), progress=0.0) progress.add('export_levels', active=False, title=_('Grade Levels'), progress=0.0) progress.add('export_persons', active=False, title=_('Persons'), progress=0.0) progress.add('export_contacts', active=False, title=_('Contacts'), progress=0.0) progress.add('export_courses', active=False, title=_('Courses'), progress=0.0) progress.add('export_sections', active=False, title=_('Sections'), progress=0.0) progress.add('export_sections_enrollment', active=False, title=_('Section Enrollment'), progress=0.0) progress.add('export_section_timetables', active=False, title=_('Section Schedules'), progress=0.0) progress.add('export_groups', active=False, title=_('Groups'), progress=0.0) progress.add('overall', title=_('School Data'), progress=0.0) def update(self): super(MegaExporter, self).update() self.addImporters(self.task_progress) def render(self, workbook): datafile = StringIO() workbook.save(datafile) data = datafile.getvalue() self.setUpHeaders(data) return data def __call__(self): self.makeProgress() self.task_progress.title = _("Exporting school data") self.addImporters(self.task_progress) wb = xlwt.Workbook() self.export_school_years(wb) self.export_terms(wb) self.export_school_timetables(wb) self.export_resources(wb) self.export_levels(wb) self.export_persons(wb) self.export_contacts(wb) self.export_courses(wb) self.export_sections(wb) self.export_sections_enrollment(wb) self.export_section_timetables(wb) self.export_groups(wb) self.task_progress.title = _("Export complete") self.task_progress.force('overall', progress=1.0) data = self.render(wb) return data
def makeProgress(self): task_id = getattr(self.request, 'task_id', None) self.task_progress = TaskProgress(task_id)
class MegaExporter(SchoolTimetableExportView): overall_line_id = 'overall' def print_table(self, table, ws, row=0, col=0): for y, cells in enumerate(table): self.print_row(cells, ws, row=(row+y), col=col) return len(table) def print_row(self, cells, ws, row=0, col=0): for x, cell in enumerate(cells): self.write(ws, row, col+x, cell.data, **cell.style) def format_table(self, fields, items, importer=None, major_progress=(), sort=True): headers = [Header(header) for header, style, getter in fields] rows = [] total_items = len(removeSecurityProxy(items)) for n, item in enumerate(items): row = [style(getter(item)) for header, style, getter in fields] rows.append(row) if importer is not None: self.progress(importer, normalized_progress( *(major_progress + (n, total_items)))) if sort: rows.sort() return [headers] + rows def format_school_years(self): fields = [('ID', Text, attrgetter('__name__')), ('Title', Text, attrgetter('title')), ('Start', Date, attrgetter('first')), ('End', Date, attrgetter('last'))] items = ISchoolYearContainer(self.context).values() result = self.format_table(fields, items, importer='export_school_years') return result def export_school_years(self, wb): self.task_progress.force('export_school_years', active=True) ws = wb.add_sheet("School Years") self.print_table(self.format_school_years(), ws) self.finish('export_school_years') def calculate_holidays_and_weekdays(self): work_days = 0.0 days_of_week = {} for dow in range(7): days_of_week[dow] = [0, 0] school_years = ISchoolYearContainer(self.context).values() for school_year in school_years: terms = ITermContainer(school_year).values() for term in terms: for date in term: if term.isSchoolday(date): days_of_week[date.weekday()][0] += 1 work_days += 1 else: days_of_week[date.weekday()][1] += 1 if work_days == 0: return [[], list(range(7)), []] coefficients = [counts[0] / work_days for day, counts in sorted(days_of_week.items())] # Weekends weekends = [] for n, k in enumerate(coefficients): if k < 0.1: weekends.append(n) # Weekend exceptions and holidays holidays = [] weekend_exceptions = [] for school_year in school_years: terms = ITermContainer(school_year).values() for term in terms: for date in term: if term.isSchoolday(date) and date.weekday() in weekends: weekend_exceptions.append(date) elif not term.isSchoolday(date) and date.weekday() not in weekends: holidays.append(date) holiday_ranges = merge_date_ranges(holidays) return [holiday_ranges, weekends, weekend_exceptions] def format_holidays(self, holidays): if not holidays: return [] table = [[], [Header("Holidays")]] table.extend([[Date(start), Date(end)] for start, end in holidays]) return table def format_weekends(self, weekends): if not weekends: return [] table = [[], [Header("Weekends")]] weekdays = map(Text, ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']) table.append(weekdays) table.append([weekday in weekends and Text('X') or Text('') for weekday in range(len(weekdays))]) return table def format_weekend_exceptions(self, working_weekends): if not working_weekends: return [] table = [[], [Header("Working weekends")]] table.extend([[Date(day)] for day in working_weekends]) return table def format_terms(self): fields = [('SchoolYear', Text, lambda t: t.__parent__.__name__), ('ID', Text, attrgetter('__name__')), ('Title', Text, attrgetter('title')), ('Start', Date, attrgetter('first')), ('End', Date, attrgetter('last'))] school_years = ISchoolYearContainer(self.context).values() items = [] for year in school_years: items.extend([term for term in ITermContainer(year).values()]) terms_table = self.format_table(fields, items, importer='export_terms') holidays, weekends, exceptions = self.calculate_holidays_and_weekdays() terms_table.extend(self.format_holidays(holidays)) terms_table.extend(self.format_weekends(weekends)) terms_table.extend(self.format_weekend_exceptions(exceptions)) return terms_table def export_terms(self, wb): self.task_progress.force('export_terms', active=True) ws = wb.add_sheet("Terms") self.print_table(self.format_terms(), ws) self.finish('export_terms') def format_persons(self): fields = [('User Name', Text, attrgetter('__name__')), ('Prefix', Text, attrgetter('prefix')), ('First Name', Text, attrgetter('first_name')), ('Middle Name', Text, attrgetter('middle_name')), ('Last Name', Text, attrgetter('last_name')), ('Suffix', Text, attrgetter('suffix')), ('Preferred Name', Text, attrgetter('preferred_name')), ('Birth Date', Date, attrgetter('birth_date')), ('Gender', Text, attrgetter('gender')), ('Password', Text, lambda p: None)] def demographics_getter(attribute): def getter(person): demographics = IDemographics(person) return demographics[attribute] return getter app = ISchoolToolApplication(None) demographics_fields = IDemographicsFields(app) for field in demographics_fields.values(): title = field.title format = Text if isinstance(field, DateFieldDescription): format = Date getter = demographics_getter(field.name) fields.append((title, format, getter)) items = self.context['persons'].values() return self.format_table(fields, items, importer='export_persons') def export_persons(self, wb): self.task_progress.force('export_persons', active=True) ws = wb.add_sheet("Persons") self.print_table(self.format_persons(), ws) self.finish('export_persons') def format_contact_persons(self): def contact_getter(attribute): def getter(contact): person = IBasicPerson(contact.__parent__, None) if person is None: return getattr(contact, attribute) if attribute == '__name__': return person.username return '' return getter fields = [('ID', Text, contact_getter('__name__')), ('Prefix', Text, contact_getter('prefix')), ('First Name', Text, contact_getter('first_name')), ('Middle Name', Text, contact_getter('middle_name')), ('Last Name', Text, contact_getter('last_name')), ('Suffix', Text, contact_getter('suffix')), ('Address line 1', Text, attrgetter('address_line_1')), ('Address line 2', Text, attrgetter('address_line_2')), ('City', Date, attrgetter('city')), ('State', Date, attrgetter('state')), ('Country', Date, attrgetter('country')), ('Postal code', Date, attrgetter('postal_code')), ('Home phone', Text, attrgetter('home_phone')), ('Work phone', Text, attrgetter('work_phone')), ('Mobile phone', Text, attrgetter('mobile_phone')), ('Email', Text, attrgetter('email')), ('Language', Text, attrgetter('language'))] items = [] for person in self.context['persons'].values(): items.append(IContact(person)) for contact in IContactContainer(self.context).values(): items.append(contact) return self.format_table(fields, items, importer='export_contacts', major_progress=(0,2)) def format_person_contacts(self, person, major_progress=()): contacts = IContactable(person).contacts rows = [] for contact in contacts.all(): row = [] row.append(Text(person.username)) target_person = IBasicPerson(contact.__parent__, None) if target_person is None: row.append(Text(contact.__name__)) else: row.append(Text(target_person.username)) state = contacts.state(contact) for x, (date, meaning, code) in enumerate(state): row.append(Date(date)) row.append(Text(code)) rows.append(row) return rows def format_contact_relationships(self): rows = [] persons = self.context['persons'] total = len(persons) for nperson, person in enumerate(persons.values()): person = removeSecurityProxy(person) person_rows = self.format_person_contacts( person, major_progress=(1, 2, nperson, total)) rows.extend(person_rows) rows.sort() headers = [Header('Person ID'), Header('Contact ID'), Header('Relationship')] rows.insert(0, headers) return rows def export_contacts(self, wb): self.task_progress.force('export_contacts', active=True) ws = wb.add_sheet("Contact Persons") self.print_table(self.format_contact_persons(), ws) ws = wb.add_sheet("Contact Relationships") self.print_table(self.format_contact_relationships(), ws) self.finish('export_contacts') def format_resources(self): fields = [('ID', Text, attrgetter('__name__')), ('Type', Text, lambda r: r.__class__.__name__), ('Title', Text, attrgetter('title'))] items = self.context['resources'].values() return self.format_table(fields, items, importer='export_resources') def export_resources(self, wb): self.task_progress.force('export_resources', active=True) ws = wb.add_sheet("Resources") self.print_table(self.format_resources(), ws) self.finish('export_resources') def format_levels(self): fields = [('ID', Text, attrgetter('__name__')), ('Title', Text, attrgetter('title'))] levels = ILevelContainer(self.context) items = levels.values() return self.format_table(fields, items, importer='export_levels', sort=False) def export_levels(self, wb): self.task_progress.force('export_levels', active=True) ws = wb.add_sheet("Grade Levels") self.print_table(self.format_levels(), ws) self.finish('export_levels') def format_courses(self): def get_course_level(course): if course.levels: return ', '.join([l.__name__ for l in course.levels]) fields = [('School Year', Text, lambda c: ISchoolYear(c).__name__), ('ID', Text, attrgetter('__name__')), ('Title', Text, attrgetter('title')), ('Description', Text, attrgetter('description')), ('Local ID', Text, attrgetter('course_id')), ('Government ID', Text, attrgetter('government_id')), ('Credits', Text, attrgetter('credits')), ('Grade Level ID', Text, get_course_level)] school_years = ISchoolYearContainer(self.context).values() items = [] for year in school_years: items.extend([term for term in ICourseContainer(year).values()]) return self.format_table(fields, items, importer='export_courses') def export_courses(self, wb): self.task_progress.force('export_courses', active=True) ws = wb.add_sheet("Courses") self.print_table(self.format_courses(), ws) self.finish('export_courses') def format_timetables(self, section, ws, offset): schedules = IScheduleContainer(section) if not schedules: return offset schedules = list(sorted(schedules.values(), key=lambda s: s.timetable.__name__)) for schedule in schedules: timetable = schedule.timetable self.write_header(ws, offset, 0, "School Timetable") self.write(ws, offset, 1, timetable.__name__) offset += 1 self.write(ws, offset, 0, "Consecutive periods as one") self.write(ws, offset, 1, schedule.consecutive_periods_as_one and 'yes' or 'no') offset += 1 self.write_header(ws, offset, 0, "Day") self.write_header(ws, offset, 1, "Period") offset += 1 for period in schedule.periods: day = period.__parent__ self.write(ws, offset, 0, day.title) self.write(ws, offset, 1, period.title) offset += 1 offset += 1 return offset def format_section(self, year, courses, term, section, ws, row): resources = [r.__name__ for r in section.resources] self.write(ws, row, 0, year.__name__) self.write(ws, row, 1, courses) self.write(ws, row, 2, term.__name__) self.write(ws, row, 3, section.__name__) if section.previous: self.write(ws, row, 4, section.previous.__name__) if section.next: self.write(ws, row, 5, section.next.__name__) self.write(ws, row, 6, section.title) if section.description: self.write(ws, row, 7, section.description) self.write(ws, row, 8, ', '.join(resources)) def export_sections(self, wb): self.task_progress.force('export_sections', active=True) ws = wb.add_sheet("Sections") headers = ["School Year", "Courses", "Term", "Section ID", "Previous ID", "Next ID", "Title", "Description", "Resources"] for index, header in enumerate(headers): self.write_header(ws, 0, index, header) sections = [] for year in ISchoolYearContainer(self.context).values(): for term in year.values(): for section in ISectionContainer(term).values(): if not list(section.courses): continue courses = ', '.join([c.__name__ for c in section.courses]) sections.append((year, courses, term.first, term, section.__name__, section)) row = 1 sections.sort() n_sections = len(sections) for n, (year, courses, first, term, section_id, section) in enumerate(sections): self.format_section(year, courses, term, section, ws, row) self.progress('export_sections', normalized_progress( n, n_sections)) row += 1 self.finish('export_sections') def format_membership_block(self, relationship, headers): items = sorted(relationship.all(), key=lambda item: item.__name__) if not items: return [] table = [headers] for item in items: cells = [Text(item.__name__), Text('')] state = relationship.state(item) for x, (date, meaning, code) in enumerate(state): cells.append(Date(date)) cells.append(Text(code)) table.append(cells) table.append([]) return table def export_section_enrollment(self, ws, year, term, section, row=0): row += self.print_table([ [Header('School Year'), Header('Term'), Header('Section ID')], [Text(year.__name__), Text(term.__name__), Text(section.__name__)], [], ], ws, row=row) row += self.print_table( self.format_membership_block(section.instructors, [Header('Instructors')]), ws, row=row, col=0) row += self.print_table( self.format_membership_block(section.members, [Header('Students')]), ws, row=row, col=0) return row def export_sections_enrollment(self, wb): self.task_progress.force('export_sections_enrollment', active=True) ws = wb.add_sheet("SectionEnrollment") row = 0 years = ISchoolYearContainer(self.context) total_years = len(years) for ny, year in enumerate(sorted(years.values(), key=lambda year: year.first)): total_terms = len(year) for nt, term in enumerate(sorted(year.values(), key=lambda term: term.first)): sections = ISectionContainer(term) total_sections = len(sections) for ns, section in enumerate(sorted(sections.values(), key=lambda section: section.__name__)): row = self.export_section_enrollment( ws, year, term, section, row=row) self.progress( 'export_sections_enrollment', normalized_progress( ny, total_years, nt, total_terms, ns, total_sections, )) self.finish('export_sections_enrollment') def format_timetable_sections(self, year, timetable_sections, ws, row): headers = ["School Year", "Term", "Section ID"] for index, header in enumerate(headers): self.write_header(ws, row, index, header) row += 1 for first, term, section_id, section in sorted(timetable_sections): self.write(ws, row, 0, year.__name__) self.write(ws, row, 1, term.__name__) self.write(ws, row, 2, section.__name__) row += 1 return row + 1 def format_timetables_block(self, timetables, ws, row): for timetable in timetables: parts = timetable.split(',') self.write_header(ws, row, 0, "Timetable") self.write(ws, row, 1, parts[0]) self.write_header(ws, row, 2, "Consecutive") self.write(ws, row, 3, parts[1]) row += 2 self.write_header(ws, row, 0, "Day") self.write_header(ws, row, 1, "Period ID") row += 1 parts = parts[2:] while parts: day, period = parts[:2] self.write(ws, row, 0, day) self.write(ws, row, 1, period) parts = parts[2:] row += 1 return row + 1 def export_section_timetables(self, wb): self.task_progress.force('export_section_timetables', active=True) ws = wb.add_sheet("SectionTimetables") year_sections = {} for year in ISchoolYearContainer(self.context).values(): sections = year_sections[year] = {} for term in year.values(): for section in ISectionContainer(term).values(): if not list(section.courses): continue timetables = [] for schedule in IScheduleContainer(section).values(): if schedule.timetable.__name__ is None: # LP: #1281335 continue parts = [schedule.timetable.__name__] if schedule.consecutive_periods_as_one: parts.append('yes') else: parts.append('no') for period in schedule.periods: day = period.__parent__ parts.append(day.title) parts.append(period.title) timetables.append(','.join(parts)) if not len(timetables): continue timetables = tuple(timetables) timetable_sections = sections.setdefault(timetables, []) timetable_sections.append((term.first, term, section.__name__, section)) row = 0 for ny, (year, sections) in enumerate(sorted(year_sections.items())): for nt, (timetables, timetable_sections) in enumerate(sorted(sections.items())): row = self.format_timetable_sections(year, timetable_sections, ws, row) row = self.format_timetables_block(timetables, ws, row) self.progress('export_section_timetables', normalized_progress( ny, len(year_sections), nt, len(sections) )) self.finish('export_section_timetables') def format_group(self, group, ws, offset): fields = [lambda i: ("Group Title", i.title, None), lambda i: ("ID", i.__name__, None), lambda i: ("School Year", ISchoolYear(i.__parent__).__name__, None), lambda i: ("Description", i.description, None)] offset = self.listFields(group, fields, ws, offset) offset += self.print_table( self.format_membership_block(group.members, [Header('Members')]), ws, row=offset, col=0) offset += 1 leaders = IAsset(group).leaders offset += self.print_table( self.format_membership_block(leaders, [Header('Leaders')]), ws, row=offset, col=0) return offset def export_groups(self, wb): self.task_progress.force('export_groups', active=True) ws = wb.add_sheet("Groups") 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)): groups = IGroupContainer(school_year) for ng, group in enumerate(sorted(groups.values(), key=lambda i: i.__name__)): row = self.format_group(group, ws, row) + 1 self.progress('export_groups', normalized_progress( ny, len(school_years), ng, len(groups) )) self.finish('export_groups') def makeProgress(self): self.task_progress = TaskProgress(None) def addImporters(self, progress): progress.add('export_school_years', active=False, title=_('School Years'), progress=0.0) progress.add('export_terms', active=False, title=_('Terms'), progress=0.0) progress.add('export_school_timetables', active=False, title=_('School Timetables'), progress=0.0) progress.add('export_resources', active=False, title=_('Resources'), progress=0.0) progress.add('export_levels', active=False, title=_('Grade Levels'), progress=0.0) progress.add('export_persons', active=False, title=_('Persons'), progress=0.0) progress.add('export_contacts', active=False, title=_('Contacts'), progress=0.0) progress.add('export_courses', active=False, title=_('Courses'), progress=0.0) progress.add('export_sections', active=False, title=_('Sections'), progress=0.0) progress.add('export_sections_enrollment', active=False, title=_('Section Enrollment'), progress=0.0) progress.add('export_section_timetables', active=False, title=_('Section Schedules'), progress=0.0) progress.add('export_groups', active=False, title=_('Groups'), progress=0.0) progress.add('overall', title=_('School Data'), progress=0.0) def update(self): super(MegaExporter, self).update() self.addImporters(self.task_progress) def render(self, workbook): datafile = StringIO() workbook.save(datafile) data = datafile.getvalue() self.setUpHeaders(data) return data def __call__(self): self.makeProgress() self.task_progress.title = _("Exporting school data") self.addImporters(self.task_progress) wb = xlwt.Workbook() self.export_school_years(wb) self.export_terms(wb) self.export_school_timetables(wb) self.export_resources(wb) self.export_levels(wb) self.export_persons(wb) self.export_contacts(wb) self.export_courses(wb) self.export_sections(wb) self.export_sections_enrollment(wb) self.export_section_timetables(wb) self.export_groups(wb) self.task_progress.title = _("Export complete") self.task_progress.force('overall', progress=1.0) data = self.render(wb) return data