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

351 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2025-01-29 15:39 +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 = 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/eventList.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 

184 

185 eligibilityTable = [] 

186 

187 for program in programs: 

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

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

190 .where(ProgramBan.user == volunteer, 

191 ProgramBan.program == program, 

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

193 onTranscriptQuery = list(ProgramBan.select(ProgramBan) 

194 .where(ProgramBan.user == volunteer, 

195 ProgramBan.program == program, 

196 ProgramBan.unbanNote.is_null(), 

197 ProgramBan.removeFromTranscript == 0)) 

198 

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

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

201 try: 

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

203 except KeyError: 

204 allTrainingsComplete = False 

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

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

207 "completedTraining": allTrainingsComplete, 

208 "trainingList": userParticipatedTrainingEvents, 

209 "isNotBanned": (not banNotes), 

210 "banNote": noteForDict, 

211 "onTranscript": onTranscript}), 

212 

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

214 

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

216 

217 managersProgramDict = getManagerProgramDict(g.current_user) 

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

219 totalSustainedEngagements = getEngagementTotal(getCommunityEngagementByTerm(volunteer)) 

220 

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

222 programs = programs, 

223 programsInterested = programsInterested, 

224 upcomingEvents = upcomingEvents, 

225 participatedEvents = participatedEvents, 

226 rsvpedEvents = rsvpedEvents, 

227 permissionPrograms = permissionPrograms, 

228 eligibilityTable = eligibilityTable, 

229 volunteer = volunteer, 

230 backgroundTypes = backgroundTypes, 

231 allBackgroundHistory = allBackgroundHistory, 

232 currentDateTime = datetime.datetime.now(), 

233 profileNotes = profileNotes, 

234 bonnerRequirements = bonnerRequirements, 

235 managersList = managersList, 

236 participatedInLabor = getCeltsLaborHistory(volunteer), 

237 totalSustainedEngagements = totalSustainedEngagements, 

238 ) 

239 abort(403) 

240 

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

242def emergencyContactInfo(username): 

243 """ 

244 This loads the Emergency Contact Page 

245 """ 

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

247 abort(403) 

248 

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

250 

251 if request.method == 'GET': 

252 readOnly = g.current_user.username != username 

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

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

255 username=username, 

256 contactInfo=contactInfo, 

257 readOnly=readOnly 

258 ) 

259 

260 elif request.method == 'POST': 

261 if g.current_user.username != username: 

262 abort(403) 

263 

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

265 if not rowsUpdated: 

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

267 

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

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

270 

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

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

273 else: 

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

275 

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

277def insuranceInfo(username): 

278 """ 

279 This loads the Insurance Information Page 

280 """ 

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

282 abort(403) 

283 

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

285 

286 if request.method == 'GET': 

287 readOnly = g.current_user.username != username 

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

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

290 username=username, 

291 userInsuranceInfo=userInsuranceInfo, 

292 readOnly=readOnly 

293 ) 

294 

295 # Save the form data 

296 elif request.method == 'POST': 

297 if g.current_user.username != username: 

298 abort(403) 

299 

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

301 if not rowsUpdated: 

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

303 

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

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

306 

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

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

309 else: 

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

311 

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

313def travelForm(username): 

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

315 abort(403) 

316 

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

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

319 .join(InsuranceInfo, JOIN.LEFT_OUTER) 

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

321 if not list(user): 

322 abort(404) 

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

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

325 

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

327 userData = userData 

328 ) 

329 

330 

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

332def addNote(): 

333 """ 

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

335 """ 

336 postData = request.form 

337 try: 

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

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

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

341 except Exception as e: 

342 print("Error adding note", e) 

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

344 return "Failed to add profile note", 500 

345 

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

347def deleteNote(username): 

348 """ 

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

350 """ 

351 try: 

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

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

354 except Exception as e: 

355 print("Error deleting note", e) 

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

357 return "success" 

358 

359# ===========================Ban=============================================== 

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

361def ban(program_id, username): 

362 """ 

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

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

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

366 """ 

367 postData = request.form 

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

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

370 

371 try: 

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

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

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

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

376 return "Successfully banned the volunteer." 

