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

194 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-01-29 16:34 +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 app.models.user import User 

6from app.models.term import Term 

7from app.models.course import Course 

8from app.models.courseStatus import CourseStatus 

9from app.models.courseInstructor import CourseInstructor 

10from app.models.courseQuestion import CourseQuestion 

11from app.models.attachmentUpload import AttachmentUpload 

12from app.logic.utils import selectSurroundingTerms, getFilesFromRequest 

13from app.logic.fileHandler import FileHandler 

14from app.logic.serviceLearningCoursesData import getServiceLearningCoursesData, withdrawProposal, renewProposal 

15from app.logic.courseManagement import updateCourse, createCourse 

16from app.logic.downloadFile import * 

17from app.logic.courseManagement import approvedCourses 

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 = getServiceLearningCoursesData(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 

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

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

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

46def slcEditProposal(courseID): 

47 """ 

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

49 given a courseID. 

50 """ 

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

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

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

54 

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

56 course = Course.get_by_id(courseID) 

57 courseStatus = CourseStatus.get_by_id(course.status) 

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 return render_template('serviceLearning/slcNewProposal.html', 

74 course = course, 

75 questionanswers = questionanswers, 

76 terms = terms, 

77 statusOfCourse = statusOfCourse, 

78 courseStatus = courseStatus, 

79 courseInstructor = courseInstructor, 

80 filepaths = filepaths, 

81 redirectTarget=getRedirectTarget()) 

82 else: 

83 abort(403) 

84 

85 

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

87def slcCreateCourse(): 

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

89 course = createCourse(g.current_user) 

90 

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

92 

93 

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

95def slcExitView(): 

96 if getRedirectTarget(): 

97 return redirect(getRedirectTarget(True)) 

98 else: 

99 return redirect("/serviceLearning/courseManagement") 

100 

101 

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

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

104def slcSaveContinue(): 

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

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

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

108 

109 if not course: 

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

111 else: 

112 course.status = CourseStatus.IN_PROGRESS 

113 course.save() 

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

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

116 if getRedirectTarget(): 

117 return redirect(getRedirectTarget(True)) 

118 return redirect("/serviceLearning/courseManagement") 

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

120 

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

122def slcCreateOrEdit(): 

123 if request.method == "POST": 

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

125 if not course: 

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

127 else: 

128 if getRedirectTarget(False): 

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

130 return redirect('/serviceLearning/courseManagement') 

131 

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

133 courseData = None 

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

135 terms = terms, 

136 courseData = courseData, 

137 redirectTarget = getRedirectTarget(True)) 

138 

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

140def approveCourse(): 

141 """ 

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

143 approve button. 

144 return: empty string because AJAX needs to receive something 

145 """ 

146 

147 try: 

148 # We are only approving, and not updating 

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

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

151 

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

153 else: 

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

155 

156 course.status = CourseStatus.APPROVED 

157 course.save() 

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

159 

160 except Exception as e: 

161 print(e) 

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

163 return "" 

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

165def unapproveCourse(): 

166 """ 

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

168 unapprove button. 

169 return: empty string because AJAX needs to receive something 

170 """ 

171 

172 try: 

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

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

175 else: 

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

177 

178 course.status = CourseStatus.SUBMITTED 

179 course.save() 

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

181 

182 except Exception as e: 

183 print(e) 

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

185 

186 return "" 

187 

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

189def updateInstructorPhone(): 

190 instructorData = request.get_json() 

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

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

193 return "success" 

194 

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

196def withdrawCourse(courseID): 

197 try: 

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

199 withdrawProposal(courseID) 

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

201 else: 

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

203 except Exception as e: 

204 print(e) 

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

206 return "" 

207 

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

209def renewCourse(courseID, termID): 

210 """ 

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

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

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

214 """ 

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

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

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

218 try: 

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

220 renewedProposal = renewProposal(courseID, termID) 

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

222 return str(renewedProposal.id) 

223 else: 

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

225 except Exception as e: 

226 print(e) 

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

228 

229 return "", 500 

230 

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

232def printCourse(courseID): 

233 """ 

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

235 """ 

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

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

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

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

240 try: 

241 course = Course.get_by_id(courseID) 

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

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

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

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

246 

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

248 course = course, 

249 pdfCourse = pdfCourse, 

250 pdfInstructor = pdfInstructor, 

251 pdfQuestions = pdfQuestions, 

252 questionanswers=questionanswers 

253 ) 

254 except Exception as e: 

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

256 print(e) 

257 return "", 500 

258 else: 

259 abort(403) 

260 

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

262def uploadCourseFile(): 

263 try: 

264 attachment = getFilesFromRequest(request) 

265 courseID = request.form["courseID"] 

266 addFile= FileHandler(attachment, courseId=courseID) 

267 addFile.saveFiles() 

268 except: 

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

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

271 

272 

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

274def deleteCourseFile(): 

275 fileData= request.form 

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

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

278 return "" 

279 

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

281def downloadApprovedCourses(termID): 

282 """ 

283 This function allows the download of csv file 

284 """ 

285 try: 

286 designator = "downloadApprovedCourses" 

287 csvInfo = approvedCourses(termID) 

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

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

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

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

292 

293 except Exception as e: 

294 print(e) 

295 return ""