From dffc1d65e6c935d8b9642c40256be03c240d5a40 Mon Sep 17 00:00:00 2001
From: Jorran de Wit <jorrandewit@outlook.com>
Date: Tue, 20 Feb 2018 21:00:03 +0100
Subject: [PATCH] Fix mail mixins

---
 invitations/mixins.py | 46 +++++++++++++++++++++++++++++--------------
 invitations/views.py  |  4 ++--
 mails/forms.py        |  7 +++++--
 mails/mixins.py       | 13 ++++++++++--
 4 files changed, 49 insertions(+), 21 deletions(-)

diff --git a/invitations/mixins.py b/invitations/mixins.py
index 8635746bd..5ae863900 100644
--- a/invitations/mixins.py
+++ b/invitations/mixins.py
@@ -17,12 +17,40 @@ class PermissionsMixin(LoginRequiredMixin, PermissionRequiredMixin):
     pass
 
 
-class SaveAndSendFormMixin:
+class BaseFormViewMixin:
+    send_mail = None
+
+    @transaction.atomic
+    def form_valid(self, form):
+        # Communication with the user.
+        model_name = self.object._meta.verbose_name
+        model_name = model_name[:1].upper() + model_name[1:]  # Hack it to capitalize the name
+        if self.send_mail:
+            self.object.mail_sent()
+            messages.success(self.request, '{} updated and sent'.format(model_name))
+        else:
+            messages.success(self.request, '{} updated'.format(model_name))
+        return super().form_valid(form)
+
+
+class SendMailFormMixin(BaseFormViewMixin):
     """
-    Use the Save or Save and Send option to send the mail out after form is valid.
+    Send mail out if form is valid.
     """
-    send_mail = None
+    def post(self, request, *args, **kwargs):
+        # Intercept the specific submit value before validation the form so `MailEditorMixin`
+        # can use this data.
+        if self.send_mail is None:
+            # Communicate with the `MailEditorMixin` whether the mails should go out or not.
+            self.send_mail = request.user.has_perm('scipost.can_manage_registration_invitations')
+            self.has_permission_to_send_mail = self.send_mail
+        return super().post(request, *args, **kwargs)
 
+
+class SaveAndSendFormMixin(BaseFormViewMixin):
+    """
+    Use the Save or Save and Send option to send the mail out after form is valid.
+    """
     def post(self, request, *args, **kwargs):
         # Intercept the specific submit value before validation the form so `MailEditorMixin`
         # can use this data.
@@ -34,15 +62,3 @@ class SaveAndSendFormMixin:
         # Communicate with the `MailEditorMixin` whether the mails should go out or not.
         self.has_permission_to_send_mail = self.send_mail
         return super().post(request, *args, **kwargs)
-
-    @transaction.atomic
-    def form_valid(self, form):
-        # Communication with the user.
-        model_name = self.object._meta.verbose_name
-        model_name = model_name[:1].upper() + model_name[1:]  # Hack it to capitalize the name
-        if self.send_mail:
-            self.object.mail_sent()
-            messages.success(self.request, '{} updated and sent'.format(model_name))
-        else:
-            messages.success(self.request, '{} updated'.format(model_name))
-        return super().form_valid(form)
diff --git a/invitations/views.py b/invitations/views.py
index 2dca81c25..6525ca66b 100644
--- a/invitations/views.py
+++ b/invitations/views.py
@@ -10,7 +10,7 @@ from .forms import RegistrationInvitationForm, RegistrationInvitationReminderFor
     RegistrationInvitationMarkForm, RegistrationInvitationMapToContributorForm,\
     CitationNotificationForm, SuggestionSearchForm, RegistrationInvitationFilterForm,\
     CitationNotificationProcessForm, RegistrationInvitationAddCitationForm
