Coverage for app/controllers/serviceLearning/routes.py: 27%

199 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-06-21 18:28 +0000

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

2from werkzeug.utils import safe_join 

3import os 

4from peewee import * 

5from typing import Dict, Any, List 

6 

7from app.models.user import User 

8from app.models.term import Term 

9from app.models.course import Course 

10from app.models.courseStatus import CourseStatus 

11from app.models.courseInstructor import CourseInstructor 

12from app.models.courseQuestion import CourseQuestion 

13from app.models.attachmentUpload import AttachmentUpload 

14from app.logic.utils import selectSurroundingTerms, getFilesFromRequest 

15from app.logic.fileHandler import FileHandler 

16from app.logic.serviceLearningCourses import getSLProposalInfoForUser, withdrawProposal, renewProposal, updateCourse, createCourse, approvedCourses 

17from app.logic.downloadFile import * 

18from app.logic.utils import getRedirectTarget, setRedirectTarget 

19from app.controllers.serviceLearning import serviceLearning_bp 

20 

21 

22@serviceLearning_bp.route('/serviceLearning/courseManagement', methods = ['GET']) 

23@serviceLearning_bp.route('/serviceLearning/courseManagement/<username>', methods = ['GET']) 

24def serviceCourseManagement(username=None): 

25 try: 

26 user = User.get(User.username==username) if username else g.current_user 

27 except DoesNotExist: 

28 abort(404) 

29 

30 isRequestingForSelf = g.current_user == user 

31 if g.current_user.isCeltsAdmin or (g.current_user.isFaculty and isRequestingForSelf): 

32 setRedirectTarget(request.full_path) 

33 courseDict = getSLProposalInfoForUser(user) 

34 termList = selectSurroundingTerms(g.current_term, prevTerms=0) 

35 return render_template('serviceLearning/slcManagement.html', 

36 user=user, 

37 courseDict=courseDict, 

38 termList=termList) 

39 else: 

40 abort(403) 

41 

42@serviceLearning_bp.route('/serviceLearning/viewProposal/<courseID>', methods=['GET']) 

43@serviceLearning_bp.route('/serviceLearning/editProposal/upload/<courseID>', methods=['GET']) 

44@serviceLearning_bp.route('/serviceLearning/editProposal/<courseID>', methods=['GET']) 

45def slcEditProposal(courseID): 

46 """ 

47 Route for editing proposals, it will fill the form with the data found in the database 

48 given a courseID. 

49 """ 

50 instructors = CourseInstructor.select().where(CourseInstructor.course==courseID) 

51 courseInstructors = [instructor.user for instructor in instructors] 

52 isCourseCreator = Course.select().where(Course.createdBy == g.current_user, Course.id==courseID).exists() 

53 

54 if g.current_user.isCeltsAdmin or g.current_user in courseInstructors or isCourseCreator: 

55 course = Course.get_by_id(courseID) 

56 courseStatus = CourseStatus.get_by_id(course.status) 

57 print("Type of courseStatus:", type(courseStatus)) 

58 courseStatusInt = courseStatus.get_id() 

59 approved = 3 

60 # Condition to check the route you are comming from 

61 if courseStatusInt==approved and request.path == f"/serviceLearning/editProposal/{courseID}": 

62 return redirect(f"/serviceLearning/viewProposal/{courseID}") 

63 else: 

64 statusOfCourse = Course.select(Course.status) 

65 questionData = (CourseQuestion.select().where(CourseQuestion.course == course)) 

66 questionAnswers = [question.questionContent for question in questionData] 

67 courseInstructor = CourseInstructor.select().where(CourseInstructor.course == courseID) 

68 associatedAttachments = AttachmentUpload.select().where(AttachmentUpload.course == course.id) 

69 

70 filePaths = FileHandler(courseId=course.id).retrievePath(associatedAttachments) 

71 

72 terms = selectSurroundingTerms(g.current_term, 0) 

73 

74 return render_template('serviceLearning/slcNewProposal.html', 

75 course = course, 

76 questionanswers = questionAnswers, 

77 terms = terms, 

78 statusOfCourse = statusOfCourse, 

79 courseInstructor = courseInstructor, 

80 filePaths = filePaths, 

81 courseStatus = courseStatus, 

82 redirectTarget = getRedirectTarget()) 

83 

84 else: 

85 abort(403) 

86 

87 

88@serviceLearning_bp.route('/serviceLearning/createCourse', methods=['POST']) 

89def slcCreateCourse(): 

90 """will give a new course ID so that it can redirect to an edit page""" 

91 course = createCourse(g.current_user) 

92 

