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

Completely overhaul signups view #4425

Merged
merged 1 commit into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions uber/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,17 @@ def CURRENT_ADMIN(self):
except Exception:
return {}

@request_cached_property
@dynamic
def CURRENT_VOLUNTEER(self):
try:
from uber.models import Session
with Session() as session:
attendee = session.logged_in_volunteer()
return attendee.to_dict()
except Exception:
return {}

@request_cached_property
@dynamic
def DEPARTMENTS(self):
Expand Down
11 changes: 3 additions & 8 deletions uber/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -961,20 +961,15 @@ def checklist_status(self, slug, department_id):
}

def jobs_for_signups(self, all=False):
fields = [
'name', 'department_id', 'department_name', 'description',
'weight', 'start_time_local', 'end_time_local', 'duration',
'weighted_hours', 'restricted', 'extra15', 'taken',
'visibility', 'is_public', 'is_setup', 'is_teardown']
jobs = self.logged_in_volunteer().possible_and_current
jobs = self.logged_in_volunteer().possible
restricted_minutes = set()
for job in jobs:
if job.required_roles:
restricted_minutes.add(frozenset(job.minutes))
if all:
return [job.to_dict(fields) for job in jobs]
return jobs
return [
job.to_dict(fields)
job
for job in jobs if (job.required_roles or frozenset(job.minutes) not in restricted_minutes)]

def possible_match_list(self):
Expand Down
4 changes: 4 additions & 0 deletions uber/models/commerce.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ def all_sorted_items_and_txns(self):
@property
def sorted_txns(self):
return sorted([txn for txn in self.receipt_txns], key=lambda x: x.added)

@property
def sorted_items(self):
return sorted([item for item in self.receipt_items], key=lambda x: x.added)

@property
def total_processing_fees(self):
Expand Down
148 changes: 121 additions & 27 deletions uber/site_sections/staffing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@
from datetime import datetime, timedelta
from pockets.autolog import log
import ics
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
from uber.utils import check_csrf, create_valid_user_supplied_redirect_url, ensure_csrf_token_exists, localized_now
from uber.models import Attendee, Job
from uber.utils import check_csrf, create_valid_user_supplied_redirect_url, ensure_csrf_token_exists, localized_now, extract_urls


def _convert_urls(desc):
urls = extract_urls(desc)
log.error(urls)
for url in urls:
desc = desc.replace(url, f'<a href="{url}" target="_blank">{url}</a>')
return desc


@all_renderable()
Expand Down Expand Up @@ -208,8 +217,7 @@ def shifts(self, session, view='', start='', all=''):
assigned_dept_ids = set(volunteer.assigned_depts_ids)
has_public_jobs = False
for job in joblist:
job['is_public_to_volunteer'] = job['is_public'] and job['department_id'] not in assigned_dept_ids
if job['is_public_to_volunteer']:
if job.is_public and job.department_id not in assigned_dept_ids:
has_public_jobs = True

has_setup = volunteer.can_work_setup or any(d.is_setup_approval_exempt for d in volunteer.assigned_depts)
Expand All @@ -226,28 +234,111 @@ def shifts(self, session, view='', start='', all=''):
else:
start = datetime.strptime(start, '%Y-%m-%dT%H:%M:%S.%f')

if has_setup and has_teardown:
cal_length = c.CON_TOTAL_DAYS
elif has_setup:
cal_length = con_days + c.SETUP_SHIFT_DAYS
elif has_teardown:
cal_length = con_days + 2 # There's no specific config for # of shift signup days
else:
cal_length = con_days
end = c.TEARDOWN_JOB_END if has_teardown else c.ESCHATON

total_duration = 0
event_dates = []
day = start
while day <= end:
total_duration += 1
if c.EPOCH <= day and day <= c.ESCHATON:
event_dates.append(day.strftime('%Y-%m-%d'))
day += timedelta(days=1)

default_filters = []
for department in volunteer.assigned_depts:
default_filters.append({
'id': department.id,
'title': department.name,
})
other_filters = [
{'id': 'public', 'title': "Public Shifts",},
]

return {
'jobs': joblist,
'has_public_jobs': has_public_jobs,
'has_public_jobs': session.query(Job).filter(Job.is_public == True).count(),
'depts_with_roles': [membership.department.name for membership in volunteer.dept_memberships_with_role],
'assigned_depts_list': [(dept.id, dept.name) for dept in volunteer.assigned_depts],
'name': volunteer.full_name,
'hours': volunteer.weighted_hours,
'assigned_depts_labels': volunteer.assigned_depts_labels,
'default_filters': default_filters,
'all_filters': default_filters + other_filters,
'view': view,
'start': start,
'end': start + timedelta(days=cal_length),
'start': start.date(),
'end': end.date(),
'total_duration': total_duration,
'highlighted_dates': event_dates,
'setup_duration': 0 if not has_setup else (c.EPOCH - c.SETUP_JOB_START).days,
'teardown_duration': 0 if not has_teardown else (c.TEARDOWN_JOB_END - c.ESCHATON).days,
'start_day': c.SHIFTS_START_DAY if has_setup else c.EPOCH,
'show_all': all,
}

