Coverage for app/controllers/main/routes.py: 23%

389 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2025-07-22 20:03 +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 

7 

8from app.controllers.main import main_bp 

9from app import app 

10from app.models.term import Term 

11from app.models.user import User 

12from app.models.note import Note 

13from app.models.event import Event 

14from app.models.program import Program 

15from app.models.interest import Interest 

16from app.models.eventRsvp import EventRsvp 

17from app.models.celtsLabor import CeltsLabor 

18from app.models.programBan import ProgramBan 

19from app.models.profileNote import ProfileNote 

20from app.models.insuranceInfo import InsuranceInfo 

21from app.models.certification import Certification 

22from app.models.programManager import ProgramManager 

23from app.models.backgroundCheck import BackgroundCheck 

24from app.models.emergencyContact import EmergencyContact 

25from app.models.eventParticipant import EventParticipant 

26from app.models.courseInstructor import CourseInstructor 

27from app.models.backgroundCheckType import BackgroundCheckType 

28 

29from app.logic.events import getUpcomingEventsForUser, getParticipatedEventsForUser, getTrainingEvents, getEventRsvpCountsForTerm, getUpcomingStudentLedCount, getStudentLedEvents, getBonnerEvents, getOtherEvents, getEngagementEvents 

30from app.logic.transcript import * 

31from app.logic.loginManager import logout 

32from app.logic.searchUsers import searchUsers 

33from app.logic.utils import selectSurroundingTerms 

34from app.logic.celtsLabor import getCeltsLaborHistory 

35from app.logic.createLogs import createRsvpLog, createActivityLog 

36from app.logic.certification import getCertRequirementsWithCompletion 

37from app.logic.landingPage import getManagerProgramDict, getActiveEventTab 

38from app.logic.minor import toggleMinorInterest, declareMinorInterest, getCommunityEngagementByTerm, getEngagementTotal 

39from app.logic.participants import unattendedRequiredEvents, trainedParticipants, getParticipationStatusForTrainings, checkUserRsvp, addPersonToEvent 

40from app.logic.users import addUserInterest, removeUserInterest, banUser, unbanUser, isEligibleForProgram, getUserBGCheckHistory, addProfileNote, deleteProfileNote, updateDietInfo 

41 

42@main_bp.route('/logout', methods=['GET']) 

43def redirectToLogout(): 

44 return redirect(logout()) 

45 

46@main_bp.route('/', methods=['GET']) 

47def landingPage(): 

48 

49 managerProgramDict = getManagerProgramDict(g.current_user) 

50 # Optimize the query to fetch programs with non-canceled, non-past events in the current term 

51 

52 programsWithEventsList = list(Program.select(Program, Event) 

53 .join(Event) 

54 .where((Event.term == g.current_term) & (Event.isCanceled == False)) 

55 .distinct() 

56 .execute()) # Ensure only unique programs are included 

57 # Limit returned list to events in the future 

58 futureEvents = [p for p in programsWithEventsList if not p.event.isPastEnd] 

59 

60 return render_template("/main/landingPage.html", 

61 managerProgramDict=managerProgramDict, 

62 term=g.current_term, 

63 programsWithEventsList = futureEvents) 

64 

65 

66 

67 

68@main_bp.route('/goToEventsList/<programID>', methods=['GET']) 

69def goToEventsList(programID): 

70 return {"activeTab": getActiveEventTab(programID)} 

71 

72@main_bp.route('/eventsList/<selectedTerm>', methods=['GET'], defaults={'activeTab': "studentLedEvents", 'programID': 0}) 

73@main_bp.route('/eventsList/<selectedTerm>/<activeTab>', methods=['GET'], defaults={'programID': 0}) 

74@main_bp.route('/eventsList/<selectedTerm>/<activeTab>/<programID>', methods=['GET']) 

75def events(selectedTerm, activeTab, programID): 

76 currentTerm = g.current_term 

77 if selectedTerm: 

78 currentTerm = selectedTerm 

79 

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] 

84 

