Skip to content

Commit 451d74d

Browse files
committed
Adding celery and model to store Email Templates
1 parent 874f521 commit 451d74d

12 files changed

Lines changed: 117 additions & 13 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FROM ubuntu:20.04
22

33
RUN apt-get update -y
4-
RUN apt-get install python3 python3-pip libmysqlclient-dev mysql-client vim -y
4+
RUN apt-get install python3 python3-pip libmysqlclient-dev mysql-client vim sqlite3 -y
55

66
WORKDIR /hackathon-app
77
COPY ./requirements.txt /hackathon-app/requirements.txt

accounts/admin.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
44
from django.contrib.auth.decorators import login_required
55

6-
from .models import CustomUser, Organisation
6+
from .models import CustomUser, Organisation, EmailTemplate
77
from accounts.models import SlackSiteSettings
88

99

@@ -49,8 +49,13 @@ class CustomUserAdmin(BaseUserAdmin):
4949
readonly_fields = ('last_login', 'date_joined', 'user_type')
5050

5151

52+
class EmailTemplateAdmin(admin.ModelAdmin):
53+
list_display = ('display_name', 'subject', 'template_name', 'is_active', )
54+
55+
5256
# sign-in via allauth required before accessing the admin panel
5357
admin.site.login = login_required(admin.site.login)
5458
admin.site.register(CustomUser, CustomUserAdmin)
5559
admin.site.register(Organisation)
5660
admin.site.register(SlackSiteSettings)
61+
admin.site.register(EmailTemplate, EmailTemplateAdmin)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Generated by Django 3.1.13 on 2023-01-04 15:38
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('accounts', '0018_slacksitesettings'),
10+
]
11+
12+
operations = [
13+
migrations.CreateModel(
14+
name='EmailTemplate',
15+
fields=[
16+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
17+
('display_name', models.CharField(max_length=255)),
18+
('description', models.TextField(blank=True, null=True)),
19+
('template_name', models.CharField(max_length=255)),
20+
('subject', models.CharField(max_length=1048)),
21+
('plain_text_message', models.TextField()),
22+
('html_message', models.TextField(blank=True, null=True)),
23+
('is_active', models.BooleanField(default=True)),
24+
],
25+
),
26+
]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 3.1.13 on 2023-01-04 16:55
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('accounts', '0019_emailtemplate'),
10+
]
11+
12+
operations = [
13+
migrations.AlterModelOptions(
14+
name='emailtemplate',
15+
options={'verbose_name': 'Email Template', 'verbose_name_plural': 'Email Templates'},
16+
),
17+
migrations.AlterField(
18+
model_name='emailtemplate',
19+
name='template_name',
20+
field=models.CharField(max_length=255, unique=True),
21+
),
22+
]

accounts/models.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,20 @@ def __str__(self):
210210
class Meta:
211211
verbose_name = 'Slack Site Settings'
212212
verbose_name_plural = 'Slack Site Settings'
213+
214+
215+
class EmailTemplate(models.Model):
216+
display_name = models.CharField(max_length=255)
217+
description = models.TextField(null=True, blank=True)
218+
template_name = models.CharField(max_length=255, unique=True)
219+
subject = models.CharField(max_length=1048)
220+
plain_text_message = models.TextField()
221+
html_message = models.TextField(null=True, blank=True)
222+
is_active = models.BooleanField(default=True)
223+
224+
class Meta:
225+
verbose_name = 'Email Template'
226+
verbose_name_plural = 'Email Templates'
227+
228+
def __str__(self):
229+
return self.display_name

docker-compose.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ services:
3333
- "8000:8000"
3434
tty: true
3535
stdin_open: true
36+
37+
hackathon-worker:
38+
image: hackathon-app
39+
environment:
40+
- ENV_FILE=/hackathon-app/.env
41+
- DEVELOPMENT=1
42+
entrypoint: ["celery", "-A", "main", "worker", "-l", "info"]
43+
volumes:
44+
- ./data/:/hackathon-app/data/
45+
- ./.env:/hackathon-app/.env
3646

3747
mysql:
3848
image: docker.io/mysql:5.6.36
@@ -45,8 +55,12 @@ services:
4555
MYSQL_PASSWORD: gummyball
4656
volumes:
4757
- ./data/mysql:/var/lib/mysql
58+
- ./hackathon/:/hackathon-app/hackathon/
4859

4960
smtp:
5061
image: mailhog/mailhog:v1.0.1
5162
ports:
5263
- "8026:8025"
64+
65+
redis:
66+
image: redis

hackathon/tasks.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from celery import shared_task
55
from django.conf import settings
6+
from django.core.exceptions import ObjectDoesNotExist
67
from django.core.mail import send_mail
78
from smtplib import SMTPException
89

@@ -12,22 +13,22 @@
1213

1314