@ajax_gettable
def get_available_jobs(self, session, all=False, highlight=False, **params):
joblist = session.jobs_for_signups(all=all)

volunteer = session.logged_in_volunteer()
assigned_dept_ids = set(volunteer.assigned_depts_ids)
event_list = []

for job in joblist:
resource_id = job.department_id
bg_color = "#0d6efd"
if job.is_public and job.department_id not in assigned_dept_ids:
resource_id = "public"
bg_color = "#0dcaf0"
if highlight and len(job.shifts) == 0:
bg_color = "#dc3545"
event_list.append({
'id': job.id,
'resourceIds': [resource_id],
'allDay': False,
'start': job.start_time_local.isoformat(),
'end': job.end_time_local.isoformat(),
'title': f"{job.name}",
'backgroundColor': bg_color,
'extendedProps': {
'department_name': job.department_name,
'desc': _convert_urls(job.description),
'desc_text': job.description,
'weight': job.weight,
'slots': f"{len(job.shifts)}/{job.slots}",
'is_public': job.is_public,
'assigned': False,
}
})
return event_list

@ajax_gettable
def get_assigned_jobs(self, session, **params):
volunteer = session.logged_in_volunteer()
event_list = []

for shift in volunteer.shifts:
job = shift.job
event_list.append({
'id': shift.id,
'resourceIds': [job.department_id],
'allDay': False,
'start': job.start_time_local.isoformat(),
'end': job.end_time_local.isoformat(),
'title': f"{job.name}",
'backgroundColor': '#198754',
'extendedProps': {
'department_name': job.department_name,
'desc': _convert_urls(job.description),
'desc_text': job.description,
'weight': job.weight,
'slots': f"{len(job.shifts)}/{job.slots}",
'is_public': job.is_public,
'assigned': True,
}
})
return event_list


def shifts_ical(self, session, **params):
attendee = session.logged_in_volunteer()
Expand Down Expand Up @@ -277,28 +368,31 @@ def jobs(self, session, all=False):

@check_shutdown
@ajax
def sign_up(self, session, job_id, all=False):
return {
'error': session.assign(session.logged_in_volunteer().id, job_id),
'jobs': session.jobs_for_signups(all=all)
}
def sign_up(self, session, job_id, **params):
message = session.assign(session.logged_in_volunteer().id, job_id)
if message:
return {'success': False, 'message': message}
return {'success': True, 'message': "Signup complete!"}

@check_shutdown
@ajax
def drop(self, session, job_id, all=False):
def drop(self, session, shift_id, all=False):
if c.AFTER_DROP_SHIFTS_DEADLINE:
return {
'error': "You can no longer drop shifts.",
'jobs': session.jobs_for_signups(all=all)
'success': False,
'message': "You can no longer drop shifts."
}
try:
shift = session.shift(job_id=job_id, attendee_id=session.logged_in_volunteer().id)
shift = session.shift(shift_id)
session.delete(shift)
session.commit()
except Exception:
pass
except NoResultFound:
return {
'success': True,
'message': "You've already dropped or have been unassigned from this shift."
}
finally:
return {'jobs': session.jobs_for_signups(all=all)}
return {'success': True, 'message': "Shift dropped."}

@public
def login(self, session, message='', first_name='', last_name='', email='', zip_code='', original_location=None):
Expand Down
2 changes: 1 addition & 1 deletion uber/templates/base.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% import 'macros.html' as macros with context %}
{% set page_ro = false %}
{% set bootstrap5 = 'preregistration' in c.PAGE_PATH or 'landing' in c.PAGE_PATH or 'art_show_applications' in c.PAGE_PATH or 'attractions' in c.PAGE_PATH or 'hotel_lottery' in c.PAGE_PATH or 'marketplace' in c.PAGE_PATH or admin_area %}
{% set bootstrap5 = 'preregistration' in c.PAGE_PATH or 'landing' in c.PAGE_PATH or 'art_show_applications' in c.PAGE_PATH or 'attractions' in c.PAGE_PATH or 'hotel_lottery' in c.PAGE_PATH or 'marketplace' in c.PAGE_PATH or 'staffing' in c.PAGE_PATH or admin_area %}
<!DOCTYPE HTML>
<html lang="en">
<head>
Expand Down
75 changes: 49 additions & 26 deletions uber/templates/signup_base.html
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@
{%- import 'macros.html' as macros -%}
<!doctype html>
<html>
<head>
<title>{{ name }}'s shifts</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
{{ "styles/styles.css"|serve_static_content }}
{{ "fullcalendar-5.3.2/lib/main.min.css"|serve_static_content }}
<meta name="viewport"
content="
height = device-height,
width = device-width,
initial-scale = 1.0,
minimum-scale = 1.0,
maximum-scale = 1.0,
user-scalable = no
" />
{% block page_style %}{% endblock %}
</head>
<body>
<div class="container-fluid">
{% block main_content %} {% endblock %}
</div>
</body>
{% block page_script %} {% endblock %}
</html>
{% extends "preregistration/preregbase.html" %}