85 term: Term = Term.get_by_id(currentTerm) 

86 

87 currentEventRsvpAmount = getEventRsvpCountsForTerm(term) 

88 studentLedEvents = getStudentLedEvents(term) 

89 countUpcomingStudentLedEvents = getUpcomingStudentLedCount(term, currentTime) 

90 trainingEvents = getTrainingEvents(term, g.current_user) 

91 engagementEvents = getEngagementEvents(term) 

92 bonnerEvents = getBonnerEvents(term) 

93 otherEvents = getOtherEvents(term) 

94 

95 managersProgramDict = getManagerProgramDict(g.current_user) 

96 

97 # Fetch toggle state from session  

98 toggleState = request.args.get('toggleState', 'unchecked') 

99 

100 # compile all student led events into one list 

101 studentEvents = [] 

102 for studentEvent in studentLedEvents.values(): 

103 studentEvents += studentEvent # add all contents of studentEvent to the studentEvents list 

104 

105 # Get the count of all term events for each category to display in the event list page. 

106 studentLedEventsCount: int = len(studentEvents) 

107 trainingEventsCount: int = len(trainingEvents) 

108 engagementEventsCount: int = len(engagementEvents) 

109 bonnerEventsCount: int = len(bonnerEvents) 

110 otherEventsCount: int = len(otherEvents) 

111 

112 # gets only upcoming events to display in indicators 

113 if (toggleState == 'unchecked'): 

114 studentLedEventsCount: int = sum(list(countUpcomingStudentLedEvents.values())) 

115 for event in trainingEvents: 

116 if event.isPastEnd: 

117 trainingEventsCount -= 1 

118 for event in engagementEvents: 

119 if event.isPastEnd: 

120 engagementEventsCount -= 1 

121 for event in bonnerEvents: 

122 if event.isPastEnd: 

123 bonnerEventsCount -= 1 

124 for event in otherEvents: 

125 if event.isPastEnd: 

126 otherEventsCount -= 1 

127 

128 # Handle ajax request for Event category header number notifiers and toggle 

129 if request.headers.get('X-Requested-With') == 'XMLHttpRequest': 

130 return jsonify({ 

131 "studentLedEventsCount": studentLedEventsCount, 

132 "trainingEventsCount": trainingEventsCount, 

133 "engagementEventsCount": engagementEventsCount, 

134 "bonnerEventsCount": bonnerEventsCount, 

135 "otherEventsCount": otherEventsCount, 

136 "toggleStatus": toggleState 

137 }) 

138 

139 return render_template("/events/eventList.html", 

140 selectedTerm = term, 

141 studentLedEvents = studentLedEvents, 

142 trainingEvents = trainingEvents, 

143 engagementEvents = engagementEvents, 

144 bonnerEvents = bonnerEvents, 

145 otherEvents = otherEvents, 

146 listOfTerms = listOfTerms, 

147 rsvpedEventsID = rsvpedEventsID, 

148 currentEventRsvpAmount = currentEventRsvpAmount, 

149 currentTime = currentTime, 

150 user = g.current_user, 

151 activeTab = activeTab, 

152 programID = int(programID), 

153 managersProgramDict = managersProgramDict, 

154 countUpcomingStudentLedEvents = countUpcomingStudentLedEvents, 

155 toggleState = toggleState, 

156 ) 

157 

158@main_bp.route('/profile/<username>', methods=['GET']) 

159def viewUsersProfile(username): 

160 """ 

161 This function displays the information of a volunteer to the user 

162 """ 

163 try: 

164 volunteer = User.get(User.username == username) 

165 except Exception as e: 

166 if g.current_user.isAdmin: 

167 flash(f"{username} does not exist! ", category='danger') 

168 return redirect(url_for('admin.studentSearchPage')) 

169 else: 

170 abort(403) # Error 403 if non admin/student-staff user trys to access via url 

171 

172 if (g.current_user == volunteer) or g.current_user.isAdmin: 

173 upcomingEvents = getUpcomingEventsForUser(volunteer) 