1415
@shared_task
15-
def send_email_from_template(user, hackathon, template_name):
16+
def send_email_from_template(user_email, user_name, hackathon_display_name, template_name):
1617
try:
17-
template = EmailTemplate.objects.get(template_name=template_name)
18-
user_name = user.first_name or user.email
18+
template = EmailTemplate.objects.get(template_name=template_name, is_active=True)
19+
user_name = user_name or user_email
1920
slack_settings = SlackSiteSettings.objects.first()
2021
if slack_settings and slack_settings.enable_welcome_emails:
2122
send_mail(
22-
subject=template.format(hackathon=hackathon.display_name),
23-
message=template.plain_text_message.format(student=user_name, hackathon=hackathon.display_name),
24-
html_message=template.html_message.format(student=user_name, hackathon=hackathon.display_name),
25-
from_email=slack_settings.from_email,
26-
recipient_list=[user.email],
23+
subject=template.subject.format(hackathon=hackathon_display_name),
24+
message=template.plain_text_message.format(student=user_name, hackathon=hackathon_display_name),
25+
html_message=template.html_message.format(student=user_name, hackathon=hackathon_display_name),
26+
from_email=settings.DEFAULT_FROM_EMAIL,
27+
recipient_list=[user_email],
2728
fail_silently=False,
2829
)
2930
logger.info("Email {template_name} sucessfully sent to user {user.id}.")
30-
except template.DoesNotExist:
31+
except ObjectDoesNotExist:
3132
logger.exception(
3233
(f"There is no template with the name {template_name}."
3334
"Please create it on the Django Admin Panel"))

hackathon/views.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
HackAwardForm, HackTeamForm
1818
from .lists import AWARD_CATEGORIES
1919
from .helpers import format_date, query_scores, create_judges_scores_table
20+
from .tasks import send_email_from_template
2021

2122
from accounts.models import UserType
2223
from accounts.decorators import can_access, has_access_to_hackathon
@@ -416,14 +417,17 @@ def enroll_toggle(request):
416417
id=request.POST.get("hackathon-id"))
417418
if request.user in hackathon.judges.all():
418419
hackathon.judges.remove(request.user)
420+
send_email_from_template.apply_async(args=[request.user.email, request.user.first_name, hackathon.display_name, 'withdraw_judge'])
419421
messages.success(request, "You have withdrawn from judging.")
420422
elif request.user in hackathon.participants.all():
421423
hackathon.participants.remove(request.user)
424+
send_email_from_template.apply_async(args=[request.user.email, request.user.first_name, hackathon.display_name, 'withdraw_participant'])
422425
messages.success(request,
423426
"You have withdrawn from this Hackaton.")
424427
elif (request.POST.get('enrollment-type') == 'judge'
425428
and request.user.user_type in judge_user_types):
426429
hackathon.judges.add(request.user)
430+
send_email_from_template.apply_async(args=[request.user.email, request.user.first_name, hackathon.display_name, 'enroll_judge'])
427431
messages.success(request, "You have enrolled as a facilitator/judge.") # noqa: E501
428432
else:
429433
if hackathon.max_participants_reached():
@@ -432,6 +436,7 @@ def enroll_toggle(request):
432436
return redirect(reverse('hackathon:view_hackathon', kwargs={
433437
'hackathon_id': request.POST.get("hackathon-id")}))
434438
hackathon.participants.add(request.user)
439+
send_email_from_template.apply_async(args=[request.user.email, request.user.first_name, hackathon.display_name, 'enroll_participant'])
435440
messages.success(request, "You have enrolled successfully.")
436441

437442
return redirect(reverse(

main/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .celery import app as celery_app
2+
3+
__all__ = ['celery_app']

main/settings.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"allauth.account",
3737
"allauth.socialaccount",
3838
"crispy_forms",
39+
"django_celery_results",
3940

4041
# custom apps
4142
"accounts",
@@ -100,14 +101,14 @@
100101

101102
EMAIL_BACKEND = os.environ.get(
102103
'EMAIL_BACKEND', 'django.core.mail.backends.console.EmailBackend')
104+
DEFAULT_FROM_EMAIL = (os.environ.get('DEFAULT_FROM_EMAIL')
105+
or os.environ.get("SUPPORT_EMAIL"))
103106
if EMAIL_BACKEND == 'django.core.mail.backends.smtp.EmailBackend':
104107
EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', 'False') == 'True'
105108
EMAIL_PORT = int(os.environ.get('EMAIL_PORT', 25))
106109
EMAIL_HOST = os.environ.get('EMAIL_HOST')
107110
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
108111
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
109-
DEFAULT_FROM_EMAIL = (os.environ.get('DEFAULT_FROM_EMAIL')
110-
or os.environ.get("SUPPORT_EMAIL"))
111112

112113
AUTH_USER_MODEL = "accounts.CustomUser"
113114
ACCOUNT_SIGNUP_FORM_CLASS = "accounts.forms.SignupForm"
@@ -163,6 +164,12 @@
163164
},
164165
]
165166

167+
# Celery
168+
CELERY_BROKER_URL = os.environ.get('CELERY_BROKER', 'redis://redis:6379')
169+
CELERY_RESULT_BACKEND = os.environ.get('CELERY_RESULT_BACKEND', 'redis://redis:6379') # noqa: E501
170+
CELERY_ACCEPT_CONTENT = os.environ.get('CELERY_ACCEPT_CONTENT', 'application/json').split(',') # noqa: E501
171+
CELERY_TASK_SERIALIZER = os.environ.get('CELERY_TASK_SERIALIZER', 'json')
172+
CELERY_RESULT_SERIALIZER = os.environ.get('CELERY_RESULT_SERIALIZER', 'json')
166173

167174
LANGUAGE_CODE = "en-us"
168175
TIME_ZONE = "UTC"

0 commit comments

Comments
 (0)