Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Program Management section of Admin Settings #1281

Open
wants to merge 55 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
f850ec3
New Branch with changes from previous. Image
JohnCox2211 Jul 5, 2024
d5fe95d
changed coverImage to be a blobfield. cleaned up
JohnCox2211 Jul 5, 2024
ebf80d2
More attempts for file handling, trying to modify
JohnCox2211 Jul 8, 2024
0053012
Deleted partner.py because it was not being used
JohnCox2211 Jul 8, 2024
874a913
added some notes about what returns are for
JohnCox2211 Jul 9, 2024
d1f035a
modified the modal so we could store the images of the filepaths
Kafui123 Jul 10, 2024
230ee45
modified image storing to database
Kafui123 Jul 10, 2024
decdb3d
we are on to something
Kafui123 Jul 10, 2024
19c1b2c
Fixed Issuegit status !
Kafui123 Jul 11, 2024
be36260
Picture appeared, at some point of time, but it disappeared again. Cu…
Jul 11, 2024
a7eb026
changes we have made so far
Kafui123 Jul 12, 2024
e40eb96
Issue fixed, the modal works, the delete button does not close the mo…
Jul 15, 2024
19040fd
updated code that reflects all the changes that work
Kafui123 Jul 16, 2024
4702612
Merge branch 'development' into refactorProgramMgmt
AravDe Jul 17, 2024
f8a6a2a
modified changes
Kafui123 Jul 17, 2024
14b3eca
updates
Kafui123 Jul 17, 2024
4089296
Test suites almost fixed. Working on Mocking Filestorage object for t…
Jul 17, 2024
7f27709
updated code yet
Kafui123 Jul 19, 2024
abc75f0
Added scroll feature to modal but now planning on removing again. Tes…
Jul 22, 2024
7f472f9
modified changes
Kafui123 Jul 22, 2024
7067204
modified code
Kafui123 Jul 22, 2024
ddcae6f
Handing over to Kafui
Jul 22, 2024
f1280c6
modified changes
Kafui123 Jul 22, 2024
8545c4e
changes
Kafui123 Jul 22, 2024
52d56ab
Changes to Kafui
esw0624 Jul 22, 2024
04c7f87
modified changes
Kafui123 Jul 22, 2024
4a663bd
modified changes
Kafui123 Jul 22, 2024
16407d5
updates for pr
Kafui123 Jul 22, 2024
0399f4b
Merge branch 'development' into refactorProgramMgmt
Kafui123 Jul 22, 2024
3f99551
Update for my local branch
esw0624 Jul 23, 2024
7f219b5
final code ready for review
Kafui123 Jul 23, 2024
d631b1f
final code changes
Kafui123 Jul 23, 2024
2aaf254
Merge branch 'development' into refactorProgramMgmt
Kafui123 Jul 23, 2024
bfe21fe
Update
esw0624 Jul 24, 2024
2aaf332
Update for branch
esw0624 Jul 25, 2024
6a7af85
userpr
Kafui123 Jul 24, 2024
91d55b6
modified changes
Kafui123 Jul 24, 2024
a1ca894
checking to see if my commits are being sent to the remote bramch
Kafui123 Jul 24, 2024
cdbc950
this commit reflects all updated changes that my partner, eun can pul…
Kafui123 Jul 25, 2024
e1ff16b
necessary merge to get in sync with my remotebranch
Kafui123 Jul 25, 2024
38fbf19
final code changes for July 25
Kafui123 Jul 25, 2024
9831544
commit for friday july -26 (most recent code update)
Kafui123 Jul 26, 2024
f4a42d6
Merge branch 'development' into refactorProgramMgmt
esw0624 Jul 26, 2024
dca0ec5
most recent code on july 29th
Kafui123 Jul 29, 2024
5ce9768
most recent code for july 30th
Kafui123 Jul 30, 2024
bd5bed9
most recent code change for july 30th
Kafui123 Jul 30, 2024
adc1087
final code ready for pr review july 31st
Kafui123 Jul 31, 2024
57fee5b
Merge branch 'development' into refactorProgramMgmt
BrianRamsay Jul 31, 2024
b58673b
final code changes for July 31st
Kafui123 Jul 31, 2024
f092bba
final code updates for July 31st
Kafui123 Jul 31, 2024
57da6e1
merge necessary to update my local branch to my remote branch
Kafui123 Jul 31, 2024
7d7fb9a
most recent code update for august 2nd
Kafui123 Aug 2, 2024
002d470
Merge branch 'development' into refactorProgramMgmt
bledsoef Aug 22, 2024
eea8a51
Switch the landingPage image names to program IDs
WackyWeaver Sep 4, 2024
fd01a4b
Merge branch 'refactorProgramMgmt' of https://github.com/BCStudentSof…
WackyWeaver Sep 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ ldap:

files:
base_path: 'app/static/files'
image_path: 'app/static/images'
landing_page_path: 'landingPage'
email_attachment_path: 'emailattachments'
event_attachment_path: 'eventattachments'
course_attachment_path: 'courseattachments'
Expand Down
45 changes: 18 additions & 27 deletions app/controllers/admin/userManagement.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from app.logic.userManagement import changeProgramInfo
from app.logic.utils import selectSurroundingTerms
from app.logic.term import addNextTerm, changeCurrentTerm
from app.logic.fileHandler import FileHandler
from app.models.attachmentUpload import AttachmentUpload

@admin_bp.route('/admin/manageUsers', methods = ['POST'])
def manageUsers():
Expand Down Expand Up @@ -48,43 +50,32 @@ def manageUsers():
flash(user.firstName + " " + user.lastName + " is no longer a CELTS Student Staff", 'success')
return ("success")

@admin_bp.route('/addProgramManagers', methods=['POST'])
def addProgramManagers():
eventData = request.form
try:
return addProgramManager(eventData['username'],int(eventData['programID']))
except Exception as e:
print(e)
flash('Error while trying to add a manager.','warning')
abort(500,"'Error while trying to add a manager.'")

@admin_bp.route('/removeProgramManagers', methods=['POST'])
def removeProgramManagers():
eventData = request.form
try:
return removeProgramManager(eventData['username'],int(eventData['programID']))
except Exception as e:
print(e)
flash('Error while removing a manager.','warning')
abort(500,"Error while trying to remove a manager.")
@admin_bp.route('/deleteProgramFile', methods=['POST'])
def deleteProgramFile():
programFile=FileHandler(programId=request.form["programID"])
programFile.deleteFile(request.form["fileId"])
return ""

@admin_bp.route('/admin/updateProgramInfo/<programID>', methods=['POST'])
def updateProgramInfo(programID):
"""Grabs info and then outputs it to logic function"""
programInfo = request.form # grabs user inputs
if g.current_user.isCeltsAdmin:
try:
changeProgramInfo(programInfo["programName"], #calls logic function to add data to database
programInfo["contactEmail"],
programInfo["contactName"],
programInfo["location"],
programID)
programInfo = request.form # grabs user inputs
uploadedFile = request.files.get('modalProgramImage')
changeProgramInfo(programID, uploadedFile, **programInfo)

associatedAttachments = list(AttachmentUpload.select().where(AttachmentUpload.program == programID).execute())

filePaths = FileHandler(programId=programID).retrievePath(associatedAttachments)


file_paths = {filename: path_info[0] for filename, path_info in filePaths.items()}
flash("Program updated", "success")
return redirect(url_for("admin.userManagement", accordion="program"))
except Exception as e:
print(e)
flash('Error while updating program info.','warning')
print("error: ", e)
flash('Error while updating program info.','warning')
abort(500,'Error while updating program.')
abort(403)

Expand Down
47 changes: 41 additions & 6 deletions app/logic/fileHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,25 @@
from flask import redirect, url_for
from app import app
from app.models.attachmentUpload import AttachmentUpload
from app.models.program import Program
import glob

class FileHandler:
def __init__(self, files=None, courseId=None, eventId=None):
self.files = files
self.path = app.config['files']['base_path']
def __init__(self, files=None, courseId=None, eventId=None, programId=None):
self.files = files
if not isinstance(self.files, list):
self.files = [self.files]
self.path = app.config['files']['base_path']
self.courseId = courseId
self.eventId = eventId
self.programId = programId
if courseId:
self.path = os.path.join(self.path, app.config['files']['course_attachment_path'], str(courseId))
elif eventId:
self.path = os.path.join(self.path, app.config['files']['event_attachment_path'])

elif programId:
self.path = os.path.join(app.config['files']['image_path'], app.config['files']['landing_page_path'])

def makeDirectory(self):
try:
extraDir = str(self.eventId) if self.eventId else ""
Expand All @@ -25,17 +32,19 @@ def makeDirectory(self):

def getFileFullPath(self, newfilename=''):
try:
filePath = (os.path.join(self.path, newfilename))
if self.eventId or self.courseId or self.programId:
filePath = (os.path.join(self.path, newfilename))
Kafui123 marked this conversation as resolved.
Show resolved Hide resolved
except AttributeError:
pass
except FileExistsError:
pass
return filePath