174 participatedEvents = getParticipatedEventsForUser(volunteer) 

175 programs = Program.select() 

176 if not g.current_user.isBonnerScholar and not g.current_user.isAdmin: 

177 programs = programs.where(Program.isBonnerScholars == False) 

178 interests = Interest.select(Interest, Program).join(Program).where(Interest.user == volunteer) 

179 programsInterested = [interest.program for interest in interests] 

180 

181 rsvpedEventsList = EventRsvp.select(EventRsvp, Event).join(Event).where(EventRsvp.user == volunteer) 

182 rsvpedEvents = [event.event.id for event in rsvpedEventsList] 

183 

184 programManagerPrograms = ProgramManager.select(ProgramManager, Program).join(Program).where(ProgramManager.user == volunteer) 

185 permissionPrograms = [entry.program.id for entry in programManagerPrograms] 

186 

187 allBackgroundHistory = getUserBGCheckHistory(volunteer) 

188 backgroundTypes = list(BackgroundCheckType.select()) 

189 

190 

191 

192 eligibilityTable = [] 

193 

194 for program in programs: 

195 banNotes = list(ProgramBan.select(ProgramBan, Note) 

196 .join(Note, on=(ProgramBan.banNote == Note.id)) 

197 .where(ProgramBan.user == volunteer, 

198 ProgramBan.program == program, 

199 ProgramBan.endDate > datetime.datetime.now()).execute()) 

200 onTranscriptQuery = list(ProgramBan.select(ProgramBan) 

201 .where(ProgramBan.user == volunteer, 

202 ProgramBan.program == program, 

203 ProgramBan.unbanNote.is_null(), 

204 ProgramBan.removeFromTranscript == 0)) 

205 

206 onTranscript = True if len(onTranscriptQuery) > 0 else False 

207 userParticipatedTrainingEvents = getParticipationStatusForTrainings(program, [volunteer], g.current_term) 

208 try: 

209 allTrainingsComplete = False not in [attended for event, attended in userParticipatedTrainingEvents[username]] # Did volunteer attend all events 

210 except KeyError: 

211 allTrainingsComplete = False 

212 noteForDict = banNotes[-1].banNote.noteContent if banNotes else "" 

213 eligibilityTable.append({"program": program, 

214 "completedTraining": allTrainingsComplete, 

215 "trainingList": userParticipatedTrainingEvents, 

216 "isNotBanned": (not banNotes), 

217 "banNote": noteForDict, 

218 "onTranscript": onTranscript}), 

219 

220 profileNotes = ProfileNote.select().where(ProfileNote.user == volunteer) 

221 

222 bonnerRequirements = getCertRequirementsWithCompletion(certification=Certification.BONNER, username=volunteer) 

223 

224 managersProgramDict = getManagerProgramDict(g.current_user) 

225 managersList = [id[1] for id in managersProgramDict.items()] 

226 totalSustainedEngagements = getEngagementTotal(getCommunityEngagementByTerm(volunteer)) 

227 

228 return render_template ("/main/userProfile.html", 

229 username=username, 

230 programs = programs, 

231 programsInterested = programsInterested, 

232 upcomingEvents = upcomingEvents, 

233 participatedEvents = participatedEvents, 

234 rsvpedEvents = rsvpedEvents, 

235 permissionPrograms = permissionPrograms, 

236 eligibilityTable = eligibilityTable, 

237 volunteer = volunteer, 

238 backgroundTypes = backgroundTypes, 

239 allBackgroundHistory = allBackgroundHistory, 

240 currentDateTime = datetime.datetime.now(), 

241 profileNotes = profileNotes, 

242 bonnerRequirements = bonnerRequirements, 

243 managersList = managersList, 

244 participatedInLabor = getCeltsLaborHistory(volunteer), 

245 totalSustainedEngagements = totalSustainedEngagements, 

246 expressInterest = volunteer.minorInterest 

247 ) 

248 abort(403) 

249 

250@main_bp.route('/profile/<username>/emergencyContact', methods=['GET', 'POST']) 

