Coverage for app/controllers/serviceLearning/routes.py: 27%
198 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-07-24 12:19 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-07-24 12:19 +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
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
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 = 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)
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()
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 courseStatusInt = courseStatus.get_id()
58 approved = 3
59 # Condition to check the route you are comming from
60 if courseStatusInt==approved and request.path == f"/serviceLearning/editProposal/{courseID}":
61 return redirect(f"/serviceLearning/viewProposal/{courseID}")
62 else:
63 statusOfCourse = Course.select(Course.status)
64 questionData = (CourseQuestion.select().where(CourseQuestion.course == course))
65 questionAnswers = [question.questionContent for question in questionData]
66 courseInstructor = CourseInstructor.select().where(CourseInstructor.course == courseID)
67 associatedAttachments = AttachmentUpload.select().where(AttachmentUpload.course == course.id)
69 filePaths = FileHandler(courseId=course.id).retrievePath(associatedAttachments)
71 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 courseInstructor = courseInstructor,
79 filePaths = filePaths,
80 courseStatus = courseStatus,
81 redirectTarget = getRedirectTarget())
83 else:
84 abort(403)
87@serviceLearning_bp.route('/serviceLearning/createCourse', methods=['POST'])
88def slcCreateCourse():
89 """will give a new course ID so that it can redirect to an edit page"""
90 course = createCourse(g.current_user)
92 return redirect(url_for('serviceLearning.slcEditProposal', courseID = course.id))
95@serviceLearning_bp.route('/serviceLearning/exit', methods=['GET'])
96def slcExitView():
97 if getRedirectTarget():
98 return redirect(getRedirectTarget(True))
99 else:
100 return redirect("/serviceLearning/courseManagement")
103@serviceLearning_bp.route('/serviceLearning/saveExit', methods=['POST'])
104@serviceLearning_bp.route('/serviceLearning/saveProposal', methods=['POST'])
105def slcSaveContinue():
106 """Will update the the course proposal and return an empty string since ajax request needs a response
107 Also, it updates the course status as 'in progress'"""
108 course = updateCourse(request.form.copy(), attachments=getFilesFromRequest(request))
110 if not course:
111 flash("Error saving changes", "danger")
112 else:
113 course.status = CourseStatus.IN_PROGRESS
114 course.save()
115 flash(f"Proposal has been saved.", "success")
116 if request.path == "/serviceLearning/saveExit":
117 if getRedirectTarget():
118 return redirect(getRedirectTarget(True))
119 return redirect("/serviceLearning/courseManagement")
120 return redirect(f'/serviceLearning/editProposal/{request.form["courseID"]}?tab=2')
122@serviceLearning_bp.route('/serviceLearning/newProposal', methods=['GET', 'POST'])
123def slcCreateOrEdit():
124 if request.method == "POST":
125 course = updateCourse(request.form.copy())
126 if not course:
127 flash("Error saving changes", "danger")
128 else:
129 if getRedirectTarget(False):
130 return redirect('' + getRedirectTarget(True) + '')
131 return redirect('/serviceLearning/courseManagement')
133 terms = Term.select().where(Term.year >= g.current_term.year)
134 return render_template('serviceLearning/slcNewProposal.html',
135 terms = terms,
136 courseData = None,
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 ""
209@serviceLearning_bp.route('/proposalReview/', methods = ['GET', 'POST'])
210def reviewProposal() -> str:
211 """
212 this function gets the submitted course id and returns the its data to the review proposal modal
213 """
214 courseID: Dict[str, Any] = request.form
215 course: Course = Course.get_by_id(courseID["course_id"])
216 instructorsData: List[CourseInstructor] = course.courseInstructors
217 return render_template('/serviceLearning/reviewProposal.html',
218 course=course,
219 instructorsData=instructorsData)
221@serviceLearning_bp.route('/serviceLearning/renew/<courseID>/<termID>/', methods = ['POST'])
222def renewCourse(courseID, termID):
223 """
224 This function checks to see if the user is a CELTS admin or is
225 an instructor of a course (faculty) and allows courses to be renewed.
226 :return: empty string because AJAX needs to receive something
227 """
228 instructors = CourseInstructor.select().where(CourseInstructor.course==courseID)
229 courseInstructors = [instructor.user for instructor in instructors]
230 isCourseCreator = Course.select().where(Course.createdBy == g.current_user, Course.id==courseID).exists()
231 try:
232 if g.current_user.isCeltsAdmin or g.current_user in courseInstructors or isCourseCreator:
233 renewedProposal = renewProposal(courseID, termID)
234 flash("Course successfully renewed", 'success')
235 return str(renewedProposal.id)
236 else:
237 flash("Unauthorized to perform this action", 'warning')
238 except Exception as e:
239 print(e)
240 flash("Renewal Unsuccessful", 'warning')
242 return "", 500
244@serviceLearning_bp.route('/serviceLearning/print/<courseID>', methods=['GET'])
245def printCourse(courseID):
246 """
247 This function will print a PDF of an SLC proposal.
248 """
249 instructors = CourseInstructor.select().where(CourseInstructor.course==courseID)
250 courseInstructors = [instructor.user for instructor in instructors]
251 isCreator = Course.select().where(Course.createdBy == g.current_user, Course.id==courseID).exists()
252 if g.current_user.isCeltsAdmin or g.current_user in courseInstructors or isCreator:
253 try:
254 course = Course.get_by_id(courseID)
255 pdfCourse = Course.select().where(Course.id == courseID)
256 pdfInstructor = CourseInstructor.select().where(CourseInstructor.course == courseID)
257 pdfQuestions = (CourseQuestion.select().where(CourseQuestion.course == course))
258 questionanswers = [question.questionContent for question in pdfQuestions]
260 return render_template('serviceLearning/slcFormPrint.html',
261 course = course,
262 pdfCourse = pdfCourse,
263 pdfInstructor = pdfInstructor,
264 pdfQuestions = pdfQuestions,
265 questionanswers=questionanswers
266 )
267 except Exception as e:
268 flash("An error was encountered when printing, please try again.", 'warning')
269 print(e)
270 return "", 500
271 else:
272 abort(403)
274@serviceLearning_bp.route("/uploadCourseFile", methods=['GET', "POST"])
275def uploadCourseFile():
276 try:
277 attachment = getFilesFromRequest(request)
278 courseID = request.form["courseID"]
279 addFile = FileHandler(attachment, courseId=courseID)
280 addFile.saveFiles()
281 except:
282 flash("No file selected.", "warning")
283 return redirect('/serviceLearning/editProposal/upload/'+courseID)
286@serviceLearning_bp.route("/deleteCourseFile", methods=["POST"])
287def deleteCourseFile():
288 fileData= request.form
289 courseFile=FileHandler(courseId=fileData["databaseId"])
290 courseFile.deleteFile(fileData["fileId"])
291 return ""
293@serviceLearning_bp.route('/serviceLearning/downloadApprovedCourses/<termID>', methods = ['GET'])
294def downloadApprovedCourses(termID):
295 """
296 This function allows the download of csv file
297 """
298 try:
299 designator = "downloadApprovedCourses"
300 csvInfo = approvedCourses(termID)
301 fileFormat = {"headers":["Course Name", "Course Number", "Faculty", "Term", "Previously Approved Course?"]}
302 filePath = safe_join(os.getcwd(), app.config['files']['base_path'])
303 newFile = fileMaker(designator, csvInfo, "CSV", fileFormat)
304 return send_from_directory(filePath, 'ApprovedCourses.csv', as_attachment=True)
306 except Exception as e:
307 print(e)
308 return ""