Coverage for app/controllers/admin/userManagement.py: 28%

159 statements  

« prev     ^ index     » next       coverage.py v7.10.2, created at 2026-08-24 19:35 +0000

1import os 

2from pathlib import Path 

3import re 

4 

5from flask import render_template,request, flash, g, abort, redirect, send_file, url_for, jsonify, session 

6from peewee import fn, JOIN, DoesNotExist 

7from playhouse.shortcuts import model_to_dict 

8from werkzeug.utils import secure_filename 

9 

10 

11from app import app 

12from app.logic.term import changeCurrentTerm 

13from app.controllers.admin import admin_bp 

14from app.logic.fileHandler import FileHandler 

15from app.logic.userManagement import addCeltsAdmin,addCeltsStudentStaff,createSpreadsheetForRosters,addCeltsOperationsTeam,removeCeltsAdmin,removeCeltsStudentStaff,removeCeltsOperationsTeam 

16from app.logic.userManagement import changeProgramInfo 

17from app.logic.participants import getTrainingsForInterestedParticipants, getParticipantsForProgramForAY 

18from app.logic.utils import selectSurroundingTerms 

19from app.logic.term import addNextTerm, changeCurrentTerm 

20from app.logic.users import getProgramInterest 

21from app.logic.volunteers import setProgramManager 

22from app.models.attachmentUpload import AttachmentUpload 

23from app.models.programManager import ProgramManager 

24from app.models.programBan import ProgramBan 

25from app.models.user import User 

26from app.models.term import Term 

27from app.models.user import User 

28from app.models.program import Program 

29 

30@admin_bp.route('/admin/manageUsers', methods = ['POST']) 

31def manageUsers(): 

32 eventData = request.form 

33 user = eventData['user'] 

34 method = eventData['method'] 

35 username = re.sub("[()]","", (user.split())[-1]) 

36 

37 try: 

38 user = User.get_by_id(username) 

39 except Exception as e: 

40 print(e) 

41 flash(username + " is an invalid user.", "danger") 

42 return ("danger", 500) 

43 

44 if method == "addCeltsAdmin": 

45 if user.isStudent and not user.isCeltsStudentStaff: 

46 flash(user.firstName + " " + user.lastName + " cannot be added as a CELTS-Link admin", 'danger') 

47 else: 

48 if user.isCeltsAdmin: 

49 flash(user.firstName + " " + user.lastName + " is already a CELTS-Link Admin", 'danger') 

50 else: 

51 addCeltsAdmin(user) 

52 flash(user.firstName + " " + user.lastName + " has been added as a CELTS-Link Admin", 'success') 

53 elif method == "addCeltsStudentStaff": 

54 if not user.isStudent: 

55 flash(username + " cannot be added as CELTS Student Staff", 'danger') 

56 else: 

57 if user.isCeltsStudentStaff: 

58 flash(user.firstName + " " + user.lastName + " is already a CELTS Student Staff", 'danger') 

59 else: 

60 addCeltsStudentStaff(user) 

61 flash(user.firstName + " " + user.lastName + " has been added as a CELTS Student Staff", 'success') 

62 elif method == "addCeltsOperationsTeam": 

63 addCeltsOperationsTeam(user) 

64 flash(user.firstName + " " + user.lastName + " has been added as a CELTS Operations Team member", "success") 

65 elif method == "removeCeltsAdmin": 

66 removeCeltsAdmin(user) 

67 flash(user.firstName + " " + user.lastName + " is no longer a CELTS Admin ", 'success') 

68 elif method == "removeCeltsStudentStaff": 

69 removeCeltsStudentStaff(user) 

70 flash(user.firstName + " " + user.lastName + " is no longer a CELTS Student Staff", 'success') 

71 elif method == "removeCeltsOperationsTeam": 

72 removeCeltsOperationsTeam(user) 

73 flash(user.firstName + " " + user.lastName + " is no longer a CELTS Operations Team member", "success") 

74 return ("success", 200) 

75 

76@admin_bp.route('/deleteProgramFile', methods=['POST']) 

77def deleteProgramFile(): 

78 programFile=FileHandler(programId=request.form["programID"]) 

79 programFile.deleteFile(request.form["fileId"]) 

80 return "" 

81 

82@admin_bp.route('/admin/updateProgramInfo/<programID>', methods=['POST']) 

83def updateProgramInfo(programID): 

84 if g.current_user.canManageProgram(programID): 

85 try: 

86 programInfo = request.form # grabs user inputs 

87 uploadedFile = request.files.get('modalProgramImage') 

88 changeProgramInfo(programID, uploadedFile, **programInfo) 

89 

90 flash("Program updated", "success") 

91 return redirect(url_for("admin.userManagement", accordion="program")) 

92 except Exception as e: 

93 flash('Error while updating program info.','warning') 

94 abort(500,'Error while updating program.') 

95 abort(403) 

96 

97 

98@admin_bp.route('/admin/getProgramInfo/<programID>', methods = ['GET']) 

99def getProgramInfo(programID): 

100 if g.current_user.canManageProgram(programID): 

101 try: 

102 targetProgram = Program.get_by_id(programID) 

103 programInfo = model_to_dict(targetProgram, recurse=False) 