251def emergencyContactInfo(username): 

252 """ 

253 This loads the Emergency Contact Page 

254 """ 

255 if not (g.current_user.username == username or g.current_user.isCeltsAdmin): 

256 abort(403) 

257 

258 user = User.get(User.username == username) 

259 

260 if request.method == 'GET': 

261 readOnly = g.current_user.username != username 

262 contactInfo = EmergencyContact.get_or_none(EmergencyContact.user_id == username) 

263 return render_template ("/main/emergencyContactInfo.html", 

264 username=username, 

265 contactInfo=contactInfo, 

266 readOnly=readOnly 

267 ) 

268 

269 elif request.method == 'POST': 

270 if g.current_user.username != username: 

271 abort(403) 

272 

273 rowsUpdated = EmergencyContact.update(**request.form).where(EmergencyContact.user == username).execute() 

274 if not rowsUpdated: 

275 EmergencyContact.create(user = username, **request.form) 

276 

277 createActivityLog(f"{g.current_user.fullName} updated {user.fullName}'s emergency contact information.") 

278 flash('Emergency contact information saved successfully!', 'success') 

279 

280 if request.args.get('action') == 'exit': 

281 return redirect (f"/profile/{username}") 

282 else: 

283 return redirect (f"/profile/{username}/insuranceInfo") 

284 

285@main_bp.route('/profile/<username>/insuranceInfo', methods=['GET', 'POST']) 

286def insuranceInfo(username): 

287 """ 

288 This loads the Insurance Information Page 

289 """ 

290 if not (g.current_user.username == username or g.current_user.isCeltsAdmin): 

291 abort(403) 

292 

293 user = User.get(User.username == username) 

294 

295 if request.method == 'GET': 

296 readOnly = g.current_user.username != username 

297 userInsuranceInfo = InsuranceInfo.get_or_none(InsuranceInfo.user == username) 

298 return render_template ("/main/insuranceInfo.html", 

299 username=username, 

300 userInsuranceInfo=userInsuranceInfo, 

301 readOnly=readOnly 

302 ) 

303 

304 # Save the form data 

305 elif request.method == 'POST': 

306 if g.current_user.username != username: 

307 abort(403) 

308 

309 rowsUpdated = InsuranceInfo.update(**request.form).where(InsuranceInfo.user == username).execute() 

310 if not rowsUpdated: 

311 InsuranceInfo.create(user = username, **request.form) 

312 

313 createActivityLog(f"{g.current_user.fullName} updated {user.fullName}'s insurance information.") 

314 flash('Insurance information saved successfully!', 'success') 

315 

316 if request.args.get('action') == 'exit': 

317 return redirect (f"/profile/{username}") 

318 else: 

319 return redirect (f"/profile/{username}/emergencyContact") 

320 

321@main_bp.route('/profile/<username>/travelForm', methods=['GET', 'POST']) 

322def travelForm(username): 

323 if not (g.current_user.username == username or g.current_user.isCeltsAdmin): 

324 abort(403) 

325 

326 user = (User.select(User, EmergencyContact, InsuranceInfo) 

327 .join(EmergencyContact, JOIN.LEFT_OUTER).switch() 

328 .join(InsuranceInfo, JOIN.LEFT_OUTER) 

329 .where(User.username == username).limit(1)) 

330 if not list(user): 

331 abort(404) 

332 userList = list(user.dicts())[0] 

333 userList = [{key: value if value else '' for (key, value) in userList.items()}] 

334 

335 return render_template ('/main/travelForm.html', 

336 userList = userList 

337 ) 

338 

339@main_bp.route('/event/<eventID>/travelForm', methods=['GET', 'POST']) 

340def eventTravelForm(eventID): 

341 try: 

342 event = Event.get_by_id(eventID) 

343 except DoesNotExist as e: 

344 print(f"No event found for {eventID}", e) 

345 abort(404) 

346 

347 if not (g.current_user.isCeltsAdmin): 

348 abort(403) 

349 

