Add description to reminder recipient field
[cds-indico.git] / indico / modules / events / reminders / forms.py
blob8962fd468634bd7dfe5994d28ffb0c541bf8868f
1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 from __future__ import unicode_literals
19 from datetime import datetime, date
21 import pytz
22 from babel.dates import get_timezone
23 from flask import session
24 from wtforms.ext.dateutil.fields import DateField
25 from wtforms.fields import BooleanField, TextAreaField, SelectField
26 from wtforms.validators import DataRequired, InputRequired, ValidationError
27 from wtforms_components import TimeField
29 from indico.util.date_time import now_utc
30 from indico.util.i18n import _
31 from indico.util.string import to_unicode
32 from indico.web.forms.base import IndicoForm, generated_data
33 from indico.web.forms.fields import EmailListField, IndicoRadioField, TimeDeltaField
34 from indico.web.forms.validators import UsedIf
35 from MaKaC.common.timezoneUtils import DisplayTZ
38 class ReminderForm(IndicoForm):
39 default_widget_attrs = {'absolute_time': {'placeholder': 'HH:MM'}}
40 recipient_fields = {'recipients', 'send_to_participants'}
41 schedule_fields = {'schedule_type', 'absolute_date', 'absolute_time', 'relative_delta'}
42 schedule_recipient_fields = recipient_fields | schedule_fields
44 # Schedule
45 schedule_type = IndicoRadioField(_('Type'), [DataRequired()],
46 choices=[('relative', _("Relative to the event start time")),
47 ('absolute', _("Fixed date/time")),
48 ('now', _('Send immediately'))])
49 relative_delta = TimeDeltaField(_('Offset'), [UsedIf(lambda form, field: form.schedule_type.data == 'relative'),
50 DataRequired()])
51 absolute_date = DateField(_('Date'), [UsedIf(lambda form, field: form.schedule_type.data == 'absolute'),
52 DataRequired()], parse_kwargs={'dayfirst': True})
53 absolute_time = TimeField(_('Time'), [UsedIf(lambda form, field: form.schedule_type.data == 'absolute'),
54 InputRequired()])
55 # Recipients
56 recipients = EmailListField(_('Email addresses'), description=_('One email address per line.'))
57 send_to_participants = BooleanField(_('Participants'),
58 description=_('Send the reminder to all participants/registrants '
59 'of the event.'))
60 # Misc
61 reply_to_address = SelectField(_('Reply-to'), [DataRequired()],
62 description=_('The email address users may send replies to.'))
63 message = TextAreaField(_('Note'), description=_('A custom message to include in the email.'))
64 include_summary = BooleanField(_('Include agenda'),
65 description=_("Includes a simple text version of the event's agenda in the email."))
67 def __init__(self, *args, **kwargs):
68 self.event = kwargs.pop('event')
69 super(ReminderForm, self).__init__(*args, **kwargs)
70 self.absolute_time.description = _('Your active timezone is {tz}.').format(tz=self.timezone)
71 self._set_email_choices()
72 if self.event.getType() == 'simple_event':
73 del self.include_summary
75 def _set_email_choices(self):
76 # User
77 emails = {session.user.email: session.user.full_name}
78 # Creator
79 emails[self.event.getCreator().getEmail()] = self.event.getCreator().getStraightFullName(upper=False)
80 # Support
81 support = self.event.getSupportInfo()
82 emails[support.getEmail()] = support.getCaption() or support.getEmail()
83 # Chairs
84 emails.update((x.getEmail(), x.getDirectFullName()) for x in self.event.getChairList())
85 # Current email to avoid destructive modifications
86 emails.setdefault(self.reply_to_address.object_data, self.reply_to_address.object_data)
87 # Sanitize and format emails
88 emails = {to_unicode(email.strip().lower()): '{} <{}>'.format(name, email)
89 for email, name in emails.iteritems()
90 if email and email.strip()}
91 self.reply_to_address.choices = sorted(emails.items(), key=lambda x: (x[0] != session.user.email, x[1].lower()))
93 def validate_recipients(self, field):
94 if not field.data and not self.send_to_participants.data:
95 raise ValidationError(_('If participants are not included you need to specify recipients.'))
97 def validate_send_to_participants(self, field):
98 if not field.data and not self.recipients.data:
99 raise ValidationError(_('If no recipients are specified you need to include participants.'))
101 def validate_schedule_type(self, field):
102 # Be graceful and allow a reminder that's in the past but on the same day.
103 # It will be sent immediately but that way we are a little bit more user-friendly
104 if field.data != 'now' and self.scheduled_dt.data.date() < now_utc().date():
105 raise ValidationError(_('The specified date is in the past'))
107 def validate_absolute_date(self, field):
108 if self.schedule_type.data == 'absolute' and field.data < date.today():
109 raise ValidationError(_('The specified date is in the past'))
111 @property
112 def timezone(self):
113 return DisplayTZ(conf=self.event).getDisplayTZ()
115 @generated_data
116 def scheduled_dt(self):
117 if self.schedule_type.data == 'absolute':
118 dt = datetime.combine(self.absolute_date.data, self.absolute_time.data)
119 return get_timezone(self.timezone).localize(dt).astimezone(pytz.utc)
120 elif self.schedule_type.data == 'relative':
121 return self.event.getStartDate() - self.relative_delta.data
122 elif self.schedule_type.data == 'now':
123 return now_utc()
125 @generated_data
126 def event_start_delta(self):
127 return self.relative_delta.data if self.schedule_type.data == 'relative' else None