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
« 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
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)
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
55 return True
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
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
74 """
75 interestToDelete = Interest.get_or_none(Interest.program == program_id, Interest.user == username)
76 if interestToDelete:
77 interestToDelete.delete_instance()
78 return True
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)
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)
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)
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
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 """
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))
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)
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 """
153 noteForDb = Note.create(createdBy = creator,
154 createdOn = datetime.datetime.now(),
155 noteContent = note,
156 isPrivate = 0,
157 noteType = "ban")
159 ProgramBan.create(program = program_id,
160 user = username,
161 endDate = banEndDate,
162 banNote = noteForDb)
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()
186def getUserBGCheckHistory(username):
187 """
188 Get a users background check history
189 """
190 bgHistory = {'CAN': [], 'FBI': [], 'SHS': [], 'BSL': [],'DDC':[]}
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
200def addProfileNote(visibility, bonner, noteTextbox, username):
201 if bonner:
202 visibility = 1 # bonner notes are always admins and the student
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
214def deleteProfileNote(noteId):
215 return ProfileNote.delete().where(ProfileNote.id == noteId).execute()
217def updateDietInfo(username, dietContent):
218 """
219 Creates or update a user's diet information
220 """
222 User.update(dietRestriction = dietContent).where(User.username == username).execute()
224 return ""