From 8ab751e2ae9cd4ade40f466c8ae55af6e4d8ffcd Mon Sep 17 00:00:00 2001 From: papi Date: Sun, 5 May 2024 16:53:10 +0300 Subject: [PATCH] Using celery workers to handle email sending --- .gitignore | 3 +++ README.md | 13 +++++++++++++ accounts/forms.py | 18 +++--------------- accounts/tasks.py | 31 +++++++++++++++++++++++++++++++ config/__init__.py | 5 +++++ config/celery.py | 22 ++++++++++++++++++++++ config/settings.py | 12 ++++++++++++ requirements/base.txt | 5 +++++ 8 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 accounts/tasks.py create mode 100644 config/celery.py diff --git a/.gitignore b/.gitignore index 47a6826..d71554a 100644 --- a/.gitignore +++ b/.gitignore @@ -146,3 +146,6 @@ media/registration_form/* !media/result_sheet/ media/result_sheet/* !media/result_sheet/README.txt + +# Custom +dump.rdb \ No newline at end of file diff --git a/README.md b/README.md index db67e24..b43dabe 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ If you would like to contribute, simply begin by implementing one from the list - [Python3.8+](https://www.python.org/downloads/) - [PostgreSQL database](https://www.postgresql.org/download/) +- [Redis](https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/) # Installation @@ -97,6 +98,18 @@ python manage.py createsuperuser python manage.py runserver ``` +Make sure your Redis server is running + +```bash +redis-server +``` + +Start the celery worker + +```bash +celery -A config.celery worker -l INFO +``` + Last but not least, go to this address http://127.0.0.1:8000 ### References diff --git a/accounts/forms.py b/accounts/forms.py index 6cbdaec..8ec182c 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -1,7 +1,6 @@ from datetime import datetime from django.conf import settings -from django.core.mail import send_mail from django import forms from django.db import transaction from django.contrib.auth.forms import ( @@ -11,6 +10,7 @@ from django.contrib.auth.forms import ( from django.contrib.auth.forms import PasswordResetForm from course.models import Program from .models import User, Student, Parent, RELATION_SHIP, LEVEL, GENDERS +from .tasks import send_new_student_email, send_new_lecturer_email class StaffAddForm(UserCreationForm): @@ -134,13 +134,7 @@ class StaffAddForm(UserCreationForm): user.save() # Send email with the generated credentials - send_mail( - "Your Django LMS account credentials", - f"Your username: {generated_username}\nYour password: {generated_password}", - "from@example.com", - [user.email], - fail_silently=False, - ) + send_new_lecturer_email.delay(user.pk, generated_password) return user @@ -299,13 +293,7 @@ class StudentAddForm(UserCreationForm): ) # Send email with the generated credentials - send_mail( - "Your Django LMS account credentials", - f"Your ID: {generated_username}\nYour password: {generated_password}", - settings.EMAIL_FROM_ADDRESS, - [user.email], - fail_silently=False, - ) + send_new_student_email.delay(user.pk, generated_password) return user diff --git a/accounts/tasks.py b/accounts/tasks.py new file mode 100644 index 0000000..206599f --- /dev/null +++ b/accounts/tasks.py @@ -0,0 +1,31 @@ +import time +from celery import shared_task +from django.conf import settings +from django.contrib.auth import get_user_model +from django.core.mail import send_mail + + +def send_email(user, subject, msg): + send_mail( + subject, + msg, + settings.EMAIL_FROM_ADDRESS, + [user.email], + fail_silently=False, + ) + + +@shared_task +def send_new_student_email(user_pk, password): + user = get_user_model().objects.get(pk=user_pk) + subject = "Your Dj LMS account credentials" + 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." + send_email(user, subject, msg) + + +@shared_task +def send_new_lecturer_email(user_pk, password): + user = get_user_model().objects.get(pk=user_pk) + subject = "Your Dj LMS account credentials" + 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." + send_email(user, subject, msg) diff --git a/config/__init__.py b/config/__init__.py index e69de29..5568b6d 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -0,0 +1,5 @@ +# This will make sure the app is always imported when +# Django starts so that shared_task will use this app. +from .celery import app as celery_app + +__all__ = ("celery_app",) diff --git a/config/celery.py b/config/celery.py new file mode 100644 index 0000000..f03d052 --- /dev/null +++ b/config/celery.py @@ -0,0 +1,22 @@ +import os + +from celery import Celery + +# Set the default Django settings module for the 'celery' program. +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") + +app = Celery("config") + +# Using a string here means the worker doesn't have to serialize +# the configuration object to child processes. +# - namespace='CELERY' means all celery-related configuration keys +# should have a `CELERY_` prefix. +app.config_from_object("django.conf:settings", namespace="CELERY") + +# Load task modules from all registered Django apps. +app.autodiscover_tasks() + + +@app.task(bind=True, ignore_result=True) +def debug_task(self): + print(f"Request: {self.request!r}") diff --git a/config/settings.py b/config/settings.py index 97a88e6..d9df0c7 100644 --- a/config/settings.py +++ b/config/settings.py @@ -251,3 +251,15 @@ STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" STUDENT_ID_PREFIX = config("STUDENT_ID_PREFIX", "ugr") LECTURER_ID_PREFIX = config("LECTURER_ID_PREFIX", "lec") + +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.redis.RedisCache", + "LOCATION": "redis://127.0.0.1:6379", + } +} + +# celery setting. +CELERY_BROKER_URL = "redis://localhost:6379/0" +CELERY_CACHE_BACKEND = "default" +CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True diff --git a/requirements/base.txt b/requirements/base.txt index 4aec2f0..39716a3 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -24,6 +24,11 @@ django-jet-reboot==1.3.5 # Environment variable python-decouple==3.8 +# Celery/redis +celery==5.4.0 +redis==5.0.4 +hiredis==2.3.2 + # Payments stripe==5.5.0 gopay==2.0.1