377 except Exception as e: 

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

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

380 return "Failed to ban the volunteer", 500 

381 

382# ===========================Unban=============================================== 

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

384def unban(program_id, username): 

385 """ 

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

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

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

389 """ 

390 postData = request.form 

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

392 try: 

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

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

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

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

397 return "Successfully unbanned the volunteer" 

398 

399 except Exception as e: 

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

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

402 return "Failed to unban the volunteer", 500 

403 

404 

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

406def addInterest(program_id, username): 

407 """ 

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

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

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

411 """ 

412 try: 

413 success = addUserInterest(program_id, username) 

414 if success: 

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

416 return "" 

417 else: 

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

419 

420 except Exception as e: 

421 print(e) 

422 return "Error Updating Interest", 500 

423 

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

425def removeInterest(program_id, username): 

426 """ 

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

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

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

430 """ 

431 try: 

432 removed = removeUserInterest(program_id, username) 

433 if removed: 

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

435 return "" 

436 else: 

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

438 except Exception as e: 

439 print(e) 

440 return "Error Updating Interest", 500 

441 

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

443def volunteerRegister(): 

444 """ 

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

446 for the event they have clicked register for. 

447 """ 

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

449 program = event.program 

450 user = g.current_user 

451 

452 isAdded = checkUserRsvp(user, event) 

453 isEligible = isEligibleForProgram(program, user) 

454 listOfRequirements = unattendedRequiredEvents(program, user) 

455 

456 personAdded = False 

457 if isEligible: 

458 personAdded = addPersonToEvent(user, event) 

459 if personAdded and listOfRequirements: 

460 reqListToString = ', '.join(listOfRequirements) 

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

462 elif personAdded: 

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

464 else: 

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

466 else: 

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

468 

469 

470 if 'from' in request.form: 

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

472 return '' 

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

474 

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

476def RemoveRSVP(): 

477 """ 

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

479 """ 

480 eventData = request.form 

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

482 

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

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

485 currentRsvpParticipant.delete_instance() 

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

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

488 if 'from' in eventData: 

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

490 return '' 

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

492 

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

494def serviceTranscript(username): 

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

496 if user is None: 

497 abort(404) 

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

499 abort(403) 

500 

501 slCourses = getSlCourseTranscript(username) 

502 totalHours = getTotalHours(username) 

503 allEventTranscript = getProgramTranscript(username) 

504 startDate = getStartYear(username) 

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

506 allEventTranscript = allEventTranscript, 

507 slCourses = slCourses.objects(), 

508 totalHours = totalHours, 

509 startDate = startDate, 

510 userData = user) 

511 

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

513def updateTranscript(username, program_id): 

514 # Check user permissions 

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

516 if user is None: 

517 abort(404) 

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

519 abort(403) 

520 

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

522 data = request.json 

523 

524 # Retrieve removeFromTranscript value from the request data 

525 removeFromTranscript = data.get('removeFromTranscript') 

526 

527 # Update the ProgramBan object matching the program_id and username 

528 try: 

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

530 bannedProgramForUser.removeFromTranscript = removeFromTranscript 

531 bannedProgramForUser.save() 

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

533 except ProgramBan.DoesNotExist: 

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

535 

536 

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

538def searchUser(query): 

539 

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

541 

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

543 try: 

544 query = query.strip() 

545 search = query.upper() 

546 splitSearch = search.split() 

547 searchResults = searchUsers(query,category) 

548 return searchResults 

549 except Exception as e: 

550 print(e) 

551 return "Error in searching for user", 500 

552 

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

554def contributors(): 

555 return render_template("/contributors.html") 

556 

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

558def getDietInfo(): 

559 dietaryInfo = request.form 

560 user = dietaryInfo["user"] 

561 dietInfo = dietaryInfo["dietInfo"] 

562 

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

564 updateDietInfo(user, dietInfo) 

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

566 if len(dietInfo) > 0: 

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

568 else: 

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

570 

571 

572 return " " 

573 

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

575def indicateMinorInterest(username): 

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

577 toggleMinorInterest(username) 

578 

579 else: 

580 abort(403) 

581 

582 return ""