diff options
-rw-r--r-- | alphabetlearning/payments/forms.py | 14 | ||||
-rw-r--r-- | alphabetlearning/payments/migrations/0013_alter_emailverification_email.py | 18 | ||||
-rw-r--r-- | alphabetlearning/payments/models.py | 3 | ||||
-rw-r--r-- | alphabetlearning/payments/views.py | 147 | ||||
-rw-r--r-- | alphabetlearning/templates/pages/home.html | 282 |
5 files changed, 267 insertions, 197 deletions
diff --git a/alphabetlearning/payments/forms.py b/alphabetlearning/payments/forms.py new file mode 100644 index 0000000..f69397f --- /dev/null +++ b/alphabetlearning/payments/forms.py @@ -0,0 +1,14 @@ +from django import forms +from .models import EmailVerification + + +class EmailVerificationForm(forms.ModelForm): + class Meta: + model = EmailVerification + fields = ['email'] + + def clean_email(self): + email = self.cleaned_data.get('email') + if EmailVerification.objects.filter(email=email).exists(): + raise forms.ValidationError("This email address is already in use.") + return email
\ No newline at end of file diff --git a/alphabetlearning/payments/migrations/0013_alter_emailverification_email.py b/alphabetlearning/payments/migrations/0013_alter_emailverification_email.py new file mode 100644 index 0000000..5d537bb --- /dev/null +++ b/alphabetlearning/payments/migrations/0013_alter_emailverification_email.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.4 on 2024-12-05 16:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('payments', '0012_rename_pendingemailverification_emailverification'), + ] + + operations = [ + migrations.AlterField( + model_name='emailverification', + name='email', + field=models.EmailField(max_length=254, unique=True), + ), + ] diff --git a/alphabetlearning/payments/models.py b/alphabetlearning/payments/models.py index 9ea9de2..3a3ba10 100644 --- a/alphabetlearning/payments/models.py +++ b/alphabetlearning/payments/models.py @@ -10,7 +10,7 @@ from alphabetlearning.resources.models import Resource class EmailVerification(models.Model): - email = models.EmailField() + email = models.EmailField(unique=True) verification_token = models.UUIDField(default=uuid.uuid4, editable=False) created_at = models.DateTimeField(auto_now_add=True) is_verified = models.BooleanField(default=False) @@ -23,7 +23,6 @@ class EmailVerification(models.Model): def __str__(self): return f"Email verification for {self.email}" - class EmailSignup(models.Model): email = models.EmailField(unique=True) date_added = models.DateTimeField(auto_now_add=True) diff --git a/alphabetlearning/payments/views.py b/alphabetlearning/payments/views.py index 4b6f79f..dda7900 100644 --- a/alphabetlearning/payments/views.py +++ b/alphabetlearning/payments/views.py @@ -18,7 +18,7 @@ from alphabetlearning.payments.models import EmailSignup from alphabetlearning.payments.models import EmailVerification from alphabetlearning.resources.models import Resource from alphabetlearning.users.models import User - +from .forms import EmailVerificationForm from .models import CartItem from .models import Price from .models import ShoppingCart @@ -56,70 +56,101 @@ class SuccessEmailSignupView(TemplateView): def email_signup_verification(request): if request.method == "POST": - email = request.POST.get("email") - - # Create pending verification - pending_verification = EmailVerification.objects.create( - email=email, - ) - - # Generate verification URL - verification_url = request.build_absolute_uri( - reverse('payments:verify_email', args=[str(pending_verification.verification_token)]) - ) - - # Send verification email - subject = 'Alphabet Learning - Email Verification' - html_message = f''' - <html> - <body> - <img src="http://localhost:8000/static/images/AL_long_logo_black_grey.png" alt="Alphabet Learning Logo" style="max-width: 200px; margin-bottom: 20px;"> - <p>Hi!</p> - <p>You recently requested to sign up to the Alphabet Learning contact list.</p> - <p>Please click the following link to verify your email address within 24 hours:</p> - <p><a href="{verification_url}">{verification_url}</a></p> - <p>If you didn't request this, please ignore this email.</p> - <p>Best regards,</p> - <p>The Alphabet Learning Team</p> - </body> - </html> + form = EmailVerificationForm(request.POST) + if form.is_valid(): + # Create pending verification + pending_verification = EmailVerification.objects.create( + email=form.cleaned_data.get("email"), + ) + # Generate verification URL + verification_url:str = request.build_absolute_uri( + reverse('payments:verify_email', args=[str(pending_verification.verification_token)]) + ) + email = process_verification_emails(verification_url, form.cleaned_data.get("email"), pending_verification, request) + return render(request, 'payments/verification_sent.html', { + 'email': email + }) + else: + email = process_verification_emails(request.POST.get("email"), warn=True) + return render(request, 'payments/verification_sent.html', { + 'email': email + }) + else: + form = EmailVerificationForm() + return render(request, "pages/home.html", {"form": form}) # Adjust as necessary + + +def process_verification_emails(email: str, verification_url: str=False, email_verification_obj: EmailVerification=False, warn=False): + + if warn is False: + html_warning_message = f''' + <p>Please click the following link to verify your email address within 24 hours:</p> + <p><a href="{verification_url}">{verification_url}</a></p> + <p>If you didn't request this, please ignore this email.</p> ''' - message = f''' - Hi!, - - You recently requested to sign up to the Alphabet Learning contact list. - + warning_message = f''' Please click the following link to verify your email address within 24 hours: {verification_url} If you didn't request this, please ignore this email. - - Best regards, - The Alphabet Learning Team ''' - send_mail( - subject, - message, - settings.DEFAULT_FROM_EMAIL, - [email], - fail_silently=False, - html_message=html_message - ) - admin_message = f''' - Joanna/Matthew, - - {email} has just signed up to the Alphabet Learning contact list. They are awaiting verification. - - I will email again if they follow through with the verification. - - Best regards, - The Alphabet Learning Server + admin_warn = "They are not already subscribed." + else: + html_warning_message = f''' + <p>You are already subscribed to our list - no further action is required.</p> ''' + warning_message = ''' + You are already subscribed to our list - no further action is required. + ''' + admin_warn = "They have already subscribed so have been told of this fact in their verification email. No further action required." + + # Send verification email + subject = 'Alphabet Learning - Email Verification' + html_message = f''' + <html> + <body> + <img src="http://localhost:8000/static/images/AL_long_logo_black_grey.png" alt="Alphabet Learning Logo" style="max-width: 200px; margin-bottom: 20px;"> + <p>Hi!</p> + <p>You recently requested to sign up to the Alphabet Learning contact list.</p> + {html_warning_message} + <p>Best regards,</p> + <p>The Alphabet Learning Team</p> + </body> + </html> + ''' + message = f''' + Hi!, + + You recently requested to sign up to the Alphabet Learning contact list. + + {warning_message} + + Best regards, + The Alphabet Learning Team + ''' + send_mail( + subject, + message, + settings.DEFAULT_FROM_EMAIL, + [email], + fail_silently=False, + html_message=html_message + ) + admin_message = f''' + Joanna/Matthew, + + {email} has just signed up to the Alphabet Learning contact list. They are awaiting verification. + + {admin_warn} + + I will email again if they follow through with the verification. + + Best regards, + The Alphabet Learning Server + ''' + mail_admins(subject, admin_message, fail_silently=False) + return email + - mail_admins(subject, admin_message, fail_silently=False) - return render(request, 'payments/verification_sent.html', { - 'email': email - }) - return render(request, "pages/home.html") # Adjust as necessary def verify_email(request, token): try: pending = EmailVerification.objects.get( diff --git a/alphabetlearning/templates/pages/home.html b/alphabetlearning/templates/pages/home.html index bda011c..e0827c1 100644 --- a/alphabetlearning/templates/pages/home.html +++ b/alphabetlearning/templates/pages/home.html @@ -1,18 +1,18 @@ {% extends "base.html" %} {% load static %} {% block content %} -<div class="container text-center"> - <div class="row"> - <div class="px-4 py-5 mt-5 mb-0"> - <h1 class="display-1 fw-bold">Alphabet Learning</h1> - <p class="display-6 mb-4 mt-4 p-4 rounded" style="color: #919191"> - High quality educational resources focused on simple concepts - and the first steps in learning. - </p> + <div class="container text-center"> + <div class="row"> + <div class="px-4 py-5 mt-5 mb-0"> + <h1 class="display-1 fw-bold">Alphabet Learning</h1> + <p class="display-6 mb-4 mt-4 p-4 rounded" style="color: #919191"> + High quality educational resources focused on simple concepts + and the first steps in learning. + </p> + </div> </div> - </div> - <hr - style=" + <hr + style=" border: none; height: 10px; background: linear-gradient( @@ -28,38 +28,46 @@ width: 100%; margin: 20px 0; " - /> + /> - <div class="row justify-content-center my-5"> - <div class="col-lg-12"> - <h2 class="display-4 font-weight-bolder my-3">Sign up</h2> - <div> - <p class="display-6 mb-4" style="color: darkgray"> - To be informed of the site launch and receive FREE resource - credits, join our new customer mailing list... - </p> - </div> - <form - method="post" - action="{% url 'payments:email_signup_verification' %}" - class="mb-4" - style="padding: 30px 0" - > - {% csrf_token %} - <div class="my-5"> - <div class="mb-4 text-start"> - <input - type="email" - class="sign-up-form-input" - id="email" - name="email" - required - placeholder="Your email address..." - /> - </div> - <button - type="submit" - style=" + <div class="row justify-content-center my-5"> + <div class="col-lg-12"> + <h2 class="display-4 font-weight-bolder my-3">Sign up</h2> + <div> + <p class="display-6 mb-4" style="color: darkgray"> + To be informed of the site launch and receive FREE resource + credits, join our new customer mailing list... + </p> + </div> + <form + method="post" + action="{% url 'payments:email_signup_verification' %}" + class="mb-4" + style="padding: 30px 0" + > + {% csrf_token %} + {{ form.non_field_errors }} + <div class="my-5"> + {% if form.email.errors %} + <div class="text-start my-2 border border-danger text-danger rounded"> + <p> + {{ form.email.errors }} + </p> + </div> + {% endif %} + <div class="mb-4 text-start"> + <input + type="email" + class="sign-up-form-input" + id="email" + name="email" + required + placeholder="Your email address..." + /> + </div> + <button + type="submit" + style=" background-color: red; color: white; border: none; @@ -68,33 +76,33 @@ font-size: 1.5rem; font-weight: bold; " - > - Submit - </button> - </div> - <p class="text-muted text-center mt-3"> - <small + > + Submit + </button> + </div> + <p class="text-muted text-center mt-3"> + <small >By joining our list, you agree to our - <a - href="{% url 'payments:privacy_policy' %}" - class="text-decoration-none" + <a + href="{% url 'payments:privacy_policy' %}" + class="text-decoration-none" >Privacy and Legal Notice</a - >.</small - > + >.</small + > + </p> + </form> + </div> + <div class="col-lg-12"> + <h2 class="display-4 font-weight-bolder my-3">Bonus offer!</h2> + <p class="display-6 mb-4" style="color: darkgray"> + As a thank-you, the first fifty customers who join our mailing + list will receive a 50% discount once the site is live. </p> - </form> - </div> - <div class="col-lg-12"> - <h2 class="display-4 font-weight-bolder my-3">Bonus offer!</h2> - <p class="display-6 mb-4" style="color: darkgray"> - As a thank-you, the first fifty customers who join our mailing - list will receive a 50% discount once the site is live. - </p> + </div> </div> - </div> - <hr - style=" + <hr + style=" border: none; height: 10px; background: linear-gradient( @@ -110,87 +118,87 @@ width: 100%; margin: 20px 0; " - /> + /> - <div class="row justify-content-center"> - <div class="col-md-4 mb-5 mb-md-0"> - <img - src="{% static 'images/funnel4.png' %}" - class="img-fluid rotated-image" - alt="Funnel 1" - /> - </div> - <div class="col-md-4 mb-5 mb-md-0"> - <img - src="{% static 'images/funnel5.png' %}" - class="img-fluid rotated-image" - alt="Funnel 2" - /> - </div> - <div class="col-md-4 mb-5 mb-md-0"> - <img - src="{% static 'images/funnel6.png' %}" - class="img-fluid rotated-image" - alt="Funnel 3" - /> + <div class="row justify-content-center"> + <div class="col-md-4 mb-5 mb-md-0"> + <img + src="{% static 'images/funnel4.png' %}" + class="img-fluid rotated-image" + alt="Funnel 1" + /> + </div> + <div class="col-md-4 mb-5 mb-md-0"> + <img + src="{% static 'images/funnel5.png' %}" + class="img-fluid rotated-image" + alt="Funnel 2" + /> + </div> + <div class="col-md-4 mb-5 mb-md-0"> + <img + src="{% static 'images/funnel6.png' %}" + class="img-fluid rotated-image" + alt="Funnel 3" + /> + </div> </div> - </div> - <div class="row my-5 d-flex align-items-stretch"> - <div class="col-md-12 d-flex"> - <div class="p-4 flex-fill"> - <h2 class="display-4 font-weight-bolder my-3"> - Learning from A to Z + <div class="row my-5 d-flex align-items-stretch"> + <div class="col-md-12 d-flex"> + <div class="p-4 flex-fill"> + <h2 class="display-4 font-weight-bolder my-3"> + Learning from A to Z + </h2> + <p + class="display-6" + style="margin-bottom: 20px; color: darkgray" + > + Focused on early concepts, these resources are designed to + be accessible to all learners. + </p> + </div> + </div> + <div class="display-4 font-weight-bolder my-5"> + <h2 class="display-4 font-weight-bolder mb-2"> + No commitment required </h2> - <p - class="display-6" - style="margin-bottom: 20px; color: darkgray" - > - Focused on early concepts, these resources are designed to - be accessible to all learners. + <p class="display-6" style="margin-bottom: 20px; color: darkgray"> + Resources will be available to purchase individually without a + subscription. </p> </div> </div> - <div class="display-4 font-weight-bolder my-5"> - <h2 class="display-4 font-weight-bolder mb-2"> - No commitment required - </h2> - <p class="display-6" style="margin-bottom: 20px; color: darkgray"> - Resources will be available to purchase individually without a - subscription. - </p> - </div> - </div> - <div class="row justify-content-center my-5"> - <div class="col-md-4 mb-5 mb-md-0"> - <img - src="{% static 'images/funnel1.png' %}" - class="img-fluid rotated-image" - alt="Funnel 1" - /> - </div> - <div class="col-md-4 mb-5 mb-md-0"> - <img - src="{% static 'images/funnel2.png' %}" - class="img-fluid rotated-image" - alt="Funnel 2" - /> - </div> - <div class="col-md-4 mb-5 mb-md-0"> - <img - src="{% static 'images/funnel3.png' %}" - class="img-fluid rotated-image" - alt="Funnel 3" - /> + <div class="row justify-content-center my-5"> + <div class="col-md-4 mb-5 mb-md-0"> + <img + src="{% static 'images/funnel1.png' %}" + class="img-fluid rotated-image" + alt="Funnel 1" + /> + </div> + <div class="col-md-4 mb-5 mb-md-0"> + <img + src="{% static 'images/funnel2.png' %}" + class="img-fluid rotated-image" + alt="Funnel 2" + /> + </div> + <div class="col-md-4 mb-5 mb-md-0"> + <img + src="{% static 'images/funnel3.png' %}" + class="img-fluid rotated-image" + alt="Funnel 3" + /> + </div> </div> + <p + class="display-6 mb-4 mt-4 p-4 col-12 rounded text-center" + style="color: darkgray" + > + Alphabet Learning is currently in active <br/>development and will be + launched in Spring 2025. + </p> </div> - <p - class="display-6 mb-4 mt-4 p-4 col-12 rounded text-center" - style="color: darkgray" - > - Alphabet Learning is currently in active <br />development and will be - launched in Spring 2025. - </p> -</div> {% endblock content %} |