From 8294cf1dd3cd212fa754d986abc254a5c7c8792c Mon Sep 17 00:00:00 2001 From: Jorran de Wit <jorrandewit@outlook.com> Date: Tue, 10 Oct 2017 16:47:35 +0200 Subject: [PATCH] Add followup email + editable emails --- mails/forms.py | 55 +++++++++++++----- .../partners_followup_mail.json | 7 +++ .../mail_templates/partners_followup_mail.txt | 17 ++++++ .../mail_templates/partners_initial_mail.json | 7 +++ .../mail_templates/partners_initial_mail.txt | 31 ++++++++++ mails/views.py | 4 ++ partners/forms.py | 20 ------- .../partners/_prospective_partner_card.html | 12 +++- partners/urls.py | 4 ++ partners/views.py | 58 ++++++++++--------- 10 files changed, 150 insertions(+), 65 deletions(-) create mode 100644 mails/templates/mail_templates/partners_followup_mail.json create mode 100644 mails/templates/mail_templates/partners_followup_mail.txt create mode 100644 mails/templates/mail_templates/partners_initial_mail.json create mode 100644 mails/templates/mail_templates/partners_initial_mail.txt diff --git a/mails/forms.py b/mails/forms.py index 9e8b9fbeb..a034d1a75 100644 --- a/mails/forms.py +++ b/mails/forms.py @@ -17,6 +17,7 @@ class EmailTemplateForm(forms.Form): def __init__(self, *args, **kwargs): self.mail_code = kwargs.pop('mail_code') + self.mail_fields = None super().__init__(*args) # Gather data @@ -27,19 +28,25 @@ class EmailTemplateForm(forms.Form): self.mail_data = json.loads(open(json_location).read()) # Object - self.object = kwargs.get(self.mail_data.get('context_object')) - recipient = self.object - for attr in self.mail_data.get('to_address').split('.'): - recipient = getattr(recipient, attr) - if inspect.ismethod(recipient): - recipient = recipient() - self.recipient = recipient + self.object = kwargs.get(self.mail_data.get('context_object', ''), None) + self.recipient = None + if self.object: + recipient = self.object + for attr in self.mail_data.get('to_address').split('.'): + recipient = getattr(recipient, attr) + if inspect.ismethod(recipient): + recipient = recipient() + self.recipient = recipient + + if not self.recipient: + self.fields['extra_recipient'].label = "Send this email to" + self.fields['extra_recipient'].required = True # Set the data as initials self.fields['text'].initial = self.mail_template self.fields['subject'].initial = self.mail_data['subject'] - def send(self): + def save_data(self): # Get text and html message = self.cleaned_data['text'] html_template = loader.get_template('email/general.html') @@ -47,7 +54,7 @@ class EmailTemplateForm(forms.Form): # Get recipients list. Try to send through BCC to prevent privacy issues! bcc_list = [] - if self.mail_data.get('bcc_to'): + if self.mail_data.get('bcc_to') and self.object: bcc_to = self.object for attr in self.mail_data.get('bcc_to').split('.'): bcc_to = getattr(bcc_to, attr) @@ -57,8 +64,12 @@ class EmailTemplateForm(forms.Form): else: bcc_list = bcc_to - if self.cleaned_data.get('extra_recipient'): + if self.cleaned_data.get('extra_recipient') and self.recipient: bcc_list.append(self.cleaned_data.get('extra_recipient')) + elif self.cleaned_data.get('extra_recipient') and not self.recipient: + self.recipient = [self.cleaned_data.get('extra_recipient')] + elif not self.recipient: + self.add_error('extra_recipient', 'Please fill the bcc field to send the mail.') # Check the send list if isinstance(self.recipient, list): @@ -82,14 +93,28 @@ class EmailTemplateForm(forms.Form): elif isinstance(recipient, str): _recipients.append(recipient) + self.mail_fields = { + 'subject': self.cleaned_data['subject'], + 'message': message, + 'html_message': html_message, + 'recipients': _recipients, + 'bcc_list': bcc_list, + } + + def clean(self): + data = super().clean() + self.save_data() + return data + + def send(self): # Send the mail email = EmailMultiAlternatives( - self.cleaned_data['subject'], - message, + self.mail_fields['subject'], + self.mail_fields['message'], '%s <%s>' % (self.mail_data.get('from_address_name', 'SciPost'), self.mail_data.get('from_address', 'no-reply@scipost.org')), # From - _recipients, # To - bcc=bcc_list, + self.mail_fields['recipients'], # To + bcc=self.mail_fields['bcc_list'], reply_to=[self.mail_data.get('from_address', 'no-reply@scipost.org')]) - email.attach_alternative(html_message, 'text/html') + email.attach_alternative(self.mail_fields['html_message'], 'text/html') email.send(fail_silently=False) diff --git a/mails/templates/mail_templates/partners_followup_mail.json b/mails/templates/mail_templates/partners_followup_mail.json new file mode 100644 index 000000000..efb95bbc8 --- /dev/null +++ b/mails/templates/mail_templates/partners_followup_mail.json @@ -0,0 +1,7 @@ +{ + "subject": "SciPost: Supporting Partners Board", + "to_address": "email", + "from_address_name": "SciPost Supporting Partners", + "from_address": "partners@scipost.org", + "context_object": "contact" +} diff --git a/mails/templates/mail_templates/partners_followup_mail.txt b/mails/templates/mail_templates/partners_followup_mail.txt new file mode 100644 index 000000000..136e2d335 --- /dev/null +++ b/mails/templates/mail_templates/partners_followup_mail.txt @@ -0,0 +1,17 @@ +Dear {{ contact.get_title_display }} {{ contact.last_name }}, + +Recently we contacted you about the SciPost Supporting Partners Board. We would like to know if you and your institution are interested in joining the Supporting Partners Board. + +It is greatly appreciated if you could take a few minutes to read through this document and let us know whether your institution would consider joining. + +It would be a privilege to welcome you as members of our Supporting Partners Board. Support takes the form of a small financial commitment, collectively pooled to enable SciPost to perform all its publication-related activities, maintain its online portal and implement its long-term development plan. + +Your support at this time is crucially required to make our initiative sustainable, and to help make it possible for the community to reap all the benefits deriving form its viable implementation. + +I will be happy to provide any required further details. If you are interested, you can simply get in touch via this address (partners@scipost.org). I sincerely hope that SciPost will be able to count on your support. + +If you not the right person in your organization to contact about this topic, please let us know. + +On behalf of the SciPost Foundation, +Prof. dr Jean-Sébastien Caux +J.S.Caux@uva.nl diff --git a/mails/templates/mail_templates/partners_initial_mail.json b/mails/templates/mail_templates/partners_initial_mail.json new file mode 100644 index 000000000..efb95bbc8 --- /dev/null +++ b/mails/templates/mail_templates/partners_initial_mail.json @@ -0,0 +1,7 @@ +{ + "subject": "SciPost: Supporting Partners Board", + "to_address": "email", + "from_address_name": "SciPost Supporting Partners", + "from_address": "partners@scipost.org", + "context_object": "contact" +} diff --git a/mails/templates/mail_templates/partners_initial_mail.txt b/mails/templates/mail_templates/partners_initial_mail.txt new file mode 100644 index 000000000..739744c47 --- /dev/null +++ b/mails/templates/mail_templates/partners_initial_mail.txt @@ -0,0 +1,31 @@ +Dear {{ contact.get_title_display }} {{ contact.last_name }}, + +You might by now have heard of SciPost, a recently-launched initiative aiming to bring disruptive change to current academic publishing practices. + +In summary, SciPost is a publication portal managed by professional scientists, offering (among others) high-quality Open Access journals with innovative forms of refereeing, and a means of commenting on all existing literature. SciPost is established as a not-for-profit foundation devoted to serving the interests of the international scientific community. +The site is anchored at https://scipost.org. Many further details about SciPost, its principles, ideals and implementation can be found at https://scipost.org/about and https://scipost.org/FAQ. + +Crucially, as explained on our Partners page at https://scipost.org/partners, SciPost follows a completely different funding model than traditional publishers, and provides a cost-slashing alternative to existing platforms. SciPost charges neither subscription fees, nor article processing charges; its activities are instead to be collectively financed through a Supporting Partners Board, formed by a worldwide consortium of institutions and organizations which directly or indirectly benefit from SciPost’s activities. + +Support takes the form of a small financial commitment, collectively pooled to enable SciPost to perform all its publication-related activities, maintain its online portal and implement its long-term development plan. + +In the agreement template, which you can find online at https://scipost.org/static/scipost/SPB/SciPost_Supporting_Partner_Agreement.pdf, you will find many more specific details about our operations, requirements and funding strategy. I would greatly appreciate if you took a few minutes to read through this document. + +It would be a privilege to welcome you as members of our Supporting Partners Board. I am hereby contacting you to enquire whether your institution would consider joining. Your support at this time is crucially required to make our initiative sustainable, and to help make it possible for the community to reap all the benefits deriving form its viable implementation. + +I will be happy to provide any required further details. If you are interested, you can simply get in touch via this address (partners@scipost.org). I sincerely hope that SciPost will be able to count on your support. + +On behalf of the SciPost Foundation, +Prof. dr Jean-Sébastien Caux +J.S.Caux@uva.nl +http://jscaux.org +--------------------------------------------- +Institute for Theoretical Physics +University of Amsterdam +Science Park 904 +1098 XH Amsterdam +The Netherlands +--------------------------------------------- +tel.: +31 (0)20 5255775 +fax: +31 (0)20 5255778 +--------------------------------------------- diff --git a/mails/views.py b/mails/views.py index 04dce36dd..f7fedc01d 100644 --- a/mails/views.py +++ b/mails/views.py @@ -10,6 +10,10 @@ class MailEditingSubView(object): self.template_name = kwargs.get('template', 'mails/mail_form.html') self.mail_form = EmailTemplateForm(request.POST or None, mail_code=mail_code, **kwargs) + @property + def recipients_string(self): + return ', '.join(getattr(self.mail_form, 'mail_fields', {}).get('recipients', [''])) + def is_valid(self): return self.mail_form.is_valid() diff --git a/partners/forms.py b/partners/forms.py index 87322b2d6..18a2df781 100644 --- a/partners/forms.py +++ b/partners/forms.py @@ -458,26 +458,6 @@ class ProspectiveContactForm(forms.ModelForm): widgets = {'prospartner': forms.HiddenInput()} -class EmailProspectivePartnerContactForm(forms.Form): - email_subject = forms.CharField(widget=forms.Textarea(), - initial='Supporting Partners Board') - message = forms.CharField(widget=forms.Textarea(), required=False) - include_SPB_summary = forms.BooleanField( - required=False, initial=True, - label='include SPB summary with message') - - def __init__(self, *args, **kwargs): - super(EmailProspectivePartnerContactForm, self).__init__(*args, **kwargs) - self.fields['email_subject'].widget.attrs.update( - {'rows': 1}) - self.fields['message'].widget.attrs.update( - {'placeholder': 'Write your message in this box (optional).'}) - - -class EmailProspectivePartnerGenericForm(EmailProspectivePartnerContactForm): - email = forms.EmailField(label='Generic address for emailing') - - class ProspectivePartnerEventForm(forms.ModelForm): class Meta: model = ProspectivePartnerEvent diff --git a/partners/templates/partners/_prospective_partner_card.html b/partners/templates/partners/_prospective_partner_card.html index 28f587665..5ab2d85a1 100644 --- a/partners/templates/partners/_prospective_partner_card.html +++ b/partners/templates/partners/_prospective_partner_card.html @@ -15,7 +15,10 @@ <p>{{ pp.get_status_display }}</p> </div> <div class="col-md-7"> - <a href="{% url 'partners:email_prospartner_generic' prospartner_id=pp.id %}">Compose email to a generic address</a> + <ul> + <li><a href="{% url 'partners:email_prospartner_generic' prospartner_id=pp.id %}">Compose email to a generic address</a></li> + <li><a href="{% url 'partners:email_prospartner_generic' prospartner_id=pp.id mail='followup' %}">Compose follow-up email to a generic address</a></li> + </ul> <h3>Contacts:</h3> <a class="d-inline-block mb-2" href="{% url 'partners:add_prospartner_contact' prospartner_id=pp.id %}">Add a contact</a> <table class="table"> @@ -31,7 +34,12 @@ <td>{{ contact.role }}</td> <td>{{ contact.get_title_display }} {{ contact.first_name }} {{ contact.last_name }}</td> <td>{{ contact.email }}</td> - <td><a href="{% url 'partners:email_prospartner_contact' contact_id=contact.id %}">Compose email</a></td> + <td> + <ul> + <li><a href="{% url 'partners:email_prospartner_contact' contact_id=contact.id %}">Compose email</a> + <li><a href="{% url 'partners:email_prospartner_contact' contact_id=contact.id mail='followup' %}">Compose follow-up email</a> + </ul> + </td> </tr> {% empty %} <tr> diff --git a/partners/urls.py b/partners/urls.py index f376c8de2..b7d4e8638 100644 --- a/partners/urls.py +++ b/partners/urls.py @@ -13,6 +13,8 @@ urlpatterns = [ name='add_prospective_partner'), url(r'^prospects/contacts/(?P<contact_id>[0-9]+)/email$', views.email_prospartner_contact, name='email_prospartner_contact'), + url(r'^prospects/contacts/(?P<contact_id>[0-9]+)/email/(?P<mail>followup)$', + views.email_prospartner_contact, name='email_prospartner_contact'), url(r'^prospects/(?P<prospartner_id>[0-9]+)/contacts/add$', views.add_prospartner_contact, name='add_prospartner_contact'), @@ -20,6 +22,8 @@ urlpatterns = [ views.promote_prospartner, name='promote_prospartner'), url(r'^prospects/(?P<prospartner_id>[0-9]+)/email_generic', views.email_prospartner_generic, name='email_prospartner_generic'), + url(r'^prospects/(?P<prospartner_id>[0-9]+)/email_generic/(?P<mail>followup)', + views.email_prospartner_generic, name='email_prospartner_generic'), url(r'^prospects/(?P<prospartner_id>[0-9]+)/events/add$', views.add_prospartner_event, name='add_prospartner_event'), diff --git a/partners/views.py b/partners/views.py index 1a94818df..0acab83ef 100644 --- a/partners/views.py +++ b/partners/views.py @@ -10,6 +10,8 @@ from django.utils import timezone from guardian.decorators import permission_required +from mails.views import MailEditingSubView + from .constants import PROSPECTIVE_PARTNER_REQUESTED,\ PROSPECTIVE_PARTNER_APPROACHED, PROSPECTIVE_PARTNER_ADDED,\ PROSPECTIVE_PARTNER_EVENT_REQUESTED, PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT @@ -17,13 +19,12 @@ from .models import Partner, ProspectivePartner, ProspectiveContact, ContactRequ ProspectivePartnerEvent, MembershipAgreement, Contact, Institution,\ PartnersAttachment from .forms import ProspectivePartnerForm, ProspectiveContactForm,\ - EmailProspectivePartnerContactForm, PromoteToPartnerForm,\ + PromoteToPartnerForm,\ ProspectivePartnerEventForm, MembershipQueryForm,\ PartnerForm, ContactForm, ContactFormset, ContactModelFormset,\ NewContactForm, InstitutionForm, ActivationForm, PartnerEventForm,\ MembershipAgreementForm, RequestContactForm, RequestContactFormSet,\ - ProcessRequestContactForm, PartnersAttachmentFormSet, PartnersAttachmentForm,\ - EmailProspectivePartnerGenericForm + ProcessRequestContactForm, PartnersAttachmentFormSet, PartnersAttachmentForm from .utils import PartnerUtils @@ -261,10 +262,15 @@ def add_prospartner_contact(request, prospartner_id): @permission_required('scipost.can_email_prospartner_contact', return_403=True) @transaction.atomic -def email_prospartner_contact(request, contact_id): +def email_prospartner_contact(request, contact_id, mail=None): contact = get_object_or_404(ProspectiveContact, pk=contact_id) - form = EmailProspectivePartnerContactForm(request.POST or None) - if form.is_valid(): + + if mail == 'followup': + code = 'partners_followup_mail' + else: + code = 'partners_initial_mail' + mail_request = MailEditingSubView(request, mail_code=code, contact=contact) + if mail_request.is_valid(): comments = 'Email sent to %s.' % str(contact) prospartnerevent = ProspectivePartnerEvent( prospartner=contact.prospartner, @@ -277,25 +283,26 @@ def email_prospartner_contact(request, contact_id): PROSPECTIVE_PARTNER_ADDED]: contact.prospartner.status = PROSPECTIVE_PARTNER_APPROACHED contact.prospartner.save() - PartnerUtils.load({'contact': contact, - 'email_subject': form.cleaned_data['email_subject'], - 'message': form.cleaned_data['message'], - 'include_SPB_summary': form.cleaned_data['include_SPB_summary']}) - PartnerUtils.email_prospartner_contact() - messages.success(request, 'Email successfully sent') + messages.success(request, 'Email successfully sent.') + mail_request.send() return redirect(reverse('partners:dashboard')) - context = {'contact': contact, 'form': form} - return render(request, 'partners/email_prospartner_contact.html', context) + else: + return mail_request.return_render() @permission_required('scipost.can_email_prospartner_contact', return_403=True) @transaction.atomic -def email_prospartner_generic(request, prospartner_id): +def email_prospartner_generic(request, prospartner_id, mail=None): prospartner = get_object_or_404(ProspectivePartner, pk=prospartner_id) - form = EmailProspectivePartnerGenericForm(request.POST or None) - if form.is_valid(): - comments = 'Email sent to %s.' % form.cleaned_data['email'] + + if mail == 'followup': + code = 'partners_followup_mail' + else: + code = 'partners_initial_mail' + mail_request = MailEditingSubView(request, mail_code=code) + if mail_request.is_valid(): + comments = 'Email sent to %s.' % str(mail_request.recipients_string) prospartnerevent = ProspectivePartnerEvent( prospartner=prospartner, event=PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT, @@ -307,17 +314,12 @@ def email_prospartner_generic(request, prospartner_id): PROSPECTIVE_PARTNER_ADDED]: prospartner.status = PROSPECTIVE_PARTNER_APPROACHED prospartner.save() - PartnerUtils.load({'institution_name': prospartner.institution_name, - 'email': form.cleaned_data['email'], - 'email_subject': form.cleaned_data['email_subject'], - 'message': form.cleaned_data['message'], - 'include_SPB_summary': form.cleaned_data['include_SPB_summary']}) - - PartnerUtils.email_prospartner_generic() - messages.success(request, 'Email successfully sent') + + messages.success(request, 'Email successfully sent.') + mail_request.send() return redirect(reverse('partners:dashboard')) - context = {'prospartner': prospartner, 'form': form} - return render(request, 'partners/email_prospartner_generic.html', context) + else: + return mail_request.return_render() @permission_required('scipost.can_manage_SPB', return_403=True) -- GitLab