350 if request.method == "POST" and request.form.getlist("username") != []: 

351 usernameList = request.form.getlist("username") 

352 usernameList = usernameList.copy() 

353 userList = [] 

354 for username in usernameList: 

355 user = (User.select(User, EmergencyContact, InsuranceInfo) 

356 .join(EmergencyContact, JOIN.LEFT_OUTER).switch() 

357 .join(InsuranceInfo, JOIN.LEFT_OUTER) 

358 .where(User.username == username).limit(1)) 

359 if not list(username): 

360 abort(404) 

361 userData = list(user.dicts())[0] 

362 userData = {key: value if value else '' for (key, value) in userData.items()} 

363 userList.append(userData) 

364 

365 

366 else: 

367 return redirect(f"/event/{eventID}/volunteer_details") 

368 

369 

370 return render_template ('/main/travelForm.html', 

371 usernameList = usernameList, 

372 userList = userList, 

373 ) 

374 

375@main_bp.route('/profile/addNote', methods=['POST']) 

376def addNote(): 

377 """ 

378 This function adds a note to the user's profile. 

379 """ 

380 postData = request.form 

381 try: 

382 note = addProfileNote(postData["visibility"], postData["bonner"] == "yes", postData["noteTextbox"], postData["username"]) 

383 flash("Successfully added profile note", "success") 

384 return redirect(url_for("main.viewUsersProfile", username=postData["username"])) 

385 except Exception as e: 

386 print("Error adding note", e) 

387 flash("Failed to add profile note", "danger") 

388 return "Failed to add profile note", 500 

389 

390@main_bp.route('/<username>/deleteNote', methods=['POST']) 

391def deleteNote(username): 

392 """ 

393 This function deletes a note from the user's profile. 

394 """ 

395 try: 

396 deleteProfileNote(request.form["id"]) 

397 flash("Successfully deleted profile note", "success") 

398 except Exception as e: 

399 print("Error deleting note", e) 

400 flash("Failed to delete profile note", "danger") 

401 return "success" 

402 

403# ===========================Ban=============================================== 

404@main_bp.route('/<username>/ban/<program_id>', methods=['POST']) 

405def ban(program_id, username): 

406 """ 

407 This function updates the ban status of a username either when they are banned from a program. 

408 program_id: the primary id of the program the student is being banned from 

409 username: unique value of a user to correctly identify them 

410 """ 

411 postData = request.form 

412 banNote = postData["note"] # This contains the note left about the change 

413 banEndDate = postData["endDate"] # Contains the date the ban will no longer be effective 

414 

415 try: 

416 banUser(program_id, username, banNote, banEndDate, g.current_user) 

417 programInfo = Program.get(int(program_id)) 

418 flash("Successfully banned the volunteer", "success") 

419 createActivityLog(f'Banned {username} from {programInfo.programName} until {banEndDate}.') 

420 return "Successfully banned the volunteer." 

421 except Exception as e: 

422 print("Error while updating ban", e) 

423 flash("Failed to ban the volunteer", "danger") 

424 return "Failed to ban the volunteer", 500 

425 

426# ===========================Unban=============================================== 

427@main_bp.route('/<username>/unban/<program_id>', methods=['POST']) 

428def unban(program_id, username): 

429 """ 

430 This function updates the ban status of a username either when they are unbanned from a program. 

431 program_id: the primary id of the program the student is being unbanned from 

432 username: unique value of a user to correctly identify them 

433 """ 

434 postData = request.form 

435 unbanNote = postData["note"] # This contains the note left about the change 

436 try: 

437 unbanUser(program_id, username, unbanNote, g.current_user) 

438 programInfo = Program.get(int(program_id)) 

439 createActivityLog(f'Unbanned {username} from {programInfo.programName}.') 

440 flash("Successfully unbanned the volunteer", "success") 

441 return "Successfully unbanned the volunteer" 

442 

443 except Exception as e: 

444 print("Error while updating Unban", e) 

445 flash("Failed to unban the volunteer", "danger") 

