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
« 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
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)
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)
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()
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)
70 filepaths = FileHandler(courseId=course.id).retrievePath(associatedAttachments)
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)
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)
91 return redirect(url_for('serviceLearning.slcEditProposal', courseID = course.id))
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")
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))
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')
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')
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))
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 """
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'])
152 # We have data and need to update the course first
153 else:
154 course = updateCourse(request.form.copy())
156 course.status = CourseStatus.APPROVED
157 course.save()
158 flash("Course approved!", "success")
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 """
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())
178 course.status = CourseStatus.SUBMITTED
179 course.save()
180 flash("Course unapproved!", "success")
182 except Exception as e:
183 print(e)
184 flash("Course was not unapproved!", "danger")
186 return ""
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"
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 ""
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')
229 return "", 500
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]
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)
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)
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 ""
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)
293 except Exception as e:
294 print(e)
295 return ""