Skip to content

Commit

Permalink
feat(backend): add sending login credentials email (#64)
Browse files Browse the repository at this point in the history
* feat(backend): add sending login credentials email

* feat(backend): add retry policy on sending emails
  • Loading branch information
Adibov authored Dec 5, 2023
1 parent 7ca9504 commit 331d7d3
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 58 deletions.
4 changes: 3 additions & 1 deletion backend/aaiss_backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,6 @@
PAYWALL = env.str("PAYWALL", "ZIFY")

#ZIFY
ZIFY_AUTH = env.str("ZIFY_AUTH", "")
ZIFY_AUTH = env.str("ZIFY_AUTH", "")

SKYROOM_URL = env.str("SKYROOM_URL", "https://www.skyroom.online/ch/aut_ceit_ssc/aaiss")
97 changes: 42 additions & 55 deletions backend/backend_api/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django import forms
from django.contrib import admin
from django.template.loader import render_to_string

from aaiss_backend.settings import SKYROOM_URL
from backend_api import models
from backend_api.email import MailerThread
from backend_api.models import Discount, Presentation, PresentationParticipation, WorkshopRegistration
Expand Down Expand Up @@ -37,52 +39,6 @@ class UserAdmin(admin.ModelAdmin):
list_display = ('account',)


class MailerForm(forms.ModelForm):
HTML_body = forms.CharField(widget=forms.Textarea)

class Meta:
model = models.Mailer
fields = '__all__'


class MailerAdmin(admin.ModelAdmin):
model = models.Mailer
form = MailerForm

def execute_mailer(self, request, obj):
for mailer in obj:
if mailer.target_mode == 1:
targets = models.User.objects.all()
mails = []
for target in targets:
mails.append(target.account.email)
MailerThread(mailer.subject, mails, mailer.HTML_body).start()
elif mailer.target_mode == 2:
mails = []
for workshop in mailer.workshop_selection.all():
for user in models.User.objects.all():
if workshop in user.registered_workshops.all():
if __name__ == '__main__':
mails.append(user.account.email)
MailerThread(mailer.subject, mails, mailer.HTML_body).start()
elif mailer.target_mode == 3:
mails = []
for user in models.User.objects.all():
if user.registered_for_presentations:
mails.append(user.account.email)
MailerThread(mailer.subject, mails, mailer.HTML_body).start()
elif mailer.target_mode == 4:
targets = mailer.user_selection.all()
mails = []
for target in targets:
mails.append(target.account.email)
MailerThread(mailer.subject, mails, mailer.HTML_body).start()

execute_mailer.short_description = 'Send selected mails'
execute_mailer.allow_tags = True
actions = ['execute_mailer']


class DiscountAdmin(admin.ModelAdmin):
list_display = ('__str__', 'is_active', 'discount_percent', 'capacity', 'remaining_capacity', 'expiration_date')
readonly_fields = ('participants',)
Expand Down Expand Up @@ -113,7 +69,7 @@ class Meta:
class PresentationAdmin(admin.ModelAdmin):
list_display = ('__str__', 'level', 'no_of_participants', 'year')
readonly_fields = ('participants',)
actions = ['export_login_credentials']
actions = ['export_login_credentials', 'send_registration_emails']

class Meta:
model = Presentation
Expand All @@ -123,18 +79,34 @@ class Meta:
def export_login_credentials(self, request, obj):
user_credentials: list[SkyroomCredentials] = []
for presentation in obj:
for presentation_registration in presentation.presentationparticipation_set.filter(
for registration in presentation.presentationparticipation_set.filter(
status=PresentationParticipation.StatusChoices.PURCHASED):
user_credentials.append(
SkyroomCredentials(presentation_registration.username, presentation_registration.password,
presentation_registration.user.account.email))
SkyroomCredentials(registration.username, registration.password,
registration.user.account.email))
return convert_credentials_to_csv_response(user_credentials)

@admin.action(description='Send registration emails')
def send_registration_emails(self, request, obj):
for presentation in obj:
for registration in presentation.presentationparticipation_set.filter(
status=PresentationParticipation.StatusChoices.PURCHASED):
MailerThread(f"AAISS login credentials for {presentation.name}",
[registration.user.account.email],
render_to_string('login_credentials.html',
{
'username': registration.username,
'password': registration.password,
'meeting_url': SKYROOM_URL,
'meeting_type': 'presentation',
'meeting_title': presentation.name,
})).start()


class WorkshopAdmin(admin.ModelAdmin):
list_display = ('__str__', 'capacity', 'cost', 'has_project', 'level', 'no_of_participants', 'year')
readonly_fields = ('participants',)
actions = ['export_login_credentials']
actions = ['export_login_credentials', 'send_registration_emails']

class Meta:
model = models.Workshop
Expand All @@ -144,13 +116,29 @@ class Meta:
def export_login_credentials(self, request, obj):
user_credentials: list[SkyroomCredentials] = []
for workshop in obj:
for workshop_registration in workshop.workshopregistration_set.filter(
for registration in workshop.workshopregistration_set.filter(
status=WorkshopRegistration.StatusChoices.PURCHASED):
user_credentials.append(
SkyroomCredentials(workshop_registration.username, workshop_registration.password,
workshop_registration.user.account.email))
SkyroomCredentials(registration.username, registration.password,
registration.user.account.email))
return convert_credentials_to_csv_response(user_credentials)

@admin.action(description='Send registration emails')
def send_registration_emails(self, request, obj):
for workshop in obj:
for registration in workshop.workshopregistration_set.filter(
status=WorkshopRegistration.StatusChoices.PURCHASED):
MailerThread(f"AAISS login credentials for {workshop.name}",
[registration.user.account.email],
render_to_string('login_credentials.html',
{
'username': registration.username,
'password': registration.password,
'meeting_url': SKYROOM_URL,
'meeting_type': 'workshop',
'meeting_title': workshop.name,
})).start()


class MiscAdmin(admin.ModelAdmin):
list_display = ('__str__', 'year')
Expand All @@ -163,7 +151,6 @@ class Meta:
admin.site.register(models.Teacher, TeacherAdmin)
admin.site.register(models.Presenter, PresenterAdmin)
admin.site.register(models.User, UserAdmin)
admin.site.register(models.Mailer, MailerAdmin)
admin.site.register(models.Discount, DiscountAdmin)
admin.site.register(models.Payment, PaymentAdmin)
admin.site.register(models.WorkshopRegistration)
Expand Down
16 changes: 15 additions & 1 deletion backend/backend_api/email.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import threading
from time import sleep

from django.conf import settings
from django.core.mail import EmailMessage
Expand All @@ -8,6 +9,9 @@


class MailerThread(threading.Thread):
_MAXIMUM_RETRIES = 5
_SLEEP_INTERVAL_SECONDS = 5

def __init__(self, subject: str, targets: list[str], html_body: str):
self.subject = subject
self.targets = targets
Expand All @@ -28,7 +32,17 @@ def run(self):
)
email.content_subtype = "html"
if ENABLE_SENDING_EMAIL:
email.send(fail_silently=False)
has_send = False
for i in range(self._MAXIMUM_RETRIES):
try:
email.send(fail_silently=True)
has_send = True
break
except Exception as e:
print(f"Exception raised while sending email: {e}")
sleep(self._SLEEP_INTERVAL_SECONDS)
if not has_send:
print(f"Failed to send email to {self.targets} after {self._MAXIMUM_RETRIES} retries")
else:
print(f"Sent the following email (change ENABLE_SENDING_EMAIL to True to actually send the email):")
print(f"To: {email.bcc}\nSubject: {email.subject}\n\nBody: {email.body}\n\n")
Expand Down
1 change: 0 additions & 1 deletion backend/backend_api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ def __str__(self):
name = ""
for presenter in self.presenters.all():
name += presenter.name + " "
print(name)
return f"{name}: {self.name}"


Expand Down
17 changes: 17 additions & 0 deletions backend/templates/html/login_credentials.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AAISS 2023 Login Credentials</title>
</head>
<body>
<div>You've registered to <b>{{ meeting_title }}</b>, to enter the {{ meeting_type }} use the following credentials:
</div>

<br>
<a href="{{ meeting_url }}">Meeting link</a>
<br>
<div>Username: <b>{{ username }}</b></div>
<div>Password: <b>{{ password }}</b></div>
</body>
</html>

0 comments on commit 331d7d3

Please sign in to comment.