membershipworks: Add upcoming events generator
This commit is contained in:
parent
7afcc1f9e0
commit
97bcc1df6d
@ -37,6 +37,7 @@ INSTALLED_APPS = [
|
||||
"rest_framework",
|
||||
"rest_framework.authtoken",
|
||||
"django_q",
|
||||
"django_bleach",
|
||||
"tasks.apps.TasksConfig",
|
||||
"rentals.apps.RentalsConfig",
|
||||
"membershipworks.apps.MembershipworksConfig",
|
||||
|
@ -0,0 +1,121 @@
|
||||
{% extends "base.dj.html" %}
|
||||
|
||||
{% load bleach_tags %}
|
||||
|
||||
{% block title %}Upcoming Events{% endblock %}
|
||||
{% block content %}
|
||||
<div id="preview">
|
||||
<p>
|
||||
<img class="aligncenter size-medium wp-image-2319"
|
||||
src="https://claremontmakerspace.org/wp-content/uploads/2019/03/CMS-Logo-b-y-g-300x168.png"
|
||||
alt=""
|
||||
width="300"
|
||||
height="168" />
|
||||
</p>
|
||||
<p>Greetings Upper Valley Makers:</p>
|
||||
<p>We have an exciting list of upcoming classes at the Claremont MakerSpace that we think might interest you.</p>
|
||||
<div>
|
||||
<strong>For most classes and events, CMS MEMBERSHIP IS NOT REQUIRED.</strong> That said, members receive a discount
|
||||
on registration and there are some classes/events that are for members only (this will be clearly noted in the event
|
||||
description).
|
||||
</div>
|
||||
<div>
|
||||
<strong>Class policies</strong> (liability waiver, withdrawal, cancellation, etc.) can be found <a href="https://claremontmakerspace.org/class-policies/"
|
||||
data-wpel-link="internal">here</a>.
|
||||
</div>
|
||||
<div>
|
||||
<strong>Instructors:</strong> Interested in teaching a class at CMS? Please fill out our <a href="https://claremontmakerspace.org/cms-class-proposal-form/"
|
||||
data-wpel-link="internal">Class Proposal Form</a>.
|
||||
</div>
|
||||
<div>
|
||||
<strong>Tours:</strong> Want to see what the Claremont MakerSpace is all about? Tours are by appointment only.
|
||||
</div>
|
||||
<a href="https://tickets.claremontmakerspace.org/open.php"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener external"
|
||||
data-wpel-link="external">Contact Us</a> to schedule your tour where you can learn about all the awesome tools that
|
||||
the CMS offers access to, as well as how membership, classes, and studio spaces work.
|
||||
<hr />
|
||||
{% for section in event_sections %}
|
||||
{% if section.events %}
|
||||
<h1>{{ section.title }}</h1>
|
||||
<h4>
|
||||
<i>{{ section.blurb }}</i>
|
||||
</h4>
|
||||
{% for event in section.events %}
|
||||
{% with url="https://claremontmakerspace.org/events/#!event/register/"|add:event.url %}
|
||||
{% spaceless %}
|
||||
<h2 style="text-align: center;">
|
||||
<a href="{{ url }}">
|
||||
{# djlint:off H006,H013 #}
|
||||
{% if "lgo" in event %}<img class="alignleft" width="400" src="{{ event.lgo.l }}">{% endif %}
|
||||
{# djlint:on #}
|
||||
<span>{{ event.ttl|bleach }}</span>
|
||||
</a>
|
||||
</h2>
|
||||
{% endspaceless %}
|
||||
{% spaceless %}
|
||||
<div>
|
||||
{# wordpress is very annoying with spacing here #}
|
||||
{# djlint:off #}
|
||||
<i>
|
||||
{# TODO: different dates probably implies multiple instances. Should read RRULE or similar from the event notes #}
|
||||
{{ event.sdp_dt|date }} {{ event.sdp_dt|time }} — {% if event.sdp_dt.date != event.edp_dt.date %}{{ event.edp_dt|date }}{% endif %} {{ event.edp_dt|time }}
|
||||
</i>
|
||||
{# djlint:on #}
|
||||
</div>
|
||||
{% endspaceless %}
|
||||
{% if not section.truncate %}
|
||||
<div>{{ event.dtl|bleach:"a,abbr,acronym,b,blockquote,code,em,i,li,ol,strong,ul,p,span,br,div" }}</div>
|
||||
<div>
|
||||
<a href="{{ url }}">Register for this class now!</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<hr />
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<div style="clear: both;">
|
||||
<div>Happy Makin’!</div>
|
||||
<div>
|
||||
We are grateful for all of the public support that our 501(c)(3), non-profit organization receives. If you’d
|
||||
like to make a donation,please visit the <a href="https://claremontmakerspace.org/support/"><strong>Support Us
|
||||
page</strong></a> of our website.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="position-fixed end-0 bottom-0">
|
||||
<button id="copy-button"
|
||||
type="button"
|
||||
class="btn btn-primary m-3"
|
||||
data-bs-toggle="popover"
|
||||
data-bs-content="Copied!">
|
||||
<i class="bi bi-clipboard-fill"></i> Copy to clipboard
|
||||
</button>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
<script>
|
||||
// TODO: This should use the newer Clipboard API, but Firefox doesn't support it yet
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem
|
||||
function copyToClipboard(event) {
|
||||
const cb = e => {
|
||||
e.clipboardData.setData("text/html", document.getElementById("preview").innerHTML);
|
||||
e.clipboardData.setData("text/plain", document.getElementById("preview").innerHTML);
|
||||
e.preventDefault();
|
||||
};
|
||||
document.addEventListener("copy", cb);
|
||||
document.execCommand("copy");
|
||||
document.removeEventListener("copy", cb);
|
||||
|
||||
bootstrap.Popover.getInstance(event.target).show();
|
||||
setTimeout(() => bootstrap.Popover.getInstance(event.target).hide(), 1000);
|
||||
}
|
||||
const button = document.getElementById("copy-button");
|
||||
const popover = new bootstrap.Popover(button, {
|
||||
trigger: "manual"
|
||||
})
|
||||
button.addEventListener("click", copyToClipboard);
|
||||
</script>
|
||||
{% endblock %}
|
@ -1,6 +1,6 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import MemberAutocomplete
|
||||
from .views import MemberAutocomplete, upcoming_events
|
||||
|
||||
app_name = "membershipworks"
|
||||
|
||||
@ -10,4 +10,9 @@ urlpatterns = [
|
||||
MemberAutocomplete.as_view(),
|
||||
name="member-autocomplete",
|
||||
),
|
||||
path(
|
||||
"upcoming-events/",
|
||||
upcoming_events,
|
||||
name="upcoming-events",
|
||||
),
|
||||
]
|
||||
|
@ -1,6 +1,15 @@
|
||||
from datetime import datetime
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
|
||||
from dal import autocomplete
|
||||
|
||||
from .models import Member
|
||||
from membershipworks import MembershipWorks
|
||||
|
||||
|
||||
class MemberAutocomplete(autocomplete.Select2QuerySetView):
|
||||
@ -12,3 +21,84 @@ class MemberAutocomplete(autocomplete.Select2QuerySetView):
|
||||
return Member.objects.none()
|
||||
else:
|
||||
return super().get_queryset()
|
||||
|
||||
|
||||
@login_required
|
||||
# TODO: permission required?
|
||||
def upcoming_events(request):
|
||||
now = datetime.now()
|
||||
|
||||
membershipworks = MembershipWorks()
|
||||
membershipworks.login(
|
||||
settings.MEMBERSHIPWORKS_USERNAME, settings.MEMBERSHIPWORKS_PASSWORD
|
||||
)
|
||||
|
||||
events = membershipworks.get_events_list(now)
|
||||
if "error" in events:
|
||||
messages.add_message(
|
||||
request,
|
||||
messages.ERROR,
|
||||
f"MembershipWorks Error: {events['error']}",
|
||||
)
|
||||
# TODO: this should probably be an HTTP 500 response
|
||||
return render(request, "base.dj.html")
|
||||
|
||||
ongoing_events = []
|
||||
full_events = []
|
||||
upcoming_events = []
|
||||
for event in events["evt"]:
|
||||
try:
|
||||
# ignore hidden events
|
||||
if event["cal"] == 0:
|
||||
continue
|
||||
event_details = membershipworks.get_event_by_eid(event["eid"])
|
||||
|
||||
# Convert timestamps to datetime objects
|
||||
event_details["sdp_dt"] = datetime.fromtimestamp(event_details["sdp"])
|
||||
event_details["edp_dt"] = datetime.fromtimestamp(event_details["edp"])
|
||||
print(event_details["ttl"])
|
||||
|
||||
# registration has already ended
|
||||
if (
|
||||
"erd" in event_details
|
||||
and datetime.fromtimestamp(event_details["erd"]) < now
|
||||
):
|
||||
ongoing_events.append(event_details)
|
||||
# class is full
|
||||
elif event_details["cnt"] >= event_details["cap"]:
|
||||
full_events.append(event_details)
|
||||
else:
|
||||
upcoming_events.append(event_details)
|
||||
|
||||
except KeyError as e:
|
||||
messages.add_message(
|
||||
request,
|
||||
messages.ERROR,
|
||||
f"Event '{event.get('ttl')}' missing required property: '{e.args[0]}'",
|
||||
)
|
||||
# TODO: this should probably be an HTTP 500 response
|
||||
return render(request, "base.dj.html")
|
||||
|
||||
context = {
|
||||
"event_sections": [
|
||||
{
|
||||
"title": "Upcoming Events",
|
||||
"blurb": "Events that are currently open for registration.",
|
||||
"events": upcoming_events,
|
||||
"truncate": False,
|
||||
},
|
||||
{
|
||||
"title": "Just Missed",
|
||||
"blurb": "These classes are currently full at time of writing. If you are interested, please check the event's page; spots occasionally open up. Keep an eye on this newsletter to see when these classes are offered again.",
|
||||
"events": full_events,
|
||||
"truncate": True,
|
||||
},
|
||||
{
|
||||
"title": "Ongoing Events",
|
||||
"blurb": "These events are ongoing. Registration is currently closed, but these events may be offered again in the future.",
|
||||
"events": ongoing_events,
|
||||
"truncate": True,
|
||||
},
|
||||
]
|
||||
}
|
||||
return render(request, "membershipworks/upcoming_events.dj.html", context)
|
||||
|
15
pdm.lock
15
pdm.lock
@ -5,7 +5,7 @@
|
||||
groups = ["default", "debug", "lint", "server", "typing", "dev"]
|
||||
strategy = ["cross_platform"]
|
||||
lock_version = "4.4"
|
||||
content_hash = "sha256:8afb89517cfd55ec9138e679d7df47143d3dda10543096382656cb2028e97b50"
|
||||
content_hash = "sha256:4b66341c252a0c283b65ee725342a18f2b71c34811cc7853c75e78fde80815df"
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
@ -443,6 +443,19 @@ files = [
|
||||
{file = "django-autocomplete-light-3.9.7.tar.gz", hash = "sha256:a34f192ac438c4df056dbfd399550799ddc631c4661960134ded924648770373"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-bleach"
|
||||
version = "1.0.0"
|
||||
summary = "Easily use bleach with Django models and templates"
|
||||
dependencies = [
|
||||
"Django>=1.11",
|
||||
"bleach>=1.5.0",
|
||||
]
|
||||
files = [
|
||||
{file = "django-bleach-1.0.0.tar.gz", hash = "sha256:2586b90d641d4d7e70ee353570ad33d3625ed4b97036a3ea5b03ea1bb5bbeccd"},
|
||||
{file = "django_bleach-1.0.0-py2.py3-none-any.whl", hash = "sha256:60074a4f4bc8d5200fdb2e03dce16fb4913427698b64570bc3e1a7ea1b8c3cf7"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-debug-toolbar"
|
||||
version = "4.2.0"
|
||||
|
@ -28,6 +28,7 @@ dependencies = [
|
||||
"django-object-actions~=4.2",
|
||||
"udm-rest-client~=1.2",
|
||||
"openapi-client-udm~=1.0",
|
||||
"django-bleach~=1.0",
|
||||
]
|
||||
requires-python = ">=3.11"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user