Coverage for app/logic/users.py: 92%

84 statements  

« prev     ^ index     » next       coverage.py v7.10.2, created at 2026-08-24 19:35 +0000

1from app.models.eventParticipant import EventParticipant 

2from app.models.program import Program 

3from app.models.term import Term 

4from app.models.user import User 

5from app.models.event import Event 

6from app.models.programBan import ProgramBan 

7from app.models.interest import Interest 

8from app.models.note import Note 

9from app.models.user import User 

10from app.models.profileNote import ProfileNote 

11from app.models.programBan import ProgramBan 

12from app.models.backgroundCheck import BackgroundCheck 

13from app.models.backgroundCheckType import BackgroundCheckType 

14from app.logic.volunteers import addUserBackgroundCheck 

15import datetime 

16from peewee import JOIN, DoesNotExist, fn 

17from dateutil import parser 

18from flask import g 

19from playhouse.shortcuts import model_to_dict 

20 

21def isEligibleForProgram(program, user): 

22 """ 

23 Verifies if a given user is eligible for a program by checking if they are: 

24 1. Banned from a program. 

25 2. Missed All Volunteer Training (volunteers) or All CELTS training (labor) 

26 3. Missed Program-specific training 

27 4. Not signed the handbook (or expired) 

28 5. Background Check Submitted (does not matter if it passed or not) 

29 

30 :param program: accepts a Program object or a valid programid 

31 :param user: accepts a User object or userid 

32 :return: True if the user is not banned and meets the requirements, and False otherwise 

33 """ 

34 now = datetime.datetime.now() 

35 try: 

36 user = User.get_by_id(user) 

37 except DoesNotExist: 

38 raise DoesNotExist 

39 # Banned? 

40 if (ProgramBan.select().where(ProgramBan.user == user, ProgramBan.program == program, ProgramBan.endDate > now, ProgramBan.unbanNote == None).exists()): 

41 return False 

42 # Missed trainings? 

43 if user not in trainedParticipants(program, g.current_term): 

44 return False 

45 # Missing signature? 

46 if not user.signatureTerm: 

47 return False 

48 # Old signature? 

49 elif not user.signatureTerm.academicYear == g.current_term.academicYear: 

50 return False 

51 # Background check submitted? 

52 if not (User.select(User.username, BackgroundCheck.dateCompleted).join(BackgroundCheck).distinct()): 

53 return False 

54 

55 return True 

56 

57def addUserInterest(program_id, username): 

58 """ 

59 This function is used to add an interest to . 

60 Parameters: 

61 program_id: id of the program the user is interested in 

62 username: username of the user showing interest 

63 """ 

64 Interest.get_or_create(program = program_id, user = username) 

65 return True 

66 

67def removeUserInterest(program_id, username): 

68 """ 

69 This function is used to add or remove interest from the interest table. 

70 Parameters: 

71 program_id: id of the program the user is interested in 

72 username: username of the user showing disinterest 

73 

74 """ 

75 interestToDelete = Interest.get_or_none(Interest.program == program_id, Interest.user == username) 

76 if interestToDelete: 

77 interestToDelete.delete_instance() 

78 return True 

79 

80def getUserInterest(username): 

81 """ 

82 This function is used to retrieve a user's interests. 

83 Parameters:  

84 username: username of the user showing interest 

85 """ 

86 return Interest.select().where(Interest.user == username) 

87 

88def getProgramInterest(program): 

89 """ 

90 This function is used to retrieve a programs's interested users. 

91 Parameters: 

92 program: Program object 

93 """ 

94 return User.select().join(Interest).where(Interest.program == program) 

95 

96def getBannedUsers(program): 

97 """ 

98 This function returns users banned from a program. 

99 """ 

100 return ProgramBan.select().where(ProgramBan.program == program, ProgramBan.unbanNote == None) 

101 

102def isBannedFromEvent(username, eventId): 

103 """ 

104 This function returns whether the user is banned from the program associated with an event. 

105 """ 

106 program = Event.get_by_id(eventId).program 

107 user = User.get(User.username == username) 

108 isBanned = (ProgramBan.select() 

109 .join(User) 

110 .switch(ProgramBan) 

111 .join(Program) 

112 .where(ProgramBan.user == user, 

113 ProgramBan.program == program, 

114 ProgramBan.endDate > datetime.datetime.now(), 

115 ProgramBan.unbanNote.is_null()).exists() 

116 ) 

117 return isBanned 

118 

