diff --git a/src/shop/email.py b/src/shop/email.py index 5c22f603..5181050c 100644 --- a/src/shop/email.py +++ b/src/shop/email.py @@ -1,52 +1,8 @@ -from django.core.mail import EmailMultiAlternatives -from django.conf import settings -from django.template.loader import render_to_string +from utils.email import _send_email import logging logger = logging.getLogger("bornhack.%s" % __name__) - -def send_email(emailtype, recipient, formatdict, subject, sender='BornHack ', attachment=None): - ### determine email type, set template and attachment vars - html_template=None - - if emailtype == 'invoice': - text_template = 'emails/invoice_email.txt' - html_template = 'emails/invoice_email.html' - attachment_filename = formatdict['filename'] - elif emailtype == 'creditnote': - text_template = 'emails/creditnote_email.txt' - html_template = 'emails/creditnote_email.html' - attachment_filename = formatdict['creditnote'].filename - elif emailtype == 'testmail': - text_template = 'emails/testmail.txt' - else: - logger.error('Unknown email type: %s' % emailtype) - return False - - try: - ### put the basic email together - msg = EmailMultiAlternatives(subject, render_to_string(text_template, formatdict), sender, [recipient], [settings.ARCHIVE_EMAIL]) - - ### is there a html version of this email? - if html_template: - msg.attach_alternative(render_to_string(html_template, formatdict), 'text/html') - - ### is there a pdf attachment to this mail? - if attachment: - msg.attach(attachment_filename, attachment, 'application/pdf') - - except Exception as E: - logger.exception('exception while rendering email: %s' % E) - return False - - ### send the email - msg.send() - - ### all good - return True - - def send_creditnote_email(creditnote): # put formatdict together formatdict = { @@ -56,15 +12,17 @@ def send_creditnote_email(creditnote): subject = 'BornHack creditnote %s' % creditnote.pk # send mail - return send_email( - emailtype='creditnote', + return _send_email( + text_template='emails/creditnote_email.txt', + html_template='emails/creditnote_email.html', recipient=creditnote.user.email, formatdict=formatdict, subject=subject, - sender='info@bornhack.dk', attachment=creditnote.pdf.read(), + attachment_filename=creditnote.filename ) + def send_invoice_email(invoice): # put formatdict together formatdict = { @@ -76,20 +34,20 @@ def send_invoice_email(invoice): subject = 'BornHack invoice %s' % invoice.pk # send mail - return send_email( - emailtype='invoice', + return _send_email( + text_template='emails/invoice_email.txt', + html_template='emails/invoice_email.html', recipient=invoice.order.user.email, formatdict=formatdict, subject=subject, - sender='info@bornhack.dk', attachment=invoice.pdf.read(), + attachment_filename=invoice.filename ) def send_test_email(recipient): - return send_email( - emailtype='testmail', + return _send_email( + text_template='emails/testmail.txt', recipient=recipient, - subject='testmail from bornhack website', + subject='testmail from bornhack website' ) - diff --git a/src/teams/admin.py b/src/teams/admin.py index 3ffe9b35..67ff70b6 100644 --- a/src/teams/admin.py +++ b/src/teams/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin - from .models import Team, TeamArea, TeamMember +from .email import send_add_membership_email, send_remove_membership_email admin.site.register(TeamArea) @@ -35,11 +35,18 @@ class TeamMemberAdmin(admin.ModelAdmin): def add_member(self, request, queryset): teams_count = queryset.values('team').distinct().count() - rows_updated = queryset.update(approved=True) + updated = 0 + + for membership in queryset: + membership.approved = True + membership.save() + updated += 1 + send_add_membership_email(membership) + self.message_user( request, 'Added {} user(s) to {} team(s).'.format( - rows_updated, + updated, teams_count ) ) @@ -47,11 +54,17 @@ class TeamMemberAdmin(admin.ModelAdmin): def remove_member(self, request, queryset): teams_count = queryset.values('team').distinct().count() - users_removed = queryset.delete()[0] + updated = 0 + + for membership in queryset: + send_remove_membership_email(membership) + membership.delete() + updated += 1 + self.message_user( request, 'Removed {} user(s) from {} team(s).'.format( - users_removed, + updated, teams_count ) ) diff --git a/src/teams/email.py b/src/teams/email.py new file mode 100644 index 00000000..94d408d7 --- /dev/null +++ b/src/teams/email.py @@ -0,0 +1,58 @@ +from utils.email import _send_email +import logging +logger = logging.getLogger("bornhack.%s" % __name__) + + +def send_add_membership_email(membership): + formatdict = { + 'team': membership.team.name, + 'camp': membership.team.camp.title + } + + return _send_email( + text_template='emails/add_membership_email.txt', + html_template='emails/add_membership_email.html', + recipient=membership.user.email, + formatdict=formatdict, + subject='Team update from {}'.format(membership.team.camp.title) + ) + + +def send_remove_membership_email(membership): + formatdict = { + 'team': membership.team.name, + 'camp': membership.team.camp.title + } + + if membership.approved: + text_template = 'emails/remove_membership_email.txt', + html_template = 'emails/remove_membership_email.html' + else: + text_template = 'emails/unapproved_membership_email.txt', + html_template = 'emails/unapproved_membership_email.html' + + return _send_email( + text_template=text_template, + html_template=html_template, + recipient=membership.user.email, + formatdict=formatdict, + subject='Team update from {}'.format(membership.team.camp.title) + ) + + +def send_new_membership_email(membership): + formatdict = { + 'team': membership.team.name, + 'camp': membership.team.camp.title + } + + return _send_email( + text_template='emails/new_membership_email.txt', + html_template='emails/new_membership_email.html', + recipient=membership.user.email, + formatdict=formatdict, + subject='New membership request for {} at {}'.format( + membership.team.name, + membership.team.camp.title + ) + ) diff --git a/src/teams/models.py b/src/teams/models.py index ad28bcf2..fd8aced4 100644 --- a/src/teams/models.py +++ b/src/teams/models.py @@ -1,6 +1,9 @@ from django.db import models +from django.db.models.signals import post_save +from django.dispatch import receiver from django.utils.text import slugify from utils.models import CampRelatedModel +from .email import send_new_membership_email from django.core.exceptions import ValidationError from django.contrib.auth.models import User @@ -13,7 +16,10 @@ class TeamArea(CampRelatedModel): name = models.CharField(max_length=255) description = models.TextField(default='') camp = models.ForeignKey('camps.Camp') - responsible = models.ManyToManyField('auth.User', related_name='responsible_team_areas') + responsible = models.ManyToManyField( + 'auth.User', + related_name='responsible_team_areas' + ) def __str__(self): return '{} ({})'.format(self.name, self.camp) @@ -27,10 +33,18 @@ class Team(CampRelatedModel): name = models.CharField(max_length=255) slug = models.SlugField(max_length=255, blank=True) camp = models.ForeignKey('camps.Camp') - area = models.ForeignKey('teams.TeamArea', related_name='teams', on_delete=models.PROTECT) + area = models.ForeignKey( + 'teams.TeamArea', + related_name='teams', + on_delete=models.PROTECT + ) description = models.TextField() needs_members = models.BooleanField(default=True) - members = models.ManyToManyField('auth.User', related_name='teams', through='teams.TeamMember') + members = models.ManyToManyField( + 'auth.User', + related_name='teams', + through='teams.TeamMember' + ) def __str__(self): return '{} ({})'.format(self.name, self.camp) @@ -61,7 +75,10 @@ class Team(CampRelatedModel): @property def responsible(self): if TeamMember.objects.filter(team=self, responsible=True).exists(): - return User.objects.filter(teammember__team=self, teammember__responsible=True) + return User.objects.filter( + teammember__team=self, + teammember__responsible=True + ) else: return self.area.responsible.all() @@ -73,5 +90,12 @@ class TeamMember(models.Model): responsible = models.BooleanField(default=False) def __str__(self): - return '{} is {} member of team {}'.format(self.user, '' if self.approved else 'an unapproved', self.team) + return '{} is {} member of team {}'.format( + self.user, '' if self.approved else 'an unapproved', self.team + ) + +@receiver(post_save, sender=TeamMember) +def send_responsible_email(sender, instance, created, **kwargs): + if created: + send_new_membership_email(instance) diff --git a/src/teams/templates/emails/add_membership_email.html b/src/teams/templates/emails/add_membership_email.html new file mode 100644 index 00000000..5c416f6d --- /dev/null +++ b/src/teams/templates/emails/add_membership_email.html @@ -0,0 +1,10 @@ +Hello!
+
+You're now a member of the {{ team }} team at {{ camp }}. +
+Thank you for helping out! +
+
+Best regards,
+
+The BornHack Team
diff --git a/src/teams/templates/emails/add_membership_email.txt b/src/teams/templates/emails/add_membership_email.txt new file mode 100644 index 00000000..0835153b --- /dev/null +++ b/src/teams/templates/emails/add_membership_email.txt @@ -0,0 +1,10 @@ +Hello! + +You're now a member of the {{ team }} team at {{ camp }}. + +Thank you for helping out! + + +Best regards, + +The BornHack Team diff --git a/src/teams/templates/emails/new_membership_email.html b/src/teams/templates/emails/new_membership_email.html new file mode 100644 index 00000000..2be0413f --- /dev/null +++ b/src/teams/templates/emails/new_membership_email.html @@ -0,0 +1,8 @@ +Hello!
+
+There's a new membership request for the {{ team }} team at {{ camp }}. +
+
+Best regards,
+
+The BornHack Team
diff --git a/src/teams/templates/emails/new_membership_email.txt b/src/teams/templates/emails/new_membership_email.txt new file mode 100644 index 00000000..2bd9e4d9 --- /dev/null +++ b/src/teams/templates/emails/new_membership_email.txt @@ -0,0 +1,8 @@ +Hello! + +There's a new membership request for the {{ team }} team at {{ camp }}. + + +Best regards, + +The BornHack Team diff --git a/src/teams/templates/emails/remove_membership_email.html b/src/teams/templates/emails/remove_membership_email.html new file mode 100644 index 00000000..23bf0288 --- /dev/null +++ b/src/teams/templates/emails/remove_membership_email.html @@ -0,0 +1,8 @@ +Hello!
+
+You've been removed from the {{ team }} team at {{ camp }}. +
+
+Best regards,
+
+The BornHack Team
diff --git a/src/teams/templates/emails/remove_membership_email.txt b/src/teams/templates/emails/remove_membership_email.txt new file mode 100644 index 00000000..625d2344 --- /dev/null +++ b/src/teams/templates/emails/remove_membership_email.txt @@ -0,0 +1,8 @@ +Hello! + +You've been removed from the {{ team }} team at {{ camp }}. + + +Best regards, + +The BornHack Team diff --git a/src/teams/templates/emails/unapproved_membership_email.html b/src/teams/templates/emails/unapproved_membership_email.html new file mode 100644 index 00000000..521022df --- /dev/null +++ b/src/teams/templates/emails/unapproved_membership_email.html @@ -0,0 +1,8 @@ +Hello!
+
+Your membership of {{ team }} team at {{ camp }} was not approved. +
+
+Best regards,
+
+The BornHack Team
diff --git a/src/teams/templates/emails/unapproved_membership_email.txt b/src/teams/templates/emails/unapproved_membership_email.txt new file mode 100644 index 00000000..e573c258 --- /dev/null +++ b/src/teams/templates/emails/unapproved_membership_email.txt @@ -0,0 +1,8 @@ +Hello! + +Your membership of {{ team }} team at {{ camp }} was not approved. + + +Best regards, + +The BornHack Team diff --git a/src/utils/email.py b/src/utils/email.py new file mode 100644 index 00000000..7ee5af4a --- /dev/null +++ b/src/utils/email.py @@ -0,0 +1,46 @@ +from django.core.mail import EmailMultiAlternatives +from django.conf import settings +from django.template.loader import render_to_string +import logging +logger = logging.getLogger("bornhack.%s" % __name__) + + +def _send_email( + text_template, + recipient, + formatdict, + subject, + html_template=None, + sender='BornHack ', + attachment=None, + attachment_filename=None +): + try: + # put the basic email together + msg = EmailMultiAlternatives( + subject, + render_to_string(text_template, formatdict), + sender, + [recipient], + [settings.ARCHIVE_EMAIL] + ) + + # is there a html version of this email? + if html_template: + msg.attach_alternative( + render_to_string(html_template, formatdict), + 'text/html' + ) + + # is there a pdf attachment to this mail? + if attachment: + msg.attach(attachment_filename, attachment, 'application/pdf') + + except Exception as e: + logger.exception('exception while rendering email: {}'.format(e)) + return False + + # send the email + msg.send() + + return True