Coverage for app/logic/utils.py: 71%

65 statements  

« prev     ^ index     » next       coverage.py v7.10.2, created at 2026-10-10 20:46 +0000

1from datetime import datetime 

2import collections.abc as collections 

3 

4from flask import session 

5from peewee import DoesNotExist 

6 

7from app.models.term import Term 

8 

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. 

14 

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]}" 

27 

28 prevTerms -= 1 

29 

30 surroundingTerms = (Term.select() 

31 .where(Term.termOrder >= startOrder, Term.year <= currentTerm.year + 2) 

32 .order_by(Term.termOrder)) 

33 

34 if summerOnly: 

35 surroundingTerms = surroundingTerms.where(Term.isSummer) 

36 

37 return surroundingTerms 

38 

39def selectAllSummerTerms(currentTerm, student): 

40 """ 

41 Selects the summer terms during which a CCE Minor student could be enrolled. 

42 """ 

43 

44 # The year when the student was admitted is inferred from their current class level.  

45 classYears = { 

46 "Freshman": 1, 

47 "Sophomore": 2, 

48 "Junior": 3, 

49 "Senior": 4, 

50 "Graduating": 4 # "Graduating" students are seniors graduating at the end of the current term.  

51 } 

52 

53 if student.hasGraduated or student.rawClassLevel not in classYears: 

54 return [] 

55 

56 classYear = classYears[student.rawClassLevel] 

57 

58 isSpring = currentTerm.description.startswith("Spring") 

59 isGraduating = student.rawClassLevel == "Graduating" 

60 

61 # First summer the student can request 

62 if isSpring or isGraduating: 

63 firstSummer = currentTerm.year - classYear + 1 

64 else: 

65 firstSummer = currentTerm.year - classYear + 2 

66 

67 # Last summer the student can request 

68 if isSpring and isGraduating: 

69 lastSummer = currentTerm.year - 1 

70 else: 

71 lastSummer = currentTerm.year 

72 

73 return (Term.select() 

74 .where(Term.isSummer, 

75 Term.year >= firstSummer, 

76 Term.year <= lastSummer) 

77 .order_by(Term.termOrder)) 

78 

79def getStartofCurrentAcademicYear(currentTerm): 

80 if ("Summer" in currentTerm.description) or ("Spring" in currentTerm.description): 

81 fallTerm = Term.select().where(Term.year==currentTerm.year-1, Term.description == f"Fall {currentTerm.year-1}").get() 

82 return fallTerm 

83 return currentTerm 

84 

85def format24HourTime(unformattedTime): 

86 """ 

87 Turns a time string or datetime object into a string with a time in 24 hour format 

88 unformattedTime: expects a string with format HH:mm AM/PM or HH:mm OR a datetime object 

89 returns: a string in 24 hour format HH:mm 

90 """ 

91 if type(unformattedTime) == str: 

92 try: 

93 formattedTime = datetime.strptime(unformattedTime, "%I:%M %p").strftime("%H:%M") # Converts string to datetime then back to string and formats correctly 

94 return formattedTime 

95 except ValueError: 

96 # calling strptime here to explicitly raise an exception if it wasn't properly in 24 hour format 

97 formattedTime = datetime.strptime(unformattedTime, "%H:%M") 

98 return unformattedTime 

99 else: 

100 formattedTime = unformattedTime.strftime("%H:%M") 

101 return formattedTime 

102 

103def getUsernameFromEmail(email): 

104 return email.split("@")[0] 

105 

106def getFilesFromRequest(request): 

107 attachmentFiles = request.files.getlist("attachmentObject") 

108 fileDoesNotExist = attachmentFiles[0].content_type == "application/octet-stream" 

109 if fileDoesNotExist: 

110 attachmentFiles = None 

111 

112 return attachmentFiles 

113 

114def getRedirectTarget(popTarget=False): 

115 """ 

116 This function returns a string with the URL or route to a page in the Application 

117 saved with setRedirectTarget() and is able to pop the value from the session 

118 to make it an empty value 

119 popTarget: expects a bool value to determine whether or not to reset 

120 redirectTarget to an emtpy value 

121 return: a string with the URL or route to a page in the application that was 

122 saved in setRedirectTarget() 

123 """ 

124 if "redirectTarget" not in session: 

125 return '' 

126 

127 target = session["redirectTarget"] 

128 if popTarget: 

129 session.pop("redirectTarget") 

130 return target 

131 

132def setRedirectTarget(target): 

133 """ 

134 This function saves the target URL in the session for future redirection 

135 to said page 

136 target: expects a string that is a URL or a route to a page in the application 

137 return: None 

138 """ 

139 session["redirectTarget"] = target 

140