93 return redirect(url_for('serviceLearning.slcEditProposal', courseID = course.id)) 

94 

95 

96@serviceLearning_bp.route('/serviceLearning/exit', methods=['GET']) 

97def slcExitView(): 

98 if getRedirectTarget(): 

99 return redirect(getRedirectTarget(True)) 

100 else: 

101 return redirect("/serviceLearning/courseManagement") 

102 

103 

104@serviceLearning_bp.route('/serviceLearning/saveExit', methods=['POST']) 

105@serviceLearning_bp.route('/serviceLearning/saveProposal', methods=['POST']) 

106def slcSaveContinue(): 

107 """Will update the the course proposal and return an empty string since ajax request needs a response 

108 Also, it updates the course status as 'in progress'""" 

109 course = updateCourse(request.form.copy(), attachments=getFilesFromRequest(request)) 

110 

111 if not course: 

112 flash("Error saving changes", "danger") 

113 else: 

114 course.status = CourseStatus.IN_PROGRESS 

115 course.save() 

116 flash(f"Proposal has been saved.", "success") 

117 if request.path == "/serviceLearning/saveExit": 

118 if getRedirectTarget(): 

119 return redirect(getRedirectTarget(True)) 

120 return redirect("/serviceLearning/courseManagement") 

121 return redirect(f'/serviceLearning/editProposal/{request.form["courseID"]}?tab=2') 

122 

123@serviceLearning_bp.route('/serviceLearning/newProposal', methods=['GET', 'POST']) 

124def slcCreateOrEdit(): 

125 if request.method == "POST": 

126 course = updateCourse(request.form.copy()) 

127 if not course: 

128 flash("Error saving changes", "danger") 

129 else: 

130 if getRedirectTarget(False): 

131 return redirect('' + getRedirectTarget(True) + '') 

132 return redirect('/serviceLearning/courseManagement') 

133 

134 terms = Term.select().where(Term.year >= g.current_term.year) 

135 return render_template('serviceLearning/slcNewProposal.html', 

136 terms = terms, 

137 courseData = None, 

138 redirectTarget = getRedirectTarget(True)) 

139 

140@serviceLearning_bp.route('/serviceLearning/approveCourse', methods=['POST']) 

141def approveCourse(): 

142 """ 

143 This function updates and approves a Service-Learning Course when using the 

144 approve button. 

145 return: empty string because AJAX needs to receive something 

146 """ 

147 

148 try: 

149 # We are only approving, and not updating 

150 if len(request.form) == 1: 

151 course = Course.get_by_id(request.form['courseID']) 

152 

153 # We have data and need to update the course first 

154 else: 

155 course = updateCourse(request.form.copy()) 

156 

157 course.status = CourseStatus.APPROVED 

158 course.save() 

159 flash("Course approved!", "success") 

160 

161 except Exception as e: 

162 print(e) 

163 flash("Course not approved!", "danger") 

164 return "" 

165@serviceLearning_bp.route('/serviceLearning/unapproveCourse', methods=['POST']) 

166def unapproveCourse(): 

167 """ 

168 This function updates and unapproves a Service-Learning Course when using the 

169 unapprove button. 

170 return: empty string because AJAX needs to receive something 

171 """ 

172 

173 try: 

174 if len(request.form) == 1: 

175 course = Course.get_by_id(request.form['courseID']) 

176 else: 

177 course = updateCourse(request.form.copy()) 

178 

179 course.status = CourseStatus.SUBMITTED 

180 course.save() 

181 flash("Course unapproved!", "success") 

182 

183 except Exception as e: 

184 print(e) 

185 flash("Course was not unapproved!", "danger") 

186 

187 return "" 

188 

189@serviceLearning_bp.route('/updateInstructorPhone', methods=['POST']) 

190def updateInstructorPhone(): 

191 instructorData = request.get_json() 

192 (User.update(phoneNumber=instructorData[1]) 

193 .where(User.username == instructorData[0])).execute() 

194 return "success" 

195 

196@serviceLearning_bp.route('/serviceLearning/withdraw/<courseID>', methods = ['POST']) 

197def withdrawCourse(courseID): 

198 try: 

199 if g.current_user.isAdmin or g.current_user.isFaculty: 

200 withdrawProposal(courseID) 

201 flash("Course successfully withdrawn", 'success') 

202 else: 

203 flash("Unauthorized to perform this action", 'warning') 

204 except Exception as e: 

205 print(e) 

206 flash("Withdrawal Unsuccessful", 'warning') 

207 return "" 

208 

209 

210@serviceLearning_bp.route('/proposalReview/', methods = ['GET', 'POST']) 

211def reviewProposal() -> str: 