104 return jsonify([programInfo]) 

105 except DoesNotExist as e: 

106 flash('Program not found') 

107 print("Debug Here \n", e) 

108 abort(404) 

109 except Exception as e: 

110 flash('Failed to retrieve data','warning') 

111 print(e) 

112 abort(500, 'Failed to retrieve data') 

113 abort(403) 

114 

115 

116@admin_bp.route('/admin', methods = ['GET']) 

117def userManagement(): 

118 terms = selectSurroundingTerms(g.current_term) 

119 

120 currentPrograms = ( 

121 Program 

122 .select( 

123 Program, 

124 fn.GROUP_CONCAT(fn.COALESCE(fn.CONCAT(User.firstName, ' ', User.lastName, '#', User.username), '')).alias('managers') 

125 ) 

126 .join(ProgramManager, JOIN.LEFT_OUTER, on=(Program.id == ProgramManager.program)) 

127 .join(User, JOIN.LEFT_OUTER, on=(ProgramManager.user == User.username)) 

128 ) 

129 

130 if not g.current_user.isCeltsAdmin and not g.current_user.isCeltsOperationsTeam: #Allows CELTS Operations Team to view all programs. 

131 currentPrograms = currentPrograms.where(ProgramManager.user == g.current_user.username) 

132 

133 currentPrograms = list(currentPrograms.group_by(Program.id)) 

134 currentAdmins = list(User.select().where(User.isCeltsAdmin)) 

135 currentStudentStaff = list(User.select().where(User.isCeltsStudentStaff)) 

136 if g.current_user.isCeltsAdmin or g.current_user.isProgramManager or g.current_user.isCeltsOperationsTeam: 

137 return render_template('admin/userManagement.html', 

138 terms = terms, 

139 programs = currentPrograms, 

140 currentAdmins = currentAdmins, 

141 currentStudentStaff = currentStudentStaff, 

142 ) 

143 abort(403) 

144 

145@admin_bp.route('/admin/changeTerm', methods=['POST']) 

146def changeTerm(): 

147 newTerm = changeCurrentTerm(int(request.form.get('id'))) 

148 flash(f"Current term successfully changed to {newTerm.description}", "success") 

149 

150 return "" 

151 

152@admin_bp.route('/admin/addNewTerm', methods = ['POST']) 

153def addNewTerm(): 

154 newTerm = addNextTerm() 

155 flash(f"Successfully added {newTerm.description}", "success") 

156 

157 return "" 

158 

159@admin_bp.route('/upload/<userFileCategory>/<userTermId>', methods = ['POST']) 

160def upload(userFileCategory, userTermId): 

161 try: 

162 handbookTerm = Term.get_by_id(userTermId) 

163 except DoesNotExist: 

164 abort(405) 

165 

166 if userFileCategory not in ["laborHandbook", "volunteerHandbook"]: 

167 abort(405) 

168 fileCategory = userFileCategory 

169 

170 # Save file to fs 

171 file = request.files[fileCategory] 

172 newFilename = g.current_term.academicYear + "-" + fileCategory + "." + secure_filename(file.filename).split(".")[-1] 

173 

174 dir_path = Path(app.config['files']['base_path'], fileCategory) 

175 dir_path.mkdir(parents=True, exist_ok=True) 

176 full_path = os.path.join(dir_path, newFilename) 

177 if os.path.exists(full_path): 

178 os.remove(full_path) 

179 file.save(full_path) 

180 

181 # Update all terms in the Academic Year with the handbook filename 

182 for ayTerm in Term.select().where(Term.academicYear == handbookTerm.academicYear): 

183 setattr(ayTerm, fileCategory, newFilename) 

184 ayTerm.save() 

185 

186 # refresh the session with the new object 

187 changeCurrentTerm(g.current_term, refreshOnly=True) 

188 

189 flash(f"Handbook saved successfully to {ayTerm.description}!", "success") 

190 return redirect(request.referrer) 

191 

192@admin_bp.route('/viewRoster/<programID>', methods = ['GET']) 

193def viewRoster(programID): 

194 program = Program.get_by_id(programID) 

195 

196 interestedUsers = list(getProgramInterest(program)) 

197 trainedAndInterested = getTrainingsForInterestedParticipants(program, interestedUsers) 

198 lastYearsParticipants = getParticipantsForProgramForAY(program, g.current_term.previousAcademicYear) 

199 currentYearsParticipants = getParticipantsForProgramForAY(program, g.current_term.academicYear) 

200 return render_template('admin/viewRoster.html', 

201 program = program, 

202 interestedUsers = interestedUsers, 

203 trainedAndInterested = trainedAndInterested, 

204 lastYearsParticipants = lastYearsParticipants, 

205 currentYearsParticipants = currentYearsParticipants 

206 ) 

207 

208@admin_bp.route('/exportRosters/<programID>/<academicYear>', methods = ['GET']) 

209def exportRosters(programID, academicYear): 

210 try: 

211 outFile = createSpreadsheetForRosters(academicYear, programID) 

212 filepath = os.path.abspath(outFile) 

213 return send_file(filepath, as_attachment=True, download_name=filepath.split("/")[-1], mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') 

214 except DoesNotExist: 

215 abort(403)