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

183 statements  

« prev     ^ index     » next       coverage.py v7.2.5, created at 2023-06-13 18:20 +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.controllers.main.routes 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 if g.current_user.isStudent: 

26 abort(403) 

27 if g.current_user.isCeltsAdmin or g.current_user.isFaculty: 

28 setRedirectTarget("/serviceLearning/courseManagement") 

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

30 courseDict = getServiceLearningCoursesData(user) 

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

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

33 user=user, 

34 courseDict=courseDict, 

35 termList=termList) 

36 else: 

37 flash("Unauthorized to view page", 'warning') 

38 return redirect(url_for('main.events', selectedTerm=g.current_term)) 

39 

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

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

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

43def slcEditProposal(courseID): 

44 """ 

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

46 given a courseID. 

47 """ 

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

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

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

51 

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

53 course = Course.get_by_id(courseID) 

54 courseStatus = CourseStatus.get_by_id(course.status) 

55 courseStatusInt = courseStatus.get_id() 

56 approved = 3 

57 # Condition to check the route you are comming from 

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

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

60 else: 

61 statusOfCourse = Course.select(Course.status) 

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

63 questionanswers = [question.questionContent for question in questionData] 

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

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

66 

67 filepaths = FileHandler(courseId=course.id).retrievePath(associatedAttachments) 

68 

69 terms = selectSurroundingTerms(g.current_term, 0) 

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

71 course = course, 

72 questionanswers = questionanswers, 

73 terms = terms, 

74 statusOfCourse = statusOfCourse, 

75 courseStatus = courseStatus, 

76 courseInstructor = courseInstructor, 

77 filepaths = filepaths, 

78 redirectTarget=getRedirectTarget()) 

79 else: 

80 abort(403) 

81 

82 

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

84def slcCreateCourse(): 

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

86 course = createCourse(g.current_user) 

87 

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

89 

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

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

92def slcSaveContinue(): 

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

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

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

96 

97 if not course: 

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

99 else: 

100 course.status = CourseStatus.IN_PROGRESS 

101 course.save() 

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

103 return "" 

104 

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

106def slcCreateOrEdit(): 

107 if request.method == "POST": 

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

109 if not course: 

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

111 else: 

112 if getRedirectTarget(False): 

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

114 return redirect('/serviceLearning/courseManagement') 

115 

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

117 courseData = None 

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

119 terms = terms, 

120 courseData = courseData, 

121 redirectTarget = getRedirectTarget(True)) 

122 

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

124def approveCourse(): 

125 """ 

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

127 approve button. 

128 return: empty string because AJAX needs to receive something 

129 """ 

130 

131 try: 

132 # We are only approving, and not updating 

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

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

135 

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

137 else: 

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

139 

140 course.status = CourseStatus.APPROVED 

141 course.save() 

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

143 

144 except Exception as e: 

145 print(e) 

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

147 return "" 

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

149def unapproveCourse(): 

150 """ 

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

152 unapprove button. 

153 return: empty string because AJAX needs to receive something 

154 """ 

155 

156 try: 

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

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

159 else: 

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

161 

162 course.status = CourseStatus.SUBMITTED 

163 course.save() 

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

165 

166 except Exception as e: 

167 print(e) 

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

169 

170 return "" 

171 

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

173def updateInstructorPhone(): 

174 instructorData = request.get_json() 

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

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

177 return "success" 

178 

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

180def withdrawCourse(courseID): 

181 try: 

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

183 withdrawProposal(courseID) 

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

185 else: 

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

187 except Exception as e: 

188 print(e) 

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

190 return "" 

191 

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

193def renewCourse(courseID, termID): 

194 """ 

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

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

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

198 """ 

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

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

201 try: 

202 if g.current_user.isCeltsAdmin or g.current_user in courseInstructors: 

203 renewedProposal = renewProposal(courseID, termID) 

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

205 return str(renewedProposal.id) 

206 else: 

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

208 except Exception as e: 

209 print(e) 

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

211 

212 return "", 500 

213 

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

215def printCourse(courseID): 

216 """ 

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

218 """ 

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

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

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

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

223 try: 

224 course = Course.get_by_id(courseID) 

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

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

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

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

229 

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

231 course = course, 

232 pdfCourse = pdfCourse, 

233 pdfInstructor = pdfInstructor, 

234 pdfQuestions = pdfQuestions, 

235 questionanswers=questionanswers 

236 ) 

237 except Exception as e: 

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

239 print(e) 

240 return "", 500 

241 else: 

242 abort(403) 

243 

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

245def uploadCourseFile(): 

246 try: 

247 attachment = getFilesFromRequest(request) 

248 courseID = request.form["courseID"] 

249 addFile= FileHandler(attachment, courseId=courseID) 

250 addFile.saveFiles() 

251 except: 

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

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

254 

255 

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

257def deleteCourseFile(): 

258 fileData= request.form 

259 courseFile=FileHandler(courseId=fileData["courseId"]) 

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

261 return "" 

262 

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

264def downloadApprovedCourses(termID): 

265 """ 

266 This function allows the download of csv file 

267 """ 

268 try: 

269 designator = "downloadApprovedCourses" 

270 csvInfo = approvedCourses(termID) 

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

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

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

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

275 

276 except Exception as e: 

277 print(e) 

278 return ""