diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py
index 996de6b45..64ae34764 100644
--- a/app/controllers/admin/routes.py
+++ b/app/controllers/admin/routes.py
@@ -333,7 +333,7 @@ def adminLogs():
@admin_bp.route("/deleteEventFile", methods=["POST"])
def deleteEventFile():
fileData= request.form
- eventfile=FileHandler(eventId=fileData["eventId"])
+ eventfile=FileHandler(eventId=fileData["databaseId"])
eventfile.deleteFile(fileData["fileId"])
return ""
diff --git a/app/controllers/main/routes.py b/app/controllers/main/routes.py
index cdd544eb1..a20661b9f 100644
--- a/app/controllers/main/routes.py
+++ b/app/controllers/main/routes.py
@@ -379,7 +379,7 @@ def getAllCourseInstructors(term=None):
This function selects all the Instructors Name and the previous courses
"""
if g.current_user.isCeltsAdmin:
- setRedirectTarget("/manageServiceLearning")
+ setRedirectTarget(request.full_path)
courseDict = getCourseDict()
term = Term.get_or_none(Term.id == term) or g.current_term
diff --git a/app/controllers/serviceLearning/routes.py b/app/controllers/serviceLearning/routes.py
index 407bcc2ea..eabb3d075 100644
--- a/app/controllers/serviceLearning/routes.py
+++ b/app/controllers/serviceLearning/routes.py
@@ -90,12 +90,21 @@ def slcCreateCourse():
return redirect(url_for('serviceLearning.slcEditProposal', courseID = course.id))
+
+@serviceLearning_bp.route('/serviceLearning/exit', methods=['GET'])
+def slcExitView():
+ if getRedirectTarget():
+ return redirect(getRedirectTarget(True))
+ else:
+ return redirect("/serviceLearning/courseManagement")
+
+
@serviceLearning_bp.route('/serviceLearning/saveExit', methods=['POST'])
@serviceLearning_bp.route('/serviceLearning/saveProposal', methods=['POST'])
def slcSaveContinue():
"""Will update the the course proposal and return an empty string since ajax request needs a response
Also, it updates the course status as 'in progress'"""
- course = updateCourse(request.form.copy())
+ course = updateCourse(request.form.copy(), attachments=getFilesFromRequest(request))
if not course:
flash("Error saving changes", "danger")
@@ -103,7 +112,11 @@ def slcSaveContinue():
course.status = CourseStatus.IN_PROGRESS
course.save()
flash(f"Proposal has been saved.", "success")
- return ""
+ if request.path == "/serviceLearning/saveExit":
+ if getRedirectTarget():
+ return redirect(getRedirectTarget(True))
+ return redirect("/serviceLearning/courseManagement")
+ return redirect(f'/serviceLearning/editProposal/{request.form["courseID"]}?tab=2')
@serviceLearning_bp.route('/serviceLearning/newProposal', methods=['GET', 'POST'])
def slcCreateOrEdit():
@@ -260,7 +273,7 @@ def uploadCourseFile():
@serviceLearning_bp.route("/deleteCourseFile", methods=["POST"])
def deleteCourseFile():
fileData= request.form
- courseFile=FileHandler(courseId=fileData["courseId"])
+ courseFile=FileHandler(courseId=fileData["databaseId"])
courseFile.deleteFile(fileData["fileId"])
return ""
diff --git a/app/logic/courseManagement.py b/app/logic/courseManagement.py
index 20ae4069d..243469aa2 100644
--- a/app/logic/courseManagement.py
+++ b/app/logic/courseManagement.py
@@ -7,6 +7,7 @@
from app.models.courseStatus import CourseStatus
from app.logic.createLogs import createAdminLog
from app.logic.fileHandler import FileHandler
+from app.logic.utils import getFilesFromRequest
from app.models.course import Course
from app.models.term import Term
from app.models.user import User
@@ -53,7 +54,7 @@ def createCourse(creator="No user provided"):
return course
-def updateCourse(courseData, attachment=None):
+def updateCourse(courseData, attachments=None):
"""
This function will take in courseData for the SLC proposal page and a dictionary
of instuctors assigned to the course and update the information in the db.
@@ -89,11 +90,11 @@ def updateCourse(courseData, attachment=None):
for instructor in instructorList:
CourseInstructor.create(course=course, user=instructor)
createAdminLog(f"Saved SLC proposal: {courseData['courseName']}")
- if attachment:
- addFile= FileHandler(attachment, courseId=course.id)
+ if attachments:
+ addFile= FileHandler(attachments, courseId=course.id)
addFile.saveFiles()
return Course.get_by_id(course.id)
except Exception as e:
print(e)
transaction.rollback()
- return False
+ return False
\ No newline at end of file
diff --git a/app/static/js/base.js b/app/static/js/base.js
index 0b06e2fc6..9b13d8991 100644
--- a/app/static/js/base.js
+++ b/app/static/js/base.js
@@ -124,3 +124,77 @@ function setCharacterLimit(textboxId, labelId){
$(labelId).text("Remaining Characters: " + 0);
}
}
+
+function hasUniqueFileName(fileName){
+ return $(".fileName[data-filename='" + fileName + "']").length == 0;
+}
+
+function getSelectedFiles(){
+ let _fileHolder = new DataTransfer();
+ $(".fileHolder").each(function(){
+ _fileHolder.items.add($(this).data("file"));
+ });
+ return _fileHolder.files;
+}
+
+function handleFileSelection(fileInputId){
+ var fileBoxId = "#" + fileInputId
+ var attachedObjectContainerId = fileInputId + "Container"
+ $(fileBoxId).after(`
`)
+ var objectContainerId = "#" + attachedObjectContainerId
+ $(fileBoxId).on('change', function() {
+ const selectedFiles = $(fileBoxId).prop('files');
+ for (let i = 0; i < selectedFiles.length; i++){
+ const file = selectedFiles[i];
+ if (hasUniqueFileName(file.name)){
+ let fileName = (file.name.length > 25) ? file.name.slice(0,10) + '...' + file.name.slice(-10) : file.name;
+ let fileExtension = file.name.split(".").pop();
+ let iconClass = '';
+ switch(fileExtension) {
+ case 'jpg':
+ case 'png':
+ case 'jpeg':
+ iconClass = "bi-file-image";
+ break
+ case 'pdf':
+ iconClass = 'bi-filetype-pdf';
+ break
+ case 'docx':
+ iconClass = 'bi-filetype-docx';
+ break
+ case 'xlsx':
+ iconClass = 'bi-filetype-xlsx';
+ break
+ default:
+ iconClass = 'bi-file-earmark-arrow-up';
+ }
+ let trashNum = ($(objectContainerId+ " .row").length)
+ var fullTrashId = "#trash" + trashNum
+ $(objectContainerId).append(" \
+ \
+
\
+
" + fileName + "
\
+
\
+
")
+ $(fullTrashId).data("file", file);
+ $(fullTrashId).data("file-container-id", attachedObjectContainerId);
+ $(fullTrashId).on("click", function() {
+ let elementFileNum = $(this).data('filenum');
+ let attachedObjectContainerId = $(this).data('file-container-id');
+ $("#"+ attachedObjectContainerId + " #attachedFilesRow" + elementFileNum).remove();
+ $(fileBoxId).prop('files', getSelectedFiles());
+ })
+ $(fileBoxId).data("file-num", $(fileBoxId).data("file-num") + 1)
+ }
+ else{
+ msgToast("File with filename '" + file.name + "' has already been added to this event")
+ }
+ }
+ $(fileBoxId).prop('files', getSelectedFiles());
+ });
+
+}
\ No newline at end of file
diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js
index 8265c2d2a..fb16d0d6a 100644
--- a/app/static/js/createEvents.js
+++ b/app/static/js/createEvents.js
@@ -61,22 +61,6 @@ function format24to12HourTime(timeStr){
}
-
-function getSelectedFiles(){
- let _fileHolder = new DataTransfer();
- $(".fileHolder").each(function(){
- _fileHolder.items.add($(this).data("file"));
- });
- return _fileHolder.files;
-}
-
-
-function hasUniqueFileName(fileName){
- return $(".fileName[data-filename='" + fileName + "']").length == 0;
-}
-
-
-
/*
* Run when the webpage is ready for javascript
*/
@@ -85,58 +69,7 @@ $(document).ready(function() {
calculateRecurringEventFrequency();
}
- var fileNum = 0;
- $("#attachmentObject").on('change', function() {
- const selectedFiles = $("#attachmentObject").prop('files');
- for (let i = 0; i < selectedFiles.length; i++) {
- const file = selectedFiles[i];
- if (hasUniqueFileName(file.name)){
- let fileName = (file.name.length > 25) ? file.name.slice(0,10) + '...' + file.name.slice(-10) : file.name;
- let fileExtension = file.name.split(".").pop();
- let iconClass = '';
- switch(fileExtension) {
- case 'jpg':
- case 'png':
- case 'jpeg':
- iconClass = "bi-file-image";
- break
- case 'pdf':
- iconClass = 'bi-filetype-pdf';
- break
- case 'docx':
- iconClass = 'bi-filetype-docx';
- break
- case 'xlsx':
- iconClass = 'bi-filetype-xlsx';
- break
- default:
- iconClass = 'bi-file-earmark-arrow-up';
- }
- $("#attachedObjectContainer").append(" \
-
\
-
" + fileName + "
\
-
\
-
")
- $("#trash"+fileNum).data("file", file);
- $("#trash"+fileNum).on("click", function() {
- let elementFileNum = $(this).data('filenum');
- $("#attachedFilesRow" + elementFileNum).remove();
- $("#attachmentObject").prop('files', getSelectedFiles());
- })
- fileNum++;
- }
- else{
- msgToast("File with filename '" + file.name + "' has already been added to this event")
- }
- }
- $("#attachmentObject").prop('files', getSelectedFiles());
- });
-
-
+ handleFileSelection("attachmentObject")
$("#checkRSVP").on("click", function() {
if ($("#checkRSVP").is(":checked")) {
@@ -274,25 +207,6 @@ $(document).ready(function() {
$("#hiddenFacilitatorArray").attr("value", facilitatorArray);
$(this).closest("tr").remove();
});
- $(".removeAttachment").on("click", function(){
-
- let fileId= $(this).data("id")
- let fileData = {fileId : fileId,
- eventId:this.id}
- $.ajax({
- type:"POST",
- url: "/deleteEventFile",
- data: fileData, //get the startDate, endDate and name as a dictionary
- success: function(){
- msgFlash("Attachment removed successfully")
- $("#attachment_"+fileId).remove()
-
- },
- error: function(error){
- msgFlash(error)
- }
- });
- });
$("#endDatePicker").change(function(){
updateDate(this)
});
diff --git a/app/static/js/displayFilesMacro.js b/app/static/js/displayFilesMacro.js
new file mode 100644
index 000000000..10f767273
--- /dev/null
+++ b/app/static/js/displayFilesMacro.js
@@ -0,0 +1,21 @@
+$(document).ready(function(){
+ $(".removeAttachment").on("click", function(){
+ let fileId= $(this).data("id")
+ let deleteLink = $(this).data("delete-url")
+ let fileData = {fileId : fileId,
+ databaseId:$(this).data('database-id')}
+ $.ajax({
+ type:"POST",
+ url: deleteLink,
+ data: fileData, //get the startDate, endDate and name as a dictionary
+ success: function(){
+ msgFlash("Attachment removed successfully")
+ $("#attachment_"+fileId).remove()
+
+ },
+ error: function(error){
+ msgFlash(error)
+ }
+ });
+ });
+})
diff --git a/app/static/js/slcNewProposal.js b/app/static/js/slcNewProposal.js
index 40041a4ce..9cdce1831 100644
--- a/app/static/js/slcNewProposal.js
+++ b/app/static/js/slcNewProposal.js
@@ -3,45 +3,12 @@ import searchUser from './searchUser.js'
var currentTab = 0; // Current tab is set to be the first tab (0)
$(document).ready(function(e) {
- disableSyllabusUploadFile()
- $(".removeAttachment").on("click", function(){
-
- let fileId= $(this).data("id")
- let fileData = {fileId : fileId,
- courseId:this.id}
- $.ajax({
- type:"POST",
- url: "/deleteCourseFile",
- data: fileData, //get the startDate, endDate and name as a dictionary
- success: function(){
- $("#modalAttachment_"+fileId).remove()
- $("#pageAttachment_"+fileId).remove()
- currentTab = 1;
-
- },
- error: function(error){
- msgFlash(error)
- }
- });
- });
-
-
- $("#attachmentObject").on('fileloaded', function() {
- enableSyllabusUploadFile()
- })
-
- $("#syllabusUploadButton").on("click", function() {
- saveCourseData('/serviceLearning/saveProposal', function() {})
- $("#syllabusUploadModal").modal("toggle")
- })
-
- $("#attachmentObject").fileinput({
- allowedFileExtensions:["pdf","jpg","png","gif", "csv", "docx", "jpg", "jpeg", "jfif"]
- })
+ handleFileSelection("attachmentObject")
// set up the current tab and button state
- if(window.location.href.includes("upload")) {
- currentTab = 1
+ const urlParams = new URLSearchParams(window.location.search);
+ if (urlParams.get('tab')){
+ currentTab = Number(urlParams.get('tab'));
}
showTab(currentTab);
@@ -114,6 +81,7 @@ $(document).ready(function(e) {
});
$("#saveContinue").on("click", function() {
+
if(readOnly()) {
let allTabs = $(".tab");
displayCorrectTab(1)
@@ -124,30 +92,21 @@ $(document).ready(function(e) {
// TODO nothing?
}
}
-
- //this will save the change from the current page and move to the next page
- let allTabs = $(".tab");
- if (currentTab == (allTabs.length - 2)) {
-
- saveCourseData("/serviceLearning/saveContinue", function() {
- displayCorrectTab(1);
- })
+ else{
+ if (!validateForm()) return;
+ $('#slcNewProposal').attr("action", "/serviceLearning/saveProposal")
+ $('#slcNewProposal').submit()
}
- else if (currentTab == (allTabs.length - 1)){
- saveCourseData("/serviceLearning/saveExit", function() {
- window.location.replace("/serviceLearning/courseManagement");
- });
- }
});
- $("#saveExit").on("click", function() {
- saveCourseData("/serviceLearning/saveExit", function() {
- window.location.replace("/serviceLearning/courseManagement");
- });
+ $('#saveExit').on("click", function(){
+ if (!validateForm()) return;
+ $('#slcNewProposal').attr("action", "/serviceLearning/saveExit")
+ $('#slcNewProposal').submit()
})
$("#exitButton").on("click", function() {
- window.location.replace("/serviceLearning/courseManagement")
+ window.location.replace('/serviceLearning/exit')
})
if(!readOnly()) {
@@ -161,7 +120,9 @@ $(document).ready(function(e) {
// Add course instructor event handlers
// -----------------------------------------
$("#instructorTable").on("click", "#remove", function() {
- $(this).closest("tr").remove();
+ let closestRow = $(this).closest("tr")
+ $("#instructorTableNames input[value="+closestRow.data('username')+"]").remove()
+ closestRow.remove();
});
$("#courseInstructor").on('input', function() {
searchUser("courseInstructor", createNewRow, true, null, "instructor");
@@ -228,7 +189,6 @@ function displayCorrectTab(navigateTab) {
if (currentTab >= allTabs.length) {
$("#nextButton").prop("disabled", true)
- addInstructorsToForm()
$("#slcNewProposal").submit();
return false;
}
@@ -274,8 +234,7 @@ function showTab(currentTab) {
$("#submitAndApproveButton").show();
$("#nextButton").text("Submit Proposal");
$("#nextButton").show();
- $("#saveContinue").text("Save and Exit");
- $("#saveExit").hide()
+ $("#saveContinue").hide();
$("#exitButton").hide()
if(readOnly()) {
$("#nextButton").text("Next");
@@ -309,12 +268,12 @@ function saveCourseData(url, successCallback) {
}
function validateForm() {
- // This function ensures our form fields are valid
- // Returns true if we are just viewing a form
- // TODO: Generalize form validation to include textareas and selects
+ // This function ensures our form fields are valid
+ // Returns true if we are just viewing a form
+ // TODO: Generalize form validation to include textareas and selects
- if (readOnly())
- return true;
+ if (readOnly())
+ return true;
let valid = true;
@@ -348,12 +307,6 @@ function validateForm() {
// Instructor manipulation functions
// -------------------------------------
//
-function addInstructorsToForm() {
- var form = $("#slcNewProposal");
- $.each(getCourseInstructors(), function(idx,username) {
- form.append($(""));
- });
-}
function getRowUsername(element) {
return $(element).closest("tr").data("username")
@@ -384,7 +337,6 @@ function createNewRow(selectedInstructor) {
let editLink = newRow.find("td:eq(0) a")
editLink.attr("id", "editButton-" + username);
- newRow.attr("data-username", username)
editLink.attr("data-username", username)
newRow.prop("hidden", false);
lastRow.after(newRow);
@@ -395,13 +347,13 @@ function createNewRow(selectedInstructor) {
if (username){
setupPhoneNumber(edit, input)
}
+
+ $("#instructorTableNames").append('')
}
function getCourseInstructors() {
// get usernames out of the table rows into an array
- return $("#instructorTable tr")
- .map((i,el) => $(el).data('username')).get()
- .filter(val => (val))
+ return $("#instructorTableNames input").map((i,el) => $(el).val())
}
function disableSyllabusUploadFile() {
diff --git a/app/templates/admin/createEvent.html b/app/templates/admin/createEvent.html
index 772862284..a0d0b1c58 100644
--- a/app/templates/admin/createEvent.html
+++ b/app/templates/admin/createEvent.html
@@ -22,6 +22,7 @@
{% block scripts %}
{{super()}}
+
{% endblock %}
@@ -235,31 +236,12 @@
{% if filepaths %}
+ {% from 'displayFilesMacro.html' import displayFiles %}
+ {{ displayFiles(filepaths, 'Event Attachments', '/deleteEventFile', '{{course.id}}') }}
+
{% endif %}
diff --git a/app/templates/displayFilesMacro.html b/app/templates/displayFilesMacro.html
new file mode 100644
index 000000000..048e61522
--- /dev/null
+++ b/app/templates/displayFilesMacro.html
@@ -0,0 +1,23 @@
+{% macro displayFiles(filepaths, titleName, deleteLink, databaseId) %}
+
+
+ {% for key, value in filepaths.items() %}
+
+
+ {% set filename = key[:8]+ "..." +key[-10:] if key| length > 25 else key %}
+ {{filename}}
+ |
+
+
+ |
+
+ {% endfor %}
+
+{% endmacro %}
diff --git a/app/templates/serviceLearning/slcNewProposal.html b/app/templates/serviceLearning/slcNewProposal.html
index 44e843b56..065c24ef1 100644
--- a/app/templates/serviceLearning/slcNewProposal.html
+++ b/app/templates/serviceLearning/slcNewProposal.html
@@ -3,9 +3,9 @@
{% block scripts %}
{{super()}}
+
-
{% endblock %}
{% block styles %}
@@ -15,7 +15,7 @@
{% endblock %}
{% block app_content %}
-
-
-
{% endblock %}
diff --git a/app/templates/serviceLearning/slcProposal.html b/app/templates/serviceLearning/slcProposal.html
index 4c76d336c..d461e3d39 100644
--- a/app/templates/serviceLearning/slcProposal.html
+++ b/app/templates/serviceLearning/slcProposal.html
@@ -25,7 +25,7 @@ New Proposal For Service-Learning Course
- Edit
+ Edit
|
@@ -37,7 +37,7 @@ New Proposal For Service-Learning Course
|
{{instructor.user.firstName}} {{instructor.user.lastName}} ({{instructor.user.email}})
- Edit
+ Edit
|
@@ -48,6 +48,11 @@ New Proposal For Service-Learning Course
+
+ {% for instructor in courseInstructor %}
+
+ {% endfor %}
+
New Proposal For Service-Learning Course
-
-
+
+
+
+
+
+
{% if filepaths %}
{% endif %}
+
+
|