212 """ 

213 this function gets the submitted course id and returns the its data to the review proposal modal 

214 """ 

215 courseID: Dict[str, Any] = request.form 

216 course: Course = Course.get_by_id(courseID["course_id"]) 

217 instructorsData: List[CourseInstructor] = course.courseInstructors 

218 return render_template('/serviceLearning/reviewProposal.html', 

219 course=course, 

220 instructorsData=instructorsData) 

221 

222@serviceLearning_bp.route('/serviceLearning/renew/<courseID>/<termID>/', methods = ['POST']) 

223def renewCourse(courseID, termID): 

224 """ 

225 This function checks to see if the user is a CELTS admin or is 

226 an instructor of a course (faculty) and allows courses to be renewed. 

227 :return: empty string because AJAX needs to receive something 

228 """ 

229 instructors = CourseInstructor.select().where(CourseInstructor.course==courseID) 

230 courseInstructors = [instructor.user for instructor in instructors] 

231 isCourseCreator = Course.select().where(Course.createdBy == g.current_user, Course.id==courseID).exists() 

232 try: 

233 if g.current_user.isCeltsAdmin or g.current_user in courseInstructors or isCourseCreator: 

234 renewedProposal = renewProposal(courseID, termID) 

235 flash("Course successfully renewed", 'success') 

236 return str(renewedProposal.id) 

237 else: 

238 flash("Unauthorized to perform this action", 'warning') 

239 except Exception as e: 

240 print(e) 

241 flash("Renewal Unsuccessful", 'warning') 

242 

243 return "", 500 

244 

245@serviceLearning_bp.route('/serviceLearning/print/<courseID>', methods=['GET']) 

246def printCourse(courseID): 

247 """ 

248 This function will print a PDF of an SLC proposal. 

249 """ 

250 instructors = CourseInstructor.select().where(CourseInstructor.course==courseID) 

251 courseInstructors = [instructor.user for instructor in instructors] 

252 isCreator = Course.select().where(Course.createdBy == g.current_user, Course.id==courseID).exists() 

253 if g.current_user.isCeltsAdmin or g.current_user in courseInstructors or isCreator: 

254 try: 

255 course = Course.get_by_id(courseID) 

256 pdfCourse = Course.select().where(Course.id == courseID) 

257 pdfInstructor = CourseInstructor.select().where(CourseInstructor.course == courseID) 

258 pdfQuestions = (CourseQuestion.select().where(CourseQuestion.course == course)) 

259 questionanswers = [question.questionContent for question in pdfQuestions] 

260 

261 return render_template('serviceLearning/slcFormPrint.html', 

262 course = course, 

263 pdfCourse = pdfCourse, 

264 pdfInstructor = pdfInstructor, 

265 pdfQuestions = pdfQuestions, 

266 questionanswers=questionanswers 

267 ) 

268 except Exception as e: 

269 flash("An error was encountered when printing, please try again.", 'warning') 

270 print(e) 

271 return "", 500 

272 else: 

273 abort(403) 

274 

275@serviceLearning_bp.route("/uploadCourseFile", methods=['GET', "POST"]) 

276def uploadCourseFile(): 

277 try: 

278 attachment = getFilesFromRequest(request) 

279 courseID = request.form["courseID"] 

280 addFile = FileHandler(attachment, courseId=courseID) 

281 addFile.saveFiles() 

282 except: 

283 flash("No file selected.", "warning") 

284 return redirect('/serviceLearning/editProposal/upload/'+courseID) 

285 

286 

287@serviceLearning_bp.route("/deleteCourseFile", methods=["POST"]) 

288def deleteCourseFile(): 

289 fileData= request.form 

290 courseFile=FileHandler(courseId=fileData["databaseId"]) 

291 courseFile.deleteFile(fileData["fileId"]) 

292 return "" 

293 

294@serviceLearning_bp.route('/serviceLearning/downloadApprovedCourses/<termID>', methods = ['GET']) 

295def downloadApprovedCourses(termID): 

296 """ 

297 This function allows the download of csv file 

298 """ 

299 try: 

300 designator = "downloadApprovedCourses" 

301 csvInfo = approvedCourses(termID) 

302 fileFormat = {"headers":["Course Name", "Course Number", "Faculty", "Term", "Previously Approved Course?"]} 

303 filePath = safe_join(os.getcwd(), app.config['files']['base_path']) 

304 newFile = fileMaker(designator, csvInfo, "CSV", fileFormat) 

305 return send_from_directory(filePath, 'ApprovedCourses.csv', as_attachment=True) 

306 

307 except Exception as e: 

308 print(e) 

309 return ""