446 return "Failed to unban the volunteer", 500 

447 

448 

449@main_bp.route('/<username>/addInterest/<program_id>', methods=['POST']) 

450def addInterest(program_id, username): 

451 """ 

452 This function adds a program to the list of programs a user interested in 

453 program_id: the primary id of the program the student is adding interest of 

454 username: unique value of a user to correctly identify them 

455 """ 

456 try: 

457 success = addUserInterest(program_id, username) 

458 if success: 

459 flash("Successfully added " + Program.get_by_id(program_id).programName + " as an interest", "success") 

460 return "" 

461 else: 

462 flash("Was unable to remove " + Program.get_by_id(program_id).programName + " as an interest.", "danger") 

463 

464 except Exception as e: 

465 print(e) 

466 return "Error Updating Interest", 500 

467 

468@main_bp.route('/<username>/removeInterest/<program_id>', methods=['POST']) 

469def removeInterest(program_id, username): 

470 """ 

471 This function removes 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 try: 

476 removed = removeUserInterest(program_id, username) 

477 if removed: 

478 flash("Successfully removed " + Program.get_by_id(program_id).programName + " as an interest.", "success") 

479 return "" 

480 else: 

481 flash("Was unable to remove " + Program.get_by_id(program_id).programName + " as an interest.", "danger") 

482 except Exception as e: 

483 print(e) 

484 return "Error Updating Interest", 500 

485 

486@main_bp.route('/rsvpForEvent', methods = ['POST']) 

487def volunteerRegister(): 

488 """ 

489 This function selects the user ID and event ID and registers the user 

490 for the event they have clicked register for. 

491 """ 

492 event = Event.get_by_id(request.form['id']) 

493 program = event.program 

494 user = g.current_user 

495 

496 isAdded = checkUserRsvp(user, event) 

497 isEligible = isEligibleForProgram(program, user) 

498 listOfRequirements = unattendedRequiredEvents(program, user) 

499 

500 personAdded = False 

501 if isEligible: 

502 personAdded = addPersonToEvent(user, event) 

503 if personAdded and listOfRequirements: 

504 reqListToString = ', '.join(listOfRequirements) 

505 flash(f"{user.firstName} {user.lastName} successfully registered. However, the following training may be required: {reqListToString}.", "success") 

506 elif personAdded: 

507 flash("Successfully registered for event!","success") 

508 else: 

509 flash(f"RSVP Failed due to an unknown error.", "danger") 

510 else: 

511 flash(f"Cannot RSVP. Contact CELTS administrators: {app.config['celts_admin_contact']}.", "danger") 

512 

513 

514 if 'from' in request.form: 

515 if request.form['from'] == 'ajax': 

516 return '' 

517 return redirect(url_for("admin.eventDisplay", eventId=event.id)) 

518 

519@main_bp.route('/rsvpRemove', methods = ['POST']) 

520def RemoveRSVP(): 

521 """ 

522 This function deletes the user ID and event ID from database when RemoveRSVP is clicked 

