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

360 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-09-13 19:44 +0000

1import json 

2import datetime 

3from peewee import JOIN 

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 

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, 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 currentTime = datetime.datetime.now() 

80 

81 listOfTerms = Term.select() 

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.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 bonnerEvents = getBonnerEvents(term) 

92 otherEvents = getOtherEvents(term) 

93 

94 managersProgramDict = getManagerProgramDict(g.current_user) 

95 

96 # Fetch toggle state from session  

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

98 

99 # compile all student led events into one list 

100 studentEvents = [] 

101 for studentEvent in studentLedEvents.values(): 

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

103 

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

105 studentLedEventsCount: int = len(studentEvents) 

106 trainingEventsCount: int = len(trainingEvents) 

107 bonnerEventsCount: int = len(bonnerEvents) 

108 otherEventsCount: int = len(otherEvents) 

109 

110 # gets only upcoming events to display in indicators 

111 if (toggleState == 'unchecked'): 

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

113 for event in trainingEvents: 

114 if event.isPastEnd: 

115 trainingEventsCount -= 1 

116 for event in bonnerEvents: 

117 if event.isPastEnd: 

118 bonnerEventsCount -= 1 

119 for event in otherEvents: 

120 if event.isPastEnd: 

121 otherEventsCount -= 1 

122 

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

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

125 return jsonify({ 

126 "studentLedEventsCount": studentLedEventsCount, 

127 "trainingEventsCount": trainingEventsCount, 

128 "bonnerEventsCount": bonnerEventsCount, 

129 "otherEventsCount": otherEventsCount, 

130 "toggleStatus": toggleState 

131 }) 

132 

133 return render_template("/events/event_list.html", 

134 selectedTerm = term, 

135 studentLedEvents = studentLedEvents, 

136 trainingEvents = trainingEvents, 

137 bonnerEvents = bonnerEvents, 

138 otherEvents = otherEvents, 

139 listOfTerms = listOfTerms, 

140 rsvpedEventsID = rsvpedEventsID, 

141 currentEventRsvpAmount = currentEventRsvpAmount, 

142 currentTime = currentTime, 

143 user = g.current_user, 

144 activeTab = activeTab, 

145 programID = int(programID), 

146 managersProgramDict = managersProgramDict, 

147 countUpcomingStudentLedEvents = countUpcomingStudentLedEvents, 

148 toggleState = toggleState, 

149 ) 

150 

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

152def viewUsersProfile(username): 

153 """ 

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

155 """ 

156 try: 

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

158 except Exception as e: 

159 if g.current_user.isAdmin: 

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

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

162 else: 

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

164 

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

166 upcomingEvents = getUpcomingEventsForUser(volunteer) 

167 participatedEvents = getParticipatedEventsForUser(volunteer) 

168 programs = Program.select() 

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

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

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

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

173 

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

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

176 

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

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

179 

180 allBackgroundHistory = getUserBGCheckHistory(volunteer) 

181 backgroundTypes = list(BackgroundCheckType.select()) 

182 

183 eligibilityTable = [] 

184 

185 for program in programs: 

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

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

188 .where(ProgramBan.user == volunteer, 

189 ProgramBan.program == program, 

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

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

192 try: 

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

194 except KeyError: 

195 allTrainingsComplete = False 

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

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

198 "completedTraining": allTrainingsComplete, 

199 "trainingList": userParticipatedTrainingEvents, 

200 "isNotBanned": (not banNotes), 

201 "banNote": noteForDict}) 

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

203 

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

205 

206 managersProgramDict = getManagerProgramDict(g.current_user) 

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

208 totalSustainedEngagements = getEngagementTotal(getCommunityEngagementByTerm(volunteer)) 

209 

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

211 programs = programs, 

212 programsInterested = programsInterested, 

213 upcomingEvents = upcomingEvents, 

214 participatedEvents = participatedEvents, 

215 rsvpedEvents = rsvpedEvents, 

216 permissionPrograms = permissionPrograms, 

217 eligibilityTable = eligibilityTable, 

218 volunteer = volunteer, 

219 backgroundTypes = backgroundTypes, 

220 allBackgroundHistory = allBackgroundHistory, 

221 currentDateTime = datetime.datetime.now(), 

222 profileNotes = profileNotes, 

223 bonnerRequirements = bonnerRequirements, 

224 managersList = managersList, 

225 participatedInLabor = getCeltsLaborHistory(volunteer), 

226 totalSustainedEngagements = totalSustainedEngagements, 

227 ) 

228 abort(403) 

229 

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

231def emergencyContactInfo(username): 

232 """ 

233 This loads the Emergency Contact Page 

234 """ 

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

236 abort(403) 

237 

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

239 

240 if request.method == 'GET': 

241 readOnly = g.current_user.username != username 

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

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

244 username=username, 

245 contactInfo=contactInfo, 

246 readOnly=readOnly 

247 ) 

248 

249 elif request.method == 'POST': 

250 if g.current_user.username != username: 

251 abort(403) 

252 

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

254 if not rowsUpdated: 

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

256 

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

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

259 

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

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

262 else: 

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

264 

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

266def insuranceInfo(username): 

267 """ 

268 This loads the Insurance Information Page 

269 """ 

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

271 abort(403) 

272 

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

274 

275 if request.method == 'GET': 

276 readOnly = g.current_user.username != username 

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

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

279 username=username, 

280 userInsuranceInfo=userInsuranceInfo, 

281 readOnly=readOnly 

282 ) 

283 

284 # Save the form data 

285 elif request.method == 'POST': 

286 if g.current_user.username != username: 

287 abort(403) 

288 

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

290 if not rowsUpdated: 

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

292 

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

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

295 

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

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

298 else: 

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

300 

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

302def travelForm(username): 

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

