aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Lemon <y@yulqen.org>2024-12-04 17:11:55 +0000
committerMatthew Lemon <y@yulqen.org>2024-12-04 17:11:55 +0000
commit7cd2fd2b75bc5597e9b2a128bf61201910be6df2 (patch)
tree411c26f821129f196b2a38863a34b05e4e8388e9
parent4b21e3889e8337fa5bc9e58cdfc61a9f2019adc9 (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.py7
-rw-r--r--alphabetlearning/payments/views.py51
-rw-r--r--alphabetlearning/templates/payments/success_email_signup.html22
-rw-r--r--config/settings/base.py2
-rw-r--r--config/settings/local.py15
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
# ------------------------------------------------------------------------------