diff --git a/cfp/emails.py b/cfp/emails.py index 78b6c30..a4ca517 100644 --- a/cfp/emails.py +++ b/cfp/emails.py @@ -5,7 +5,7 @@ from pprint import pformat from textwrap import indent from mailing.utils import send_message -from .environment import TalkEnvironment +from .environment import TalkEnvironment, SpeakerEnvironment def talk_email_render_preview(talk, speaker, subject, body): @@ -24,6 +24,22 @@ def talk_email_render_preview(talk, speaker, subject, body): return preview +def speaker_email_render_preview(speaker, subject, body): + env = SpeakerEnvironment(speaker) + try: + subject = env.from_string(subject).render() + except Exception: + return _('There is an error in your subject template.') + try: + body = env.from_string(body).render() + except Exception: + return _('There is an error in your body template.') + context = {'speaker': env.globals['speaker']} + preview = '' + _('Environment:') + '\n\n' + escape(indent(pformat(context, indent='2'), ' ')) + preview += '\n\n' + _('Subject:') + ' ' + escape(subject) + '\n' + _('Body:') + '\n' + escape(body) + return preview + + def talk_email_send(talks, subject, body): sent = 0 for talk in talks.all(): @@ -34,3 +50,14 @@ def talk_email_send(talks, subject, body): send_message(speaker.conversation, talk.site.conference, subject=s, content=c) sent += 1 return sent + + +def speaker_email_send(speakers, subject, body): + sent = 0 + for speaker in speakers.all(): + env = SpeakerEnvironment(speaker) + s = env.from_string(subject).render() + c = env.from_string(body).render() + send_message(speaker.conversation, speaker.site.conference, subject=s, content=c) + sent += 1 + return sent diff --git a/cfp/environment.py b/cfp/environment.py index ac8247a..0a527cf 100644 --- a/cfp/environment.py +++ b/cfp/environment.py @@ -20,11 +20,16 @@ def talk_to_dict(talk): } -def speaker_to_dict(speaker): - return { +def speaker_to_dict(speaker, include_talks=False): + d = { 'name': speaker.name, 'email': speaker.email, } + if include_talks: + d.update({ + 'talks': list(map(talk_to_dict, speaker.talk_set.all())), + }) + return d class TalkEnvironment(SandboxedEnvironment): @@ -34,3 +39,11 @@ class TalkEnvironment(SandboxedEnvironment): 'talk': talk_to_dict(talk), 'speaker': speaker_to_dict(speaker), }) + + +class SpeakerEnvironment(SandboxedEnvironment): + def __init__(self, speaker, **options): + super().__init__(**options) + self.globals.update({ + 'speaker': speaker_to_dict(speaker, include_talks=True), + }) diff --git a/cfp/forms.py b/cfp/forms.py index 9d6478f..9164250 100644 --- a/cfp/forms.py +++ b/cfp/forms.py @@ -11,7 +11,7 @@ from django_select2.forms import ModelSelect2MultipleWidget from .models import Participant, Talk, TalkCategory, Track, Tag, \ Conference, Room, Volunteer, Activity -from .environment import TalkEnvironment +from .environment import TalkEnvironment, SpeakerEnvironment ACCEPTATION_CHOICES = [ @@ -183,7 +183,7 @@ class TalkActionForm(forms.Form): track = forms.ChoiceField(required=False, choices=[], label=_('Assign to a track')) tag = forms.ChoiceField(required=False, choices=[], label=_('Add a tag')) room = forms.ChoiceField(required=False, choices=[], label=_('Put in a room')) - email = forms.BooleanField(label=_('Send a email')) + email = forms.BooleanField(required=False, label=_('Send a email')) def __init__(self, *args, **kwargs): site = kwargs.pop('site') @@ -198,6 +198,16 @@ class TalkActionForm(forms.Form): self.fields['room'].choices = [(None, "---------")] + list(rooms.values_list('slug', 'name')) +class SpeakerActionForm(forms.Form): + speakers = forms.MultipleChoiceField(choices=[]) + email = forms.BooleanField(required=False, label=_('Send a email')) + + def __init__(self, *args, **kwargs): + speakers = kwargs.pop('speakers') + super().__init__(*args, **kwargs) + self.fields['speakers'].choices = [(speaker.pk, None) for speaker in speakers.all()] + + class NotifyForm(forms.Form): notify = forms.BooleanField(initial=True, required=False, label=_('Notify by mail?')) @@ -252,14 +262,20 @@ class EmailForm(forms.Form): email = forms.EmailField(required=True, label=_('Email')) -class PreviewMailForm(forms.Form): +class PreviewTalkMailForm(forms.Form): speaker = forms.IntegerField() talk = forms.IntegerField() subject = forms.CharField(required=False, label=_('Subject')) body = forms.CharField(required=False, label=_('Body')) -class SendMailForm(forms.Form): +class PreviewSpeakerMailForm(forms.Form): + speaker = forms.IntegerField() + subject = forms.CharField(required=False, label=_('Subject')) + body = forms.CharField(required=False, label=_('Body')) + + +class SendTalkMailForm(forms.Form): subject = forms.CharField() body = forms.CharField(widget=forms.Textarea) confirm = forms.BooleanField(required=False, label=_('I read my self twice, confirm sending')) @@ -287,6 +303,33 @@ class SendMailForm(forms.Form): return self.cleaned_data.get(template) +class SendSpeakerMailForm(forms.Form): + subject = forms.CharField() + body = forms.CharField(widget=forms.Textarea) + confirm = forms.BooleanField(required=False, label=_('I read my self twice, confirm sending')) + + def __init__(self, *args, **kwargs): + self._speakers = kwargs.pop('speakers') + super().__init__(*args, **kwargs) + self._env = dict() + + def clean_subject(self): + return self.clean_template('subject') + + def clean_body(self): + return self.clean_template('body') + + def clean_template(self, template): + try: + for speaker in self._speakers.all(): + env = self._env.get(speaker, SpeakerEnvironment(speaker)) + env.from_string(self.cleaned_data.get(template)).render() + except Exception as e: + raise forms.ValidationError(_("Your template does not compile (at least) with speaker '%(speaker)s'.") % + {'speaker': speaker}) + return self.cleaned_data.get(template) + + class UsersWidget(ModelSelect2MultipleWidget): model = User search_fields = [ '%s__icontains' % field for field in UserAdmin.search_fields ] diff --git a/cfp/templates/cfp/staff/participant_list.html b/cfp/templates/cfp/staff/participant_list.html index 773fc2e..343d01a 100644 --- a/cfp/templates/cfp/staff/participant_list.html +++ b/cfp/templates/cfp/staff/participant_list.html @@ -5,6 +5,14 @@ {% block content %} +{% if pending_email %} +
@@ -34,11 +42,15 @@ +
+ {% endblock %} diff --git a/cfp/templates/cfp/staff/speaker_email.html b/cfp/templates/cfp/staff/speaker_email.html new file mode 100644 index 0000000..28f729d --- /dev/null +++ b/cfp/templates/cfp/staff/speaker_email.html @@ -0,0 +1,111 @@ +{% extends 'cfp/staff/base.html' %} +{% load i18n bootstrap3 staticfiles %} + +{% block speakerstab %} class="active"{% endblock %} + +{% block content %} + +{% trans "Show filtering options…" %}
++ + {% trans "Show filtering options…" %} + +