119def trainedParticipants(programID, targetTerm): 

120 """ 

121 This function tracks the users who have attended every Prerequisite 

122 event and adds them to a list that will not flag them when tracking hours. 

123 Returns a list of user objects who've completed all training events. 

124 """ 

125 

126 # Reset program eligibility each term for all other trainings 

127 isRelevantAllVolunteer = (Event.isAllVolunteerTraining | Event.isCeltsTraining) & (Event.term.academicYear == targetTerm.academicYear) 

128 isRelevantProgramTraining = (Event.program == programID) & (Event.term == targetTerm) & (Event.isTraining) 

129 allTrainings = (Event.select() 

130 .join(Term) 

131 .where(isRelevantAllVolunteer | isRelevantProgramTraining, 

132 Event.isCanceled == False)) 

133 

134 fullyTrainedUsers = (User.select() 

135 .join(EventParticipant) 

136 .where(EventParticipant.event.in_(allTrainings)) 

137 .group_by(EventParticipant.user) 

138 .having(fn.Count(EventParticipant.user) == len(allTrainings)).order_by(User.username)) 

139 return list(fullyTrainedUsers) 

140 

141def banUser(program_id, username, note, banEndDate, creator): 

142 """ 

143 This function creates an entry in the note table and programBan table in order 

144 to ban the selected user. 

145 Parameters: 

146 program_id: primary id of the program the user has been banned from 

147 username: username of the user to be banned 

148 note: note left about the ban, expected to be a reason why the change is needed 

149 banEndDate: date when the ban will end 

150 creator: the admin or person with authority who created the ban 

151 """ 

152 

153 noteForDb = Note.create(createdBy = creator, 

154 createdOn = datetime.datetime.now(), 

155 noteContent = note, 

156 isPrivate = 0, 

157 noteType = "ban") 

158 

159 ProgramBan.create(program = program_id, 

160 user = username, 

161 endDate = banEndDate, 

162 banNote = noteForDb) 

163 

164def unbanUser(program_id, username, note, creator): 

165 """ 

166 This function creates an entry in the note table and programBan table in order 

167 to unban the selected user. 

168 Parameters: 

169 program_id: primary id of the program the user has been unbanned from 

170 username: username of the user to be unbanned 

171 note: note left about the ban, expected to be a reason why the change is needed 

172 creator: the admin or person with authority who removed the ban 

173 """ 

174 noteForDb = Note.create(createdBy = creator, 

175 createdOn = datetime.datetime.now(), 

176 noteContent = note, 

177 isPrivate = 0, 

178 noteType = "unban") 

179 (ProgramBan.update(endDate = datetime.datetime.now(), 

180 unbanNote = noteForDb, 

181 removeFromTranscript = 0) 

182 .where(ProgramBan.program == program_id, 

183 ProgramBan.user == username, 

184 ProgramBan.endDate > datetime.datetime.now())).execute() 

185 

186def getUserBGCheckHistory(username): 

187 """ 

188 Get a users background check history 

189 """ 

190 bgHistory = {'CAN': [], 'FBI': [], 'SHS': [], 'BSL': [],'DDC':[]} 

191 

192 allBackgroundChecks = (BackgroundCheck.select(BackgroundCheck, BackgroundCheckType) 

193 .join(BackgroundCheckType) 

194 .where(BackgroundCheck.user == username, BackgroundCheck.deletionDate == None) 

195 .order_by(BackgroundCheck.dateCompleted.desc())) 

196 for row in allBackgroundChecks: 

197 bgHistory[row.type_id].append(row) 

198 return bgHistory 

199 

200def addProfileNote(visibility, bonner, noteTextbox, username): 

201 if bonner: 

202 visibility = 1 # bonner notes are always admins and the student 

203 

204 noteForDb = Note.create(createdBy = g.current_user, 

205 createdOn = datetime.datetime.now(), 

206 noteContent = noteTextbox, 

207 noteType = "profile") 

208 createProfileNote = ProfileNote.create(user = User.get(User.username == username), 

209 note = noteForDb, 

210 isBonnerNote = bonner, 

211 viewTier = visibility) 

212 return createProfileNote 

213 

214def deleteProfileNote(noteId): 

215 return ProfileNote.delete().where(ProfileNote.id == noteId).execute() 

216 

217def updateDietInfo(username, dietContent): 

218 """ 

219 Creates or update a user's diet information 

220 """ 

221 

222 User.update(dietRestriction = dietContent).where(User.username == username).execute() 

223 

224 return ""