Coverage for app/logic/utils.py: 54%
63 statements
« prev ^ index » next coverage.py v7.10.2, created at 2026-08-06 22:03 +0000
« prev ^ index » next coverage.py v7.10.2, created at 2026-08-06 22:03 +0000
1from datetime import datetime
2import collections.abc as collections
4from flask import session
5from peewee import DoesNotExist
7from app.models.term import Term
9def selectSurroundingTerms(currentTerm, prevTerms=2, summerOnly=False):
10 """
11 Returns a list of term objects around the provided Term object for the current term.
12 Chooses the previous terms according to the prevTerms parameter (defaulting to 2),
13 and then chooses terms for the next two years after the current term.
15 To get only the current and future terms, pass prevTerms=0.
16 """
17 # Find the starting term
18 startOrder = currentTerm.termOrder
19 while(prevTerms > 0):
20 orderPieces = startOrder.split('-')
21 if(orderPieces[1] == "1"):
22 orderPieces[0] = int(orderPieces[0]) - 1
23 orderPieces[1] = 3
24 else:
25 orderPieces[1] = int(orderPieces[1]) - 1
26 startOrder = f"{orderPieces[0]}-{orderPieces[1]}"
28 prevTerms -= 1
30 surroundingTerms = (Term.select()
31 .where(Term.termOrder >= startOrder, Term.year <= currentTerm.year + 2)
32 .order_by(Term.termOrder))
34 if summerOnly:
35 surroundingTerms = surroundingTerms.where(Term.isSummer)
37 return surroundingTerms
39def selectAllSummerTerms(currentTerm, student):
40 """
41 Select the summer terms during which a CCE Minor student could be enrolled.
43 The user record does not store an admission date, so the admission academic
44 year is inferred from the student's current class level. The range never
45 extends beyond the student's inferred final school year; students marked as
46 ``Graduating`` are treated as fifth-year/fall-graduating students.
47 """
48 classYears = {
49 "Freshman": 1,
50 "Sophomore": 2,
51 "Junior": 3,
52 "Senior": 4,
53 "Graduating": 5,
54 }
56 if student.hasGraduated or student.rawClassLevel not in classYears:
57 return []
59 classYear = classYears[student.rawClassLevel]
60 # A Spring/Summer term belongs to the academic year that began the prior fall.
61 academicYearStart = (currentTerm.year if currentTerm.description.startswith("Fall")
62 else currentTerm.year - 1)
63 inferredAdmissionYear = academicYearStart - (classYear - 1)
65 firstSummer = inferredAdmissionYear + 1
66 lastSummer = inferredAdmissionYear + max(4, classYear) - 1
67 if currentTerm.description.startswith("Summer"):
68 lastSummer = max(lastSummer, currentTerm.year)
70 return (Term.select()
71 .where(Term.isSummer,
72 Term.year >= firstSummer,
73 Term.year <= lastSummer)
74 .order_by(Term.termOrder))
76def getStartofCurrentAcademicYear(currentTerm):
77 if ("Summer" in currentTerm.description) or ("Spring" in currentTerm.description):
78 fallTerm = Term.select().where(Term.year==currentTerm.year-1, Term.description == f"Fall {currentTerm.year-1}").get()
79 return fallTerm
80 return currentTerm
82def format24HourTime(unformattedTime):
83 """
84 Turns a time string or datetime object into a string with a time in 24 hour format
85 unformattedTime: expects a string with format HH:mm AM/PM or HH:mm OR a datetime object
86 returns: a string in 24 hour format HH:mm
87 """
88 if type(unformattedTime) == str:
89 try:
90 formattedTime = datetime.strptime(unformattedTime, "%I:%M %p").strftime("%H:%M") # Converts string to datetime then back to string and formats correctly
91 return formattedTime
92 except ValueError:
93 # calling strptime here to explicitly raise an exception if it wasn't properly in 24 hour format
94 formattedTime = datetime.strptime(unformattedTime, "%H:%M")
95 return unformattedTime
96 else:
97 formattedTime = unformattedTime.strftime("%H:%M")
98 return formattedTime
100def getUsernameFromEmail(email):
101 return email.split("@")[0]
103def getFilesFromRequest(request):
104 attachmentFiles = request.files.getlist("attachmentObject")
105 fileDoesNotExist = attachmentFiles[0].content_type == "application/octet-stream"
106 if fileDoesNotExist:
107 attachmentFiles = None
109 return attachmentFiles
111def getRedirectTarget(popTarget=False):
112 """
113 This function returns a string with the URL or route to a page in the Application
114 saved with setRedirectTarget() and is able to pop the value from the session
115 to make it an empty value
116 popTarget: expects a bool value to determine whether or not to reset
117 redirectTarget to an emtpy value
118 return: a string with the URL or route to a page in the application that was
119 saved in setRedirectTarget()
120 """
121 if "redirectTarget" not in session:
122 return ''
124 target = session["redirectTarget"]
125 if popTarget:
126 session.pop("redirectTarget")
127 return target
129def setRedirectTarget(target):
130 """
131 This function saves the target URL in the session for future redirection
132 to said page
133 target: expects a string that is a URL or a route to a page in the application
134 return: None
135 """
136 session["redirectTarget"] = target