class ScheduleSurveyForm(IndicoForm): start_dt = IndicoDateTimeField( _("Start"), [ UsedIf(lambda form, field: form.allow_reschedule_start), Optional(), DateTimeRange(earliest='now') ], default_time=time(0, 0), description=_("Moment when the survey will open for submissions")) end_dt = IndicoDateTimeField( _("End"), [Optional(), LinkedDateTime('start_dt')], default_time=time(23, 59), description=_("Moment when the survey will close")) resend_start_notification = BooleanField( _('Resend start notification'), widget=SwitchWidget(), description=_("Resend the survey start notification.")) def __init__(self, *args, **kwargs): survey = kwargs.pop('survey') self.allow_reschedule_start = kwargs.pop('allow_reschedule_start') self.timezone = survey.event_new.timezone super(IndicoForm, self).__init__(*args, **kwargs) if not survey.start_notification_sent or not self.allow_reschedule_start: del self.resend_start_notification
class CERNAccessForm(RequestFormBase): regforms = IndicoSelectMultipleCheckboxField(_('Registration forms'), [DataRequired(_('At least one registration form has to be selected'))], widget=JinjaWidget('regform_list_widget.html', 'cern_access')) regform_data_mode = IndicoEnumSelectField(_('Show during user registration'), enum=RegformDataMode, keep_enum=False, description=_("When enabled, users can request site access while " "registering and provide their additional personal data " "in the registration form. When set to required, the user " "cannot register without providing this data. In any case, " "site access is only granted after a manager explicitly " "enables it for the registrations.")) start_dt_override = IndicoDateTimeField(_('Start date override'), [Optional()], description=_("If set, CERN access will be granted starting at the " "specified date instead of the event's start date")) end_dt_override = IndicoDateTimeField(_('End date override'), [Optional(), LinkedDateTime('start_dt_override', not_equal=True)], description=_("If set, CERN access will be granted until the specified date " "instead of the event's end date")) def __init__(self, *args, **kwargs): super(CERNAccessForm, self).__init__(*args, **kwargs) regforms = get_regforms(self.event) self._regform_map = {unicode(rf.id): rf for rf in regforms} self.regforms.choices = [(unicode(rf.id), rf.title) for rf in regforms] self.start_dt_override.default_time = self.event.start_dt_local.time() self.end_dt_override.default_time = self.event.end_dt_local.time() def validate_start_dt_override(self, field): if bool(self.start_dt_override.data) != bool(self.end_dt_override.data): raise ValidationError(_('You need to specify both date overrides or neither of them.')) validate_end_dt_override = validate_start_dt_override
class CERNAccessForm(RequestFormBase): regforms = IndicoSelectMultipleCheckboxField( _('Registration forms'), widget=JinjaWidget('regform_list_widget.html', 'cern_access')) start_dt_override = IndicoDateTimeField( _('Start date override'), [Optional()], description=_("If set, CERN access will be granted starting at the " "specified date instead of the event's start date")) end_dt_override = IndicoDateTimeField( _('End date override'), [Optional(), LinkedDateTime('start_dt_override', not_equal=True)], description=_( "If set, CERN access will be granted until the specified date " "instead of the event's end date")) def __init__(self, *args, **kwargs): super(CERNAccessForm, self).__init__(*args, **kwargs) regforms = get_regforms(self.event) self._regform_map = {unicode(rf.id): rf for rf in regforms} self.regforms.choices = [(unicode(rf.id), rf.title) for rf in regforms] self.start_dt_override.default_time = self.event.start_dt_local.time() self.end_dt_override.default_time = self.event.end_dt_local.time() def validate_start_dt_override(self, field): if bool(self.start_dt_override.data) != bool( self.end_dt_override.data): raise ValidationError( _('You need to specify both date overrides or neither of them.' )) validate_end_dt_override = validate_start_dt_override
class PapersScheduleForm(IndicoForm): start_dt = IndicoDateTimeField(_("Start"), [Optional()], default_time=time(0, 0), description=_("The moment users can start submitting papers")) end_dt = IndicoDateTimeField(_("End"), [Optional(), LinkedDateTime('start_dt')], default_time=time(23, 59), description=_("The moment the submission process ends")) def __init__(self, *args, **kwargs): self.event = kwargs.pop('event') super(PapersScheduleForm, self).__init__(*args, **kwargs)
class CERNAccessForm(RequestFormBase): regforms = IndicoSelectMultipleCheckboxField( _('Registration forms'), [DataRequired(_('At least one registration form has to be selected'))], widget=JinjaWidget('regform_list_widget.html', 'cern_access')) during_registration = BooleanField( _('Show during user registration'), widget=SwitchWidget(), description=_( "When enabled, users can request site access while registering " "and provide their additional personal data in the registration " "form. In any case, site access is only granted after a manager " "explicitly enables it for the registrants.")) during_registration_preselected = BooleanField( _('Preselect during user registration'), [HiddenUnless('during_registration')], widget=SwitchWidget(), description=_("Preselect the option to request site access during " "registration. Recommended if most registrants will " "need it.")) during_registration_required = BooleanField( _('Require during user registration'), [HiddenUnless('during_registration_preselected')], widget=SwitchWidget(), description=_("Require all users to provide data for site access. " "Registration without entering the data will not be " "possible.")) start_dt_override = IndicoDateTimeField( _('Start date override'), [Optional()], description=_("If set, CERN access will be granted starting at the " "specified date instead of the event's start date")) end_dt_override = IndicoDateTimeField( _('End date override'), [Optional(), LinkedDateTime('start_dt_override', not_equal=True)], description=_( "If set, CERN access will be granted until the specified date " "instead of the event's end date")) def __init__(self, *args, **kwargs): super(CERNAccessForm, self).__init__(*args, **kwargs) regforms = get_regforms(self.event) self._regform_map = {unicode(rf.id): rf for rf in regforms} self.regforms.choices = [(unicode(rf.id), rf.title) for rf in regforms] self.start_dt_override.default_time = self.event.start_dt_local.time() self.end_dt_override.default_time = self.event.end_dt_local.time() def validate_start_dt_override(self, field): if bool(self.start_dt_override.data) != bool( self.end_dt_override.data): raise ValidationError( _('You need to specify both date overrides or neither of them.' )) validate_end_dt_override = validate_start_dt_override
class EventCreationForm(EventCreationFormBase): _field_order = ('category', 'title', 'start_dt', 'end_dt', 'timezone', 'location_data', 'protection_mode') _advanced_field_order = () start_dt = IndicoDateTimeField(_("Start"), [DataRequired()], default_time=time(8), allow_clear=False) end_dt = IndicoDateTimeField( _("End"), [DataRequired(), LinkedDateTime('start_dt', not_equal=True)], default_time=time(18), allow_clear=False)
class AbstractsScheduleForm(IndicoForm): start_dt = IndicoDateTimeField(_("Start"), [Optional()], default_time=time(0, 0), description=_("The moment users can start submitting abstracts")) end_dt = IndicoDateTimeField(_("End"), [Optional(), LinkedDateTime('start_dt')], default_time=time(23, 59), description=_("The moment the submission process will end")) modification_end_dt = IndicoDateTimeField(_("Modification deadline"), [Optional(), LinkedDateTime('end_dt')], default_time=time(23, 59), description=_("Deadline until which the submitted abstracts can be " "modified")) def __init__(self, *args, **kwargs): self.event = kwargs.pop('event') super(AbstractsScheduleForm, self).__init__(*args, **kwargs)
class RegistrationFormScheduleForm(IndicoForm): start_dt = IndicoDateTimeField(_("Start"), [Optional()], default_time=time(0, 0), description=_("Moment when registrations will be open")) end_dt = IndicoDateTimeField(_("End"), [Optional(), LinkedDateTime('start_dt')], default_time=time(23, 59), description=_("Moment when registrations will be closed")) modification_end_dt = IndicoDateTimeField(_("Modification deadline"), [Optional(), LinkedDateTime('end_dt')], default_time=time(23, 59), description=_("Deadline until which registration information can be " "modified (defaults to the end date if empty)")) def __init__(self, *args, **kwargs): regform = kwargs.pop('regform') self.timezone = regform.event.timezone super(RegistrationFormScheduleForm, self).__init__(*args, **kwargs)
class RegistrationFormScheduleForm(IndicoForm): start_dt = IndicoDateTimeField( _("Start"), [Optional()], default_time=time(0, 0), description=_("Moment when registrations will be open")) end_dt = IndicoDateTimeField( _("End"), [Optional(), LinkedDateTime('start_dt')], default_time=time(23, 59), description=_("Moment when registrations will be closed")) def __init__(self, *args, **kwargs): regform = kwargs.pop('regform') self.timezone = regform.event.tz super(IndicoForm, self).__init__(*args, **kwargs)
class ContributionStartDateForm(IndicoForm): start_dt = IndicoDateTimeField(_('Start date'), [ DataRequired(), DateTimeRange(earliest=lambda form, field: form.event.start_dt, latest=lambda form, field: form.event.end_dt) ], allow_clear=False) def __init__(self, *args, **kwargs): self.contrib = kwargs.pop('contrib') self.event = self.contrib.event self.timezone = self.event.timezone super().__init__(*args, **kwargs) def validate_start_dt(self, field): event = self.contrib.event day = self.contrib.start_dt.astimezone(event.tzinfo).date() if day == event.end_dt_local.date(): latest_dt = event.end_dt error_msg = _( 'With this time, the contribution would exceed the event end time.' ) else: latest_dt = get_day_end(day, tzinfo=event.tzinfo) error_msg = _( 'With this time, the contribution would exceed the current day.' ) if field.data + self.contrib.duration > latest_dt: raise ValidationError(error_msg)
class PluginSettingsForm(IndicoForm): adams_url = URLField(_('ADaMS URL'), [DataRequired()], description=_('The URL of the ADaMS REST API')) username = StringField(_('Username'), [DataRequired()], description=_('The login used to authenticate with ADaMS service')) password = IndicoPasswordField(_('Password'), [DataRequired()], description=_('The password used to authenticate with ADaMS service')) secret_key = IndicoPasswordField(_('Secret key'), [DataRequired()], description=_('Secret key to sign ADaMS requests')) authorized_users = PrincipalListField(_('Authorized users'), allow_groups=True, description=_('List of users/groups who can send requests')) excluded_categories = MultipleItemsField('Excluded categories', fields=[{'id': 'id', 'caption': 'Category ID'}]) access_ticket_template = QuerySelectField(_("Access ticket template"), allow_blank=True, blank_text=_("No access ticket selected"), get_label='title', description=_("Ticket template allowing access to CERN")) earliest_start_dt = IndicoDateTimeField(_("Earliest start date"), [Optional()], default_time=time(0, 0), description=_("The earliest date an event can start to qualify for CERN " "access badges")) delete_personal_data_after = TimeDeltaField(_('Delete personal data'), [DataRequired()], units=('days',), description=_('Personal data will be deleted once the event has ' 'finished and the duration specified here has been ' 'exceeded. Once the data has been deleted, access badges ' 'will not be accessible anymore.')) api_username = StringField(_('Username'), [DataRequired()], description=_('The username to access the API')) api_password = IndicoPasswordField(_('Password'), [DataRequired()], toggle=True, description=_('The password to access the API')) def __init__(self, *args, **kwargs): super(PluginSettingsForm, self).__init__(*args, **kwargs) self.access_ticket_template.query = (DesignerTemplate.query .filter(DesignerTemplate.category_id == 0, DesignerTemplate.type == TemplateType.badge) .order_by(db.func.lower(DesignerTemplate.title)))
class DeadlineForm(IndicoForm): deadline = IndicoDateTimeField(_("Deadline"), [Optional()], default_time=time(23, 59)) enforce = BooleanField(_("Enforce deadline"), [HiddenUnless('deadline')], widget=SwitchWidget()) def __init__(self, *args, **kwargs): self.event = kwargs.pop('event') super(DeadlineForm, self).__init__(*args, **kwargs)
class ContributionForm(IndicoForm): title = StringField(_("Title"), [DataRequired()]) description = TextAreaField(_("Description")) start_dt = IndicoDateTimeField(_("Start date"), [DataRequired(), DateTimeRange(earliest=lambda form, field: form._get_earliest_start_dt(), latest=lambda form, field: form._get_latest_start_dt())], allow_clear=False, description=_("Start date of the contribution")) duration = TimeDeltaField(_("Duration"), [DataRequired(), MaxDuration(timedelta(hours=24))], default=timedelta(minutes=20), units=('minutes', 'hours')) type = QuerySelectField(_("Type"), get_label='name', allow_blank=True, blank_text=_("No type selected")) person_link_data = ContributionPersonLinkListField(_("People")) location_data = IndicoLocationField(_("Location")) keywords = IndicoTagListField(_('Keywords')) references = ReferencesField(_("External IDs"), reference_class=ContributionReference, description=_("Manage external resources for this contribution")) board_number = StringField(_("Board Number")) code = StringField(_('Programme code')) @generated_data def render_mode(self): return RenderMode.markdown def __init__(self, *args, **kwargs): self.event = kwargs.pop('event') self.contrib = kwargs.pop('contrib', None) self.session_block = kwargs.get('session_block') self.timezone = self.event.timezone to_schedule = kwargs.pop('to_schedule', False) super(ContributionForm, self).__init__(*args, **kwargs) self.type.query = self.event.contribution_types if self.event.type != 'conference': self.person_link_data.label.text = _("Speakers") if not self.type.query.count(): del self.type if not to_schedule and (self.contrib is None or not self.contrib.is_scheduled): del self.start_dt def _get_earliest_start_dt(self): return self.session_block.start_dt if self.session_block else self.event.start_dt def _get_latest_start_dt(self): return self.session_block.end_dt if self.session_block else self.event.end_dt def validate_duration(self, field): start_dt = self.start_dt.data if self.start_dt else None if start_dt: end_dt = start_dt + field.data if self.session_block and end_dt > self.session_block.end_dt: raise ValidationError(_("With the current duration the contribution exceeds the block end date")) if end_dt > self.event.end_dt: raise ValidationError(_('With the current duration the contribution exceeds the event end date')) @property def custom_field_names(self): return tuple([field_name for field_name in self._fields if field_name.startswith('custom_')])
class RoomAssistanceRequestForm(RequestFormBase): start_dt = IndicoDateTimeField( _('When'), [DataRequired(), DateTimeRange(earliest=now_utc())], description=_('When do you need the assistance?')) reason = TextAreaField(_('Reason'), [DataRequired()], description=_('Why are you requesting assistance?')) def validate_start_dt(self, field): localized_time = field.data.astimezone(session.tzinfo).time() is_in_working_hours = WORKING_TIME_PERIOD[ 0] <= localized_time <= WORKING_TIME_PERIOD[1] if not is_in_working_hours: raise ValidationError( 'Specified datetime is not within the working hours')
class EventDatesForm(IndicoForm): _main_fields = ('start_dt', 'end_dt', 'timezone', 'update_timetable') _override_date_fields = ('start_dt_override', 'end_dt_override') timezone = IndicoTimezoneSelectField(_('Timezone'), [DataRequired()]) start_dt = IndicoDateTimeField(_("Start"), [InputRequired()], allow_clear=False) end_dt = IndicoDateTimeField( _("End"), [InputRequired(), LinkedDateTime('start_dt', not_equal=True)], allow_clear=False) update_timetable = BooleanField( _('Update timetable'), widget=SwitchWidget(), description=_( "Move sessions/contributions/breaks in the timetable according " "to the new event start time.")) start_dt_override = IndicoDateTimeField( _("Start"), [Optional()], allow_clear=True, description=_( "Specifying this date overrides the start date displayed " "on the main conference page.")) end_dt_override = IndicoDateTimeField( _("End"), [Optional(), LinkedDateTime('start_dt_override', not_equal=True)], allow_clear=True, description=_("Specifying this date overrides the end date displayed " "on the main conference page.")) def __init__(self, *args, **kwargs): self.event = kwargs.pop('event') super(EventDatesForm, self).__init__(*args, **kwargs) # timetable synchronization self.check_timetable_boundaries = (self.event.type_ != EventType.lecture) if self.check_timetable_boundaries: self.toplevel_timetable_entries = get_top_level_entries(self.event) if not self.toplevel_timetable_entries: self.check_timetable_boundaries = False if not self.check_timetable_boundaries: del self.update_timetable # displayed dates self.has_displayed_dates = (self.event.type_ == EventType.conference) if self.has_displayed_dates: start_dt = self.start_dt.data or self.start_dt.object_data end_dt = self.end_dt.data or self.end_dt.object_data self.start_dt_override.default_time = start_dt.astimezone( timezone(self.timezone.data)).time() self.end_dt_override.default_time = end_dt.astimezone( timezone(self.timezone.data)).time() else: del self.start_dt_override del self.end_dt_override def validate_start_dt(self, field): if not self.check_timetable_boundaries or self.update_timetable.data or field.object_data == field.data: return if field.data > min(self.toplevel_timetable_entries, key=attrgetter('start_dt')).start_dt: raise ValidationError( _("To use this start date the timetable must be updated.")) def validate_end_dt(self, field): if not self.check_timetable_boundaries: return if self.update_timetable.data: # if we move timetable entries according to the start date # change, check that there's enough time at the end. start_dt_offset = self.start_dt.data - self.start_dt.object_data end_buffer = field.data - max(self.toplevel_timetable_entries, key=attrgetter('end_dt')).end_dt delta = max(timedelta(), start_dt_offset - end_buffer) if delta: delta_str = format_human_timedelta(delta, 'minutes', True) raise ValidationError( _("The event is too short to fit all timetable entries. " "It must be at least {} longer.").format(delta_str)) else: # if we do not update timetable entries, only check that # the event does not end before its last timetable entry; # a similar check for the start time is done above in that # field's validation method. max_end_dt = max(self.toplevel_timetable_entries, key=attrgetter('end_dt')).end_dt if field.data < max_end_dt: raise ValidationError( _("The event cannot end before its last timetable entry, which is at {}." ).format( to_unicode( format_datetime(max_end_dt, timezone=self.event.tzinfo))))
class ReminderForm(IndicoForm): recipient_fields = {'recipients', 'send_to_participants'} schedule_fields = {'schedule_type', 'absolute_dt', 'relative_delta'} schedule_recipient_fields = recipient_fields | schedule_fields # Schedule schedule_type = IndicoRadioField( _('Type'), [DataRequired()], choices=[('relative', _("Relative to the event start time")), ('absolute', _("Fixed date/time")), ('now', _('Send immediately'))]) relative_delta = TimeDeltaField( _('Offset'), [HiddenUnless('schedule_type', 'relative'), DataRequired()]) absolute_dt = IndicoDateTimeField(_('Date'), [ HiddenUnless('schedule_type', 'absolute'), DataRequired(), DateTimeRange() ]) # Recipients recipients = EmailListField(_('Email addresses'), description=_('One email address per line.')) send_to_participants = BooleanField( _('Participants'), description=_('Send the reminder to all participants/registrants ' 'of the event.')) # Misc reply_to_address = SelectField( _('Sender'), [DataRequired()], description=_('The email address that will show up as the sender.')) message = TextAreaField( _('Note'), description=_('A custom message to include in the email.')) include_summary = BooleanField( _('Include agenda'), description=_( "Includes a simple text version of the event's agenda in the email." )) include_description = BooleanField( _('Include description'), description=_("Includes the event's description in the email.")) def __init__(self, *args, **kwargs): self.event = kwargs.pop('event') self.timezone = self.event.timezone super().__init__(*args, **kwargs) self.reply_to_address.choices = (list( self.event.get_allowed_sender_emails( extra=self.reply_to_address.object_data).items())) if self.event.type_ == EventType.lecture: del self.include_summary def validate_recipients(self, field): if not field.data and not self.send_to_participants.data: raise ValidationError( _('If participants are not included you need to specify recipients.' )) def validate_send_to_participants(self, field): if not field.data and not self.recipients.data: raise ValidationError( _('If no recipients are specified you need to include participants.' )) def validate_schedule_type(self, field): # Be graceful and allow a reminder that's in the past but on the same day. # It will be sent immediately but that way we are a little bit more user-friendly if field.data == 'now': return scheduled_dt = self.scheduled_dt.data if scheduled_dt is not None and scheduled_dt.date() < now_utc().date(): raise ValidationError(_('The specified date is in the past')) @generated_data def scheduled_dt(self): if self.schedule_type.data == 'absolute': if self.absolute_dt.data is None: return None return self.absolute_dt.data elif self.schedule_type.data == 'relative': if self.relative_delta.data is None: return None return self.event.start_dt - self.relative_delta.data elif self.schedule_type.data == 'now': return now_utc() @generated_data def event_start_delta(self): return self.relative_delta.data if self.schedule_type.data == 'relative' else None
class CloneRepeatOnceForm(CloneRepeatFormBase): start_dt = IndicoDateTimeField(_('Starting'), allow_clear=False)