304 abort(403) 

305 

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

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

308 .join(InsuranceInfo, JOIN.LEFT_OUTER) 

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

310 if not list(user): 

311 abort(404) 

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

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

314 

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

316 userData = userData 

317 ) 

318 

319 

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

321def addNote(): 

322 """ 

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

324 """ 

325 postData = request.form 

326 try: 

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

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

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

330 except Exception as e: 

331 print("Error adding note", e) 

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

333 return "Failed to add profile note", 500 

334 

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

336def deleteNote(username): 

337 """ 

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

339 """ 

340 try: 

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

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

343 except Exception as e: 

344 print("Error deleting note", e) 

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

346 return "success" 

347 

348# ===========================Ban=============================================== 

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

350def ban(program_id, username): 

351 """ 

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

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

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

355 """ 

356 postData = request.form 

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

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

359 try: 

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

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

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

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

364 return "Successfully banned the volunteer." 

365 except Exception as e: 

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

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

368 return "Failed to ban the volunteer", 500 

369 

370# ===========================Unban=============================================== 

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

372def unban(program_id, username): 

373 """ 

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

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

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

377 """ 

378 postData = request.form 

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

380 try: 

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

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

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

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

385 return "Successfully unbanned the volunteer" 

386 

387 except Exception as e: 

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

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

390 return "Failed to unban the volunteer", 500 

391 

392 

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

394def addInterest(program_id, username): 

395 """ 

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

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

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

399 """ 

400 try: 

401 success = addUserInterest(program_id, username) 

402 if success: 

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

404 return "" 

405 else: 

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

407 

408 except Exception as e: 

409 print(e) 

410 return "Error Updating Interest", 500 

411 

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

413def removeInterest(program_id, username): 

414 """ 

415 This function removes a program to the list of programs a user interested in 

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

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

418 """ 

419 try: 

420 removed = removeUserInterest(program_id, username) 

421 if removed: 

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

423 return "" 

424 else: 

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

426 except Exception as e: 

427 print(e) 

428 return "Error Updating Interest", 500 

429 

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

431def volunteerRegister(): 

432 """ 

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

434 for the event they have clicked register for. 

435 """ 

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

437 program = event.program 

438 user = g.current_user 

439 

440 isAdded = checkUserRsvp(user, event) 

441 isEligible = isEligibleForProgram(program, user) 

442 listOfRequirements = unattendedRequiredEvents(program, user) 

443 

444 personAdded = False 

445 if isEligible: 

446 personAdded = addPersonToEvent(user, event) 

447 if personAdded and listOfRequirements: 

448 reqListToString = ', '.join(listOfRequirements) 

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

450 elif personAdded: 

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

452 else: 

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

454 else: 

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

456 

457 

458 if 'from' in request.form: 

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

460 return '' 

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

462 

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

464def RemoveRSVP(): 

465 """ 

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

467 """ 

468 eventData = request.form 

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

470 

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

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

473 currentRsvpParticipant.delete_instance() 

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

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

476 if 'from' in eventData: 

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

478 return '' 

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

480 

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

482def serviceTranscript(username): 

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

484 if user is None: 

485 abort(404) 

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

487 abort(403) 

488 

489 slCourses = getSlCourseTranscript(username) 

490 totalHours = getTotalHours(username) 

491 allEventTranscript = getProgramTranscript(username) 

492 startDate = getStartYear(username) 

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

494 allEventTranscript = allEventTranscript, 

495 slCourses = slCourses.objects(), 

496 totalHours = totalHours, 

497 startDate = startDate, 

498 userData = user) 

499 

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

501def isRemovedFromTranscript(username, program_id): 

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

503 if user is None: 

504 abort(404) 

505 

506 try: 

507 bannedProgramsForUser = ProgramBan.get((ProgramBan.program == program_id) & (ProgramBan.user == user)) 

508 # If the user is banned, check if it's marked for removal from transcript 

509 if bannedProgramsForUser.removeFromTranscript: 

510 return jsonify({'removedFromTranscript': True}) 

511 else: 

512 return jsonify({'removedFromTranscript': False}) 

513 except ProgramBan.DoesNotExist: 

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

515 

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

517def updateTranscript(username, program_id): 

518 # Check user permissions 

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

520 if user is None: 

521 abort(404) 

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

523 abort(403) 

524 

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

526 data = request.json 

527 

528 # Retrieve removeFromTranscript value from the request data 

529 removeFromTranscript = data.get('removeFromTranscript') 

530 

531 # Update the ProgramBan object matching the program_id and username 

532 try: 

533 bannedProgramsForUser = ProgramBan.get((ProgramBan.program == program_id) & (ProgramBan.user == user)) 

534 bannedProgramsForUser.removeFromTranscript = removeFromTranscript 

535 bannedProgramsForUser.save() 

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

537 except ProgramBan.DoesNotExist: 

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

539 

540 

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

542def searchUser(query): 

543 

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

545 

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

547 try: 

548 query = query.strip() 

549 search = query.upper() 

550 splitSearch = search.split() 

551 searchResults = searchUsers(query,category) 

552 return searchResults 

553 except Exception as e: 

554 print(e) 

555 return "Error in searching for user", 500 

556 

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

558def contributors(): 

559 return render_template("/contributors.html") 

560 

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

562def getDietInfo(): 

563 dietaryInfo = request.form 

564 user = dietaryInfo["user"] 

565 dietInfo = dietaryInfo["dietInfo"] 

566 

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

568 updateDietInfo(user, dietInfo) 

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

570 if len(dietInfo) > 0: 

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

572 else: 

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

574 

575 

576 return " " 

577 

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

579def indicateMinorInterest(username): 

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

581 toggleMinorInterest(username) 

582 

583 else: 

584 abort(403) 

585 

586 return ""