From 85aaf3c155b8f3a3ecf6e161335fc5f8c677ab08 Mon Sep 17 00:00:00 2001 From: Mbeweg <122580961+Mbeweg@users.noreply.github.com> Date: Thu, 25 Jul 2024 14:28:00 -0400 Subject: [PATCH 01/16] Changes to the invite cohort --- app/static/js/createEvents.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index cb93a98b3..132f434ae 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -228,3 +228,24 @@ $(document).ready(function () { setCharacterLimit($("#inputCharacters"), "#remainingCharacters"); }); + +function saveSelectedCohorts() { + const selectedCohorts = []; + $("input[name='cohorts[]']:checked").each(function () { + selectedCohorts.push($(this).val()); + }); + localStorage.setItem("selectedCohorts", JSON.stringify(selectedCohorts)); +} + +// Attach the change event to all cohort checkboxes +$(document).on("change", "input[name='cohorts[]']", saveSelectedCohorts); + +function loadSelectedCohorts() { + const selectedCohorts = JSON.parse(localStorage.getItem("selectedCohorts")) || []; + selectedCohorts.forEach(function (year) { + $(`input[name='cohorts[]'][value='${year}']`).prop("checked", true); + }); +} + +// Call the function to load selected checkboxes when the page loads +$(document).ready(loadSelectedCohorts); From d3dcc504f4bba74462fcb3af2c565738ca2b170f Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Tue, 17 Sep 2024 15:53:11 -0400 Subject: [PATCH 02/16] bonner cohort remain checked --- app/static/js/createEvents.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 132f434ae..508b37b19 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -232,20 +232,29 @@ $(document).ready(function () { function saveSelectedCohorts() { const selectedCohorts = []; $("input[name='cohorts[]']:checked").each(function () { - selectedCohorts.push($(this).val()); + selectedCohorts.push($(this).val()); }); - localStorage.setItem("selectedCohorts", JSON.stringify(selectedCohorts)); + sessionStorage.setItem("selectedCohorts", JSON.stringify(selectedCohorts)); } -// Attach the change event to all cohort checkboxes $(document).on("change", "input[name='cohorts[]']", saveSelectedCohorts); - function loadSelectedCohorts() { - const selectedCohorts = JSON.parse(localStorage.getItem("selectedCohorts")) || []; - selectedCohorts.forEach(function (year) { - $(`input[name='cohorts[]'][value='${year}']`).prop("checked", true); + const selectedCohorts = JSON.parse(sessionStorage.getItem("selectedCohorts")) || []; + selectedCohorts.forEach(function (cohort) { + $("input[name='cohorts[]'][value='" + cohort + "']").prop("checked", true); }); } -// Call the function to load selected checkboxes when the page loads -$(document).ready(loadSelectedCohorts); + +$(document).ready(function () { + loadSelectedCohorts(); + + + $("#createNewEventButton").on("click", function () { + clearSelectedCohorts(); // + }); +}); +function clearSelectedCohorts() { + sessionStorage.removeItem("selectedCohorts"); + $("input[name='cohorts[]']").prop("checked", false); +} From 100f0cceeb7b329b98e32f1139f33beeb58164af Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Fri, 20 Sep 2024 14:53:31 -0400 Subject: [PATCH 03/16] improved code --- app/static/js/createEvents.js | 61 +++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 0f4918efd..c306d3877 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -221,19 +221,25 @@ $(".startDatePicker, .endDatePicker").change(function () { }); $("#saveEvent").on('submit', function (event) { - let trainingStatus = $("#checkIsTraining").is(":checked") - let serviceHourStatus = $("#checkServiceHours").is(":checked") - let bonnersStatus = $("#checkBonners").is(":checked") - //check if user has selected a toggle, cancel form submission if not - if(trainingStatus || serviceHourStatus || bonnersStatus || $("#pageTitle").text() == 'Create All Volunteer Training'){ - // Disable button when we are ready to submit - $(this).find("input[type=submit]").prop("disabled", true); - } - else { - msgFlash("You must toggle event is a training, event earns service hours, or is a Bonners Scholars event!", "danger"); - event.preventDefault(); - } - }); + let bonnersStatus = $("#checkBonners").is(":checked"); + let eventData = { + // other event data + bonnersStatus: bonnersStatus + }; + // Now save the bonnersStatus to the backend along with other event data + $.ajax({ + type: 'POST', + url: '/saveEvent', // your save event API endpoint + data: eventData, + success: function(response) { + console.log('Event saved successfully!'); + }, + error: function(err) { + console.error('Error saving event:', err); + } + }); +}); + let modalOpenedByEditButton = false; @@ -447,3 +453,32 @@ function clearSelectedCohorts() { sessionStorage.removeItem("selectedCohorts"); $("input[name='cohorts[]']").prop("checked", false); } +$(document).ready(function() { + // Retrieve the saved bonners status from the event object + let savedBonnersStatus = getSavedBonnersStatusFromBackend(); // Replace with actual logic to get saved state + + // Set the checkbox state based on the saved status + if (savedBonnersStatus) { + $("#checkBonners").prop('checked', true); + } else { + $("#checkBonners").prop('checked', false); + } +}); + +// Function to get the saved bonners status from the backend +function getSavedBonnersStatusFromBackend() { + // Make an AJAX call to get the event data + let bonnersStatus; + $.ajax({ + type: 'GET', + url: '/getEvent', // your API endpoint to get event data + async: false, + success: function(response) { + bonnersStatus = response.bonnersStatus; // Assume this comes back in the event data + }, + error: function(err) { + console.error('Error fetching event data:', err); + } + }); + return bonnersStatus; +} From 616aa8cc7daf6948a513530d7c857cc565558f5d Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Fri, 4 Oct 2024 11:29:01 -0400 Subject: [PATCH 04/16] Bonner Cohort checkbox fixed + merge conflict --- app/static/js/createEvents.js | 74 +++++++++-------------------------- 1 file changed, 19 insertions(+), 55 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 539a170eb..3949d028b 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -311,26 +311,6 @@ $(".startDatePicker, .endDatePicker").change(function () { }); $("#saveEvent").on('submit', function (event) { - - let bonnersStatus = $("#checkBonners").is(":checked"); - let eventData = { - // other event data - bonnersStatus: bonnersStatus - }; - // Now save the bonnersStatus to the backend along with other event data - $.ajax({ - type: 'POST', - url: '/saveEvent', // your save event API endpoint - data: eventData, - success: function(response) { - console.log('Event saved successfully!'); - }, - error: function(err) { - console.error('Error saving event:', err); - } - }); -}); - let trainingStatus = $("#checkIsTraining").is(":checked") let serviceHourStatus = $("#checkServiceHours").is(":checked") let bonnersStatus = $("#checkBonners").is(":checked") @@ -346,7 +326,6 @@ $(".startDatePicker, .endDatePicker").change(function () { }); updateOfferingsTable(); - if ($("#checkIsMultipleOffering").is(":checked")){ setViewForMultipleOffering(); @@ -514,7 +493,6 @@ function saveSelectedCohorts() { sessionStorage.setItem("selectedCohorts", JSON.stringify(selectedCohorts)); } -$(document).on("change", "input[name='cohorts[]']", saveSelectedCohorts); function loadSelectedCohorts() { const selectedCohorts = JSON.parse(sessionStorage.getItem("selectedCohorts")) || []; selectedCohorts.forEach(function (cohort) { @@ -522,45 +500,31 @@ function loadSelectedCohorts() { }); } - -$(document).ready(function () { - loadSelectedCohorts(); - - - $("#createNewEventButton").on("click", function () { - clearSelectedCohorts(); // - }); -}); function clearSelectedCohorts() { sessionStorage.removeItem("selectedCohorts"); $("input[name='cohorts[]']").prop("checked", false); } -$(document).ready(function() { - // Retrieve the saved bonners status from the event object - let savedBonnersStatus = getSavedBonnersStatusFromBackend(); // Replace with actual logic to get saved state - // Set the checkbox state based on the saved status - if (savedBonnersStatus) { - $("#checkBonners").prop('checked', true); +$(document).ready(function () { + // Check if we're on the template selector page + if (window.location.pathname.includes('/eventTemplates')) { + // Add click event listeners to all program and template links + $('.list-group-item').on('click', function(e) { + e.preventDefault(); + clearSelectedCohorts(); + window.location.href = $(this).attr('href'); + }); + } else if (window.location.pathname.includes('/event/create')) { + clearSelectedCohorts(); } else { - $("#checkBonners").prop('checked', false); + loadSelectedCohorts(); } -}); -// Function to get the saved bonners status from the backend -function getSavedBonnersStatusFromBackend() { - // Make an AJAX call to get the event data - let bonnersStatus; - $.ajax({ - type: 'GET', - url: '/getEvent', // your API endpoint to get event data - async: false, - success: function(response) { - bonnersStatus = response.bonnersStatus; // Assume this comes back in the event data - }, - error: function(err) { - console.error('Error fetching event data:', err); - } + // Existing event listeners + $(document).on("change", "input[name='cohorts[]']", saveSelectedCohorts); + + // Keep the existing button listener if you have a separate "Create New Event" button elsewhere + $("#createNewEventButton").on("click", function () { + clearSelectedCohorts(); }); - return bonnersStatus; -} +}); \ No newline at end of file From 0842823f8f155d37e27dd1c39e60cf412b7ca8f0 Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Wed, 9 Oct 2024 11:51:12 -0400 Subject: [PATCH 05/16] pr modifications --- app/static/js/createEvents.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 3949d028b..a92de9d74 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -506,9 +506,7 @@ function clearSelectedCohorts() { } $(document).ready(function () { - // Check if we're on the template selector page if (window.location.pathname.includes('/eventTemplates')) { - // Add click event listeners to all program and template links $('.list-group-item').on('click', function(e) { e.preventDefault(); clearSelectedCohorts(); @@ -520,10 +518,8 @@ $(document).ready(function () { loadSelectedCohorts(); } - // Existing event listeners $(document).on("change", "input[name='cohorts[]']", saveSelectedCohorts); - // Keep the existing button listener if you have a separate "Create New Event" button elsewhere $("#createNewEventButton").on("click", function () { clearSelectedCohorts(); }); From d4078be6038250710fb70c2c0c7dea47104810c3 Mon Sep 17 00:00:00 2001 From: mbeweg Date: Fri, 18 Oct 2024 14:14:57 -0400 Subject: [PATCH 06/16] Ready for PR --- app/logic/bonner.py | 2 +- app/templates/sidebar.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/logic/bonner.py b/app/logic/bonner.py index 1fe11c5bd..7d3ad2cdb 100644 --- a/app/logic/bonner.py +++ b/app/logic/bonner.py @@ -90,4 +90,4 @@ def addBonnerCohortToRsvpLog(year, event): .where(BonnerCohort.year == year)) for bonner in bonnerCohort: fullName = bonner.fullName - createRsvpLog(eventId=event, content=f"Added {fullName} to RSVP list.") \ No newline at end of file + createRsvpLog(eventId=event, content=f"Added {fullName} to RSVP list.") \ No newline at end of file diff --git a/app/templates/sidebar.html b/app/templates/sidebar.html index a1f2f7a37..7209c437d 100644 --- a/app/templates/sidebar.html +++ b/app/templates/sidebar.html @@ -33,7 +33,7 @@ {% if g.current_user.isAdmin %}
  • - Create Event + Create Event
  • From d0a825b9a2c35d531d427cff71a7b1e0acfdc28c Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Tue, 29 Oct 2024 17:32:40 -0400 Subject: [PATCH 07/16] invitation cohort attempt --- app/controllers/admin/routes.py | 61 ++++++++++++++++++++ app/models/eventCohort.py | 13 +++++ app/static/js/createEvents.js | 99 ++++++++++++++++++++++++--------- 3 files changed, 146 insertions(+), 27 deletions(-) create mode 100644 app/models/eventCohort.py diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index df8b4f059..653c28641 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -10,6 +10,7 @@ from app.models.program import Program from app.models.event import Event from app.models.eventRsvp import EventRsvp +from app.models.eventCohort import EventCohort from app.models.eventParticipant import EventParticipant from app.models.user import User from app.models.course import Course @@ -41,6 +42,57 @@ from app.logic.spreadsheet import createSpreadsheet +@admin_bp.route('/event//invite-cohorts', methods=['POST']) +def inviteCohorts(eventId): + if not (g.current_user.isCeltsAdmin or g.current_user.isProgramManagerForEvent(Event.get_by_id(eventId))): + abort(403) + + try: + event = Event.get_by_id(eventId) + cohort_years = request.json.get('cohorts', []) + + for year in cohort_years: + try: + EventCohort.create( + event=event, + year=int(year), + invited=True, + invited_at=datetime.now() + ) + addBonnerCohortToRsvpLog(int(year), event.id) + rsvpForBonnerCohort(int(year), event.id) + + except IntegrityError: + continue + + createActivityLog(f"Invited Bonner cohorts {', '.join(map(str, cohort_years))} to event {event.name}") + return jsonify({ + "success": True, + "message": "Cohorts successfully invited", + "invited_cohorts": cohort_years + }) + + except Exception as e: + print(f"Error inviting cohorts: {e}") + return jsonify({ + "success": False, + "message": "Error inviting cohorts" + }), 500 + +@admin_bp.route('/event//cohort-status', methods=['GET']) +def getCohortStatus(eventId): + try: + invited_cohorts = EventCohort.select().where( + EventCohort.event_id == eventId, + EventCohort.invited == True + ) + return jsonify({ + "invited_cohorts": [{"year": inv.year, "invited_at": inv.invited_at} for inv in invited_cohorts] + }) + except Exception as e: + print(f"Error getting cohort status: {e}") + return jsonify({"error": "Error fetching cohort status"}), 500 + @admin_bp.route('/admin/reports') def reports(): academicYears = Term.select(Term.academicYear).distinct().order_by(Term.academicYear.desc()) @@ -314,6 +366,14 @@ def eventDisplay(eventId): if eventData['program'] and eventData['program'].isBonnerScholars: requirements = getCertRequirements(Certification.BONNER) bonnerCohorts = getBonnerCohorts(limit=5) + + invited_cohorts = list(EventCohort.select().where( + EventCohort.event_id == eventId, + EventCohort.invited == True + )) + invited_years = [inv.year for inv in invited_cohorts] + else: + requirements, bonnerCohorts, invited_years = [], [], [] rule = request.url_rule @@ -325,6 +385,7 @@ def eventDisplay(eventId): event = event, requirements = requirements, bonnerCohorts = bonnerCohorts, + invited_years = invited_years, userHasRSVPed = userHasRSVPed, isProgramManager = isProgramManager, filepaths = filepaths) diff --git a/app/models/eventCohort.py b/app/models/eventCohort.py new file mode 100644 index 000000000..0e2f78382 --- /dev/null +++ b/app/models/eventCohort.py @@ -0,0 +1,13 @@ +from datetime import datetime +from app.models import* +from app.models.event import Event +from app.models.bonnerCohort import BonnerCohort + +class EventCohort(baseModel): + event = ForeignKeyField(Event) + year = IntegerField() + invited = BooleanField(default=False) + invited_at = DateTimeField(default=datetime.now) + + class Meta: + indexes = ( (('event', 'year'), True), ) \ No newline at end of file diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index a92de9d74..9e6139aa2 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -485,42 +485,87 @@ $(".startDatePicker, .endDatePicker").change(function () { setCharacterLimit($("#inputCharacters"), "#remainingCharacters"); }); -function saveSelectedCohorts() { - const selectedCohorts = []; - $("input[name='cohorts[]']:checked").each(function () { - selectedCohorts.push($(this).val()); +function inviteCohorts(eventId, selectedCohorts) { + return $.ajax({ + type: "POST", + url: `/event/${eventId}/invite-cohorts`, + contentType: "application/json", + data: JSON.stringify({ + cohorts: selectedCohorts + }), + success: function(response) { + if (response.success) { + msgFlash("Cohorts successfully invited!", "success"); + updateCohortStatus(eventId); + } else { + msgFlash("Error inviting cohorts", "danger"); + } + } }); - sessionStorage.setItem("selectedCohorts", JSON.stringify(selectedCohorts)); } -function loadSelectedCohorts() { - const selectedCohorts = JSON.parse(sessionStorage.getItem("selectedCohorts")) || []; - selectedCohorts.forEach(function (cohort) { - $("input[name='cohorts[]'][value='" + cohort + "']").prop("checked", true); +function getCohortStatus(eventId) { + return $.ajax({ + type: "GET", + url: `/event/${eventId}/cohort-status`, + success: function(response) { + displayCohortStatus(response.invited_cohorts); + } }); } -function clearSelectedCohorts() { - sessionStorage.removeItem("selectedCohorts"); - $("input[name='cohorts[]']").prop("checked", false); +function displayCohortStatus(invitedCohorts) { + $(".cohort-status").remove(); + + invitedCohorts.forEach(cohort => { + const invitedDate = new Date(cohort.invited_at).toLocaleDateString(); + const cohortElement = $(`#cohort-${cohort.year}`); + + if (cohortElement.length) { + const statusHtml = ` +
    + + + Invited on ${invitedDate} + +
    + `; + cohortElement.closest('.form-check').append(statusHtml); + cohortElement.prop('disabled', true); + cohortElement.closest('.form-check-label').addClass('text-muted'); + } + }); } -$(document).ready(function () { - if (window.location.pathname.includes('/eventTemplates')) { - $('.list-group-item').on('click', function(e) { - e.preventDefault(); - clearSelectedCohorts(); - window.location.href = $(this).attr('href'); - }); - } else if (window.location.pathname.includes('/event/create')) { - clearSelectedCohorts(); - } else { - loadSelectedCohorts(); - } +function updateCohortStatus(eventId) { + getCohortStatus(eventId); +} - $(document).on("change", "input[name='cohorts[]']", saveSelectedCohorts); +$(document).ready(function() { + const eventId = $("#eventId").val(); + + if (eventId) { + updateCohortStatus(eventId); + } - $("#createNewEventButton").on("click", function () { - clearSelectedCohorts(); + $("#inviteCohortForm").on("submit", function(e) { + e.preventDefault(); + + const selectedCohorts = []; + $("input[name='cohorts[]']:checked").each(function() { + selectedCohorts.push($(this).val()); + }); + + if (selectedCohorts.length === 0) { + msgFlash("Please select at least one cohort to invite", "warning"); + return; + } + + inviteCohorts(eventId, selectedCohorts).then(() => { + $("input[name='cohorts[]']:checked").each(function() { + $(this).prop('checked', false); + }); + saveSelectedCohorts(); + }); }); }); \ No newline at end of file From 6ef35d2cb7d9c1ad3422e519502379ac1b0e9915 Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Thu, 31 Oct 2024 08:19:22 -0400 Subject: [PATCH 08/16] pr test --- app/models/eventCohort.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/eventCohort.py b/app/models/eventCohort.py index 0e2f78382..aba77a735 100644 --- a/app/models/eventCohort.py +++ b/app/models/eventCohort.py @@ -10,4 +10,6 @@ class EventCohort(baseModel): invited_at = DateTimeField(default=datetime.now) class Meta: - indexes = ( (('event', 'year'), True), ) \ No newline at end of file + indexes = ( (('event', 'year'), True), ) + +#wouldn't it be more logic to add columns in the bonnerCohort table instead? \ No newline at end of file From f42411ec9805c7c23536f18fb03dccb9fdb7d18f Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Mon, 4 Nov 2024 12:02:12 -0500 Subject: [PATCH 09/16] pr test --- app/models/eventCohort.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/eventCohort.py b/app/models/eventCohort.py index aba77a735..c2f1bac08 100644 --- a/app/models/eventCohort.py +++ b/app/models/eventCohort.py @@ -6,7 +6,6 @@ class EventCohort(baseModel): event = ForeignKeyField(Event) year = IntegerField() - invited = BooleanField(default=False) invited_at = DateTimeField(default=datetime.now) class Meta: From 1cd75cd6e4bb2a4e6f660fe0108e2861c917f750 Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Fri, 8 Nov 2024 14:47:48 -0500 Subject: [PATCH 10/16] pr test 1 --- app/controllers/admin/routes.py | 21 ++--------- app/static/js/createEvents.js | 63 +++++++++++++-------------------- database/migrate_db.sh | 1 + 3 files changed, 28 insertions(+), 57 deletions(-) diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index 653c28641..81fbc2f7e 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -42,13 +42,13 @@ from app.logic.spreadsheet import createSpreadsheet -@admin_bp.route('/event//invite-cohorts', methods=['POST']) +@admin_bp.route('/event//inviteCohorts', methods=['POST']) def inviteCohorts(eventId): if not (g.current_user.isCeltsAdmin or g.current_user.isProgramManagerForEvent(Event.get_by_id(eventId))): abort(403) try: - event = Event.get_by_id(eventId) + event = Event.get_or_create(id=eventId)[0] cohort_years = request.json.get('cohorts', []) for year in cohort_years: @@ -56,7 +56,6 @@ def inviteCohorts(eventId): EventCohort.create( event=event, year=int(year), - invited=True, invited_at=datetime.now() ) addBonnerCohortToRsvpLog(int(year), event.id) @@ -65,6 +64,7 @@ def inviteCohorts(eventId): except IntegrityError: continue + event.save() createActivityLog(f"Invited Bonner cohorts {', '.join(map(str, cohort_years))} to event {event.name}") return jsonify({ "success": True, @@ -79,20 +79,6 @@ def inviteCohorts(eventId): "message": "Error inviting cohorts" }), 500 -@admin_bp.route('/event//cohort-status', methods=['GET']) -def getCohortStatus(eventId): - try: - invited_cohorts = EventCohort.select().where( - EventCohort.event_id == eventId, - EventCohort.invited == True - ) - return jsonify({ - "invited_cohorts": [{"year": inv.year, "invited_at": inv.invited_at} for inv in invited_cohorts] - }) - except Exception as e: - print(f"Error getting cohort status: {e}") - return jsonify({"error": "Error fetching cohort status"}), 500 - @admin_bp.route('/admin/reports') def reports(): academicYears = Term.select(Term.academicYear).distinct().order_by(Term.academicYear.desc()) @@ -369,7 +355,6 @@ def eventDisplay(eventId): invited_cohorts = list(EventCohort.select().where( EventCohort.event_id == eventId, - EventCohort.invited == True )) invited_years = [inv.year for inv in invited_cohorts] else: diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 9e6139aa2..785f181c4 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -268,6 +268,11 @@ $(document).ready(function() { $("#checkBonners").prop('checked', true); } } +const eventId = $("#eventId").val(); + if (eventId) { + getCohortStatus(eventId); + } + // Initialize datepicker with proper options $.datepicker.setDefaults({ dateFormat: 'yy/mm/dd', // Ensures compatibility across browsers @@ -485,10 +490,23 @@ $(".startDatePicker, .endDatePicker").change(function () { setCharacterLimit($("#inputCharacters"), "#remainingCharacters"); }); +const selectedCohorts = []; +$("input[name='cohorts[]']:checked").each(function() { + selectedCohorts.push($(this).val()); +}); + +inviteCohorts(eventId, selectedCohorts) + .then(() => { + $("input[name='cohorts[]']:checked").prop('checked', false); + }) + .catch(error => { + msgFlash("Error inviting cohorts: " + error.message, "danger"); + }); + function inviteCohorts(eventId, selectedCohorts) { return $.ajax({ type: "POST", - url: `/event/${eventId}/invite-cohorts`, + url: `/event/${eventId}/inviteCohorts`, contentType: "application/json", data: JSON.stringify({ cohorts: selectedCohorts @@ -496,7 +514,7 @@ function inviteCohorts(eventId, selectedCohorts) { success: function(response) { if (response.success) { msgFlash("Cohorts successfully invited!", "success"); - updateCohortStatus(eventId); + getCohortStatus(eventId); } else { msgFlash("Error inviting cohorts", "danger"); } @@ -507,7 +525,7 @@ function inviteCohorts(eventId, selectedCohorts) { function getCohortStatus(eventId) { return $.ajax({ type: "GET", - url: `/event/${eventId}/cohort-status`, + url: `/event/${eventId}/cohortStatus`, success: function(response) { displayCohortStatus(response.invited_cohorts); } @@ -515,7 +533,7 @@ function getCohortStatus(eventId) { } function displayCohortStatus(invitedCohorts) { - $(".cohort-status").remove(); + $(".cohortStatus").add(); invitedCohorts.forEach(cohort => { const invitedDate = new Date(cohort.invited_at).toLocaleDateString(); @@ -523,7 +541,7 @@ function displayCohortStatus(invitedCohorts) { if (cohortElement.length) { const statusHtml = ` -
    +
    Invited on ${invitedDate} @@ -535,37 +553,4 @@ function displayCohortStatus(invitedCohorts) { cohortElement.closest('.form-check-label').addClass('text-muted'); } }); -} - -function updateCohortStatus(eventId) { - getCohortStatus(eventId); -} - -$(document).ready(function() { - const eventId = $("#eventId").val(); - - if (eventId) { - updateCohortStatus(eventId); - } - - $("#inviteCohortForm").on("submit", function(e) { - e.preventDefault(); - - const selectedCohorts = []; - $("input[name='cohorts[]']:checked").each(function() { - selectedCohorts.push($(this).val()); - }); - - if (selectedCohorts.length === 0) { - msgFlash("Please select at least one cohort to invite", "warning"); - return; - } - - inviteCohorts(eventId, selectedCohorts).then(() => { - $("input[name='cohorts[]']:checked").each(function() { - $(this).prop('checked', false); - }); - saveSelectedCohorts(); - }); - }); -}); \ No newline at end of file +} \ No newline at end of file diff --git a/database/migrate_db.sh b/database/migrate_db.sh index 67d1473df..f47626f7b 100755 --- a/database/migrate_db.sh +++ b/database/migrate_db.sh @@ -69,6 +69,7 @@ pem add app.models.eventRsvpLog.EventRsvpLog pem add app.models.celtsLabor.CeltsLabor pem add app.models.communityEngagementRequest.CommunityEngagementRequest pem add app.models.individualRequirement.IndividualRequirement +pem add app.models.eventCohort.EventCohort pem watch From a88b114ffc404fa25f05294c424e63ff9cdc8bfc Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Tue, 12 Nov 2024 16:38:37 -0500 Subject: [PATCH 11/16] test pr 2 --- app/controllers/admin/routes.py | 64 +++++++++++++++++---------- app/models/eventCohort.py | 1 - app/static/js/createEvents.js | 78 ++++++++++++++++----------------- 3 files changed, 80 insertions(+), 63 deletions(-) diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index 81fbc2f7e..409a44f6d 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -42,41 +42,59 @@ from app.logic.spreadsheet import createSpreadsheet -@admin_bp.route('/event//inviteCohorts', methods=['POST']) -def inviteCohorts(eventId): - if not (g.current_user.isCeltsAdmin or g.current_user.isProgramManagerForEvent(Event.get_by_id(eventId))): - abort(403) - +def invite_cohorts_to_event(event, cohort_years): + invited_cohorts = [] try: - event = Event.get_or_create(id=eventId)[0] - cohort_years = request.json.get('cohorts', []) - for year in cohort_years: + year = int(year) try: EventCohort.create( event=event, - year=int(year), + year=year, invited_at=datetime.now() ) - addBonnerCohortToRsvpLog(int(year), event.id) - rsvpForBonnerCohort(int(year), event.id) + + # Handle RSVP and logging + addBonnerCohortToRsvpLog(year, event.id) + rsvpForBonnerCohort(year, event.id) + + invited_cohorts.append(year) except IntegrityError: continue - event.save() - createActivityLog(f"Invited Bonner cohorts {', '.join(map(str, cohort_years))} to event {event.name}") - return jsonify({ - "success": True, - "message": "Cohorts successfully invited", - "invited_cohorts": cohort_years - }) + if invited_cohorts: + cohort_list = ', '.join(map(str, invited_cohorts)) + createActivityLog(f"Invited Bonner cohorts {cohort_list} to event {event.name}") + + return True, "Cohorts successfully invited", invited_cohorts except Exception as e: print(f"Error inviting cohorts: {e}") + return False, "Error inviting cohorts", [] + +@admin_bp.route('/event//inviteCohorts', methods=['POST']) +def inviteCohorts(eventId): + if not (g.current_user.isCeltsAdmin or g.current_user.isProgramManagerForEvent(Event.get_by_id(eventId))): + abort(403) + + try: + event = Event.get_or_create(id=eventId)[0] + cohort_years = request.json.get('cohorts', []) + + success, message, invited_cohorts = invite_cohorts_to_event(event, cohort_years) + + return jsonify({ + "success": success, + "message": message, + "invited_cohorts": invited_cohorts + }), 200 if success else 500 + + except Exception as e: + print(f"Error in inviteCohorts route: {e}") return jsonify({ "success": False, - "message": "Error inviting cohorts" + "message": "Error processing request" }), 500 @admin_bp.route('/admin/reports') @@ -169,10 +187,10 @@ def createEvent(templateid, programid): if savedEvents: rsvpcohorts = request.form.getlist("cohorts[]") - for year in rsvpcohorts: - rsvpForBonnerCohort(int(year), savedEvents[0].id) - addBonnerCohortToRsvpLog(int(year), savedEvents[0].id) - + if rsvpcohorts: + success, message, invited_cohorts = invite_cohorts_to_event(savedEvents[0], rsvpcohorts) + if not success: + flash(message, 'warning') noun = ((eventData.get('isRecurring') or eventData.get('isMultipleOffering')) and "Events" or "Event") # pluralize flash(f"{noun} successfully created!", 'success') diff --git a/app/models/eventCohort.py b/app/models/eventCohort.py index c2f1bac08..e60a02db7 100644 --- a/app/models/eventCohort.py +++ b/app/models/eventCohort.py @@ -11,4 +11,3 @@ class EventCohort(baseModel): class Meta: indexes = ( (('event', 'year'), True), ) -#wouldn't it be more logic to add columns in the bonnerCohort table instead? \ No newline at end of file diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 785f181c4..a2d97c94b 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -263,14 +263,10 @@ function formatDate(originalDate) { */ $(document).ready(function() { //makes sure bonners toggle will stay on between event pages - if (window.location.pathname == '/event/' + $('#newEventID').val() + '/edit') { - if ($("#checkBonners")) { - $("#checkBonners").prop('checked', true); - } -} -const eventId = $("#eventId").val(); - if (eventId) { - getCohortStatus(eventId); + if (window.location.pathname == '/event/' + $('#newEventID').val() + '/edit') { + if ($("#checkBonners")) { + $("#checkBonners").prop('checked', true); + } } // Initialize datepicker with proper options @@ -488,39 +484,42 @@ $(".startDatePicker, .endDatePicker").change(function () { }); setCharacterLimit($("#inputCharacters"), "#remainingCharacters"); -}); -const selectedCohorts = []; -$("input[name='cohorts[]']:checked").each(function() { - selectedCohorts.push($(this).val()); + const eventId = $("#eventId").val(); + if (eventId) { + const selectedCohorts = getSelectedCohorts(eventId); + + $('input[name="cohorts[]"]').each(function() { + const cohortYear = $(this).val(); + if (selectedCohorts.includes(cohortYear)) { + $(this).prop('checked', true); + } + }); + + $('input[name="cohorts[]"]').on('change', function() { + const selectedCohorts = $('input[name="cohorts[]"]:checked') + .map(function() { return $(this).val(); }) + .get(); + saveSelectedCohorts(eventId, selectedCohorts); + }); + + getCohortStatus(eventId); + } }); -inviteCohorts(eventId, selectedCohorts) - .then(() => { - $("input[name='cohorts[]']:checked").prop('checked', false); - }) - .catch(error => { - msgFlash("Error inviting cohorts: " + error.message, "danger"); - }); - -function inviteCohorts(eventId, selectedCohorts) { - return $.ajax({ - type: "POST", - url: `/event/${eventId}/inviteCohorts`, - contentType: "application/json", - data: JSON.stringify({ - cohorts: selectedCohorts - }), - success: function(response) { - if (response.success) { - msgFlash("Cohorts successfully invited!", "success"); - getCohortStatus(eventId); - } else { - msgFlash("Error inviting cohorts", "danger"); - } - } - }); -} +// //const STORAGE_KEY = 'selectedCohorts'; + +// //function saveSelectedCohorts(eventId, cohorts) { +// // const storage = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); +// // storage[eventId] = cohorts; +// localStorage.setItem(STORAGE_KEY, JSON.stringify(storage)); +// } + +// function getSelectedCohorts(eventId) { +// const storage = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); +// return storage[eventId] || []; +// } + function getCohortStatus(eventId) { return $.ajax({ @@ -533,7 +532,7 @@ function getCohortStatus(eventId) { } function displayCohortStatus(invitedCohorts) { - $(".cohortStatus").add(); + $(".cohortStatus").remove(); invitedCohorts.forEach(cohort => { const invitedDate = new Date(cohort.invited_at).toLocaleDateString(); @@ -549,6 +548,7 @@ function displayCohortStatus(invitedCohorts) {
    `; cohortElement.closest('.form-check').append(statusHtml); + cohortElement.prop('checked', true); cohortElement.prop('disabled', true); cohortElement.closest('.form-check-label').addClass('text-muted'); } From cc12edb060ebaba2c51b4c1e63ac76901cd03eac Mon Sep 17 00:00:00 2001 From: bineta doucoure Date: Fri, 22 Nov 2024 15:53:58 -0500 Subject: [PATCH 12/16] PR test 3: I haven't moved the function inviteCohortsToEvent to the events.py file, will fix --- app/controllers/admin/routes.py | 98 ++++++++++++++------------- app/logic/events.py | 1 + app/static/js/createEvents.js | 15 +--- app/templates/events/createEvent.html | 10 ++- 4 files changed, 61 insertions(+), 63 deletions(-) diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index 28a2abf65..b71622543 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -21,6 +21,7 @@ from app.models.eventRsvpLog import EventRsvpLog from app.models.attachmentUpload import AttachmentUpload from app.models.bonnerCohort import BonnerCohort +from app.models.eventCohort import EventCohort from app.models.certification import Certification from app.models.user import User from app.models.term import Term @@ -41,61 +42,61 @@ from app.controllers.admin import admin_bp from app.logic.spreadsheet import createSpreadsheet +@admin_bp.route('/event//cohortStatus', methods=['GET']) +def getCohortStatus(eventId): + + try: + event = Event.get_by_id(eventId) + invited_cohorts = EventCohort.select().where( + EventCohort.event == event + ).order_by(EventCohort.year.desc()) + + cohort_data = [{ + 'year': cohort.year, + 'invited_at': cohort.invited_at.strftime('%Y-%m-%d %H:%M:%S') + } for cohort in invited_cohorts] + + return jsonify({ + 'status': 'success', + 'invited_cohorts': cohort_data + }) + + except Event.DoesNotExist: + return jsonify({ + 'status': 'error', + 'message': 'Event not found' + }), 404 + except Exception as e: + print(f"Error getting cohort status: {e}") + return jsonify({ + 'status': 'error', + 'message': 'Internal server error' + }), 500 -def invite_cohorts_to_event(event, cohort_years): +def inviteCohortsToEvent(event, cohort_years): invited_cohorts = [] try: for year in cohort_years: year = int(year) - try: - EventCohort.create( - event=event, - year=year, - invited_at=datetime.now() - ) - - # Handle RSVP and logging - addBonnerCohortToRsvpLog(year, event.id) - rsvpForBonnerCohort(year, event.id) - - invited_cohorts.append(year) - - except IntegrityError: - continue - + EventCohort.get_or_create( + event=event, + year=year, + defaults={'invited_at': datetime.now()} + ) + + addBonnerCohortToRsvpLog(year, event.id) + rsvpForBonnerCohort(year, event.id) + invited_cohorts.append(year) + if invited_cohorts: cohort_list = ', '.join(map(str, invited_cohorts)) - createActivityLog(f"Invited Bonner cohorts {cohort_list} to event {event.name}") + createActivityLog(f"Updated Bonner cohorts {cohort_list} for event {event.name}") - return True, "Cohorts successfully invited", invited_cohorts + return True, "Cohorts successfully updated", invited_cohorts except Exception as e: print(f"Error inviting cohorts: {e}") - return False, "Error inviting cohorts", [] - -@admin_bp.route('/event//inviteCohorts', methods=['POST']) -def inviteCohorts(eventId): - if not (g.current_user.isCeltsAdmin or g.current_user.isProgramManagerForEvent(Event.get_by_id(eventId))): - abort(403) - - try: - event = Event.get_or_create(id=eventId)[0] - cohort_years = request.json.get('cohorts', []) - - success, message, invited_cohorts = invite_cohorts_to_event(event, cohort_years) - - return jsonify({ - "success": success, - "message": message, - "invited_cohorts": invited_cohorts - }), 200 if success else 500 - - except Exception as e: - print(f"Error in inviteCohorts route: {e}") - return jsonify({ - "success": False, - "message": "Error processing request" - }), 500 + return False, f"Error updating cohorts: {e}", [] @admin_bp.route('/admin/reports') def reports(): @@ -189,7 +190,7 @@ def createEvent(templateid, programid): if savedEvents: rsvpcohorts = request.form.getlist("cohorts[]") if rsvpcohorts: - success, message, invited_cohorts = invite_cohorts_to_event(savedEvents[0], rsvpcohorts) + success, message, invited_cohorts = inviteCohortsToEvent(savedEvents[0], rsvpcohorts) if not success: flash(message, 'warning') @@ -315,6 +316,10 @@ def eventDisplay(eventId): # Validate given URL try: event = Event.get_by_id(eventId) + invited_cohorts = list(EventCohort.select().where( + EventCohort.event == event + )) + invited_years = [str(cohort.year) for cohort in invited_cohorts] except DoesNotExist as e: print(f"Unknown event: {eventId}") abort(404) @@ -375,7 +380,7 @@ def eventDisplay(eventId): invited_cohorts = list(EventCohort.select().where( EventCohort.event_id == eventId, )) - invited_years = [inv.year for inv in invited_cohorts] + invited_years = [str(cohort.year) for cohort in invited_cohorts] else: requirements, bonnerCohorts, invited_years = [], [], [] @@ -425,6 +430,7 @@ def eventDisplay(eventId): filepaths=filepaths, image=image, pageViewsCount=pageViewsCount, + invited_years=invited_years, eventCountdown=eventCountdown ) diff --git a/app/logic/events.py b/app/logic/events.py index 26feef5dc..32710b47a 100644 --- a/app/logic/events.py +++ b/app/logic/events.py @@ -707,3 +707,4 @@ def copyRsvpToNewEvent(priorEvent, newEvent): numRsvps = len(rsvpInfo) if numRsvps: createRsvpLog(newEvent, f"Copied {numRsvps} Rsvps from {priorEvent['name']} to {newEvent.name}") + diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 4a9477f56..8b91073e0 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -506,7 +506,7 @@ $(".startDatePicker, .endDatePicker").change(function () { const eventId = $("#eventId").val(); if (eventId) { - const selectedCohorts = getSelectedCohorts(eventId); + const selectedCohorts = selectedCohorts(eventId); $('input[name="cohorts[]"]').each(function() { const cohortYear = $(this).val(); @@ -526,19 +526,6 @@ $(".startDatePicker, .endDatePicker").change(function () { } }); -// //const STORAGE_KEY = 'selectedCohorts'; - -// //function saveSelectedCohorts(eventId, cohorts) { -// // const storage = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); -// // storage[eventId] = cohorts; -// localStorage.setItem(STORAGE_KEY, JSON.stringify(storage)); -// } - -// function getSelectedCohorts(eventId) { -// const storage = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); -// return storage[eventId] || []; -// } - function getCohortStatus(eventId) { return $.ajax({ diff --git a/app/templates/events/createEvent.html b/app/templates/events/createEvent.html index 1acb1be90..dea956b25 100644 --- a/app/templates/events/createEvent.html +++ b/app/templates/events/createEvent.html @@ -237,9 +237,13 @@

    {{page_title}}

    {% for year,students in bonnerCohorts.items()|reverse %}
    - -
    {% endfor %} From e179c8fcf436a28630399441f627d32217593815 Mon Sep 17 00:00:00 2001 From: Stevenson Date: Thu, 26 Dec 2024 14:30:34 -0500 Subject: [PATCH 13/16] Change variables from snake_case to camelCasee --- app/controllers/admin/routes.py | 34 ++++++++++++++++----------------- app/static/js/createEvents.js | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index b71622543..bdd645692 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -47,18 +47,18 @@ def getCohortStatus(eventId): try: event = Event.get_by_id(eventId) - invited_cohorts = EventCohort.select().where( + invitedCohorts = EventCohort.select().where( EventCohort.event == event ).order_by(EventCohort.year.desc()) - cohort_data = [{ + cohortData = [{ 'year': cohort.year, 'invited_at': cohort.invited_at.strftime('%Y-%m-%d %H:%M:%S') - } for cohort in invited_cohorts] + } for cohort in invitedCohorts] return jsonify({ 'status': 'success', - 'invited_cohorts': cohort_data + 'invitedCohorts': cohortData }) except Event.DoesNotExist: @@ -74,7 +74,7 @@ def getCohortStatus(eventId): }), 500 def inviteCohortsToEvent(event, cohort_years): - invited_cohorts = [] + invitedCohorts = [] try: for year in cohort_years: year = int(year) @@ -86,13 +86,13 @@ def inviteCohortsToEvent(event, cohort_years): addBonnerCohortToRsvpLog(year, event.id) rsvpForBonnerCohort(year, event.id) - invited_cohorts.append(year) + invitedCohorts.append(year) - if invited_cohorts: - cohort_list = ', '.join(map(str, invited_cohorts)) + if invitedCohorts: + cohort_list = ', '.join(map(str, invitedCohorts)) createActivityLog(f"Updated Bonner cohorts {cohort_list} for event {event.name}") - return True, "Cohorts successfully updated", invited_cohorts + return True, "Cohorts successfully updated", invitedCohorts except Exception as e: print(f"Error inviting cohorts: {e}") @@ -190,7 +190,7 @@ def createEvent(templateid, programid): if savedEvents: rsvpcohorts = request.form.getlist("cohorts[]") if rsvpcohorts: - success, message, invited_cohorts = inviteCohortsToEvent(savedEvents[0], rsvpcohorts) + success, message, invitedCohorts = inviteCohortsToEvent(savedEvents[0], rsvpcohorts) if not success: flash(message, 'warning') @@ -316,10 +316,10 @@ def eventDisplay(eventId): # Validate given URL try: event = Event.get_by_id(eventId) - invited_cohorts = list(EventCohort.select().where( + invitedCohorts = list(EventCohort.select().where( EventCohort.event == event )) - invited_years = [str(cohort.year) for cohort in invited_cohorts] + invitedYears = [str(cohort.year) for cohort in invitedCohorts] except DoesNotExist as e: print(f"Unknown event: {eventId}") abort(404) @@ -377,12 +377,12 @@ def eventDisplay(eventId): requirements = getCertRequirements(Certification.BONNER) bonnerCohorts = getBonnerCohorts(limit=5) - invited_cohorts = list(EventCohort.select().where( + invitedCohorts = list(EventCohort.select().where( EventCohort.event_id == eventId, )) - invited_years = [str(cohort.year) for cohort in invited_cohorts] + invitedYears = [str(cohort.year) for cohort in invitedCohorts] else: - requirements, bonnerCohorts, invited_years = [], [], [] + requirements, bonnerCohorts, invitedYears = [], [], [] rule = request.url_rule @@ -394,7 +394,7 @@ def eventDisplay(eventId): event = event, requirements = requirements, bonnerCohorts = bonnerCohorts, - invited_years = invited_years, + invitedYears = invitedYears, userHasRSVPed = userHasRSVPed, isProgramManager = isProgramManager, filepaths = filepaths) @@ -430,7 +430,7 @@ def eventDisplay(eventId): filepaths=filepaths, image=image, pageViewsCount=pageViewsCount, - invited_years=invited_years, + invitedYears=invitedYears, eventCountdown=eventCountdown ) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 8b91073e0..45727de70 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -532,7 +532,7 @@ function getCohortStatus(eventId) { type: "GET", url: `/event/${eventId}/cohortStatus`, success: function(response) { - displayCohortStatus(response.invited_cohorts); + displayCohortStatus(response.invitedCohorts); } }); } From a6a4f7d96cb2641e6ad5b6ada700a6009b1db0dc Mon Sep 17 00:00:00 2001 From: Stevenson Date: Thu, 26 Dec 2024 17:13:04 -0500 Subject: [PATCH 14/16] Fixed checkbox for event cohort --- app/controllers/admin/routes.py | 79 ++++++++++++++++++++++----- app/logic/bonner.py | 17 ++++++ app/templates/events/createEvent.html | 8 ++- 3 files changed, 87 insertions(+), 17 deletions(-) diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index bdd645692..9c73f3767 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -73,10 +73,14 @@ def getCohortStatus(eventId): 'message': 'Internal server error' }), 500 -def inviteCohortsToEvent(event, cohort_years): + +def inviteCohortsToEvent(event, cohortYears): + """ + Invites cohorts to a newly created event by associating the cohorts directly. + """ invitedCohorts = [] try: - for year in cohort_years: + for year in cohortYears: year = int(year) EventCohort.get_or_create( event=event, @@ -89,14 +93,58 @@ def inviteCohortsToEvent(event, cohort_years): invitedCohorts.append(year) if invitedCohorts: - cohort_list = ', '.join(map(str, invitedCohorts)) - createActivityLog(f"Updated Bonner cohorts {cohort_list} for event {event.name}") - - return True, "Cohorts successfully updated", invitedCohorts + cohortList = ', '.join(map(str, invitedCohorts)) + createActivityLog(f"Added Bonner cohorts {cohortList} for newly created event {event.name}") + + return True, "Cohorts successfully added to new event", invitedCohorts + + except Exception as e: + print(f"Error inviting cohorts to new event: {e}") + return False, f"Error adding cohorts to new event: {e}", [] + + +def updateEventCohorts(event, cohortYears): + """ + Updates the cohorts for an existing event by adding new ones and removing outdated ones. + """ + invitedCohorts = [] + try: + precedentInvitedCohorts = list(EventCohort.select().where(EventCohort.event == event)) + precedentInvitedYears = [str(precedentCohort.year) for precedentCohort in precedentInvitedCohorts] + + yearsToAdd = [int(year) for year in cohortYears if year not in precedentInvitedYears] + if not cohortYears: + yearsToRemove = [int(year) for year in precedentInvitedYears] + else: + yearsToRemove = [int(year) for year in precedentInvitedYears if year not in cohortYears] + + if yearsToRemove: + EventCohort.delete().where( + (EventCohort.event == event) & (EventCohort.year.in_(yearsToRemove)) + ).execute() + + for year in yearsToAdd: + EventCohort.get_or_create( + event=event, + year=year, + defaults={'invited_at': datetime.now()} + ) + + addBonnerCohortToRsvpLog(year, event.id) + rsvpForBonnerCohort(year, event.id) + invitedCohorts.append(year) + + if yearsToAdd or yearsToRemove: + cohortList = ', '.join(map(str, invitedCohorts)) + createActivityLog(f"Updated Bonner cohorts for event {event.name}. Added: {yearsToAdd}, Removed: {yearsToRemove}") + + return True, "Cohorts successfully updated for event", invitedCohorts + except Exception as e: - print(f"Error inviting cohorts: {e}") - return False, f"Error updating cohorts: {e}", [] + print(f"Error updating cohorts for event: {e}") + return False, f"Error updating cohorts for event: {e}", [] + @admin_bp.route('/admin/reports') def reports(): @@ -188,9 +236,9 @@ def createEvent(templateid, programid): validationErrorMessage = "Failed to save event." if savedEvents: - rsvpcohorts = request.form.getlist("cohorts[]") - if rsvpcohorts: - success, message, invitedCohorts = inviteCohortsToEvent(savedEvents[0], rsvpcohorts) + rsvpCohorts = request.form.getlist("cohorts[]") + if rsvpCohorts: + success, message, invitedCohorts = inviteCohortsToEvent(savedEvents[0], rsvpCohorts) if not success: flash(message, 'warning') @@ -354,8 +402,9 @@ def eventDisplay(eventId): if savedEvents: - rsvpcohorts = request.form.getlist("cohorts[]") - for year in rsvpcohorts: + rsvpCohorts = request.form.getlist("cohorts[]") + updateEventCohorts(savedEvents[0], rsvpCohorts) + for year in rsvpCohorts: rsvpForBonnerCohort(int(year), event.id) addBonnerCohortToRsvpLog(int(year), event.id) @@ -390,7 +439,7 @@ def eventDisplay(eventId): if 'edit' in rule.rule: return render_template("events/createEvent.html", eventData = eventData, - futureTerms=futureTerms, + futureTerms = futureTerms, event = event, requirements = requirements, bonnerCohorts = bonnerCohorts, @@ -419,6 +468,8 @@ def eventDisplay(eventId): currentEventRsvpAmount = getEventRsvpCount(event.id) userParticipatedTrainingEvents = getParticipationStatusForTrainings(eventData['program'], [g.current_user], g.current_term) + + return render_template("events/eventView.html", eventData=eventData, diff --git a/app/logic/bonner.py b/app/logic/bonner.py index 7d3ad2cdb..1e97f9965 100644 --- a/app/logic/bonner.py +++ b/app/logic/bonner.py @@ -8,6 +8,7 @@ from app.models.bonnerCohort import BonnerCohort from app.models.eventRsvp import EventRsvp from app.models.user import User +from app.models.eventCohort import EventCohort from app.logic.createLogs import createRsvpLog def makeBonnerXls(): @@ -83,6 +84,22 @@ def rsvpForBonnerCohort(year, event): .where(BonnerCohort.year == year), [EventRsvp.user, EventRsvp.event, EventRsvp.rsvpTime]).on_conflict(action='IGNORE').execute() +# def updateEventBonnerCohort(year, event): +# """ +# Updates the Bonner Cohorts for a given event +# """ +# eventCohort = EventCohort.select(EventCohort.where(event == event)) +# EventCohort.update() + + +# def AddEventBonnerCohort(year, event): +# """ +# Adds the Bonner Cohorts for a given event +# """ +# eventCohort = EventCohort.create(event == event, year == year, invited_at =) +# EventCohort.update() + + def addBonnerCohortToRsvpLog(year, event): """ This method adds the table information in the RSVP Log page""" bonnerCohort = list(BonnerCohort.select(fn.CONCAT(User.firstName, ' ', User.lastName).alias("fullName")) diff --git a/app/templates/events/createEvent.html b/app/templates/events/createEvent.html index 98cda7038..c49d2eceb 100644 --- a/app/templates/events/createEvent.html +++ b/app/templates/events/createEvent.html @@ -235,14 +235,16 @@

    {{page_title}}

    - {% for year,students in bonnerCohorts.items()|reverse %} + {% for year, students in bonnerCohorts.items() | reverse %}
    + {% if invitedYears and year|string in invitedYears %} + checked + {% endif %}>
    From c28fd89520a97bec99a1ffe468931411f5a4a459 Mon Sep 17 00:00:00 2001 From: Stevenson Date: Fri, 27 Dec 2024 12:04:59 -0500 Subject: [PATCH 15/16] removed unnecessary codes and moved functions to logic --- app/controllers/admin/routes.py | 125 +++++--------------------------- app/logic/events.py | 75 +++++++++++++++++++ app/static/js/createEvents.js | 56 -------------- tests/code/test_events.py | 9 +++ 4 files changed, 102 insertions(+), 163 deletions(-) diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index 9c73f3767..cb706cc26 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -10,7 +10,6 @@ from app.models.program import Program from app.models.event import Event from app.models.eventRsvp import EventRsvp -from app.models.eventCohort import EventCohort from app.models.eventParticipant import EventParticipant from app.models.user import User from app.models.course import Course @@ -32,7 +31,7 @@ from app.logic.createLogs import createActivityLog from app.logic.certification import getCertRequirements, updateCertRequirements from app.logic.utils import selectSurroundingTerms, getFilesFromRequest, getRedirectTarget, setRedirectTarget -from app.logic.events import attemptSaveMultipleOfferings, cancelEvent, deleteEvent, attemptSaveEvent, preprocessEventData, getRecurringEventsData, deleteEventAndAllFollowing, deleteAllRecurringEvents, getBonnerEvents,addEventView, getEventRsvpCount, copyRsvpToNewEvent, getCountdownToEvent, calculateNewMultipleOfferingId +from app.logic.events import attemptSaveMultipleOfferings, cancelEvent, deleteEvent, attemptSaveEvent, preprocessEventData, getRecurringEventsData, deleteEventAndAllFollowing, deleteAllRecurringEvents, getBonnerEvents,addEventView, getEventRsvpCount, copyRsvpToNewEvent, getCountdownToEvent, calculateNewMultipleOfferingId, inviteCohortsToEvent, updateEventCohorts from app.logic.participants import getParticipationStatusForTrainings, checkUserRsvp from app.logic.minor import getMinorInterest from app.logic.fileHandler import FileHandler @@ -42,109 +41,6 @@ from app.controllers.admin import admin_bp from app.logic.spreadsheet import createSpreadsheet -@admin_bp.route('/event//cohortStatus', methods=['GET']) -def getCohortStatus(eventId): - - try: - event = Event.get_by_id(eventId) - invitedCohorts = EventCohort.select().where( - EventCohort.event == event - ).order_by(EventCohort.year.desc()) - - cohortData = [{ - 'year': cohort.year, - 'invited_at': cohort.invited_at.strftime('%Y-%m-%d %H:%M:%S') - } for cohort in invitedCohorts] - - return jsonify({ - 'status': 'success', - 'invitedCohorts': cohortData - }) - - except Event.DoesNotExist: - return jsonify({ - 'status': 'error', - 'message': 'Event not found' - }), 404 - except Exception as e: - print(f"Error getting cohort status: {e}") - return jsonify({ - 'status': 'error', - 'message': 'Internal server error' - }), 500 - - -def inviteCohortsToEvent(event, cohortYears): - """ - Invites cohorts to a newly created event by associating the cohorts directly. - """ - invitedCohorts = [] - try: - for year in cohortYears: - year = int(year) - EventCohort.get_or_create( - event=event, - year=year, - defaults={'invited_at': datetime.now()} - ) - - addBonnerCohortToRsvpLog(year, event.id) - rsvpForBonnerCohort(year, event.id) - invitedCohorts.append(year) - - if invitedCohorts: - cohortList = ', '.join(map(str, invitedCohorts)) - createActivityLog(f"Added Bonner cohorts {cohortList} for newly created event {event.name}") - - return True, "Cohorts successfully added to new event", invitedCohorts - - except Exception as e: - print(f"Error inviting cohorts to new event: {e}") - return False, f"Error adding cohorts to new event: {e}", [] - - -def updateEventCohorts(event, cohortYears): - """ - Updates the cohorts for an existing event by adding new ones and removing outdated ones. - """ - invitedCohorts = [] - try: - precedentInvitedCohorts = list(EventCohort.select().where(EventCohort.event == event)) - precedentInvitedYears = [str(precedentCohort.year) for precedentCohort in precedentInvitedCohorts] - - yearsToAdd = [int(year) for year in cohortYears if year not in precedentInvitedYears] - - if not cohortYears: - yearsToRemove = [int(year) for year in precedentInvitedYears] - else: - yearsToRemove = [int(year) for year in precedentInvitedYears if year not in cohortYears] - - if yearsToRemove: - EventCohort.delete().where( - (EventCohort.event == event) & (EventCohort.year.in_(yearsToRemove)) - ).execute() - - for year in yearsToAdd: - EventCohort.get_or_create( - event=event, - year=year, - defaults={'invited_at': datetime.now()} - ) - - addBonnerCohortToRsvpLog(year, event.id) - rsvpForBonnerCohort(year, event.id) - invitedCohorts.append(year) - - if yearsToAdd or yearsToRemove: - cohortList = ', '.join(map(str, invitedCohorts)) - createActivityLog(f"Updated Bonner cohorts for event {event.name}. Added: {yearsToAdd}, Removed: {yearsToRemove}") - - return True, "Cohorts successfully updated for event", invitedCohorts - - except Exception as e: - print(f"Error updating cohorts for event: {e}") - return False, f"Error updating cohorts for event: {e}", [] - @admin_bp.route('/admin/reports') def reports(): @@ -282,7 +178,14 @@ def createEvent(templateid, programid): requirements, bonnerCohorts = [], [] if eventData['program'] is not None and eventData['program'].isBonnerScholars: requirements = getCertRequirements(Certification.BONNER) - bonnerCohorts = getBonnerCohorts(limit=5) + rawBonnerCohorts = getBonnerCohorts(limit=5) + bonnerCohorts = {} + + for year, cohort in rawBonnerCohorts.items(): + if cohort: + bonnerCohorts[year] = cohort + + return render_template(f"/events/{template.templateFile}", template = template, eventData = eventData, @@ -424,7 +327,15 @@ def eventDisplay(eventId): if eventData['program'] and eventData['program'].isBonnerScholars: requirements = getCertRequirements(Certification.BONNER) - bonnerCohorts = getBonnerCohorts(limit=5) + rawBonnerCohorts = getBonnerCohorts(limit=5) + bonnerCohorts = {} + + for year, cohort in rawBonnerCohorts.items(): + if cohort: + bonnerCohorts[year] = cohort + + print(1000*"*") + print("The bonner cohorts are ", bonnerCohorts) invitedCohorts = list(EventCohort.select().where( EventCohort.event_id == eventId, diff --git a/app/logic/events.py b/app/logic/events.py index 8cf900b91..eeafd426e 100644 --- a/app/logic/events.py +++ b/app/logic/events.py @@ -17,7 +17,9 @@ from app.models.requirementMatch import RequirementMatch from app.models.certificationRequirement import CertificationRequirement from app.models.eventViews import EventView +from app.models.eventCohort import EventCohort +from app.logic.bonner import rsvpForBonnerCohort, addBonnerCohortToRsvpLog from app.logic.createLogs import createActivityLog, createRsvpLog from app.logic.utils import format24HourTime from app.logic.fileHandler import FileHandler @@ -706,4 +708,77 @@ def copyRsvpToNewEvent(priorEvent, newEvent): numRsvps = len(rsvpInfo) if numRsvps: createRsvpLog(newEvent, f"Copied {numRsvps} Rsvps from {priorEvent['name']} to {newEvent.name}") + + +def inviteCohortsToEvent(event, cohortYears): + """ + Invites cohorts to a newly created event by associating the cohorts directly. + """ + invitedCohorts = [] + try: + for year in cohortYears: + year = int(year) + EventCohort.get_or_create( + event=event, + year=year, + defaults={'invited_at': datetime.now()} + ) + + addBonnerCohortToRsvpLog(year, event.id) + rsvpForBonnerCohort(year, event.id) + invitedCohorts.append(year) + + if invitedCohorts: + cohortList = ', '.join(map(str, invitedCohorts)) + createActivityLog(f"Added Bonner cohorts {cohortList} for newly created event {event.name}") + + return True, "Cohorts successfully added to new event", invitedCohorts + + except Exception as e: + print(f"Error inviting cohorts to new event: {e}") + return False, f"Error adding cohorts to new event: {e}", [] + + +def updateEventCohorts(event, cohortYears): + """ + Updates the cohorts for an existing event by adding new ones and removing outdated ones. + """ + invitedCohorts = [] + try: + precedentInvitedCohorts = list(EventCohort.select().where(EventCohort.event == event)) + precedentInvitedYears = [str(precedentCohort.year) for precedentCohort in precedentInvitedCohorts] + + yearsToAdd = [int(year) for year in cohortYears if year not in precedentInvitedYears] + + if not cohortYears: + yearsToRemove = [int(year) for year in precedentInvitedYears] + else: + yearsToRemove = [int(year) for year in precedentInvitedYears if year not in cohortYears] + + if yearsToRemove: + EventCohort.delete().where( + (EventCohort.event == event) & (EventCohort.year.in_(yearsToRemove)) + ).execute() + + for year in yearsToAdd: + EventCohort.get_or_create( + event=event, + year=year, + defaults={'invited_at': datetime.now()} + ) + + addBonnerCohortToRsvpLog(year, event.id) + rsvpForBonnerCohort(year, event.id) + invitedCohorts.append(year) + + if yearsToAdd or yearsToRemove: + cohortList = ', '.join(map(str, invitedCohorts)) + createActivityLog(f"Updated Bonner cohorts for event {event.name}. Added: {yearsToAdd}, Removed: {yearsToRemove}") + + return True, "Cohorts successfully updated for event", invitedCohorts + + except Exception as e: + print(f"Error updating cohorts for event: {e}") + return False, f"Error updating cohorts for event: {e}", [] + diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index d3c819617..7f4557f15 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -551,60 +551,4 @@ $(".startDatePicker, .endDatePicker").change(function () { }); setCharacterLimit($("#inputCharacters"), "#remainingCharacters"); - - const eventId = $("#eventId").val(); - if (eventId) { - const selectedCohorts = selectedCohorts(eventId); - - $('input[name="cohorts[]"]').each(function() { - const cohortYear = $(this).val(); - if (selectedCohorts.includes(cohortYear)) { - $(this).prop('checked', true); - } - }); - - $('input[name="cohorts[]"]').on('change', function() { - const selectedCohorts = $('input[name="cohorts[]"]:checked') - .map(function() { return $(this).val(); }) - .get(); - saveSelectedCohorts(eventId, selectedCohorts); - }); - - getCohortStatus(eventId); - } }); - - -function getCohortStatus(eventId) { - return $.ajax({ - type: "GET", - url: `/event/${eventId}/cohortStatus`, - success: function(response) { - displayCohortStatus(response.invitedCohorts); - } - }); -} - -function displayCohortStatus(invitedCohorts) { - $(".cohortStatus").remove(); - - invitedCohorts.forEach(cohort => { - const invitedDate = new Date(cohort.invited_at).toLocaleDateString(); - const cohortElement = $(`#cohort-${cohort.year}`); - - if (cohortElement.length) { - const statusHtml = ` -
    - - - Invited on ${invitedDate} - -
    - `; - cohortElement.closest('.form-check').append(statusHtml); - cohortElement.prop('checked', true); - cohortElement.prop('disabled', true); - cohortElement.closest('.form-check-label').addClass('text-muted'); - } - }); -} \ No newline at end of file diff --git a/tests/code/test_events.py b/tests/code/test_events.py index 19535bbe3..ada419ab0 100644 --- a/tests/code/test_events.py +++ b/tests/code/test_events.py @@ -1407,3 +1407,12 @@ def test_copyRsvpToNewEvent(): assert len(EventRsvp.select().where(EventRsvp.event_id == newEvent)) == 2 transaction.rollback() + + +@pytest.mark.integration +def test_inviteCohortsToEvent(): + pass + +@pytest.mark.integration +def test_updateEventCohorts(): + pass From a6e42dc6228b6707976d7cbe2db94f40ae480401 Mon Sep 17 00:00:00 2001 From: Stevenson Date: Mon, 30 Dec 2024 13:08:07 -0500 Subject: [PATCH 16/16] Finished test for inviteCohorts and updateCohorts to events functions --- tests/code/test_events.py | 133 ++++++++++++++++++++++++++++++++------ 1 file changed, 113 insertions(+), 20 deletions(-) diff --git a/tests/code/test_events.py b/tests/code/test_events.py index ada419ab0..a113bf76e 100644 --- a/tests/code/test_events.py +++ b/tests/code/test_events.py @@ -22,8 +22,10 @@ from app.models.interest import Interest from app.models.eventRsvp import EventRsvp from app.models.note import Note +from app.models.bonnerCohort import BonnerCohort +from app.models.eventCohort import EventCohort -from app.logic.events import preprocessEventData, validateNewEventData, getRecurringEventsData +from app.logic.events import preprocessEventData, validateNewEventData, getRecurringEventsData, inviteCohortsToEvent, updateEventCohorts from app.logic.events import attemptSaveEvent, attemptSaveMultipleOfferings, saveEventToDb, cancelEvent, deleteEvent, getParticipatedEventsForUser from app.logic.events import calculateNewrecurringId, getPreviousRecurringEventData, getUpcomingEventsForUser, calculateNewMultipleOfferingId, getPreviousMultipleOfferingEventData from app.logic.events import deleteEventAndAllFollowing, deleteAllRecurringEvents, getEventRsvpCountsForTerm, getEventRsvpCount, getCountdownToEvent, copyRsvpToNewEvent @@ -1372,6 +1374,23 @@ def test_copyRsvpToNewEvent(): priorEvent = Event.create(name = "Req and Limit", + term = 2, + description = "Event that requries RSVP and has an RSVP limit set.", + timeStart = "6:00 pm", + timeEnd = "9:00 pm", + location = "The Moon", + isRsvpRequired = 1, + startDate = "2022-12-19", + endDate = "2022-12-19", + program = 9) + + priorEvent.save() + EventRsvp.create(user = "neillz", + event = priorEvent).save() + EventRsvp.create(user = "partont", + event = priorEvent).save() + + newEvent = Event.create(name = "Req and Limit", term = 2, description = "Event that requries RSVP and has an RSVP limit set.", timeStart = "6:00 pm", @@ -1381,23 +1400,6 @@ def test_copyRsvpToNewEvent(): startDate = "2022-12-19", endDate = "2022-12-19", program = 9) - - priorEvent.save() - EventRsvp.create(user = "neillz", - event = priorEvent).save() - EventRsvp.create(user = "partont", - event = priorEvent).save() - - newEvent = Event.create(name = "Req and Limit", - term = 2, - description = "Event that requries RSVP and has an RSVP limit set.", - timeStart = "6:00 pm", - timeEnd = "9:00 pm", - location = "The Moon", - isRsvpRequired = 1, - startDate = "2022-12-19", - endDate = "2022-12-19", - program = 9) newEvent.save() assert len(EventRsvp.select().where(EventRsvp.event_id == priorEvent)) == 2 @@ -1411,8 +1413,99 @@ def test_copyRsvpToNewEvent(): @pytest.mark.integration def test_inviteCohortsToEvent(): - pass + """ + This function creates a Bonner Scholar program, attaches an event to this program, + and creates invited cohorts for this event. + """ + with mainDB.atomic() as transaction: + with app.app_context(): + g.current_user = "heggens" + + testDate = datetime.strptime("2025-08-01 05:00","%Y-%m-%d %H:%M") + programEvent = Program.create(id = 13, + programName = "Bonner Scholars", + isStudentLed = False, + isBonnerScholars = True, + contactEmail = "test@email", + contactName = "testName") + + event = Event.create(name = "Upcoming Bonner Scholars Event", + term = 2, + description = "Test upcoming bonner event.", + location = "Stephenson Building", + startDate = testDate, + endDate = testDate + timedelta(days=1), + program = programEvent) + + cohortYears = ["2020", "2021", "2024"] + success, message, invitedCohorts = inviteCohortsToEvent(event, cohortYears) + + assert success is True + assert message == "Cohorts successfully added to new event" + assert invitedCohorts == [2020, 2021, 2024] + transaction.rollback() @pytest.mark.integration def test_updateEventCohorts(): - pass + """ + This function creates a Bonner Scholar program, attaches an event to this program, + creates invited cohorts for this event, + and updates the cohorts attached to this event. + """ + with mainDB.atomic() as transaction: + with app.app_context(): + g.current_user = "heggens" + + testDate = datetime.strptime("2025-10-01 05:00","%Y-%m-%d %H:%M") + programEvent = Program.create(id = 13, + programName = "Bonner Scholars", + isStudentLed = False, + isBonnerScholars = True, + contactEmail = "test@email", + contactName = "testName") + + event = Event.create(name = "Upcoming Bonner Scholars event", + term = 2, + description = "Test upcoming bonner event.", + location = "MAC Building", + startDate = testDate, + endDate = testDate + timedelta(days=1), + program = programEvent) + + bonnerCohort1 = BonnerCohort.create(year = "2021", + user = "heggens") + + bonnerCohort2 = BonnerCohort.create(year = "2020", + user = "khatts") + + bonnerCohort3 = BonnerCohort.create(year = "2024", + user = "mupotsal") + + cohortYear1 = bonnerCohort1.year + cohortYear2 = bonnerCohort2.year + cohortYear3 = bonnerCohort3.year + + EventCohort.create(event = event, + invited_at = datetime.now(), + year = cohortYear1) + + EventCohort.create(event = event, + invited_at = datetime.now(), + year = cohortYear2) + + EventCohort.create(event = event, + invited_at = datetime.now(), + year = cohortYear3) + + cohortYears = ["2020", "2022", "2023"] + + success, message, updatedCohorts = updateEventCohorts(event, cohortYears) + print(1000*"*") + print(success, message, updatedCohorts) + + assert success is True + assert message == "Cohorts successfully updated for event" + assert updatedCohorts == [2022, 2023] + + transaction.rollback() +