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
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
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'),
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'),
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 '
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
):
77 emails
= {session
.user
.email
: session
.user
.full_name
}
79 emails
[self
.event
.getCreator().getEmail()] = self
.event
.getCreator().getStraightFullName(upper
=False)
81 support
= self
.event
.getSupportInfo()
82 emails
[support
.getEmail()] = support
.getCaption() or support
.getEmail()
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'))
113 return DisplayTZ(conf
=self
.event
).getDisplayTZ()
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':
126 def event_start_delta(self
):
127 return self
.relative_delta
.data
if self
.schedule_type
.data
== 'relative' else None