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