From c25fd45c40eb45f4775dd02998cbf9fb056633b3 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Thu, 7 Nov 2024 22:35:20 -0500 Subject: [PATCH] Alleviate performance issues for signups (WIP) Also returns your new weighted hours so we can keep that updated. --- uber/site_sections/staffing.py | 29 ++++++----- uber/templates/staffing/shifts.html | 80 ++++++++++++++++++----------- 2 files changed, 66 insertions(+), 43 deletions(-) diff --git a/uber/site_sections/staffing.py b/uber/site_sections/staffing.py index 16082e761..50b0456a5 100644 --- a/uber/site_sections/staffing.py +++ b/uber/site_sections/staffing.py @@ -2,13 +2,14 @@ from datetime import datetime, timedelta from pockets.autolog import log import ics +from sqlalchemy.orm import joinedload from sqlalchemy.orm.exc import NoResultFound from uber.config import c from uber.custom_tags import safe_string from uber.decorators import ajax, ajax_gettable, all_renderable, check_shutdown, csrf_protected, render, public from uber.errors import HTTPRedirect -from uber.models import Attendee, Job +from uber.models import Attendee, Job, Shift from uber.utils import check_csrf, create_valid_user_supplied_redirect_url, ensure_csrf_token_exists, localized_now, extract_urls @@ -307,7 +308,7 @@ def get_available_jobs(self, session, all=False, highlight=False, **params): 'desc': _convert_urls(job.description), 'desc_text': job.description, 'weight': job.weight, - 'slots': f"{len(job.shifts)}/{job.slots}", + 'slots': f"{job.slots_taken}/{job.slots}", 'is_public': job.is_public, 'assigned': False, } @@ -318,15 +319,15 @@ def get_available_jobs(self, session, all=False, highlight=False, **params): def get_assigned_jobs(self, session, **params): volunteer = session.logged_in_volunteer() event_list = [] + jobs = session.query(Job).filter(Job.shifts.any(attendee_id=volunteer.id)).options(joinedload(Job.shifts)) - for shift in volunteer.shifts: - job = shift.job + for job in jobs: if job.is_public and job.department_id not in set(volunteer.assigned_depts_ids): resource_id = "public_assigned" else: resource_id = job.department_id event_list.append({ - 'id': shift.id, + 'id': job.id, 'resourceIds': [resource_id], 'allDay': False, 'start': job.start_time_local.isoformat(), @@ -338,14 +339,13 @@ def get_assigned_jobs(self, session, **params): 'desc': _convert_urls(job.description), 'desc_text': job.description, 'weight': job.weight, - 'slots': f"{len(job.shifts)}/{job.slots}", + 'slots': f"{job.slots_taken}/{job.slots}", 'is_public': job.is_public, 'assigned': True, } }) return event_list - def shifts_ical(self, session, **params): attendee = session.logged_in_volunteer() icalendar = ics.Calendar() @@ -375,30 +375,33 @@ def jobs(self, session, all=False): @check_shutdown @ajax def sign_up(self, session, job_id, **params): - message = session.assign(session.logged_in_volunteer().id, job_id) + volunteer = session.logged_in_volunteer() + message = session.assign(volunteer.id, job_id) if message: return {'success': False, 'message': message} - return {'success': True, 'message': "Signup complete!"} + return {'success': True, 'message': "Signup complete!", 'hours': volunteer.weighted_hours} @check_shutdown @ajax - def drop(self, session, shift_id, all=False): + def drop(self, session, job_id, all=False): if c.AFTER_DROP_SHIFTS_DEADLINE: return { 'success': False, 'message': "You can no longer drop shifts." } try: - shift = session.shift(shift_id) + volunteer = session.logged_in_volunteer() + shift = session.shift(job_id=job_id, attendee_id=volunteer.id) session.delete(shift) session.commit() except NoResultFound: return { 'success': True, - 'message': "You've already dropped or have been unassigned from this shift." + 'message': "You've already dropped or have been unassigned from this shift.", + 'hours': volunteer.weighted_hours } finally: - return {'success': True, 'message': "Shift dropped."} + return {'success': True, 'message': "Shift dropped.", 'hours': volunteer.weighted_hours} @public def login(self, session, message='', first_name='', last_name='', email='', zip_code='', original_location=None): diff --git a/uber/templates/staffing/shifts.html b/uber/templates/staffing/shifts.html index 0c17d48b4..26277d17f 100644 --- a/uber/templates/staffing/shifts.html +++ b/uber/templates/staffing/shifts.html @@ -60,7 +60,7 @@

