Coverage for app/controllers/main/routes.py: 23%
415 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
1import json
2import datetime
3from peewee import JOIN, DoesNotExist
4from http import cookies
5from playhouse.shortcuts import model_to_dict
6from flask import request, render_template, jsonify, g, abort, flash, redirect, url_for, make_response, session, request
7from dateutil.relativedelta import relativedelta
10from app.controllers.main import main_bp
11from app import app
12from app.models.term import Term
13from app.models.user import User
14from app.models.note import Note
15from app.models.event import Event
16from app.models.program import Program
17from app.models.interest import Interest
18from app.models.eventRsvp import EventRsvp
19from app.models.celtsLabor import CeltsLabor
20from app.models.programBan import ProgramBan
21from app.models.profileNote import ProfileNote
22from app.models.insuranceInfo import InsuranceInfo
23from app.models.certification import Certification
24from app.models.programManager import ProgramManager
25from app.models.backgroundCheck import BackgroundCheck
26from app.models.emergencyContact import EmergencyContact
27from app.models.eventParticipant import EventParticipant
28from app.models.courseInstructor import CourseInstructor
29from app.models.backgroundCheckType import BackgroundCheckType
31from app.logic.events import getUpcomingEventsForUser, getParticipatedEventsForUser, getTrainingEvents, getEventRsvpCountsForTerm, getUpcomingVolunteerOpportunitiesCount, getVolunteerOpportunities, getBonnerEvents, getCeltsLabor, getEngagementEvents, getPastVolunteerOpportunitiesCount
32from app.logic.transcript import *
33from app.logic.loginManager import logout
34from app.logic.searchUsers import searchUsers
35from app.logic.utils import selectSurroundingTerms
36from app.logic.celtsLabor import getCeltsLaborHistory
37from app.logic.createLogs import createRsvpLog, createActivityLog
38from app.logic.certification import getCertRequirementsWithCompletion
39from app.logic.landingPage import getManagerProgramDict, getActiveEventTab
40from app.logic.minor import toggleMinorInterest, declareMinorInterest, getCommunityEngagementByTerm, getEngagementTotal
41from app.logic.participants import hasGoneToTraining, unattendedRequiredEvents, getParticipationStatusForTrainings, checkUserRsvp, addPersonToEvent
42from app.logic.users import addUserInterest, isBannedFromEvent, removeUserInterest, banUser, unbanUser, isEligibleForProgram, getUserBGCheckHistory, addProfileNote, deleteProfileNote, updateDietInfo, trainedParticipants
44@main_bp.route('/logout', methods=['GET'])
45def redirectToLogout():
46 return redirect(logout())
48@main_bp.route('/', methods=['GET'])
49def landingPage():
51 managerProgramDict = getManagerProgramDict(g.current_user)
52 # Optimize the query to fetch programs with non-canceled, non-past events in the current term
54 programsWithEventsList = list(Program.select(Program, Event)
55 .join(Event)
56 .where((Event.term == g.current_term) & (Event.isCanceled == False))
57 .distinct()
58 .execute()) # Ensure only unique programs are included
59 # Limit returned list to events in the future
60 futureEvents = [p for p in programsWithEventsList if not p.event.isPastEnd]
62 return render_template("/main/landingPage.html",
63 managerProgramDict=managerProgramDict,
64 term=g.current_term,
65 programsWithEventsList = futureEvents)
70@main_bp.route('/goToEventsList/<programID>', methods=['GET'])
71def goToEventsList(programID):
72 return {"activeTab": getActiveEventTab(programID)}
74@main_bp.route('/eventsList/<selectedTerm>', methods=['GET'], defaults={'activeTab': "volunteerOpportunities", 'programID': 0})
75@main_bp.route('/eventsList/<selectedTerm>/', methods=['GET'], defaults={'activeTab': "volunteerOpportunities", 'programID': 0})
76@main_bp.route('/eventsList/<selectedTerm>/<activeTab>', methods=['GET'], defaults={'programID': 0})
77@main_bp.route('/eventsList/<selectedTerm>/<activeTab>/<programID>', methods=['GET'])
78def events(selectedTerm, activeTab, programID):
80 currentTime = datetime.datetime.now()
81 listOfTerms = Term.select().order_by(Term.termOrder)
82 participantRSVP = EventRsvp.select(EventRsvp, Event).join(Event).where(EventRsvp.user == g.current_user)
83 rsvpedEventsID = [event.event.id for event in participantRSVP]
85 term = g.current_term
86 if selectedTerm:
87 term = selectedTerm
89 # Make sure we have a Term object
90 term = Term.get_or_none(Term.id == term)
91 if term is None:
92 term = Term.get(Term.isCurrentTerm == True)
94 currentEventRsvpAmount = getEventRsvpCountsForTerm(term)
95 volunteerOpportunities = getVolunteerOpportunities(term)
96 countUpcomingVolunteerOpportunities = getUpcomingVolunteerOpportunitiesCount(term, currentTime)
97 countPastVolunteerOpportunities = getPastVolunteerOpportunitiesCount(term, currentTime)
98 trainingEvents = getTrainingEvents(term, g.current_user)
99 engagementEvents = getEngagementEvents(term)
100 bonnerEvents = getBonnerEvents(term)
101 celtsLabor = getCeltsLabor(term)
103 managersProgramDict = getManagerProgramDict(g.current_user)
105 # Fetch toggle state from session
106 toggleState = request.args.get('toggleState', 'unchecked')
108 # compile all volunteer opportunitiesevents into one list
109 studentEvents = []
110 for studentEvent in volunteerOpportunities.values():
111 studentEvents += studentEvent # add all contents of studentEvent to the studentEvents list
113 # Get the count of all term events for each category to display in the event list page.
114 volunteerOpportunitiesCount: int = len(studentEvents)
115 countUpcomingVolunteerOpportunitiesCount: int = len(countUpcomingVolunteerOpportunities)
116 countPastVolunteerOpportunitiesCount: int = len(countPastVolunteerOpportunities)
117 trainingEventsCount: int = len(trainingEvents)
118 engagementEventsCount: int = len(engagementEvents)
119 bonnerEventsCount: int = len(bonnerEvents)
120 celtsLaborCount: int = len(celtsLabor)
122 # gets only upcoming events to display in indicators
123 if (toggleState == 'unchecked'):
124 for event in trainingEvents:
125 if event.isPastEnd:
126 trainingEventsCount -= 1
127 for event in engagementEvents:
128 if event.isPastEnd:
129 engagementEventsCount -= 1
130 for event in bonnerEvents:
131 if event.isPastEnd:
132 bonnerEventsCount -= 1
133 for event in celtsLabor:
134 if event.isPastEnd:
135 celtsLaborCount -= 1
137 # Handle ajax request for Event category header number notifiers and toggle
138 if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
139 return jsonify({
140 "volunteerOpportunitiesCount": volunteerOpportunitiesCount,
141 "countPastVolunteerOpportunitiesCount": countPastVolunteerOpportunitiesCount,
142 "countUpcomingVolunteerOpportunitiesCount": countUpcomingVolunteerOpportunitiesCount,
143 "trainingEventsCount": trainingEventsCount,
144 "engagementEventsCount": engagementEventsCount,
145 "bonnerEventsCount": bonnerEventsCount,
146 "celtsLaborCount": celtsLaborCount,
147 "toggleStatus": toggleState
148 })
149 return render_template("/events/eventList.html",
150 selectedTerm = term,
151 volunteerOpportunities = volunteerOpportunities,
152 trainingEvents = trainingEvents,
153 engagementEvents = engagementEvents,
154 bonnerEvents = bonnerEvents,
155 celtsLabor = celtsLabor,
156 listOfTerms = listOfTerms,
157 rsvpedEventsID = rsvpedEventsID,
158 currentEventRsvpAmount = currentEventRsvpAmount,
159 currentTime = currentTime,
160 user = g.current_user,
161 activeTab = activeTab,
162 programID = int(programID),
163 managersProgramDict = managersProgramDict,
164 countUpcomingVolunteerOpportunities = countUpcomingVolunteerOpportunities,
165 countPastVolunteerOpportunities = countPastVolunteerOpportunities,
166 toggleState = toggleState,
167 )
169@main_bp.route('/profile/<username>', methods=['GET'])
170def viewUsersProfile(username):
171 """
172 This function displays the information of a volunteer to the user
173 """
174 try:
175 volunteer = User.get(User.username == username)
176 except Exception as e:
177 if g.current_user.isAdmin:
178 flash(f"{username} does not exist! ", category='danger')
179 return redirect(url_for('admin.studentSearchPage'))
180 else:
181 abort(403) # Error 403 if non admin/student-staff user trys to access via url
183 if (g.current_user == volunteer) or g.current_user.isAdmin:
184 upcomingEvents = getUpcomingEventsForUser(volunteer)
185 participatedEvents = getParticipatedEventsForUser(volunteer)
186 programs = Program.select()
187 if not g.current_user.isBonnerScholar and not g.current_user.isAdmin:
188 programs = programs.where(Program.isBonnerScholars == False)
189 interests = Interest.select(Interest, Program).join(Program).where(Interest.user == volunteer)
190 programsInterested = [interest.program for interest in interests]
192 rsvpedEventsList = EventRsvp.select(EventRsvp, Event).join(Event).where(EventRsvp.user == volunteer)
193 rsvpedEvents = [event.event.id for event in rsvpedEventsList]
195 programManagerPrograms = ProgramManager.select(ProgramManager, Program).join(Program).where(ProgramManager.user == volunteer)
196 permissionPrograms = [entry.program.id for entry in programManagerPrograms]
198 allBackgroundHistory = getUserBGCheckHistory(volunteer)
199 backgroundTypes = list(BackgroundCheckType.select())
202 eligibilityTable = []
204 for program in programs:
205 banNotes = list(ProgramBan.select(ProgramBan, Note)
206 .join(Note, on=(ProgramBan.banNote == Note.id))
207 .where(ProgramBan.user == volunteer,
208 ProgramBan.program == program,
209 ProgramBan.endDate > datetime.datetime.now()).execute())
210 onTranscriptQuery = list(ProgramBan.select(ProgramBan)
211 .where(ProgramBan.user == volunteer,
212 ProgramBan.program == program,
213 ProgramBan.unbanNote.is_null(),
214 ProgramBan.removeFromTranscript == 0))
216 onTranscript = True if len(onTranscriptQuery) > 0 else False
217 userParticipatedTrainingEvents = getParticipationStatusForTrainings(program, [volunteer], g.current_term)
218 try:
219 allTrainingsComplete = False not in [attended for event, attended in userParticipatedTrainingEvents[username]] # Did volunteer attend all events
220 except KeyError:
221 allTrainingsComplete = False
222 noteForDict = banNotes[-1].banNote.noteContent if banNotes else ""
223 eligibilityTable.append({"program": program,
224 "completedTraining": allTrainingsComplete,
225 "trainingList": userParticipatedTrainingEvents,
226 "isNotBanned": (not banNotes),
227 "banNote": noteForDict,
228 "onTranscript": onTranscript}),
230 profileNotes = ProfileNote.select().where(ProfileNote.user == volunteer)
232 bonnerRequirements = getCertRequirementsWithCompletion(certification=Certification.BONNER, username=volunteer)
234 managersProgramDict = getManagerProgramDict(g.current_user)
235 managersList = [id[1] for id in managersProgramDict.items()]
236 totalSustainedEngagements = getEngagementTotal(getCommunityEngagementByTerm(volunteer))
237 handbookOverdue = getHandbookStatus(volunteer)
239 training = hasGoneToTraining(g.current_user, g.current_term)
241 return render_template ("/main/userProfile.html",
242 username=username,
243 programs = programs,
244 programsInterested = programsInterested,
245 upcomingEvents = upcomingEvents,
246 participatedEvents = participatedEvents,
247 rsvpedEvents = rsvpedEvents,
248 permissionPrograms = permissionPrograms,
249 eligibilityTable = eligibilityTable,
250 volunteer = volunteer,
251 backgroundTypes = backgroundTypes,
252 allBackgroundHistory = allBackgroundHistory,
253 currentDateTime = datetime.datetime.now(),
254 profileNotes = profileNotes,
255 bonnerRequirements = bonnerRequirements,
256 managersList = managersList,
257 participatedInLabor = getCeltsLaborHistory(volunteer),
258 totalSustainedEngagements = totalSustainedEngagements,
259 handbookOverdue = handbookOverdue,
260 training = training,
261 )
262 abort(403)
264def getHandbookStatus(volunteer):
265 handbookOverdue = False
266 if not volunteer.signatureTerm or volunteer.signatureTerm.academicYear != g.current_term.academicYear:
267 handbookOverdue = True
268 return handbookOverdue
270@main_bp.route('/profile/<username>/emergencyContact', methods=['GET', 'POST'])
271def emergencyContactInfo(username):
272 """
273 This loads the Emergency Contact Page
274 """
275 if not (g.current_user.username == username or g.current_user.isCeltsAdmin):
276 abort(403)
278 user = User.get(User.username == username)
280 if request.method == 'GET':
281 readOnly = g.current_user.username != username
282 contactInfo = EmergencyContact.get_or_none(EmergencyContact.user_id == username)
283 return render_template ("/main/emergencyContactInfo.html",
284 username=username,
285 contactInfo=contactInfo,
286 readOnly=readOnly
287 )
289 elif request.method == 'POST':
290 if g.current_user.username != username:
291 abort(403)
293 rowsUpdated = EmergencyContact.update(**request.form).where(EmergencyContact.user == username).execute()
294 if not rowsUpdated:
295 EmergencyContact.create(user = username, **request.form)
297 createActivityLog(f"{g.current_user.fullName} updated {user.fullName}'s emergency contact information.")
298 flash('Emergency contact information saved successfully!', 'success')
300 if request.args.get('action') == 'exit':
301 return redirect (f"/profile/{username}")
302 else:
303 return redirect (f"/profile/{username}/insuranceInfo")
305@main_bp.route('/profile/<username>/insuranceInfo', methods=['GET', 'POST'])
306def insuranceInfo(username):
307 """
308 This loads the Insurance Information Page
309 """
310 if not (g.current_user.username == username or g.current_user.isCeltsAdmin):
311 abort(403)
313 user = User.get(User.username == username)
315 if request.method == 'GET':
316 readOnly = g.current_user.username != username
317 userInsuranceInfo = InsuranceInfo.get_or_none(InsuranceInfo.user == username)
318 return render_template ("/main/insuranceInfo.html",
319 username=username,
320 userInsuranceInfo=userInsuranceInfo,
321 readOnly=readOnly
322 )
324 # Save the form data
325 elif request.method == 'POST':
326 if g.current_user.username != username:
327 abort(403)
329 InsuranceInfo.replace({**request.form, "user": username}).execute()
331 createActivityLog(f"{g.current_user.fullName} updated {user.fullName}'s insurance information.")
332 flash('Insurance information saved successfully!', 'success')
334 if request.args.get('action') == 'exit':
335 return redirect (f"/profile/{username}")
336 else:
337 return redirect (f"/profile/{username}/emergencyContact")
339@main_bp.route('/profile/<username>/travelForm', methods=['GET', 'POST'])
340def travelForm(username):
341 if not (g.current_user.username == username or g.current_user.isCeltsAdmin):
342 abort(403)
344 user = (User.select(User, EmergencyContact, InsuranceInfo)
345 .join(EmergencyContact, JOIN.LEFT_OUTER).switch()
346 .join(InsuranceInfo, JOIN.LEFT_OUTER)
347 .where(User.username == username).limit(1))
348 if not list(user):
349 abort(404)
350 userList = list(user.dicts())[0]
351 userList = [{key: value if value else '' for (key, value) in userList.items()}]
353 return render_template ('/main/travelForm.html',
354 userList = userList
355 )
357@main_bp.route('/event/<eventID>/travelForm', methods=['GET', 'POST'])
358def eventTravelForm(eventID):
359 try:
360 event = Event.get_by_id(eventID)
361 except DoesNotExist as e:
362 print(f"No event found for {eventID}", e)
363 abort(404)
365 if not (g.current_user.isCeltsAdmin):
366 abort(403)
368 if request.method == "POST" and request.form.getlist("username") != []:
369 usernameList = request.form.getlist("username")
370 usernameList = usernameList.copy()
371 userList = []
372 for username in usernameList:
373 user = (User.select(User, EmergencyContact, InsuranceInfo)
374 .join(EmergencyContact, JOIN.LEFT_OUTER).switch()
375 .join(InsuranceInfo, JOIN.LEFT_OUTER)
376 .where(User.username == username).limit(1))
377 if not list(username):
378 abort(404)
379 userData = list(user.dicts())[0]
380 userData = {key: value if value else '' for (key, value) in userData.items()}
381 userList.append(userData)
384 else:
385 return redirect(f"/event/{eventID}/volunteer_details")
388 return render_template ('/main/travelForm.html',
389 usernameList = usernameList,
390 userList = userList,
391 )
393@main_bp.route('/profile/addNote', methods=['POST'])
394def addNote():
395 """
396 This function adds a note to the user's profile.
397 """
398 postData = request.form
399 try:
400 note = addProfileNote(postData["visibility"], postData["bonner"] == "yes", postData["noteTextbox"], postData["username"])
401 flash("Successfully added profile note", "success")
402 return redirect(url_for("main.viewUsersProfile", username=postData["username"]))
403 except Exception as e:
404 print("Error adding note", e)
405 flash("Failed to add profile note", "danger")
406 return "Failed to add profile note", 500
409@main_bp.route('/<username>/deleteNote', methods=['POST'])
410def deleteNote(username):
411 """
412 This function deletes a note from the user's profile.
413 """
414 try:
415 deleteProfileNote(request.form["id"])
416 flash("Successfully deleted profile note", "success")
417 except Exception as e:
418 print("Error deleting note", e)
419 flash("Failed to delete profile note", "danger")
420 return "success"
422# ===========================Ban===============================================
423@main_bp.route('/<username>/ban/<program_id>', methods=['POST'])
424def ban(program_id, username):
425 """
426 This function updates the ban status of a username either when they are banned from a program.
427 program_id: the primary id of the program the student is being banned from
428 username: unique value of a user to correctly identify them
429 """
430 postData = request.form
431 banNote = postData["note"] # This contains the note left about the change
432 banEndDate = postData["endDate"] # Contains the date the ban will no longer be effective
434 try:
435 banUser(program_id, username, banNote, banEndDate, g.current_user)
436 programInfo = Program.get(int(program_id))
437 flash("Successfully marked the volunteer as ineligible", "success")
438 createActivityLog(f'Marked {username} as ineligible from {programInfo.programName} until {banEndDate}.')
439 return "Successfully marked the volunteer as ineligible."
440 except Exception as e:
441 print("Error while updating ban", e)
442 flash("Failed to mark the volunteer as ineligible", "danger")
443 return "Failed to mark the volunteer as ineligible", 500
445# ===========================Unban===============================================
446@main_bp.route('/<username>/unban/<program_id>', methods=['POST'])
447def unban(program_id, username):
448 """
449 This function updates the ban status of a username either when they are unbanned from a program.
450 program_id: the primary id of the program the student is being unbanned from
451 username: unique value of a user to correctly identify them
452 """
453 postData = request.form
454 unbanNote = postData["note"] # This contains the note left about the change
455 try:
456 unbanUser(program_id, username, unbanNote, g.current_user)
457 programInfo = Program.get(int(program_id))
458 createActivityLog(f'marked {username} as eligible from {programInfo.programName}.')
459 flash("Successfully marked the volunteer as eligible", "success")
460 return "Successfully marked the volunteer as eligible"
462 except Exception as e:
463 print("Error while updating Unban", e)
464 flash("Failed to mark the volunteer as eligible", "danger")
465 return "Failed to mark the volunteer as eligible", 500
467@main_bp.route('/<username>/addInterest/<program_id>', methods=['POST'])
468@main_bp.route('/<username>/addInterest/<program_id>/<showFlash>', methods=['POST'])
469def addInterest(program_id, username, showFlash = True):
470 """
471 This function adds a program to the list of programs a user interested in
472 program_id: the primary id of the program the student is adding interest of
473 username: unique value of a user to correctly identify them
474 """
475 showFlash = False if showFlash == "False" else True
476 try:
477 success = addUserInterest(program_id, username)
478 if success:
479 if bool(showFlash):
480 flash("Successfully added " + Program.get_by_id(program_id).programName + " as an interest", "success")
481 return jsonify(model_to_dict(User.get_or_none(User.username == username)))
482 else:
483 if bool(showFlash):
484 flash("Was unable to add " + Program.get_by_id(program_id).programName + " as an interest.", "danger")
486 except Exception as e:
487 print(e)
488 return "Error Updating Interest", 500
490@main_bp.route('/<username>/removeInterest/<program_id>', methods=['POST'])
491def removeInterest(program_id, username):
492 """
493 This function removes a program to the list of programs a user interested in
494 program_id: the primary id of the program the student is adding interest of
495 username: unique value of a user to correctly identify them
496 """
497 try:
498 removed = removeUserInterest(program_id, username)
499 if removed:
500 flash("Successfully removed " + Program.get_by_id(program_id).programName + " as an interest.", "success")
501 return ""
502 else:
503 flash("Was unable to remove " + Program.get_by_id(program_id).programName + " as an interest.", "danger")
504 except Exception as e:
505 print(e)
506 return "Error Updating Interest", 500
508@main_bp.route('/rsvpForEvent', methods = ['POST'])
509def volunteerRegister():
510 """
511 This function selects the user ID and event ID and registers the user
512 for the event they have clicked register for.
513 """
514 event = Event.get_by_id(request.form['id'])
515 program = event.program
516 user = g.current_user
517 now = datetime.datetime.now()
518 isEligible = False if isBannedFromEvent(user, event) else True
520 personAdded = False
521 if isEligible:
522 personAdded = addPersonToEvent(user, event)
523 if personAdded:
524 flash("Successfully registered for event!","success")
525 else:
526 flash(f"RSVP Failed due to an unknown error.", "danger")
527 else:
528 flash(f"Cannot RSVP. Contact CELTS administrators: {app.config['celts_admin_contact']}.", "danger")
530 if 'from' in request.form:
531 if request.form['from'] == 'ajax':
532 return ''
533 return redirect(url_for("admin.eventDisplay", eventId=event.id))
535@main_bp.route('/rsvpRemove', methods = ['POST'])
536def RemoveRSVP():
537 """
538 This function deletes the user ID and event ID from database when RemoveRSVP is clicked
539 """
540 eventData = request.form
541 event = Event.get_by_id(eventData['id'])
543 currentRsvpParticipant = EventRsvp.get(EventRsvp.user == g.current_user, EventRsvp.event == event)
544 logBody = "withdrew from the waitlist" if currentRsvpParticipant.rsvpWaitlist else "un-RSVP'd"
545 currentRsvpParticipant.delete_instance()
546 createRsvpLog(event.id, f"{g.current_user.fullName} {logBody}.")
547 flash("Successfully unregistered for event!", "success")
548 if 'from' in eventData:
549 if eventData['from'] == 'ajax':
550 return ''
551 return redirect(url_for("admin.eventDisplay", eventId=event.id))
553@main_bp.route('/profile/<username>/serviceTranscript', methods = ['GET'])
554def serviceTranscript(username):
555 user = User.get_or_none(User.username == username)
556 if user is None:
557 abort(404)
558 if user != g.current_user and not g.current_user.isAdmin:
559 abort(403)
561 slCourses = getSlCourseTranscript(username)
562 totalHours = getTotalHours(username)
563 allEventTranscript = getProgramTranscript(username)
564 zeroHourEvents = getZeroHourEvents(username)
565 startDate = getStartYear(username)
566 return render_template('main/serviceTranscript.html',
567 allEventTranscript = allEventTranscript,
568 zeroHourEvents = zeroHourEvents,
569 slCourses = slCourses.objects(),
570 totalHours = totalHours,
571 startDate = startDate,
572 userData = user)
574@main_bp.route('/profile/<username>/updateTranscript/<program_id>', methods=['POST'])
575def updateTranscript(username, program_id):
576 # Check user permissions
577 user = User.get_or_none(User.username == username)
578 if user is None:
579 abort(404)
580 if user != g.current_user and not g.current_user.isAdmin:
581 abort(403)
583 # Get the data sent from the client-side JavaScript
584 data = request.json
586 # Retrieve removeFromTranscript value from the request data
587 removeFromTranscript = data.get('removeFromTranscript')
589 # Update the ProgramBan object matching the program_id and username
590 try:
591 bannedProgramForUser = ProgramBan.get((ProgramBan.program == program_id) & (ProgramBan.user == user) & (ProgramBan.unbanNote.is_null()))
592 bannedProgramForUser.removeFromTranscript = removeFromTranscript
593 bannedProgramForUser.save()
594 return jsonify({'status': 'success'})
595 except ProgramBan.DoesNotExist:
596 return jsonify({'status': 'error', 'message': 'ProgramBan not found'})
599@main_bp.route('/searchUser/<query>', methods = ['GET'])
600def searchUser(query):
602 category= request.args.get("category")
604 '''Accepts user input and queries the database returning results that matches user search'''
605 try:
606 query = query.strip()
607 search = query.upper()
608 splitSearch = search.split()
609 searchResults = searchUsers(query,category)
610 return searchResults
611 except Exception as e:
612 print(e)
613 return "Error in searching for user", 500
615@main_bp.route('/contributors',methods = ['GET'])
616def contributors():
617 return render_template("/contributors.html")
619@main_bp.route('/updateDietInformation', methods = ['GET', 'POST'])
620def getDietInfo():
621 dietaryInfo = request.form
622 user = dietaryInfo["user"]
623 dietInfo = dietaryInfo["dietInfo"]
625 if (g.current_user.username == user) or g.current_user.isAdmin:
626 updateDietInfo(user, dietInfo)
627 userInfo = User.get(User.username == user)
628 if len(dietInfo) > 0:
629 createActivityLog(f"Updated {userInfo.fullName}'s dietary restrictions to {dietInfo}.") if dietInfo.strip() else None
630 else:
631 createActivityLog(f"Deleted all {userInfo.fullName}'s dietary restrictions dietary restrictions.")
634 return " "
636@main_bp.route('/profile/<username>/indicateInterest', methods=['POST'])
637def indicateMinorInterest(username):
638 if g.current_user.isCeltsAdmin or g.current_user.username == username:
639 data = request.get_json()
640 isAdding = data.get("isAdding", False)
642 toggleMinorInterest(username, isAdding)
644 else:
645 abort(403)
647 return ""
649@main_bp.route('/profile/<username>/updateMinorDeclaration', methods=["POST"])
650def updateMinorDeclaration(username):
651 if g.current_user.isCeltsAdmin or g.current_user.username == username:
652 declareMinorInterest(username)
653 flash("Candidate minor successfully updated", "success")
654 else:
655 flash("Error updating candidate minor status", "danger")
656 abort(403)
658 tab = request.args.get("tab", "interested")
659 return redirect(url_for('admin.manageMinor', tab=tab))
661@main_bp.route('/extravaganza', methods=['GET'])
662def extravaganza():
663 programs = Program.select().where(Program.isOtherCeltsSponsored == False,
664 Program.programName != "Hunger Initiatives",
665 Program.programName != "Bonner Scholars")
666 interests = Interest.select(Interest, Program).join(Program).where(Interest.user == g.current_user)
667 programsInterested = [interest.program for interest in interests]
669 upcomingAllVolunteers = Event.select().join(Term).where(Event.isAllVolunteerTraining, Term.academicYear == g.current_term.academicYear)
670 for training in upcomingAllVolunteers:
671 training.startDate = training.startDate.strftime("%b %d")
672 training.timeStart = training.timeStart.strftime("%I:%M %p")
674 upcomingTrainings = Event.select().join(Term).where(Event.isTraining, Term.academicYear == g.current_term.academicYear)
676 for training in upcomingTrainings:
677 training.startDate = training.startDate.strftime("%b %d")
678 training.timeStart = training.timeStart.strftime("%I:%M %p")
680 return render_template("main/extravanganzaWelcome.html",
681 programs = programs,
682 programsInterested = programsInterested,
683 upcomingTrainings = upcomingTrainings,
684 upcomingAllVolunteers = upcomingAllVolunteers
685 )