From 5a191bd2c3245beccdeda63ce481139bfa204fb8 Mon Sep 17 00:00:00 2001 From: mhewel <58829786+mhewel@users.noreply.github.com> Date: Wed, 27 Nov 2024 21:47:38 +0100 Subject: [PATCH] If user is not logged in then send token by email to validate email --- members/apps.py | 27 +++++-- members/forms/volunteer_request_form.py | 14 +++- members/models/emailitem.py | 38 +++++---- members/models/emailtemplate.py | 6 +- members/models/volunteerrequest.py | 8 -- .../templates/members/volunteer_request.html | 57 ++++++++++++- members/urls.py | 7 +- members/views/VolunteerRequest.py | 81 ++++++++++++++++++- members/views/__init__.py | 2 +- 9 files changed, 201 insertions(+), 39 deletions(-) diff --git a/members/apps.py b/members/apps.py index ae902ff4..06860cf0 100644 --- a/members/apps.py +++ b/members/apps.py @@ -1,24 +1,39 @@ from django.apps import AppConfig from django.db.utils import OperationalError + class MembersConfig(AppConfig): - name = 'members' + name = "members" def ready(self): from members.models.emailtemplate import EmailTemplate - # Check if the NEW_VOLUNTEER email template exists, and create it if it does not + # Check if email templates exists, and create them if they do not try: if not EmailTemplate.objects.filter(idname="NEW_VOLUNTEER").exists(): EmailTemplate.objects.create( idname="NEW_VOLUNTEER", name="Ny frivillig", - description="Email template for nye frivillig forespørgsler", + description="Ny frivillig forespørgsel", from_address="kontakt@codingpirates.dk", subject="Ny frivillig til Coding Pirates {{ department }}", - body_html="
A new volunteer request has been made.
Details: {{ volunteer_request }}
", - body_text="A new volunteer request has been made.\nDetails: {{ volunteer_request }}", + body_html=""" +Se detaljer i medlemssystemet, under Admin
""", + body_text=""" + Se detaljer i medlemssystemet, under Admin""", + ) + + if not EmailTemplate.objects.filter(idname="SECURITY_TOKEN").exists(): + EmailTemplate.objects.create( + idname="SECURITY_TOKEN", + name="Security Token", + description="Sikkerhedskode", + from_address="kontakt@codingpirates.dk", + subject="Sikkerhedskode for Coding Pirates", + body_html="Din sikkerhedskode er: {{ token }}
", + body_text="Din sikkerhedskode er: {{ token }}", ) + except OperationalError: # Handle the case where the database is not ready yet - pass \ No newline at end of file + pass diff --git a/members/forms/volunteer_request_form.py b/members/forms/volunteer_request_form.py index 4c9cf14e..f3c0f50d 100644 --- a/members/forms/volunteer_request_form.py +++ b/members/forms/volunteer_request_form.py @@ -42,9 +42,9 @@ def render(self, name, value, attrs=None, choices=()): class VolunteerRequestForm(forms.ModelForm): department_list = forms.ModelMultipleChoiceField( queryset=Department.objects.filter(closed_dtm__isnull=True) - .order_by("id") + .order_by("name") .distinct(), - widget=CustomCheckboxSelectMultiple(), + widget=CheckboxSelectMultiple(), required=True, label="Vælg Afdeling(er)x", ) @@ -55,6 +55,13 @@ class VolunteerRequestForm(forms.ModelForm): label="Vælg person fra familien", ) + email_token = forms.CharField( + required=False, + label="Indtast den 6-cifrede kode sendt til din email", + max_length=6, + widget=forms.HiddenInput() # Initially hidden + ) + class Meta: model = VolunteerRequest fields = [ @@ -67,6 +74,7 @@ class Meta: "info_reference", "info_whishes", "department_list", + "email_token", ] def __init__(self, *args, **kwargs): @@ -87,6 +95,7 @@ def __init__(self, *args, **kwargs): self.fields["phone"].widget = forms.HiddenInput() self.fields["age"].widget = forms.HiddenInput() self.fields["zip"].widget = forms.HiddenInput() + self.fields["email_token"].widget = forms.HiddenInput() else: self.fields["family_member"].widget = forms.HiddenInput() @@ -106,6 +115,7 @@ def __init__(self, *args, **kwargs): Div(Field("info_reference"), css_class="col-md-12"), Div(Field("info_whishes"), css_class="col-md-12"), Div(Field("department_list"), css_class="col-md-12"), + Div(Field("email_token"), css_class="col-md-12", id="email-token-field"), css_class="row", ), ), diff --git a/members/models/emailitem.py b/members/models/emailitem.py index 8add9cd3..d7b95f2d 100644 --- a/members/models/emailitem.py +++ b/members/models/emailitem.py @@ -8,6 +8,7 @@ from django.utils.html import format_html from django.utils.html import escape from django.utils.safestring import mark_safe +from django.db import transaction import uuid @@ -122,23 +123,30 @@ def email_link(self): # send this email. Notice no checking of race condition, so this should be called by # cronscript and made sure the same mail is not sent multiple times in parallel def send(self): - self.sent_dtm = timezone.now() - self.save() - try: - send_mail( - self.subject, - self.body_text, - settings.SITE_CONTACT, - (self.receiver,), - html_message=self.body_html, - ) - except Exception as e: - self.send_error = str(type(e)) - self.send_error = self.send_error + str(e) + with transaction.atomic(): + # Lock the email item to avoid race conditions + email_item = EmailItem.objects.select_for_update().get(pk=self.pk) + if email_item.sent_dtm is not None: + # Email has already been sent, so skip sending it again + return + + self.sent_dtm = timezone.now() self.save() - raise e # forward exception to job control + try: + send_mail( + self.subject, + self.body_text, + settings.SITE_CONTACT, + (self.receiver,), + html_message=self.body_html, + ) + except Exception as e: + self.send_error = str(type(e)) + self.send_error = self.send_error + str(e) + self.save() + raise e # forward exception to job control - self.save() + self.save() def __str__(self): return str(self.receiver) + " '" + self.subject + "'" diff --git a/members/models/emailtemplate.py b/members/models/emailtemplate.py index 4bd78063..bec1c00a 100644 --- a/members/models/emailtemplate.py +++ b/members/models/emailtemplate.py @@ -56,9 +56,10 @@ def makeEmail(self, receivers, context, allow_multiple_emails=False): members.models.person.Person, members.models.family.Family, members.models.department.Department, + str, ): raise Exception( - "Receiver must be of type Person or Family not " + "Receiver must be of type Person, Family, Department or email address string not " + str(type(receiver)) ) @@ -66,6 +67,9 @@ def makeEmail(self, receivers, context, allow_multiple_emails=False): if type(receiver) is str: # check if family blacklisted. (TODO) destination_address = receiver + person = None + family = None + department = None elif type(receiver) is members.models.person.Person: # skip if family does not want email if receiver.family.dont_send_mails: diff --git a/members/models/volunteerrequest.py b/members/models/volunteerrequest.py index 8d20f487..8b7fd524 100644 --- a/members/models/volunteerrequest.py +++ b/members/models/volunteerrequest.py @@ -49,11 +49,3 @@ def __str__(self): else: return f"{self.person} ({self.created.strftime('%Y-%m-%d %H:%M:%S')})" - """ - def save(self, *args, **kwargs): - print("VolunteerRequest.Save()") - print(f" pk:{self.pk} person:{self.person} name:{self.name}") - print(f" email:{self.email}. phone:{self.phone}") - super().save(*args, **kwargs) - print(" saved") - """ diff --git a/members/templates/members/volunteer_request.html b/members/templates/members/volunteer_request.html index e5013654..59e46485 100644 --- a/members/templates/members/volunteer_request.html +++ b/members/templates/members/volunteer_request.html @@ -20,11 +20,64 @@