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
« 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
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 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)
70 filePaths = FileHandler(courseId=course.id).retrievePath(associatedAttachments)
72 terms = selectSurroundingTerms(g.current_term, 0)
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())
84 else:
85 abort(403)
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)
93 return redirect(url_for('serviceLearning.slcEditProposal', courseID = course.id))
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")
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))
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')
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')
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))
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 """
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'])
153 # We have data and need to update the course first
154 else:
155 course = updateCourse(request.form.copy())
157 course.status = CourseStatus.APPROVED
158 course.save()
159 flash("Course approved!", "success")
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 """
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())
179 course.status = CourseStatus.SUBMITTED
180 course.save()
181 flash("Course unapproved!", "success")
183 except Exception as e:
184 print(e)
185 flash("Course was not unapproved!", "danger")
187 return ""
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"
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 ""
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)
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')
243 return "", 500
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]
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)
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)
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 ""
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)
307 except Exception as e:
308 print(e)
309 return ""