HTML email for new student and lecturer

This commit is contained in:
papi 2024-05-11 22:14:59 +03:00
parent 3d8baebf74
commit c432e57709
9 changed files with 716 additions and 56 deletions

View File

@ -1,8 +1,8 @@
{ {
"editor.formatOnSave": true, "editor.formatOnSave": true,
"[html]": { // "[html]": {
"editor.formatOnSave": false // "editor.formatOnSave": false
}, // },
"liveSassCompile.settings.includeItems": ["/**/static/scss/style.scss"], "liveSassCompile.settings.includeItems": ["/**/static/scss/style.scss"],
"liveSassCompile.settings.formats": [ "liveSassCompile.settings.formats": [
{ {

View File

@ -3,3 +3,12 @@ from django.apps import AppConfig
class AccountsConfig(AppConfig): class AccountsConfig(AppConfig):
name = "accounts" name = "accounts"
def ready(self) -> None:
from django.db.models.signals import post_save
from .models import User
from .signals import post_save_account_receiver
post_save.connect(post_save_account_receiver, sender=User)
return super().ready()

View File

@ -1,6 +1,3 @@
from datetime import datetime
from django.conf import settings
from django import forms from django import forms
from django.db import transaction from django.db import transaction
from django.contrib.auth.forms import ( from django.contrib.auth.forms import (
@ -10,7 +7,6 @@ from django.contrib.auth.forms import (
from django.contrib.auth.forms import PasswordResetForm from django.contrib.auth.forms import PasswordResetForm
from course.models import Program from course.models import Program
from .models import User, Student, Parent, RELATION_SHIP, LEVEL, GENDERS from .models import User, Student, Parent, RELATION_SHIP, LEVEL, GENDERS
from .tasks import send_new_student_email, send_new_lecturer_email
class StaffAddForm(UserCreationForm): class StaffAddForm(UserCreationForm):
@ -118,24 +114,9 @@ class StaffAddForm(UserCreationForm):
user.address = self.cleaned_data.get("address") user.address = self.cleaned_data.get("address")
user.email = self.cleaned_data.get("email") user.email = self.cleaned_data.get("email")
# Generate a username
registration_date = datetime.now().strftime("%Y")
total_lecturers_count = User.objects.filter(is_lecturer=True).count()
generated_username = (
f"{settings.LECTURER_ID_PREFIX}-{registration_date}-{total_lecturers_count}"
)
# Generate a password
generated_password = User.objects.make_random_password()
user.username = generated_username
user.set_password(generated_password)
if commit: if commit:
user.save() user.save()
# Send email with the generated credentials
send_new_lecturer_email.delay(user.pk, generated_password)
return user return user
@ -272,18 +253,6 @@ class StudentAddForm(UserCreationForm):
user.address = self.cleaned_data.get("address") user.address = self.cleaned_data.get("address")
user.email = self.cleaned_data.get("email") user.email = self.cleaned_data.get("email")
# Generate a username based on first and last name and registration date
registration_date = datetime.now().strftime("%Y")
total_students_count = Student.objects.count()
generated_username = (
f"{settings.STUDENT_ID_PREFIX}-{registration_date}-{total_students_count}"
)
# Generate a password
generated_password = User.objects.make_random_password()
user.username = generated_username
user.set_password(generated_password)
if commit: if commit:
user.save() user.save()
Student.objects.create( Student.objects.create(
@ -292,9 +261,6 @@ class StudentAddForm(UserCreationForm):
program=self.cleaned_data.get("program"), program=self.cleaned_data.get("program"),
) )
# Send email with the generated credentials
send_new_student_email.delay(user.pk, generated_password)
return user return user

View File

@ -0,0 +1,24 @@
from .tasks import send_new_student_email, send_new_lecturer_email
from .utils import generate_student_credentials, generate_lecturer_credentials
def post_save_account_receiver(sender, instance=None, created=False, *args, **kwargs):
"""
Send email notification
"""
if created:
if instance.is_student:
username, password = generate_student_credentials()
instance.username = username
instance.set_password(password)
instance.save()
# Send email with the generated credentials
send_new_student_email.delay(instance.pk, password)
if instance.is_lecturer:
username, password = generate_lecturer_credentials()
instance.username = username
instance.set_password(password)
instance.save()
# Send email with the generated credentials
send_new_lecturer_email.delay(instance.pk, password)

View File

@ -1,31 +1,25 @@
import time
from celery import shared_task from celery import shared_task
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.mail import send_mail from core.utils import send_html_email
def send_email(user, subject, msg):
send_mail(
subject,
msg,
settings.EMAIL_FROM_ADDRESS,
[user.email],
fail_silently=False,
)
@shared_task @shared_task
def send_new_student_email(user_pk, password): def send_new_student_email(user_pk, password):
user = get_user_model().objects.get(pk=user_pk) user = get_user_model().objects.get(pk=user_pk)
subject = "Your Dj LMS account credentials" send_html_email(
msg = f"Dear Student {user.first_name},\n\nHere are the login credentials for your DJ LMS account.\n\nYour ID: {user.username}\nYour password: {password}\n\nBe sure to change your password for security." subject="Your Dj LMS account confirmation and credentials",
send_email(user, subject, msg) recipient_list=[user.email],
template="accounts/email/new_student_account_confirmation.html",
context={"user": user, "password": password},
)
@shared_task @shared_task
def send_new_lecturer_email(user_pk, password): def send_new_lecturer_email(user_pk, password):
user = get_user_model().objects.get(pk=user_pk) user = get_user_model().objects.get(pk=user_pk)
subject = "Your Dj LMS account credentials" send_html_email(
msg = f"Dear Lecturer {user.first_name},\n\nHere are the login credentials for your DJ LMS account.\n\nYour ID: {user.username}\nYour password: {password}\n\nBe sure to change your password for security." subject="Your Dj LMS account confirmation and credentials",
send_email(user, subject, msg) recipient_list=[user.email],
template="accounts/email/new_student_account_confirmation.html",
context={"user": user, "password": password},
)

29
accounts/utils.py Normal file
View File

@ -0,0 +1,29 @@
from datetime import datetime
from django.contrib.auth import get_user_model
from django.conf import settings
def generate_password():
return get_user_model().objects.make_random_password()
def generate_student_id():
# Generate a username based on first and last name and registration date
registered_year = datetime.now().strftime("%Y")
students_count = get_user_model().objects.filter(is_student=True).count()
return f"{settings.STUDENT_ID_PREFIX}-{registered_year}-{students_count}"
def generate_lecturer_id():
# Generate a username based on first and last name and registration date
registered_year = datetime.now().strftime("%Y")
lecturers_count = get_user_model().objects.filter(is_lecturer=True).count()
return f"{settings.LECTURER_ID_PREFIX}-{registered_year}-{lecturers_count}"
def generate_student_credentials():
return generate_student_id(), generate_password()
def generate_lecturer_credentials():
return generate_lecturer_id(), generate_password()

32
core/utils.py Normal file
View File

@ -0,0 +1,32 @@
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
def send_email(user, subject, msg):
send_mail(
subject,
msg,
settings.EMAIL_FROM_ADDRESS,
[user.email],
fail_silently=False,
)
def send_html_email(subject, recipient_list, template, context):
"""A function responsible for sending HTML email"""
# Render the HTML template
html_message = render_to_string(template, context)
# Generate plain text version of the email (optional)
plain_message = strip_tags(html_message)
# Send the email
send_mail(
subject,
plain_message,
settings.EMAIL_FROM_ADDRESS,
recipient_list,
html_message=html_message,
)

View File

@ -0,0 +1,303 @@
<!DOCTYPE html>
<html>
<head>
<title>Account Confirmation</title>
<style>
:root {
--padding-base: 0.5rem;
--primary: #4caf50;
--primary-dark: #45a049;
--warning: #ffcb00;
--warning-dark: #edbe02;
--light: #ffffff;
--gmail-primary: #ebf0fb;
--gmail-secondary: #f6f9fd;
--body-color: var(--gmail-primary);
--grey-100: #e9e9e9;
--grey-200: #cfcfcf;
--grey-300: #9d9d9d;
--grey-400: #888888;
--grey-500: #555555;
--dark: #333333;
}
/* Reset default styling */
body,
p,
h1,
h2,
h3
/* h4, */
/* h5, */
/* h6 */ {
margin: 0;
padding: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #012481;
}
h1 {
font-size: 28px;
}
a {
color: #005aeb;
text-decoration: none;
}
p {
font-size: 16px;
margin-bottom: 15px;
color: #46528f;
}
th,
td {
text-align: left;
}
.header {
background-color: #ebf0fb;
border-bottom: 1px solid #cfcfcf;
padding: 0.5rem 2rem;
}
.footer {
padding: 2rem;
text-align: center;
background-color: #333333;
}
.footer p {
margin-bottom: 2px;
font-size: small;
}
.footer p,
.footer a {
color: #fff !important;
}
.container {
width: 600px;
max-width: 600px !important;
margin: 0 auto;
}
.card {
background-color: #fff;
border: 1px solid #cfcfcf;
border-radius: 5px;
overflow: hidden;
}
.card-body {
padding: 1.5rem 2rem;
}
.small {
font-size: small;
}
.mb-5 {
margin-bottom: 2rem;
}
.mb-4 {
margin-bottom: 1.5rem;
}
.mb-3 {
margin-bottom: 1rem;
}
.mb-2 {
margin-bottom: 0.8rem;
}
.mb-1 {
margin-bottom: 0.4rem;
}
.mt-5 {
margin-top: 2rem;
}
.mt-4 {
margin-top: 1.5rem;
}
.mt-3 {
margin-top: 1rem;
}
.mt-2 {
margin-top: 0.8rem;
}
.mt-1 {
margin-top: 0.4rem;
}
.ms-2 {
margin-left: 10px;
}
.ps-1 {
padding-left: 0.5rem;
}
.p-0 {
padding: 0 !important;
}
.py-3 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.py-2 {
padding-top: 0.6rem;
padding-bottom: 0.6rem;
}
.p-5 {
padding: 40px;
}
.px-5 {
padding-left: 40px;
padding-right: 40px;
}
.m-0 {
margin: 0 !important;
}
.fw-400 {
font-weight: 400 !important;
}
.lh-1 {
line-height: 1;
}
.text-muted {
color: rgba(70, 82, 143, 0.5) !important;
}
.divider {
width: 100%;
height: 1px;
border-bottom: 1px solid #cfcfcf;
}
.btn {
display: inline-block;
background-color: #e9e9e9;
color: #333333;
text-decoration: none;
padding: 10px 20px;
border-radius: 3px;
font-weight: bold;
transition: background-color 0.3s ease;
}
.btn-primary {
background-color: #4caf50;
color: #fff !important;
}
.btn-primary:hover {
background-color: #45a049;
}
.btn-warning {
background-color: #ffcb00;
color: #333333 !important;
}
.btn-warning:hover {
background-color: #edbe02;
}
.link {
text-decoration: none;
color: inherit;
}
.uppercase {
text-transform: uppercase;
}
</style>
</head>
<body
style="
font-family: 'Helvetica Neue', Arial, sans-serif;
color: #46528f;
background-color: #ebf0fb;
padding: 20px;
line-height: 1.4;
"
>
<div class="container">
<div class="card">
<div class="header">
<h2 class="text-muted lh-1">Dj LMS</h2>
<p class="small text-muted fw-400 lh-1 m-0">
Your learning management system
</p>
</div>
<div class="card-body">
<h1 class="mb-5">🚀 Confirm your account</h1>
<h4>Dear <b>{{ user.get_full_name }}</b>,</h4>
<p>
A new lecturer account with ID of <b>{user.username}</b> has been
created for you. <br />
You're receiving this e-mail because the Dj-LMS admin has given your
e-mail address to register an account on djlms.com. <br />
</p>
<h5>Login credentials for your DJ LMS account:</h5>
<ul>
<li>ID: {user.username}</li>
<li>Your password: {password}</li>
</ul>
<p>To secure your account be sure to change your password.</p>
<p>
<a
href="http://localhost:3000/auth/confirm-email?key={{ key }}"
class="btn btn-primary"
>Confirm Email and Login</a
>
</p>
<p class="text-muted small">
<mark
>⚠ If you think this email should not come to you, you can simply
ignore it.</mark
>
</p>
</div>
<div class="footer">
<p>Sincerely - djlms team!</p>
<p>
For any inquiries or assistance, please contact our support team:
</p>
<p>Email: <a href="mailto:support@djlms.com">support@djlms.com</a></p>
<p>Phone: <a href="tel:251900000000">+(251) 90-000-0000</a></p>
<p>
&copy; 2023 <a href="djlms.com">djlms.com</a> | All rights reserved.
</p>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,303 @@
<!DOCTYPE html>
<html>
<head>
<title>Account Confirmation</title>
<style>
:root {
--padding-base: 0.5rem;
--primary: #4caf50;
--primary-dark: #45a049;
--warning: #ffcb00;
--warning-dark: #edbe02;
--light: #ffffff;
--gmail-primary: #ebf0fb;
--gmail-secondary: #f6f9fd;
--body-color: var(--gmail-primary);
--grey-100: #e9e9e9;
--grey-200: #cfcfcf;
--grey-300: #9d9d9d;
--grey-400: #888888;
--grey-500: #555555;
--dark: #333333;
}
/* Reset default styling */
body,
p,
h1,
h2,
h3
/* h4, */
/* h5, */
/* h6 */ {
margin: 0;
padding: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #012481;
}
h1 {
font-size: 28px;
}
a {
color: #005aeb;
text-decoration: none;
}
p {
font-size: 16px;
margin-bottom: 15px;
color: #46528f;
}
th,
td {
text-align: left;
}
.header {
background-color: #ebf0fb;
border-bottom: 1px solid #cfcfcf;
padding: 0.5rem 2rem;
}
.footer {
padding: 2rem;
text-align: center;
background-color: #333333;
}
.footer p {
margin-bottom: 2px;
font-size: small;
}
.footer p,
.footer a {
color: #fff !important;
}
.container {
width: 600px;
max-width: 600px !important;
margin: 0 auto;
}
.card {
background-color: #fff;
border: 1px solid #cfcfcf;
border-radius: 5px;
overflow: hidden;
}
.card-body {
padding: 1.5rem 2rem;
}
.small {
font-size: small;
}
.mb-5 {
margin-bottom: 2rem;
}
.mb-4 {
margin-bottom: 1.5rem;
}
.mb-3 {
margin-bottom: 1rem;
}
.mb-2 {
margin-bottom: 0.8rem;
}
.mb-1 {
margin-bottom: 0.4rem;
}
.mt-5 {
margin-top: 2rem;
}
.mt-4 {
margin-top: 1.5rem;
}
.mt-3 {
margin-top: 1rem;
}
.mt-2 {
margin-top: 0.8rem;
}
.mt-1 {
margin-top: 0.4rem;
}
.ms-2 {
margin-left: 10px;
}
.ps-1 {
padding-left: 0.5rem;
}
.p-0 {
padding: 0 !important;
}
.py-3 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.py-2 {
padding-top: 0.6rem;
padding-bottom: 0.6rem;
}
.p-5 {
padding: 40px;
}
.px-5 {
padding-left: 40px;
padding-right: 40px;
}
.m-0 {
margin: 0 !important;
}
.fw-400 {
font-weight: 400 !important;
}
.lh-1 {
line-height: 1;
}
.text-muted {
color: rgba(70, 82, 143, 0.5) !important;
}
.divider {
width: 100%;
height: 1px;
border-bottom: 1px solid #cfcfcf;
}
.btn {
display: inline-block;
background-color: #e9e9e9;
color: #333333;
text-decoration: none;
padding: 10px 20px;
border-radius: 3px;
font-weight: bold;
transition: background-color 0.3s ease;
}
.btn-primary {
background-color: #4caf50;
color: #fff !important;
}
.btn-primary:hover {
background-color: #45a049;
}
.btn-warning {
background-color: #ffcb00;
color: #333333 !important;
}
.btn-warning:hover {
background-color: #edbe02;
}
.link {
text-decoration: none;
color: inherit;
}
.uppercase {
text-transform: uppercase;
}
</style>
</head>
<body
style="
font-family: 'Helvetica Neue', Arial, sans-serif;
color: #46528f;
background-color: #ebf0fb;
padding: 20px;
line-height: 1.4;
"
>
<div class="container">
<div class="card">
<div class="header">
<h2 class="text-muted lh-1">Dj LMS</h2>
<p class="small text-muted fw-400 lh-1 m-0">
Your learning management system
</p>
</div>
<div class="card-body">
<h1 class="mb-5">🚀 Confirm your account</h1>
<h4>Dear <b>{{ user.get_full_name }}</b>,</h4>
<p>
A new student account with ID of <b>{user.username}</b> has been
created for you. <br />
You're receiving this e-mail because the Dj-LMS admin has given your
e-mail address to register an account on djlms.com. <br />
</p>
<h5>Login credentials for your DJ LMS account:</h5>
<ul>
<li>ID: {user.username}</li>
<li>Your password: {password}</li>
</ul>
<p>To secure your account be sure to change your password.</p>
<p>
<a
href="http://localhost:3000/auth/confirm-email?key={{ key }}"
class="btn btn-primary"
>Confirm Email and Login</a
>
</p>
<p class="text-muted small">
<mark
>⚠ If you think this email should not come to you, you can simply
ignore it.</mark
>
</p>
</div>
<div class="footer">
<p>Sincerely - djlms team!</p>
<p>
For any inquiries or assistance, please contact our support team:
</p>
<p>Email: <a href="mailto:support@djlms.com">support@djlms.com</a></p>
<p>Phone: <a href="tel:251900000000">+(251) 90-000-0000</a></p>
<p>
&copy; 2023 <a href="djlms.com">djlms.com</a> | All rights reserved.
</p>
</div>
</div>
</div>
</body>
</html>