-from .mixins import RequestArgumentMixin, PermissionsMixin, SaveAndSendFormMixin
+from .mixins import RequestArgumentMixin, PermissionsMixin, SaveAndSendFormMixin, SendMailFormMixin
 from .models import RegistrationInvitation, CitationNotification
 
 from scipost.models import Contributor
@@ -172,7 +172,7 @@ class RegistrationInvitationsMapToContributorView(RequestArgumentMixin, Permissi
 
 
 class RegistrationInvitationsReminderView(RequestArgumentMixin, PermissionsMixin,
-                                          SaveAndSendFormMixin, MailEditorMixin, UpdateView):
+                                          SendMailFormMixin, MailEditorMixin, UpdateView):
     permission_required = 'scipost.can_manage_registration_invitations'
     queryset = RegistrationInvitation.objects.sent()
     success_url = reverse_lazy('invitations:list')
diff --git a/mails/forms.py b/mails/forms.py
index b69d0d037..d7c76199e 100644
--- a/mails/forms.py
+++ b/mails/forms.py
@@ -11,8 +11,10 @@ class EmailTemplateForm(forms.Form, MailUtilsMixin):
     prefix = 'mail_form'
 
     def __init__(self, *args, **kwargs):
+        self.pre_validation(*args, **kwargs)
+
         # This form shouldn't be is_bound==True is there is any non-relavant POST data given.
-        data = args[0]
+        data = args[0] or {}
         if '%s-subject' % self.prefix in data.keys():
             data = {
                 '%s-subject' % self.prefix: data.get('%s-subject' % self.prefix),
@@ -21,7 +23,7 @@ class EmailTemplateForm(forms.Form, MailUtilsMixin):
             }
         else:
             data = None
-        super().__init__(data, *args, **kwargs)
+        super().__init__(data or None)
 
         if not self.original_recipient:
             self.fields['extra_recipient'].label = "Send this email to"
@@ -36,6 +38,7 @@ class EmailTemplateForm(forms.Form, MailUtilsMixin):
         self.html_message = self.cleaned_data['text']
         self.subject = self.cleaned_data['subject']
         self.validate_message()
+        self.validate_bcc_list()
 
         # Get recipients list. Try to send through BCC to prevent privacy issues!
         if self.cleaned_data.get('extra_recipient') and self.original_recipient:
diff --git a/mails/mixins.py b/mails/mixins.py
index 029097f24..444510c4a 100644
--- a/mails/mixins.py
+++ b/mails/mixins.py
@@ -87,8 +87,16 @@ class MailUtilsMixin:
     mail_template = ''
     html_message = ''
     message = ''
+    original_recipient = ''
 
     def __init__(self, *args, **kwargs):
+        self.pre_validation(*args, **kwargs)
+        super().__init__(*args)
+
+    def pre_validation(self, *args, **kwargs):
+        """
+        This method should be called when initiating the object.
+        """
         self.mail_code = kwargs.pop('mail_code')
         self.instance = kwargs.pop('instance', None)
 
@@ -122,8 +130,7 @@ class MailUtilsMixin:
 
         self.subject = self.mail_data['subject']
 
-
-    def validate_recipients(self):
+    def validate_bcc_list(self):
         # Get recipients list. Try to send through BCC to prevent privacy issues!
         self.bcc_list = []
         if self.mail_data.get('bcc_to', False) and self.object:
@@ -141,6 +148,7 @@ class MailUtilsMixin:
         elif re.match("[^@]+@[^@]+\.[^@]+", self.mail_data.get('bcc_to', '')):
             self.bcc_list = [self.mail_data.get('bcc_to')]
 
+    def validate_recipients(self):
         # Check the send list
         if isinstance(self.original_recipient, list):
             recipients = self.original_recipient
@@ -177,6 +185,7 @@ class MailUtilsMixin:
         Only to be used when the default data is used, eg. not in the EmailTemplateForm.
         """
         self.validate_message()
+        self.validate_bcc_list()
         self.validate_recipients()
         self.save_mail_data()
 
-- 
GitLab