- You are currently signed up for {{ hours }} weighted hours worth of shifts. + You are currently signed up for {{ hours }} weighted hours worth of shifts.

Shifts that will overlap with your existing shifts will be hidden, and you will need to drop a shift to view them. @@ -237,6 +237,9 @@

if (json.success) { $("#message-alert").addClass("alert-success").show().children('span').html(message); shiftDetails.hide(); + $("#weighted-hours").text(json.hours); + $("#weighted-hours").fadeOut(500).fadeIn(500); + fetchedEventList.length = 0; ec.refetchEvents(); } else { showErrorMessage(json.message); @@ -266,7 +269,7 @@

url: 'drop', dataType: 'json', data: { - shift_id: id, + job_id: id, csrf_token: csrf_token }, success: function (json) { @@ -275,6 +278,7 @@

if (json.success) { $("#message-alert").addClass("alert-success").show().children('span').html(message); shiftDetails.hide(); + fetchedEventList.length = 0; ec.refetchEvents(); } else { showErrorMessage(json.message); @@ -347,18 +351,49 @@

} } + var fetchEventsParams = { + all: '', + highlight: '', + } + var possibleEventURLS = {'available': 'get_available_jobs', 'assigned': 'get_assigned_jobs'}; + var fetchEventsURLS = ['get_available_jobs', 'get_assigned_jobs']; + var fetchedEventList = new Array(); + let fetchEvents = function(fetchInfo, successCallback, failureCallback) { + if (fetchedEventList.length != 0) { + successCallback(fetchedEventList); + } + for (const url of fetchEventsURLS) { + $.ajax({ + method: 'GET', + url: url, + dataType: 'json', + data: fetchEventsParams, + success: function (eventList) { + fetchedEventList.push(...eventList); + }, + error: function () {} + }); + } + + console.log(fetchedEventList); + + if (fetchedEventList.length != 0) { + successCallback(fetchedEventList); + } else { + failureCallback('Unable to connect to server, please try again.'); + } + } + let addEvents = function(id) { - let eventSources = ec.getOption('eventSources'); - eventSources.push(possibleEventSources[id]); - ec.setOption('eventSources', eventSources); + fetchEventsURLS.push(possibleEventURLS[id]); + fetchedEventList.length = 0; ec.refetchEvents(); toggleButton(id, 'on'); } let removeEvents = function(id) { - let eventSources = ec.getOption('eventSources'); - updatedEventSources = eventSources.filter(function(el) { return el.url != possibleEventSources[id]['url']; }); - ec.setOption('eventSources', updatedEventSources); + fetchEventsURLS = fetchEventsURLS.filter(function(el) { return el != possibleEventURLS[id]; }); + fetchedEventList.length = 0; ec.refetchEvents(); toggleButton(id, 'off'); } @@ -366,7 +401,7 @@

let setFilters = function (dropdown_name) { let choice = $('#' + dropdown_name).val(); if (choice == "" || choice == "all") { - ec.setOption('resources', {{ default_filters|safe }}) + ec.setOption('resources', {{ default_filters|safe }}); } else { ec.setOption('resources', []); addFilter(choice); @@ -388,14 +423,13 @@

} let setFetchParams = function (paramChanges) { - currentParams = possibleEventSources['available']['extraParams']; for (const [key, value] of Object.entries(paramChanges)) { - possibleEventSources['available']['extraParams'][key] = value; + fetchEventsParams[key] = value; } - let eventSources = ec.getOption('eventSources'); - if (eventSources.filter(function(el) { return el.url == possibleEventSources['available']['url']; })) { - removeEvents('available'); - addEvents('available'); + + if ('get_available_jobs' in fetchEventsURLS) { + fetchedEventList.length = 0; + ec.refetchEvents(); } } @@ -511,20 +545,6 @@

} const allFilters = {{ all_filters|safe }} - let possibleEventSources = { - 'available': { - url: 'get_available_jobs', - method: 'GET', - extraParams: { - 'all': '', - 'highlight': '', - } - }, - 'assigned': { - url: 'get_assigned_jobs', - method: 'GET', - } - } const ec = new EventCalendar(document.getElementById('shift_cal'), { view: window.matchMedia('(max-width: 576px)').matches ? 'listWeek' : 'timeGridWeek', @@ -571,7 +591,7 @@

} }, viewDidMount: showOtherView, - eventSources: [possibleEventSources['available'], possibleEventSources['assigned']], + eventSources: [{events: fetchEvents}], eventContent: renderEvent, eventClick: showEventDetails, filterEventsWithResources: true,