Coverage for app/controllers/main/routes.py: 22%
429 statements
« prev ^ index » next coverage.py v7.10.2, created at 2026-09-04 14:24 +0000
« prev ^ index » next coverage.py v7.10.2, created at 2026-09-04 14:24 +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 *
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 try:
396 noteData = getProfileNoteData(
397 request.form,
398 includeUsername=True,
399 )
400 addProfileNote(**noteData)
401 flash("Successfully added profile note", "success")
402 except Exception as error:
403 print("Error adding profile note:", error)
404 flash("Failed to add profile note", "danger")
405 return str(error), 500
406 return "success"
407@main_bp.route("/<username>/editNote", methods=["POST"])
408def editProfileNote(username):
409 try:
410 noteData = getProfileNoteData( request.form, includeId=True, )
411 profileNote = ProfileNote.get_by_id(noteData["profileNoteID"] )
412 if (profileNote.user.username != username or (profileNote.note.createdBy != g.current_user and not g.current_user.isCeltsAdmin) ):
413 abort(403)
414 updateProfileNote(**noteData)
415 flash("Successfully updated profile note", "success")
416 except Exception as error:
417 print("Error updating profile note:", error)
418 flash("Failed to update profile note", "danger")
419 return str(error), 500
420 return "success"
421@main_bp.route('/<username>/deleteNote', methods=['POST'])
422def deleteNote(username):
423 """
424 This function deletes a note from the user's profile.
425 """
426 try:
427 deleteProfileNote(request.form["id"])
428 flash("Successfully deleted profile note", "success")
429 except Exception as e:
430 print("Error deleting note", e)
431 flash("Failed to delete profile note", "danger")
432 return "success"
434# ===========================Ban===============================================
435@main_bp.route('/<username>/ban/<program_id>', methods=['POST'])
436def ban(program_id, username):
437 """
438 This function updates the ban status of a username either when they are banned from a program.
439 program_id: the primary id of the program the student is being banned from
440 username: unique value of a user to correctly identify them
441 """
442 postData = request.form
443 banNote = postData["note"] # This contains the note left about the change
444 banEndDate = postData["endDate"] # Contains the date the ban will no longer be effective
446 try:
447 banUser(program_id, username, banNote, banEndDate, g.current_user)
448 programInfo = Program.get(int(program_id))
449 flash("Successfully marked the volunteer as ineligible", "success")
450 createActivityLog(f'Marked {username} as ineligible from {programInfo.programName} until {banEndDate}.')
451 return "Successfully marked the volunteer as ineligible."
452 except Exception as e:
453 print("Error while updating ban", e)
454 flash("Failed to mark the volunteer as ineligible", "danger")
455 return "Failed to mark the volunteer as ineligible", 500
457# ===========================Unban===============================================
458@main_bp.route('/<username>/unban/<program_id>', methods=['POST'])
459def unban(program_id, username):
460 """
461 This function updates the ban status of a username either when they are unbanned from a program.
462 program_id: the primary id of the program the student is being unbanned from
463 username: unique value of a user to correctly identify them
464 """
465 postData = request.form
466 unbanNote = postData["note"] # This contains the note left about the change
467 try:
468 unbanUser(program_id, username, unbanNote, g.current_user)
469 programInfo = Program.get(int(program_id))
470 createActivityLog(f'marked {username} as eligible from {programInfo.programName}.')
471 flash("Successfully marked the volunteer as eligible", "success")
472 return "Successfully marked the volunteer as eligible"
474 except Exception as e:
475 print("Error while updating Unban", e)
476 flash("Failed to mark the volunteer as eligible", "danger")
477 return "Failed to mark the volunteer as eligible", 500
479@main_bp.route('/<username>/addInterest/<program_id>', methods=['POST'])
480@main_bp.route('/<username>/addInterest/<program_id>/<showFlash>', methods=['POST'])
481def addInterest(program_id, username, showFlash = True):
482 """
483 This function adds a program to the list of programs a user interested in
484 program_id: the primary id of the program the student is adding interest of
485 username: unique value of a user to correctly identify them
486 """
487 showFlash = False if showFlash == "False" else True
488 try:
489 success = addUserInterest(program_id, username)
490 if success:
491 if bool(showFlash):
492 flash("Successfully added " + Program.get_by_id(program_id).programName + " as an interest", "success")
493 return jsonify(model_to_dict(User.get_or_none(User.username == username)))
494 else:
495 if bool(showFlash):
496 flash("Was unable to add " + Program.get_by_id(program_id).programName + " as an interest.", "danger")
498 except Exception as e:
499 print(e)
500 return "Error Updating Interest", 500
502@main_bp.route('/<username>/removeInterest/<program_id>', methods=['POST'])
503def removeInterest(program_id, username):
504 """
505 This function removes a program to the list of programs a user interested in
506 program_id: the primary id of the program the student is adding interest of
507 username: unique value of a user to correctly identify them
508 """
509 try:
510 removed = removeUserInterest(program_id, username)
511 if removed:
512 flash("Successfully removed " + Program.get_by_id(program_id).programName + " as an interest.", "success")
513 return ""
514 else:
515 flash("Was unable to remove " + Program.get_by_id(program_id).programName + " as an interest.", "danger")
516 except Exception as e:
517 print(e)
518 return "Error Updating Interest", 500
520@main_bp.route('/rsvpForEvent', methods = ['POST'])
521def volunteerRegister():
522 """
523 This function selects the user ID and event ID and registers the user
524 for the event they have clicked register for.
525 """
526 event = Event.get_by_id(request.form['id'])
527 program = event.program
528 user = g.current_user
529 now = datetime.datetime.now()
530 isEligible = False if isBannedFromEvent(user, event) else True
532 personAdded = False
533 if isEligible:
534 personAdded = addPersonToEvent(user, event)
535 if personAdded:
536 flash("Successfully registered for event!","success")
537 else:
538 flash(f"RSVP Failed due to an unknown error.", "danger")
539 else:
540 flash(f"Cannot RSVP. Contact CELTS administrators: {app.config['celts_admin_contact']}.", "danger")
542 if 'from' in request.form:
543 if request.form['from'] == 'ajax':
544 return ''
545 return redirect(url_for("admin.eventDisplay", eventId=event.id))
547@main_bp.route('/rsvpRemove', methods = ['POST'])
548def RemoveRSVP():
549 """
550 This function deletes the user ID and event ID from database when RemoveRSVP is clicked
551 """
552 eventData = request.form
553 event = Event.get_by_id(eventData['id'])
555 currentRsvpParticipant = EventRsvp.get(EventRsvp.user == g.current_user, EventRsvp.event == event)
556 logBody = "withdrew from the waitlist" if currentRsvpParticipant.rsvpWaitlist else "un-RSVP'd"
557 currentRsvpParticipant.delete_instance()
558 createRsvpLog(event.id, f"{g.current_user.fullName} {logBody}.")
559 flash("Successfully unregistered for event!", "success")
560 if 'from' in eventData:
561 if eventData['from'] == 'ajax':
562 return ''
563 return redirect(url_for("admin.eventDisplay", eventId=event.id))
565@main_bp.route('/profile/<username>/serviceTranscript', methods = ['GET'])
566def serviceTranscript(username):
567 user = User.get_or_none(User.username == username)
568 if user is None:
569 abort(404)
570 if user != g.current_user and not g.current_user.isAdmin:
571 abort(403)
573 slCourses = getSlCourseTranscript(username)
574 totalHours = getTotalHours(username)
575 allEventTranscript = getProgramTranscript(username)
576 zeroHourEvents = getZeroHourEvents(username)
577 startDate = getStartYear(username)
578 return render_template('main/serviceTranscript.html',
579 allEventTranscript = allEventTranscript,
580 zeroHourEvents = zeroHourEvents,
581 slCourses = slCourses.objects(),
582 totalHours = totalHours,
583 startDate = startDate,
584 userData = user)
586@main_bp.route('/profile/<username>/updateTranscript/<program_id>', methods=['POST'])
587def updateTranscript(username, program_id):
588 # Check user permissions
589 user = User.get_or_none(User.username == username)
590 if user is None:
591 abort(404)
592 if user != g.current_user and not g.current_user.isAdmin:
593 abort(403)
595 # Get the data sent from the client-side JavaScript
596 data = request.json
598 # Retrieve removeFromTranscript value from the request data
599 removeFromTranscript = data.get('removeFromTranscript')
601 # Update the ProgramBan object matching the program_id and username
602 try:
603 bannedProgramForUser = ProgramBan.get((ProgramBan.program == program_id) & (ProgramBan.user == user) & (ProgramBan.unbanNote.is_null()))
604 bannedProgramForUser.removeFromTranscript = removeFromTranscript
605 bannedProgramForUser.save()
606 return jsonify({'status': 'success'})
607 except ProgramBan.DoesNotExist:
608 return jsonify({'status': 'error', 'message': 'ProgramBan not found'})
611@main_bp.route('/searchUser/<query>', methods = ['GET'])
612def searchUser(query):
614 category= request.args.get("category")
616 '''Accepts user input and queries the database returning results that matches user search'''
617 try:
618 query = query.strip()
619 search = query.upper()
620 splitSearch = search.split()
621 searchResults = searchUsers(query,category)
622 return searchResults
623 except Exception as e:
624 print(e)
625 return "Error in searching for user", 500
627@main_bp.route('/contributors',methods = ['GET'])
628def contributors():
629 return render_template("/contributors.html")
631@main_bp.route('/updateDietInformation', methods = ['GET', 'POST'])
632def getDietInfo():
633 dietaryInfo = request.form
634 user = dietaryInfo["user"]
635 dietInfo = dietaryInfo["dietInfo"]
637 if (g.current_user.username == user) or g.current_user.isAdmin:
638 updateDietInfo(user, dietInfo)
639 userInfo = User.get(User.username == user)
640 if len(dietInfo) > 0:
641 createActivityLog(f"Updated {userInfo.fullName}'s dietary restrictions to {dietInfo}.") if dietInfo.strip() else None
642 else:
643 createActivityLog(f"Deleted all {userInfo.fullName}'s dietary restrictions dietary restrictions.")
646 return " "
648@main_bp.route('/profile/<username>/indicateInterest', methods=['POST'])
649def indicateMinorInterest(username):
650 if g.current_user.isCeltsAdmin or g.current_user.username == username:
651 data = request.get_json()
652 isAdding = data.get("isAdding", False)
654 toggleMinorInterest(username, isAdding)
656 else:
657 abort(403)
659 return ""
661@main_bp.route('/profile/<username>/updateMinorDeclaration', methods=["POST"])
662def updateMinorDeclaration(username):
663 if g.current_user.isCeltsAdmin or g.current_user.username == username:
664 declareMinorInterest(username)
665 flash("Candidate minor successfully updated", "success")
666 else:
667 flash("Error updating candidate minor status", "danger")
668 abort(403)
670 tab = request.args.get("tab", "interested")
671 return redirect(url_for('admin.manageMinor', tab=tab))
673@main_bp.route('/extravaganza', methods=['GET'])
674def extravaganza():
675 programs = Program.select().where(Program.isOtherCeltsSponsored == False,
676 Program.programName != "Hunger Initiatives",
677 Program.programName != "Bonner Scholars")
678 interests = Interest.select(Interest, Program).join(Program).where(Interest.user == g.current_user)
679 programsInterested = [interest.program for interest in interests]
681 upcomingAllVolunteers = Event.select().join(Term).where(Event.isAllVolunteerTraining, Term.academicYear == g.current_term.academicYear)
682 for training in upcomingAllVolunteers:
683 training.startDate = training.startDate.strftime("%b %d")
684 training.timeStart = training.timeStart.strftime("%I:%M %p")
686 upcomingTrainings = Event.select().join(Term).where(Event.isTraining, Term.academicYear == g.current_term.academicYear)
688 for training in upcomingTrainings:
689 training.startDate = training.startDate.strftime("%b %d")
690 training.timeStart = training.timeStart.strftime("%I:%M %p")
692 return render_template("main/extravanganzaWelcome.html",
693 programs = programs,
694 programsInterested = programsInterested,
695 upcomingTrainings = upcomingTrainings,
696 upcomingAllVolunteers = upcomingAllVolunteers
697 )