Coverage for app/controllers/main/routes.py: 29%
266 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-24 14:13 +0000
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-24 14:13 +0000
1from flask import request, render_template, g, abort, flash, redirect, url_for, session
2import datetime
3import json
4from http import cookies
6from app import app
7from app.models.program import Program
8from app.models.event import Event
9from app.models.backgroundCheck import BackgroundCheck
10from app.models.backgroundCheckType import BackgroundCheckType
11from app.models.user import User
12from app.models.eventParticipant import EventParticipant
13from app.models.interest import Interest
14from app.models.programBan import ProgramBan
15from app.models.programEvent import ProgramEvent
16from app.models.term import Term
17from app.models.eventRsvp import EventRsvp
18from app.models.note import Note
19from app.models.profileNote import ProfileNote
20from app.models.programManager import ProgramManager
21from app.models.courseStatus import CourseStatus
22from app.models.courseInstructor import CourseInstructor
23from app.models.certification import Certification
25from app.controllers.main import main_bp
26from app.logic.loginManager import logout
27from app.logic.users import addUserInterest, removeUserInterest, banUser, unbanUser, isEligibleForProgram, getUserBGCheckHistory, addProfileNote, deleteProfileNote, updateDietInfo
28from app.logic.participants import unattendedRequiredEvents, trainedParticipants, getUserParticipatedTrainingEvents, checkUserRsvp, addPersonToEvent
29from app.logic.events import *
30from app.logic.searchUsers import searchUsers
31from app.logic.transcript import *
32from app.logic.landingPage import getManagerProgramDict, getActiveEventTab
33from app.logic.manageSLFaculty import getCourseDict
34from app.logic.courseManagement import unapprovedCourses, approvedCourses
35from app.logic.utils import selectSurroundingTerms
36from app.logic.certification import getCertRequirementsWithCompletion
38@main_bp.route('/logout', methods=['GET'])
39def redirectToLogout():
40 return redirect(logout())
42@main_bp.route('/', methods=['GET'])
43def landingPage():
44 managerProgramDict = getManagerProgramDict(g.current_user)
45 programsWithEvents = list(ProgramEvent.select(ProgramEvent.program).where(ProgramEvent.event.term == g.current_term).join(Event).distinct())
46 programsWithEventsList = [program.program.id for program in programsWithEvents]
48 return render_template("/main/landingPage.html", managerProgramDict = managerProgramDict,
49 term = g.current_term,
50 programsWithEventsList = programsWithEventsList)
52@main_bp.route('/goToEventsList/<programID>', methods=['GET'])
53def goToEventsList(programID):
54 return {"activeTab": getActiveEventTab(programID)}
56@main_bp.route('/eventsList/<selectedTerm>', methods=['GET'], defaults={'activeTab': "studentLedEvents", 'programID': 0})
57@main_bp.route('/eventsList/<selectedTerm>/<activeTab>', methods=['GET'], defaults={'programID': 0})
58@main_bp.route('/eventsList/<selectedTerm>/<activeTab>/<programID>', methods=['GET'])
59def events(selectedTerm, activeTab, programID):
60 currentTerm = g.current_term
61 if selectedTerm:
62 currentTerm = selectedTerm
63 currentTime = datetime.datetime.now()
64 listOfTerms = Term.select()
65 participantRSVP = EventRsvp.select(EventRsvp, Event).join(Event).where(EventRsvp.user == g.current_user)
66 rsvpedEventsID = [event.event.id for event in participantRSVP]
67 term = Term.get_by_id(currentTerm)
68 studentLedEvents = getStudentLedEvents(term)
69 trainingEvents = getTrainingEvents(term, g.current_user)
70 bonnerEvents = getBonnerEvents(term)
71 otherEvents = getOtherEvents(term)
73 return render_template("/events/event_list.html",
74 selectedTerm = term,
75 studentLedEvents = studentLedEvents,
76 trainingEvents = trainingEvents,
77 bonnerEvents = bonnerEvents,
78 otherEvents = otherEvents,
79 listOfTerms = listOfTerms,
80 rsvpedEventsID = rsvpedEventsID,
81 currentTime = currentTime,
82 user = g.current_user,
83 activeTab = activeTab,
84 programID = int(programID))
86@main_bp.route('/profile/<username>', methods=['GET'])
87def viewUsersProfile(username):
88 """
89 This function displays the information of a volunteer to the user
90 """
91 try:
92 volunteer = User.get(User.username == username)
93 except Exception as e:
94 if g.current_user.isAdmin:
95 flash(f"{username} does not exist! ", category='danger')
96 return redirect(url_for('admin.studentSearchPage'))
97 else:
98 abort(403) # Error 403 if non admin/student-staff user trys to access via url
100 if (g.current_user == volunteer) or g.current_user.isAdmin:
101 upcomingEvents = getUpcomingEventsForUser(volunteer)
102 participatedEvents = getParticipatedEventsForUser(volunteer)
103 programs = Program.select()
104 if not g.current_user.isBonnerScholar and not g.current_user.isAdmin:
105 programs = programs.where(Program.isBonnerScholars == False)
106 interests = Interest.select(Interest, Program).join(Program).where(Interest.user == volunteer)
107 programsInterested = [interest.program for interest in interests]
109 rsvpedEventsList = EventRsvp.select(EventRsvp, Event).join(Event).where(EventRsvp.user == volunteer)
110 rsvpedEvents = [event.event.id for event in rsvpedEventsList]
112 programManagerPrograms = ProgramManager.select(ProgramManager, Program).join(Program).where(ProgramManager.user == volunteer)
113 permissionPrograms = [entry.program.id for entry in programManagerPrograms]
115 allBackgroundHistory = getUserBGCheckHistory(volunteer)
116 backgroundTypes = list(BackgroundCheckType.select())
118 eligibilityTable = []
119 for program in programs:
120 notes = list(ProgramBan.select(ProgramBan, Note)
121 .join(Note, on=(ProgramBan.banNote == Note.id))
122 .where(ProgramBan.user == volunteer,
123 ProgramBan.program == program,
124 ProgramBan.endDate > datetime.datetime.now()).execute())
126 UserParticipatedTrainingEvents = getUserParticipatedTrainingEvents(program, g.current_user, g.current_term)
127 allTrainingsComplete = not len([event for event in UserParticipatedTrainingEvents.values() if event != True])
128 noteForDict = notes[-1].banNote.noteContent if notes else ""
129 eligibilityTable.append({"program": program,
130 "completedTraining": allTrainingsComplete,
131 "trainingList": UserParticipatedTrainingEvents,
132 "isNotBanned": True if not notes else False,
133 "banNote": noteForDict})
134 profileNotes = ProfileNote.select().where(ProfileNote.user == volunteer)
135 userDietQuery = User.select().where(User.username == username)
136 userDiet = [note.dietRestriction for note in userDietQuery]
138 bonnerRequirements = getCertRequirementsWithCompletion(certification=Certification.BONNER, username=volunteer)
139 return render_template ("/main/userProfile.html",
140 programs = programs,
141 programsInterested = programsInterested,
142 upcomingEvents = upcomingEvents,
143 participatedEvents = participatedEvents,
144 rsvpedEvents = rsvpedEvents,
145 permissionPrograms = permissionPrograms,
146 eligibilityTable = eligibilityTable,
147 volunteer = volunteer,
148 backgroundTypes = backgroundTypes,
149 allBackgroundHistory = allBackgroundHistory,
150 currentDateTime = datetime.datetime.now(),
151 profileNotes = profileNotes,
152 bonnerRequirements = bonnerRequirements,
153 userDiet = userDiet
154 )
155 abort(403)
157@main_bp.route('/profile/addNote', methods=['POST'])
158def addNote():
159 """
160 This function adds a note to the user's profile.
161 """
162 postData = request.form
163 try:
164 note = addProfileNote(postData["visibility"], postData["bonner"] == "yes", postData["noteTextbox"], postData["username"])
165 flash("Successfully added profile note", "success")
166 return redirect(url_for("main.viewUsersProfile", username=postData["username"]))
167 except Exception as e:
168 print("Error adding note", e)
169 flash("Failed to add profile note", "danger")
170 return "Failed to add profile note", 500
172@main_bp.route('/<username>/deleteNote', methods=['POST'])
173def deleteNote(username):
174 """
175 This function deletes a note from the user's profile.
176 """
177 try:
178 deleteProfileNote(request.form["id"])
179 flash("Successfully deleted profile note", "success")
180 except Exception as e:
181 print("Error deleting note", e)
182 flash("Failed to delete profile note", "danger")
183 return "success"
185# ===========================Ban===============================================
186@main_bp.route('/<username>/ban/<program_id>', methods=['POST'])
187def ban(program_id, username):
188 """
189 This function updates the ban status of a username either when they are banned from a program.
190 program_id: the primary id of the program the student is being banned from
191 username: unique value of a user to correctly identify them
192 """
193 postData = request.form
194 banNote = postData["note"] # This contains the note left about the change
195 banEndDate = postData["endDate"] # Contains the date the ban will no longer be effective
196 try:
197 banUser(program_id, username, banNote, banEndDate, g.current_user)
198 programInfo = Program.get(int(program_id))
199 flash("Successfully banned the volunteer", "success")
200 createLog(f'Banned {username} from {programInfo.programName} until {banEndDate}.')
201 return "Successfully banned the volunteer."
202 except Exception as e:
203 print("Error while updating ban", e)
204 flash("Failed to ban the volunteer", "danger")
205 return "Failed to ban the volunteer", 500
207# ===========================Unban===============================================
208@main_bp.route('/<username>/unban/<program_id>', methods=['POST'])
209def unban(program_id, username):
210 """
211 This function updates the ban status of a username either when they are unbanned from a program.
212 program_id: the primary id of the program the student is being unbanned from
213 username: unique value of a user to correctly identify them
214 """
215 postData = request.form
216 unbanNote = postData["note"] # This contains the note left about the change
217 try:
218 unbanUser(program_id, username, unbanNote, g.current_user)
219 programInfo = Program.get(int(program_id))
220 createLog(f'Unbanned {username} from {programInfo.programName}.')
221 flash("Successfully unbanned the volunteer", "success")
222 return "Successfully unbanned the volunteer"
224 except Exception as e:
225 print("Error while updating Unban", e)
226 flash("Failed to unban the volunteer", "danger")
227 return "Failed to unban the volunteer", 500
230@main_bp.route('/<username>/addInterest/<program_id>', methods=['POST'])
231def addInterest(program_id, username):
232 """
233 This function adds a program to the list of programs a user interested in
234 program_id: the primary id of the program the student is adding interest of
235 username: unique value of a user to correctly identify them
236 """
237 try:
238 success = addUserInterest(program_id, username)
239 if success:
240 flash("Successfully added " + Program.get_by_id(program_id).programName + " as an interest", "success")
241 return ""
242 else:
243 flash("Was unable to remove " + Program.get_by_id(program_id).programName + " as an interest.", "danger")
245 except Exception as e:
246 print(e)
247 return "Error Updating Interest", 500
249@main_bp.route('/<username>/removeInterest/<program_id>', methods=['POST'])
250def removeInterest(program_id, username):
251 """
252 This function removes a program to the list of programs a user interested in
253 program_id: the primary id of the program the student is adding interest of
254 username: unique value of a user to correctly identify them
255 """
256 try:
257 removed = removeUserInterest(program_id, username)
258 if removed:
259 flash("Successfully removed " + Program.get_by_id(program_id).programName + " as an interest.", "success")
260 return ""
261 else:
262 flash("Was unable to remove " + Program.get_by_id(program_id).programName + " as an interest.", "danger")
263 except Exception as e:
264 print(e)
265 return "Error Updating Interest", 500
267@main_bp.route('/rsvpForEvent', methods = ['POST'])
268def volunteerRegister():
269 """
270 This function selects the user ID and event ID and registers the user
271 for the event they have clicked register for.
272 """
273 event = Event.get_by_id(request.form['id'])
274 program = event.singleProgram
275 user = g.current_user
277 isAdded = checkUserRsvp(user, event)
278 isEligible = isEligibleForProgram(program, user)
279 listOfRequirements = unattendedRequiredEvents(program, user)
281 personAdded = False
282 if isEligible:
283 personAdded = addPersonToEvent(user, event)
284 if personAdded and listOfRequirements:
285 reqListToString = ', '.join(listOfRequirements)
286 flash(f"{user.firstName} {user.lastName} successfully registered. However, the following training may be required: {reqListToString}.", "success")
287 elif personAdded:
288 flash("Successfully registered for event!","success")
289 else:
290 flash(f"RSVP Failed due to an unknown error.", "danger")
291 else:
292 flash(f"Cannot RSVP. Contact CELTS administrators: {app.config['celts_admin_contact']}.", "danger")
295 if 'from' in request.form:
296 if request.form['from'] == 'ajax':
297 return ''
298 return redirect(url_for("admin.eventDisplay", eventId=event.id))
300@main_bp.route('/rsvpRemove', methods = ['POST'])
301def RemoveRSVP():
302 """
303 This function deletes the user ID and event ID from database when RemoveRSVP is clicked
304 """
305 eventData = request.form
306 event = Event.get_by_id(eventData['id'])
308 currentRsvpParticipant = EventRsvp.get(EventRsvp.user == g.current_user, EventRsvp.event == event)
309 currentRsvpParticipant.delete_instance()
310 flash("Successfully unregistered for event!", "success")
311 if 'from' in eventData:
312 if eventData['from'] == 'ajax':
313 return ''
314 return redirect(url_for("admin.eventDisplay", eventId=event.id))
316@main_bp.route('/profile/<username>/serviceTranscript', methods = ['GET'])
317def serviceTranscript(username):
318 user = User.get_or_none(User.username == username)
319 if user is None:
320 abort(404)
321 if user != g.current_user and not g.current_user.isAdmin:
322 abort(403)
324 slCourses = getSlCourseTranscript(username)
325 totalHours = getTotalHours(username)
326 allEventTranscript = getAllEventTranscript(username)
327 startDate = getStartYear(username)
329 return render_template('main/serviceTranscript.html',
330 allEventTranscript = allEventTranscript,
331 slCourses = slCourses.objects(),
332 totalHours = totalHours,
333 startDate = startDate,
334 userData = user)
336@main_bp.route('/searchUser/<query>', methods = ['GET'])
337def searchUser(query):
339 category= request.args.get("category")
341 '''Accepts user input and queries the database returning results that matches user search'''
342 try:
343 query = query.strip()
344 search = query.upper()
345 splitSearch = search.split()
346 searchResults = searchUsers(query,category)
347 return searchResults
348 except Exception as e:
349 print(e)
350 return "Error in searching for user", 500
352@main_bp.route('/contributors',methods = ['GET'])
353def contributors():
354 return render_template("/contributors.html")
356@main_bp.route('/proposalReview/', methods = ['GET', 'POST'])
357def reviewProposal():
358 """
359 this function gets the submitted course id and returns the its data to the review proposal modal
360 """
361 courseID=request.form
362 course=Course.get_by_id(courseID["course_id"])
363 instructors_data=course.courseInstructors
364 return render_template('/main/reviewproposal.html',
365 course=course,
366 instructors_data=instructors_data)
368@main_bp.route('/manageServiceLearning', methods = ['GET', 'POST'])
369@main_bp.route('/manageServiceLearning/<term>', methods = ['GET', 'POST'])
370def getAllCourseInstructors(term=None):
371 """
372 This function selects all the Instructors Name and the previous courses
373 """
374 if g.current_user.isCeltsAdmin:
375 setRedirectTarget("/manageServiceLearning")
376 courseDict = getCourseDict()
378 term = Term.get_or_none(Term.id == term) or g.current_term
380 unapproved = unapprovedCourses(term)
381 approved = approvedCourses(term)
382 terms = selectSurroundingTerms(g.current_term)
384 return render_template('/main/manageServiceLearningFaculty.html',
385 courseInstructors = courseDict,
386 unapprovedCourses = unapproved,
387 approvedCourses = approved,
388 terms = terms,
389 term = term,
390 CourseStatus = CourseStatus)
391 else:
392 abort(403)
394def getRedirectTarget(popTarget=False):
395 """
396 This function returns a string with the URL or route to a page in the Application
397 saved with setRedirectTarget() and is able to pop the value from the session
398 to make it an empty value
399 popTarget: expects a bool value to determine whether or not to reset
400 redirectTarget to an emtpy value
401 return: a string with the URL or route to a page in the application that was
402 saved in setRedirectTarget()
403 """
404 if "redirectTarget" not in session:
405 return ''
407 target = session["redirectTarget"]
408 if popTarget:
409 session.pop("redirectTarget")
410 return target
412def setRedirectTarget(target):
413 """
414 This function saves the target URL in the session for future redirection
415 to said page
416 target: expects a string that is a URL or a route to a page in the application
417 return: None
418 """
419 session["redirectTarget"] = target
421@main_bp.route('/updateDietInformation', methods = ['GET', 'POST'])
422def getDietInfo():
423 dietaryInfo = request.form
424 user = dietaryInfo["user"]
425 dietInfo = dietaryInfo["dietInfo"]
426 if (g.current_user.username == user) or g.current_user.isAdmin:
427 updateDietInfo(user, dietInfo)
429 return " "