diff --git a/Dockerfile b/Dockerfile index b82c4fcd..8dbfdc43 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM ubuntu:20.04 RUN apt-get update -y -RUN apt-get install python3 python3-pip libmysqlclient-dev mysql-client vim -y +RUN apt-get install python3 python3-pip libmysqlclient-dev mysql-client vim sqlite3 -y WORKDIR /hackathon-app COPY ./requirements.txt /hackathon-app/requirements.txt diff --git a/accounts/admin.py b/accounts/admin.py index 574d169f..59bd3dde 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -3,7 +3,7 @@ from django.contrib.auth.forms import UserChangeForm, UserCreationForm from django.contrib.auth.decorators import login_required -from .models import CustomUser, Organisation +from .models import CustomUser, Organisation, EmailTemplate from accounts.models import SlackSiteSettings @@ -49,8 +49,13 @@ class CustomUserAdmin(BaseUserAdmin): readonly_fields = ('last_login', 'date_joined', 'user_type') +class EmailTemplateAdmin(admin.ModelAdmin): + list_display = ('display_name', 'subject', 'template_name', 'is_active', ) + + # sign-in via allauth required before accessing the admin panel admin.site.login = login_required(admin.site.login) admin.site.register(CustomUser, CustomUserAdmin) admin.site.register(Organisation) admin.site.register(SlackSiteSettings) +admin.site.register(EmailTemplate, EmailTemplateAdmin) diff --git a/accounts/migrations/0019_emailtemplate.py b/accounts/migrations/0019_emailtemplate.py new file mode 100644 index 00000000..7620335c --- /dev/null +++ b/accounts/migrations/0019_emailtemplate.py @@ -0,0 +1,26 @@ +# Generated by Django 3.1.13 on 2023-01-04 15:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0018_slacksitesettings'), + ] + + operations = [ + migrations.CreateModel( + name='EmailTemplate', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('display_name', models.CharField(max_length=255)), + ('description', models.TextField(blank=True, null=True)), + ('template_name', models.CharField(max_length=255)), + ('subject', models.CharField(max_length=1048)), + ('plain_text_message', models.TextField()), + ('html_message', models.TextField(blank=True, null=True)), + ('is_active', models.BooleanField(default=True)), + ], + ), + ] diff --git a/accounts/migrations/0020_auto_20230104_1655.py b/accounts/migrations/0020_auto_20230104_1655.py new file mode 100644 index 00000000..cd5e70c7 --- /dev/null +++ b/accounts/migrations/0020_auto_20230104_1655.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1.13 on 2023-01-04 16:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0019_emailtemplate'), + ] + + operations = [ + migrations.AlterModelOptions( + name='emailtemplate', + options={'verbose_name': 'Email Template', 'verbose_name_plural': 'Email Templates'}, + ), + migrations.AlterField( + model_name='emailtemplate', + name='template_name', + field=models.CharField(max_length=255, unique=True), + ), + ] diff --git a/accounts/models.py b/accounts/models.py index 4735770b..970e3f4f 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -210,3 +210,20 @@ def __str__(self): class Meta: verbose_name = 'Slack Site Settings' verbose_name_plural = 'Slack Site Settings' + + +class EmailTemplate(models.Model): + display_name = models.CharField(max_length=255) + description = models.TextField(null=True, blank=True) + template_name = models.CharField(max_length=255, unique=True) + subject = models.CharField(max_length=1048) + plain_text_message = models.TextField() + html_message = models.TextField(null=True, blank=True) + is_active = models.BooleanField(default=True) + + class Meta: + verbose_name = 'Email Template' + verbose_name_plural = 'Email Templates' + + def __str__(self): + return self.display_name diff --git a/docker-compose.yml b/docker-compose.yml index 24f7aea0..e8b5d687 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,6 +33,16 @@ services: - "8000:8000" tty: true stdin_open: true + + hackathon-worker: + image: hackathon-app + environment: + - ENV_FILE=/hackathon-app/.env + - DEVELOPMENT=1 + entrypoint: ["celery", "-A", "main", "worker", "-l", "info"] + volumes: + - ./data/:/hackathon-app/data/ + - ./.env:/hackathon-app/.env mysql: image: docker.io/mysql:5.6.36 @@ -45,8 +55,12 @@ services: MYSQL_PASSWORD: gummyball volumes: - ./data/mysql:/var/lib/mysql + - ./hackathon/:/hackathon-app/hackathon/ smtp: image: mailhog/mailhog:v1.0.1 ports: - "8026:8025" + + redis: + image: redis diff --git a/hackathon/tasks.py b/hackathon/tasks.py new file mode 100644 index 00000000..600d1ea2 --- /dev/null +++ b/hackathon/tasks.py @@ -0,0 +1,36 @@ +import logging +import os + +from celery import shared_task +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from django.core.mail import send_mail +from smtplib import SMTPException + +from accounts.models import EmailTemplate, SlackSiteSettings + +logger = logging.getLogger(__name__) + + +@shared_task +def send_email_from_template(user_email, user_name, hackathon_display_name, template_name): + try: + template = EmailTemplate.objects.get(template_name=template_name, is_active=True) + user_name = user_name or user_email + slack_settings = SlackSiteSettings.objects.first() + if slack_settings and slack_settings.enable_welcome_emails: + send_mail( + subject=template.subject.format(hackathon=hackathon_display_name), + message=template.plain_text_message.format(student=user_name, hackathon=hackathon_display_name), + html_message=template.html_message.format(student=user_name, hackathon=hackathon_display_name), + from_email=settings.DEFAULT_FROM_EMAIL, + recipient_list=[user_email], + fail_silently=False, + ) + logger.info("Email {template_name} sucessfully sent to user {user.id}.") + except ObjectDoesNotExist: + logger.exception( + (f"There is no template with the name {template_name}." + "Please create it on the Django Admin Panel")) + except SMTPException: + logger.exception("There was an issue sending the email.") diff --git a/hackathon/templates/hackathon/enrolment_email.txt b/hackathon/templates/hackathon/enrolment_email.txt new file mode 100644 index 00000000..6ec62ba7 --- /dev/null +++ b/hackathon/templates/hackathon/enrolment_email.txt @@ -0,0 +1,36 @@ +
Hi {student},
+ +Thank you so much for registering for the {hackathon}!
+ +
+ What does participation involve?
+ You'll be assigned to a team, and work together building a project based on the assigned theme in a limited number of days. Don't worry if you have limited coding experience, all levels are welcome, and we encourage alumni to participate!
+
+ What am I committing to?
+ We recommend at bare minimum you dedicate a minimum of 8-10 hours over the duration of the Hackathon. You will be expected to actively contribute to your team, not just observe.
+ Please check your calendar and confirm that you are available before registering, as dropping out really lets your team down, and the team will be one person fewer.
+
+ IMPORTANT!
+ Please ensure your Profile is up to date, especially the 'Latest Module' entry. This is vital for the team selection process. We try our best to balance the teams fairly, so it really helps you and your team to be accurate with your profile.
+
+ Register for the Intro Webinar!
+ Please check the #hackathon channel for details on how to register for the intro and project presentations webinar.
+
+ Need Help?
+ Please ask any questions in the #hackathon channel, the HackTeam are ready and happy to help out. You can ask them a question by using the @hackteam tag on slack.
+
Thanks again for signing up, we are excited to see what you and your team will create! Remember, hackathons are about team-building, learning and most importantly having fun. + +
+ Happy Hacking!
+ The Code Institute Community Team
+