Coverage for app/logic/bonner.py: 39%
85 statements
« prev ^ index » next coverage.py v7.2.7, created at 2025-07-22 20:03 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2025-07-22 20:03 +0000
1from collections import defaultdict
2from datetime import date
3from peewee import IntegrityError, SQL, fn
5import xlsxwriter
7from app import app
8from app.models.bonnerCohort import BonnerCohort
9from app.models.certificationRequirement import CertificationRequirement
10from app.models.event import Event
11from app.models.eventParticipant import EventParticipant
12from app.models.eventRsvp import EventRsvp
13from app.models.requirementMatch import RequirementMatch
14from app.models.user import User
15from app.models.eventCohort import EventCohort
16from app.models.term import Term
17from app.logic.createLogs import createRsvpLog
19def makeBonnerXls(selectedYear, noOfYears=1):
20 """
21 Create and save a BonnerStudents.xlsx file with all of the current and former bonner students.
22 Working with XLSX files: https://xlsxwriter.readthedocs.io/index.html
24 Params:
25 selectedYear: The cohort year of interest.
26 noOfYears: The number of years to be downloaded.
28 Returns:
29 The file path and name to the newly created file, relative to the web root.
30 """
31 selectedYear = int(selectedYear)
32 filepath = app.config['files']['base_path'] + '/BonnerStudents.xlsx'
33 workbook = xlsxwriter.Workbook(filepath, {'in_memory': True})
34 worksheet = workbook.add_worksheet('students')
35 bold = workbook.add_format({'bold': True})
37 worksheet.write('A1', 'Cohort Year', bold)
38 worksheet.set_column('A:A', 10)
39 worksheet.write('B1', 'Student', bold)
40 worksheet.set_column('B:B', 20)
41 worksheet.write('C1', 'B-Number', bold)
42 worksheet.set_column('C:C', 10)
43 worksheet.write('D1', 'Student Email', bold)
44 worksheet.set_column('D:D', 20)
46 # bonner event titles
47 bonnerEventsId = 1
48 bonnerEvents = CertificationRequirement.select().where(CertificationRequirement.certification==bonnerEventsId).order_by(CertificationRequirement.order.asc())
49 bonnerEventInfo = {bonnerEvent.id:(bonnerEvent.name, index + 4) for index, bonnerEvent in enumerate(bonnerEvents)}
50 allBonnerSpreadsheetPosition = 7
51 currentLetter = "E" # next column
52 for bonnerEvent in bonnerEvents:
53 worksheet.write(f"{currentLetter}1", bonnerEvent.name, bold)
54 worksheet.set_column(f"{currentLetter}:{currentLetter}", 30)
55 currentLetter = chr(ord(f"{currentLetter}") + 1)
57 if noOfYears == "all":
58 students = BonnerCohort.select(BonnerCohort, User).join(User).order_by(BonnerCohort.year.desc(), User.lastName)
59 else:
60 noOfYears = int(noOfYears)
61 startingYear = selectedYear - noOfYears + 1
62 students = BonnerCohort.select(BonnerCohort, User).where(BonnerCohort.year.between(startingYear, selectedYear)).join(User).order_by(BonnerCohort.year.desc(), User.lastName)
64 prev_year = 0
65 row = 0
66 for student in students:
67 if prev_year != student.year:
68 row += 1
69 prev_year = student.year
70 worksheet.write(row, 0, f"{student.year} - {student.year+1}", bold)
72 worksheet.write(row, 1, student.user.fullName)
73 worksheet.write(row, 2, student.user.bnumber)
74 worksheet.write(row, 3, student.user.email)
76 # set event fields to the default "incomplete" status
77 for eventName, eventSpreadsheetPosition in bonnerEventInfo.values():
78 worksheet.write(row, eventSpreadsheetPosition, "Incomplete")
80 bonnerEventsAttended = (
81 RequirementMatch
82 .select()
83 .join(Event, on=(RequirementMatch.event == Event.id))
84 .join(EventParticipant, on=(RequirementMatch.event == EventParticipant.event))
85 .join(CertificationRequirement, on=(RequirementMatch.requirement == CertificationRequirement.id))
86 .join(User, on=(EventParticipant.user == User.username))
87 .where((CertificationRequirement.certification_id == bonnerEventsId) & (User.username == student.user.username))
88 )
90 allBonnerMeetingDates = []
91 for attendedEvent in bonnerEventsAttended:
92 if bonnerEventInfo.get(attendedEvent.requirement.id):
93 completedEvent = bonnerEventInfo[attendedEvent.requirement.id]
94 worksheet.write(row, completedEvent[1], attendedEvent.event.startDate.strftime('%m/%d/%Y'))
95 if completedEvent[0] == "All Bonner Meeting":
96 allBonnerMeetingDates.append(attendedEvent.event.startDate.strftime('%m/%d/%Y'))
97 else:
98 raise Exception("Untracked requirements found in attended events. Debug required.")
100 worksheet.write(row, allBonnerSpreadsheetPosition, ", ".join(sorted(allBonnerMeetingDates)))
102 row += 1
104 workbook.close()
106 return filepath
108def getBonnerCohorts(limit=None, currentYear=date.today().year):
109 """
110 Return a dictionary with years as keys and a list of bonner users as values. Returns empty lists for
111 intermediate years, or the last 5 years if there are no older records.
112 """
113 bonnerCohorts = list(BonnerCohort.select(BonnerCohort, User).join(User).order_by(BonnerCohort.year).execute())
115 firstYear = currentYear - 4 if not bonnerCohorts else min(currentYear - 4, bonnerCohorts[0].year)
116 lastYear = currentYear if not bonnerCohorts else max(currentYear, bonnerCohorts[-1].year)
119 cohorts = { year: [] for year in range(firstYear, lastYear + 1) }
120 for cohort in bonnerCohorts:
121 cohorts[cohort.year].append(cohort.user)
123 # slice off cohorts that go over our limit starting with the earliest
124 if limit:
125 cohorts = dict(sorted(list(cohorts.items()), key=lambda e: e[0], reverse=True)[:limit])
127 return cohorts
131def rsvpForBonnerCohort(year, event):
132 """
133 Adds an EventRsvp record to the given event for each user in the given Bonner year.
134 """
135 EventRsvp.insert_from(BonnerCohort.select(BonnerCohort.user, event, SQL('NOW()'))
136 .where(BonnerCohort.year == year),
137 [EventRsvp.user, EventRsvp.event, EventRsvp.rsvpTime]).on_conflict(action='IGNORE').execute()
139def addBonnerCohortToRsvpLog(year, event):
140 """ This method adds the table information in the RSVP Log page"""
141 bonnerCohort = list(BonnerCohort.select(fn.CONCAT(User.firstName, ' ', User.lastName).alias("fullName"))
142 .join(User, on=(User.username == BonnerCohort.user))
143 .where(BonnerCohort.year == year))
144 for bonner in bonnerCohort:
145 fullName = bonner.fullName
146 createRsvpLog(eventId=event, content=f"Added {fullName} to RSVP list.")