def saveFiles(self, saveOriginalFile=None):
try:
try:
for file in self.files:
saveFileToFilesystem = None

if self.eventId:
attachmentName = str(saveOriginalFile.id) + "/" + file.filename
isFileInEvent = AttachmentUpload.select().where(AttachmentUpload.event_id == self.eventId,
Expand All @@ -49,11 +58,37 @@ def saveFiles(self, saveOriginalFile=None):
if not isFileInCourse:
AttachmentUpload.create(course=self.courseId, fileName=file.filename)
saveFileToFilesystem = file.filename
elif self.programId:
# Delete existing files for the program before saving the new one
existing_files = AttachmentUpload.select().where(
AttachmentUpload.program == self.programId
)

for existing_file in existing_files:
existing_file.delete_instance()

# Remove files from the filesystem
pattern = '*' + Program.get(Program.id == self.programId).programName + '*'
full_pattern = os.path.join(self.path, pattern)
files_to_delete = glob.glob(full_pattern)

for file_path in files_to_delete:
os.remove(file_path)

# Save the new file
AttachmentUpload.create(program=self.programId, fileName=file.filename)
program = Program.get(Program.id == self.programId)
file_type = file.filename.split('.')[-1]
current_programID = f"{program.id}.{file_type}"
saveFileToFilesystem = current_programID

Kafui123 marked this conversation as resolved.
Show resolved Hide resolved
else:
saveFileToFilesystem = file.filename

if saveFileToFilesystem:
self.makeDirectory()
file.save(self.getFileFullPath(newfilename=saveFileToFilesystem))

except AttributeError:
pass

Expand Down
2 changes: 1 addition & 1 deletion app/logic/landingPage.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def getManagerProgramDict(user):
managerProgramDict[program] = {"managers": "", "image": os.path.join('static', 'images/logos/celts_symbol.png')}
with os.scandir("./app/static/images/landingPage") as it:
for entry in it:
if entry.name.split('.')[0] == f'{program.programName}':
if entry.name.split('.')[0] == f'{program.id}':
managerProgramDict[program]["image"] = os.path.join('static', f'images/landingPage/{entry.name}')
break
for row in managerRows:
Expand Down
57 changes: 45 additions & 12 deletions app/logic/userManagement.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from flask import g, session
from app.logic.createLogs import createActivityLog
from playhouse.shortcuts import model_to_dict
from app.logic.fileHandler import FileHandler

def addCeltsAdmin(user):
user = User.get_by_id(user)
Expand Down Expand Up @@ -38,20 +39,52 @@ def removeCeltsStudentStaff(user):
createActivityLog(f'Removed {user.firstName} {user.lastName} from a CELTS student staff member'+
(f', and as a manager of {programManagerRoles}.' if programManagerRoles else "."))

def changeProgramInfo(programId,
attachment,
programName= None,
programDescription = None,
partner = None,
contactEmail=None,
contactName= None,
location = None,
instagramUrl = None,
facebookUrl = None,
bereaUrl = None):


def changeProgramInfo(newProgramName, newContactEmail, newContactName, newLocation, programId):
"""Updates the program info with a new sender and email."""
"""Updates the program info and logs that change"""
program = Program.get_by_id(programId)
updatedProgram = Program.update({Program.programName:newProgramName, Program.contactEmail: newContactEmail, Program.contactName:newContactName, Program.defaultLocation:newLocation}).where(Program.id==programId)
if attachment:
addFile: FileHandler = FileHandler(attachment, programId=programId)
addFile.saveFiles()
updatedProgram = Program.update(
{ Program.programName:programName,
Program.programDescription: programDescription,
Program.partner: partner,
Program.contactEmail: contactEmail,
Program.contactName: contactName,
Program.defaultLocation: location,
Program.instagramUrl:instagramUrl,
Program.facebookUrl: facebookUrl,
Program.bereaUrl: bereaUrl
}
).where(Program.id==programId)
updatedProgram.execute()
if newProgramName != program.programName:
createActivityLog(f"{program.programName} Program Name was changed to: {newProgramName}")
if newContactEmail != program.contactEmail:
createActivityLog(f"{program.programName} Contact Email was changed to: {newContactEmail}")
if newContactName != program.contactName:
createActivityLog(f"{program.programName} Contact Name was changed to: {newContactName}")
if newLocation != program.defaultLocation:
createActivityLog(f"{program.programName} Location was changed to: {newLocation}")


if programName != program.programName:
createActivityLog(f"{program.programName} Program Name was changed to: {programName}")
if programDescription != program.programDescription:
createActivityLog(f"{program.programName} Description was changed to: {programDescription}")
if partner != program.partner:
createActivityLog(f"{program.programName} Program Partner was changed to: {partner}")
if contactEmail != program.contactEmail:
createActivityLog(f"{program.programName} Contact Email was changed to: {contactEmail}")
if contactName != program.contactName:
createActivityLog(f"{program.programName} Contact Name was changed to: {contactName}")
if location != program.defaultLocation:
createActivityLog(f"{program.programName} Location was changed to: {location}")


return (f'Program email info updated')

Expand All @@ -69,4 +102,4 @@ def getAllowedTemplates(currentUser):
if currentUser.isCeltsAdmin:
return EventTemplate.select().where(EventTemplate.isVisible==True).order_by(EventTemplate.name)
else:
return []
return []
2 changes: 2 additions & 0 deletions app/models/attachmentUpload.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from app.models import*
from app.models.event import Event
from app.models.course import Course
from app.models.program import Program
from app.models.otherExperience import OtherExperience


class AttachmentUpload(baseModel):
event = ForeignKeyField(Event, null=True)
course = ForeignKeyField(Course, null=True)
program = ForeignKeyField(Program, null=True)
isDisplayed = BooleanField(default=False)
fileName = CharField()

4 changes: 0 additions & 4 deletions app/models/partner.py

This file was deleted.

3 changes: 1 addition & 2 deletions app/models/program.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from app.models import*
from app.models.term import Term
from app.models.courseStatus import CourseStatus
from app.models.partner import Partner

class Program(baseModel):
programName = CharField()
instagramUrl = TextField(null=True)
facebookUrl = TextField(null=True)
bereaUrl = TextField(null=True)
programDescription = TextField()
partner = ForeignKeyField(Partner, null=True)
partner = CharField(null=True)
isStudentLed = BooleanField(default=False)
isBonnerScholars = BooleanField(default=False)
isOtherCeltsSponsored = BooleanField(default=False)
Expand Down
2 changes: 1 addition & 1 deletion app/static/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

.toast-container{
top: 0;
z-index: 11;
z-index: 1060;
}

.form-control.invalid,
Expand Down
38 changes: 38 additions & 0 deletions app/static/css/programManagement.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.modal {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
/* Removed incorrect translate */
}

.modal-dialog-scrollable {
max-height: calc(100vh - 200px);
overflow-y: auto;
}


.info {
overflow-y: auto;
margin-top: -20px;
}

.cellSpacing {
margin: 5px;
padding: 10px;
}

.programHeader {
border-bottom: 1px solid black;
font-weight: bold;
}

.borderless {
border: 0;
}

.rightJustify {
position: absolute;
right: 10px; /* Added px to right */
}

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion app/static/js/displayFilesMacro.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
$(document).ready(function(){
$("a.fileName").tooltip();

$(".removeAttachment").on("click", function(){
$(".removeAttachment").on("click", function(e){
e.preventDefault();
let fileId = $(this).data("id");
let deleteLink = $(this).data("delete-url");
let fileData = {
Expand Down
27 changes: 27 additions & 0 deletions app/static/js/userManagement.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,33 @@ function submitRequest(method, username){
})
}

$(document).ready(function() {
$('[data-bs-toggle="modal"]').on('click', function() {
// Get the JSON data from the data-programinfo attribute
const programInfo = JSON.parse($(this).attr('data-programinfo'));
// Directly populate modal fields
$("#programName").val(programInfo.programName);
$("#programDescription").val(programInfo.programDescription);
$("#partner").val(programInfo.partner);
$("#contactEmail").val(programInfo.contactEmail);
$("#contactName").val(programInfo.contactName);
$("#location").val(programInfo.location);
$("#programid").val(programInfo.programid)
$("#instagramUrl").val(programInfo.instagramUrl);
$("#facebookUrl").val(programInfo.facebookUrl);
$("#bereaUrl").val(programInfo.bereaUrl);


handleFileSelection('modalProgramImage');
// Update the form action URL dynamically
let updateForm = $('#updateProgramForm');
updateForm.attr('action', "/admin/updateProgramInfo/" + programInfo.programid);
});
});




function submitTerm(){
var selectedTerm = $("#currentTermList .active")
var termInfo = {id: selectedTerm.val()};
Expand Down
Loading