523 """ 

524 eventData = request.form 

525 event = Event.get_by_id(eventData['id']) 

526 

527 currentRsvpParticipant = EventRsvp.get(EventRsvp.user == g.current_user, EventRsvp.event == event) 

528 logBody = "withdrew from the waitlist" if currentRsvpParticipant.rsvpWaitlist else "un-RSVP'd" 

529 currentRsvpParticipant.delete_instance() 

530 createRsvpLog(event.id, f"{g.current_user.fullName} {logBody}.") 

531 flash("Successfully unregistered for event!", "success") 

532 if 'from' in eventData: 

533 if eventData['from'] == 'ajax': 

534 return '' 

535 return redirect(url_for("admin.eventDisplay", eventId=event.id)) 

536 

537@main_bp.route('/profile/<username>/serviceTranscript', methods = ['GET']) 

538def serviceTranscript(username): 

539 user = User.get_or_none(User.username == username) 

540 if user is None: 

541 abort(404) 

542 if user != g.current_user and not g.current_user.isAdmin: 

543 abort(403) 

544 

545 slCourses = getSlCourseTranscript(username) 

546 totalHours = getTotalHours(username) 

547 allEventTranscript = getProgramTranscript(username) 

548 startDate = getStartYear(username) 

549 return render_template('main/serviceTranscript.html', 

550 allEventTranscript = allEventTranscript, 

551 slCourses = slCourses.objects(), 

552 totalHours = totalHours, 

553 startDate = startDate, 

554 userData = user) 

555 

556@main_bp.route('/profile/<username>/updateTranscript/<program_id>', methods=['POST']) 

557def updateTranscript(username, program_id): 

558 # Check user permissions 

559 user = User.get_or_none(User.username == username) 

560 if user is None: 

561 abort(404) 

562 if user != g.current_user and not g.current_user.isAdmin: 

563 abort(403) 

564 

565 # Get the data sent from the client-side JavaScript 

566 data = request.json 

567 

568 # Retrieve removeFromTranscript value from the request data 

569 removeFromTranscript = data.get('removeFromTranscript') 

570 

571 # Update the ProgramBan object matching the program_id and username 

572 try: 

573 bannedProgramForUser = ProgramBan.get((ProgramBan.program == program_id) & (ProgramBan.user == user) & (ProgramBan.unbanNote.is_null())) 

574 bannedProgramForUser.removeFromTranscript = removeFromTranscript 

575 bannedProgramForUser.save() 

576 return jsonify({'status': 'success'}) 

577 except ProgramBan.DoesNotExist: 

578 return jsonify({'status': 'error', 'message': 'ProgramBan not found'}) 

579 

580 

581@main_bp.route('/searchUser/<query>', methods = ['GET']) 

582def searchUser(query): 

583 

584 category= request.args.get("category") 

585 

586 '''Accepts user input and queries the database returning results that matches user search''' 

587 try: 

588 query = query.strip() 

589 search = query.upper() 

590 splitSearch = search.split() 

591 searchResults = searchUsers(query,category) 

592 return searchResults 

593 except Exception as e: 

594 print(e) 

595 return "Error in searching for user", 500 

596 

597@main_bp.route('/contributors',methods = ['GET']) 

598def contributors(): 

599 return render_template("/contributors.html") 

600 

601@main_bp.route('/updateDietInformation', methods = ['GET', 'POST']) 

602def getDietInfo(): 

603 dietaryInfo = request.form 

604 user = dietaryInfo["user"] 

605 dietInfo = dietaryInfo["dietInfo"] 

606 

607 if (g.current_user.username == user) or g.current_user.isAdmin: 

608 updateDietInfo(user, dietInfo) 

609 userInfo = User.get(User.username == user) 

610 if len(dietInfo) > 0: 

611 createActivityLog(f"Updated {userInfo.fullName}'s dietary restrictions to {dietInfo}.") if dietInfo.strip() else None 

612 else: 

613 createActivityLog(f"Deleted all {userInfo.fullName}'s dietary restrictions dietary restrictions.") 

614 

615 

616 return " " 

617 

618@main_bp.route('/profile/<username>/indicateInterest', methods=['POST']) 

619def indicateMinorInterest(username): 

620 if g.current_user.isCeltsAdmin or g.current_user.username == username: 

621 data = request.get_json() 

622 isAdding = data.get("isAdding", False) 

623 

624 toggleMinorInterest(username, isAdding) 

625 

626 else: 

627 abort(403) 

628 

629 return "" 

630 

631@main_bp.route('/profile/<username>/updateMinorDeclaration', methods=["POST"]) 

632def updateMinorDeclaration(username): 

633 if g.current_user.isCeltsAdmin or g.current_user.username == username: 

634 declareMinorInterest(username) 

635 flash("Candidate minor successfully updated", "success") 

636 else: 

637 flash("Error updating candidate minor status", "danger") 

638 abort(403) 

639 

640 tab = request.args.get("tab", "interested") 

641 return redirect(url_for('admin.manageMinor', tab=tab)) 

642