membershipworks: Automatically send survey emails to event attendees
This commit is contained in:
parent
b1a7467eda
commit
dcf483d19e
@ -7,6 +7,7 @@ def post_migrate_callback(sender, **kwargs):
|
|||||||
|
|
||||||
from cmsmanage.django_q2_helper import ensure_scheduled
|
from cmsmanage.django_q2_helper import ensure_scheduled
|
||||||
|
|
||||||
|
from .tasks.event_survey_emails import send_survey_emails
|
||||||
from .tasks.scrape import scrape_events, scrape_membershipworks
|
from .tasks.scrape import scrape_events, scrape_membershipworks
|
||||||
from .tasks.ucsAccounts import sync_accounts
|
from .tasks.ucsAccounts import sync_accounts
|
||||||
|
|
||||||
@ -29,6 +30,12 @@ def post_migrate_callback(sender, **kwargs):
|
|||||||
minutes=15,
|
minutes=15,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ensure_scheduled(
|
||||||
|
sync_accounts.q_task_group,
|
||||||
|
send_survey_emails,
|
||||||
|
schedule_type=Schedule.HOURLY,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MembershipworksConfig(AppConfig):
|
class MembershipworksConfig(AppConfig):
|
||||||
default_auto_field = "django.db.models.BigAutoField"
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from membershipworks.tasks.event_survey_emails import logger, send_survey_emails
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def handle(self, *args, verbosity: int, **options):
|
||||||
|
verbosity_levels = {
|
||||||
|
0: logging.ERROR,
|
||||||
|
1: logging.WARNING,
|
||||||
|
2: logging.INFO,
|
||||||
|
3: logging.DEBUG,
|
||||||
|
}
|
||||||
|
logger.setLevel(verbosity_levels.get(verbosity, logging.WARNING))
|
||||||
|
send_survey_emails()
|
@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 5.0.6 on 2024-05-20 22:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("membershipworks", "0018_eventext_details_timestamp"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="eventext",
|
||||||
|
name="should_survey",
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="eventext",
|
||||||
|
name="survey_email_sent",
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
@ -554,6 +554,9 @@ class EventExt(Event):
|
|||||||
|
|
||||||
registrations = models.JSONField(null=True, blank=True)
|
registrations = models.JSONField(null=True, blank=True)
|
||||||
|
|
||||||
|
should_survey = models.BooleanField(default=False)
|
||||||
|
survey_email_sent = models.BooleanField(default=False)
|
||||||
|
|
||||||
def get_absolute_url(self) -> str:
|
def get_absolute_url(self) -> str:
|
||||||
return reverse("membershipworks:event-detail", kwargs={"eid": self.eid})
|
return reverse("membershipworks:event-detail", kwargs={"eid": self.eid})
|
||||||
|
|
||||||
|
62
membershipworks/tasks/event_survey_emails.py
Normal file
62
membershipworks/tasks/event_survey_emails.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import logging
|
||||||
|
from collections.abc import Iterable
|
||||||
|
from urllib.parse import quote, urlencode
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core import mail
|
||||||
|
from django.db.models.functions import Now
|
||||||
|
|
||||||
|
from cmsmanage.email import TemplatedMultipartEmail
|
||||||
|
from membershipworks.models import EventExt
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class EventSurveyEmail(TemplatedMultipartEmail):
|
||||||
|
# TODO: better wording
|
||||||
|
subject = (
|
||||||
|
"[Claremont MakerSpace] Please fill out a survey for your recent CMS class!"
|
||||||
|
)
|
||||||
|
from_email = "CMS Classes <classes@claremontmakerspace.org>"
|
||||||
|
|
||||||
|
template = "membershipworks/email/event_survey.dj.html"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def survey_url(event: EventExt, attendee_name: str, attendee_email: str) -> str:
|
||||||
|
return "https://claremontmakerspace.org/class-evaluation-form?" + urlencode(
|
||||||
|
{
|
||||||
|
"event_id": event.eid,
|
||||||
|
"instructor_name": str(event.instructor) if event.instructor else "",
|
||||||
|
"event_name": event.title,
|
||||||
|
"event_date": event.start.strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
"participant_name": attendee_name,
|
||||||
|
"participant_email": attendee_email,
|
||||||
|
},
|
||||||
|
quote_via=quote,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def render_for_event(cls, event: EventExt) -> Iterable[mail.EmailMessage]:
|
||||||
|
for name, email in event.attendees.values_list("name", "email"):
|
||||||
|
sanitized_email = mail.message.sanitize_address(
|
||||||
|
(name, email), settings.DEFAULT_CHARSET
|
||||||
|
)
|
||||||
|
survey_url = cls.survey_url(event, name, email)
|
||||||
|
yield cls.render(
|
||||||
|
{"event": event, "attendee_name": name, "survey_url": survey_url},
|
||||||
|
to=[sanitized_email],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def send_survey_emails():
|
||||||
|
with mail.get_connection() as conn:
|
||||||
|
for event in EventExt.objects.filter(
|
||||||
|
occurred=True, should_survey=True, survey_email_sent=False, end__lt=Now()
|
||||||
|
):
|
||||||
|
logger.info("Sending survey messages for event: %s", event)
|
||||||
|
|
||||||
|
# mark as sent even if we don't finish, to prevent sending duplicates
|
||||||
|
event.survey_email_sent = True
|
||||||
|
event.save()
|
||||||
|
|
||||||
|
conn.send_messages(list(EventSurveyEmail.render_for_event(event)))
|
@ -0,0 +1,19 @@
|
|||||||
|
{% load nh3_tags %}
|
||||||
|
|
||||||
|
<p>Dear {{ attendee_name }},</p>
|
||||||
|
<p>
|
||||||
|
Thank you for recently attending "{{ event.details.ttl|nh3 }}" at CMS on {{ event.start|date }}! We hope you enjoyed the experience and found it both informative and inspiring.
|
||||||
|
To help us continue to offer high-quality classes and improve our programs, we would greatly appreciate your feedback.
|
||||||
|
We kindly ask you to take a few minutes to complete a brief survey about your experience.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="{{ survey_url }}">Click here to fill out the survey</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Your insights are invaluable to us and will directly contribute to enhancing our offerings and ensuring that we meet the needs and expectations of our community.
|
||||||
|
Thank you in advance for your time and feedback. If you have any additional comments or questions, please feel free to reach out to us at <a href="mailto:info@claremontmakerspace.org">info@claremontmakerspace.org</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div>The Claremont MakerSpace Team</div>
|
||||||
|
</p>
|
Loading…
Reference in New Issue
Block a user