{% block head_styles %}
{{ "deps/combined.min.css"|serve_static_content }}
<link rel="stylesheet" href="../static_views/styles/main.css" />
{{ "deps/bootstrap5/bootstrap.min.css"|serve_static_content }}
{{ "deps/bootstrap5/font-awesome.min.css"|serve_static_content }}
{{ "deps/bootstrap5/datatables.min.css"|serve_static_content }}

<!-- additional styles -->
{% block additional_styles %}
{% block page_styles %}{% endblock %}
{% endblock %}
{% endblock %}

{% block masthead %}{% endblock %}

{% block backlink %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img src="../static/images/favicon.png" alt="{{ c.EVENT_NAME }}" width="24" class="d-inline-block align-text-top">
{{ c.EVENT_NAME }} Staffing
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<ul class="navbar-nav me-auto mb-2 mb-lg-0" id="main-menu">
<li class="nav-item"><a class="nav-link{% if c.PAGE_PATH == '/staffing/index' %} active" aria-current="page"{% else %}"{% endif %} href="../staffing/index">Volunteer Checklist</a></li>
{% if c.AFTER_SHIFTS_CREATED and c.CURRENT_VOLUNTEER.shift_prereqs_complete %}
<li class="nav-item"><a class="nav-link{% if c.PAGE_PATH == '/staffing/shifts' %} active" aria-current="page"{% else %}"{% endif %} href="../staffing/shifts">Shifts</a></li>
<li class="nav-item"><a class="nav-link" href="../staffing/printable" target="_blank">Printable Shift Schedule</a></li>
{% endif %}
</ul>
<ul class="navbar-nav d-flex">
<li class="nav-item"><a href="{{ c.VOLUNTEER_PERKS_URL }}" target="_blank" class="nav-link"><i class="fa fa-question-circle"></i> Volunteering Perks</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="account-dropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<span>Logged in as: {{ c.CURRENT_VOLUNTEER.first_name }} {{ c.CURRENT_VOLUNTEER.last_name }}</span> <i title="Account Settings" class="fa fa-cog"></i>
</a>
<ul class="dropdown-menu" aria-labelledby="account-dropdown">
<li><a class="dropdown-item" href="../preregistration/confirm?id={{ c.CURRENT_VOLUNTEER.id }}">View My Badge</a></li>
<li><a class="dropdown-item" href="../staffing/login">Logout</a></li>
</ul>
</li>
</ul>
</div>
</nav>
{% endblock %}
4 changes: 2 additions & 2 deletions uber/templates/staffing/credits.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends "base.html" %}{% set admin_area=True %}
{% extends 'signup_base.html' %}
{% block title %}Volunteer Agreement{% endblock %}
{% block backlink %}{% endblock %}

{% block content %}

<h1>Name in Credits</h1>
Expand Down
4 changes: 2 additions & 2 deletions uber/templates/staffing/emergency_procedures.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends "base.html" %}{% set admin_area=True %}
{% extends 'signup_base.html' %}
{% block title %}Volunteer Agreement{% endblock %}
{% block backlink %}{% endblock %}

{% block content %}

<h1>Emergency Procedures</h1>
Expand Down
4 changes: 2 additions & 2 deletions uber/templates/staffing/food_restrictions.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends "base.html" %}{% set admin_area=True %}
{% extends 'signup_base.html' %}
{% block title %}Dietary Restrictions{% endblock %}
{% block backlink %}{% endblock %}

{% block content %}

<h2> Dietary Restrictions </h2>
Expand Down
4 changes: 2 additions & 2 deletions uber/templates/staffing/hotel.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends "base.html" %}{% set admin_area=True %}
{% extends 'signup_base.html' %}
{% block title %}Hotel Requests{% endblock %}
{% block backlink %}{% endblock %}

{% block content %}

<h2> Hotel Room Space </h2>
Expand Down
4 changes: 2 additions & 2 deletions uber/templates/staffing/index.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends "base.html" %}{% set admin_area=True %}
{% extends 'signup_base.html' %}
{% block title %}Volunteer Checklist{% endblock %}
{% block backlink %}{% endblock %}

{% block content %}

<h2> Volunteer Checklist for {{ attendee.full_name }} </h2>
Expand Down
4 changes: 2 additions & 2 deletions uber/templates/staffing/onsite_jobs.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends "base.html" %}{% set admin_area=True %}
{% extends 'signup_base.html' %}
{% block title %}On-Site Shifts{% endblock %}
{% block backlink %}{% endblock %}

{% block content %}

<h2>All Available Shifts</h2>
Expand Down
Loading
Loading