diff options
author | Matthew Lemon <y@yulqen.org> | 2024-12-04 17:11:55 +0000 |
---|---|---|
committer | Matthew Lemon <y@yulqen.org> | 2024-12-04 17:11:55 +0000 |
commit | 7cd2fd2b75bc5597e9b2a128bf61201910be6df2 (patch) | |
tree | 411c26f821129f196b2a38863a34b05e4e8388e9 | |
parent | 4b21e3889e8337fa5bc9e58cdfc61a9f2019adc9 (diff) |
Email verification
- Associated changes in the .env file now allow us to test the SMTP server config
- Added mine and J's email ad admins
- Grab env variables from the .env file in the local.py file for testing purposes
- Set an expiry of 24hrs for the validation link to work
- Added an HTML version of the verification email
-rw-r--r-- | alphabetlearning/payments/models.py | 7 | ||||
-rw-r--r-- | alphabetlearning/payments/views.py | 51 | ||||
-rw-r--r-- | alphabetlearning/templates/payments/success_email_signup.html | 22 | ||||
-rw-r--r-- | config/settings/base.py | 2 | ||||
-rw-r--r-- | config/settings/local.py | 15 |
5 files changed, 75 insertions, 22 deletions
diff --git a/alphabetlearning/payments/models.py b/alphabetlearning/payments/models.py index ce5c8aa..9ea9de2 100644 --- a/alphabetlearning/payments/models.py +++ b/alphabetlearning/payments/models.py @@ -1,8 +1,10 @@ import uuid +from datetime import timedelta from django.conf import settings from django.core.exceptions import ValidationError from django.db import models +from django.utils import timezone from alphabetlearning.resources.models import Resource @@ -13,6 +15,11 @@ class EmailVerification(models.Model): created_at = models.DateTimeField(auto_now_add=True) is_verified = models.BooleanField(default=False) + @property + def is_expired(self): + expiration_time = timedelta(hours=26) + return timezone.now() - self.created_at > expiration_time + def __str__(self): return f"Email verification for {self.email}" diff --git a/alphabetlearning/payments/views.py b/alphabetlearning/payments/views.py index bf4c3c9..4b6f79f 100644 --- a/alphabetlearning/payments/views.py +++ b/alphabetlearning/payments/views.py @@ -1,7 +1,7 @@ import stripe from django.conf import settings from django.contrib.auth.decorators import login_required -from django.core.mail import send_mail +from django.core.mail import send_mail, mail_admins from django.http import HttpResponse from django.http import HttpResponseBadRequest from django.shortcuts import get_object_or_404 @@ -70,14 +70,27 @@ def email_signup_verification(request): # Send verification email subject = 'Alphabet Learning - Email Verification' - message = f''' - Hello!, + 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> + ''' + message = f''' + Hi!, - You recently requested to sign up to the Alpabet Learning contract list. + You recently requested to sign up to the Alphabet Learning contact list. - Please click the following link to verify your email address: + 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, @@ -89,12 +102,24 @@ def email_signup_verification(request): 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 + ''' + + 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( @@ -102,6 +127,9 @@ def verify_email(request, token): is_verified=False ) + if pending.is_expired: + return render(request, 'payments/verification_failed.html') + # Create the subscriber EmailSignup.objects.create( email=pending.email, @@ -111,7 +139,14 @@ def verify_email(request, token): pending.is_verified = True pending.save() - return render(request, 'payments/verification_success.html') + mail_admins( + subject=f'{pending.email} has just signed up to the Alphabet Learning contact list.', + message=f'{pending.email} has just signed up to the Alphabet Learning contact list. Their verification was successful.\n\n\n' + f'Best regards,\n\nThe Alphabet Learning Server', + fail_silently=False, + ) + + return render(request, 'payments/success_email_signup.html') except EmailVerification.DoesNotExist: return render(request, 'payments/verification_failed.html') diff --git a/alphabetlearning/templates/payments/success_email_signup.html b/alphabetlearning/templates/payments/success_email_signup.html index 5b3b9f7..c033d0a 100644 --- a/alphabetlearning/templates/payments/success_email_signup.html +++ b/alphabetlearning/templates/payments/success_email_signup.html @@ -74,8 +74,8 @@ </h2> <div> <p class="mb-4 fs-5"> - We are very excited to have you {{ email }} join us at Alphabet Learning! - You will be updated before we are due to go live (this is currently estimated to be Spring 2025). + We are very excited to have you {{ email }} join us at Alphabet Learning! + You will be updated before we are due to go live (this is currently estimated to be Spring 2025). Once we are live we will also send you the <strong>FREE</strong> resource credits AND a <strong>50% discount</strong>. As you're an early bird, tell your friends so that they too could benefit from these exclusive offers. </p> @@ -101,7 +101,7 @@ const colors = ['#ff5258', '#ff9d3e', '#ffd850', '#2dc62b', '#197ceb', '#f19de0', '#9472eb', '#24dabc']; const container = document.querySelector('.celebration-container'); const totalLetters = 420; - + function createSpray() { for(let i = 0; i < totalLetters; i++) { setTimeout(() => { @@ -109,21 +109,21 @@ letter.className = 'letter'; letter.textContent = letters[Math.floor(Math.random() * letters.length)]; letter.style.color = colors[Math.floor(Math.random() * colors.length)]; - + // Calculate spray angle (-60 to 60 degrees) const angle = (Math.random() * 120 - 60) * (Math.PI / 180); const speed = 200 + Math.random() * 200; // Random speed for variety - + // Tighter initial spread at the source const initialSpread = Math.random() * 10 - 5; letter.style.left = `calc(50% + ${initialSpread}px)`; - + // Calculate trajectory const duration = 2 + Math.random() * 0.5; // 1-1.5s duration const xVelocity = Math.sin(angle) * speed; const yVelocity = Math.cos(angle) * speed + 200; // Adjusted to ensure letters fall below their source level const gravity = 500; // Pixels per second squared - + // Create custom animation const animation = letter.animate([ { transform: 'translate(0, 0) rotate(0deg)' }, @@ -135,15 +135,15 @@ easing: 'cubic-bezier(0.25, 0.1, 0.25, 1)', fill: 'forwards' }); - + container.appendChild(letter); - + // Remove letter after animation animation.onfinish = () => letter.remove(); }, i * 10); // Stagger creation slightly for more natural look } } - + // Create the spray once createSpray(); } @@ -154,4 +154,4 @@ {% endblock content %} {% block extra_js %} -{% endblock %}
\ No newline at end of file +{% endblock %} diff --git a/config/settings/base.py b/config/settings/base.py index 81e0f82..28e40ed 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -234,7 +234,7 @@ EMAIL_TIMEOUT = 5 # Django Admin URL. ADMIN_URL = "admin/" # https://docs.djangoproject.com/en/dev/ref/settings/#admins -ADMINS = [("""Matthew Lemon""", "y@yulqen.org")] +ADMINS = [("Matthew Lemon", "matt@matthewlemon.com"), ("Joanna Lemon", "joannalemon1@gmail.com")] # https://docs.djangoproject.com/en/dev/ref/settings/#managers MANAGERS = ADMINS # https://cookiecutter-django.readthedocs.io/en/latest/settings.html#other-environment-settings diff --git a/config/settings/local.py b/config/settings/local.py index 155b219..0e4b7e4 100644 --- a/config/settings/local.py +++ b/config/settings/local.py @@ -29,9 +29,20 @@ CACHES = { # EMAIL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#email-host -EMAIL_HOST = env("EMAIL_HOST", default="mailpit") +# EMAIL_HOST = env("EMAIL_HOST", default="mailpit") # https://docs.djangoproject.com/en/dev/ref/settings/#email-port -EMAIL_PORT = 1025 +# EMAIL_PORT = 1025 + +DEFAULT_FROM_EMAIL = env( + "DJANGO_DEFAULT_FROM_EMAIL", + default="alphabetlearning.online <help@alphabetlearning.online>", +) +SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL) +EMAIL_HOST = env('EMAIL_HOST') +EMAIL_PORT = env('EMAIL_PORT') +EMAIL_HOST_USER = env('EMAIL_HOST_USER') +EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD') +EMAIL_USE_TLS = env.bool('EMAIL_USE_TLS', default=True) # WhiteNoise # ------------------------------------------------------------------------------ |