Ejemplo n.º 1
0
class AbstractReviewForm(IndicoForm):
    """Form for reviewing an abstract"""

    _order = ('proposed_action', 'proposed_contribution_type',
              'proposed_related_abstract', 'proposed_tracks', 'comment')

    comment = TextAreaField(_("Comment"),
                            render_kw={
                                'placeholder':
                                _("You may leave a comment (only visible to "
                                  "conveners and judges)..."),
                                'class':
                                'grow'
                            })
    proposed_action = IndicoEnumSelectField(_("Proposed Action"),
                                            [DataRequired()],
                                            enum=AbstractAction)
    proposed_related_abstract = AbstractField(
        _("Target Abstract"), [
            HiddenUnless(
                'proposed_action',
                {AbstractAction.mark_as_duplicate, AbstractAction.merge}),
            DataRequired()
        ],
        description=
        _("The current abstract should be marked as duplicate of the selected one"
          ),
        ajax_endpoint='abstracts.other_abstracts')
    proposed_contribution_type = QuerySelectField(
        _("Contribution type"),
        [HiddenUnless('proposed_action', AbstractAction.accept)],
        get_label=lambda x: x.name.title(),
        allow_blank=True,
        blank_text=_("You may propose a contribution type..."))
    proposed_tracks = IndicoQuerySelectMultipleCheckboxField(
        _("Propose for tracks"), [
            HiddenUnless('proposed_action', AbstractAction.change_tracks),
            DataRequired()
        ],
        collection_class=set,
        get_label='title')

    def __init__(self, edit=False, *args, **kwargs):
        abstract = kwargs.pop('abstract')
        super(AbstractReviewForm, self).__init__(*args, **kwargs)
        self.event = abstract.event
        if not edit:
            self.proposed_action.none = _("Propose an action...")
        self.proposed_related_abstract.excluded_abstract_ids = {abstract.id}
        self.proposed_contribution_type.query = (
            ContributionType.query.with_parent(self.event).order_by(
                ContributionType.name))
        if not self.proposed_contribution_type.query.count():
            del self.proposed_contribution_type
        reviewed_for_track_ids = {t.id for t in abstract.reviewed_for_tracks}
        existing_prop_track_cond = (Track.id.in_(
            t.id for t in self.proposed_tracks.object_data)
                                    if self.proposed_tracks.object_data else
                                    False)
        self.proposed_tracks.query = (Track.query.with_parent(
            self.event).filter(
                db.or_(Track.id.notin_(reviewed_for_track_ids),
                       existing_prop_track_cond)).order_by(Track.position))
        if not self.proposed_tracks.query.count():
            del self.proposed_tracks
            self.proposed_action.skip.add(AbstractAction.change_tracks)

    @property
    def split_data(self):
        data = self.data
        return {
            'questions_data':
            {k: v
             for k, v in data.iteritems() if k.startswith('question_')},
            'review_data': {
                k: v
                for k, v in data.iteritems() if not k.startswith('question_')
            }
        }

    @property
    def has_questions(self):
        return any(x.startswith('question_') for x in self.data)
Ejemplo n.º 2
0
class RegistrationFormForm(IndicoForm):
    _price_fields = ('currency', 'base_price')
    _registrant_notification_fields = ('notification_sender_address',
                                       'message_pending', 'message_unpaid',
                                       'message_complete')
    _manager_notification_fields = ('manager_notifications_enabled',
                                    'manager_notification_recipients')
    _special_fields = _price_fields + _registrant_notification_fields + _manager_notification_fields

    title = StringField(_("Title"), [DataRequired()],
                        description=_("The title of the registration form"))
    introduction = TextAreaField(
        _("Introduction"),
        description=
        _("Introduction to be displayed when filling out the registration form"
          ))
    contact_info = StringField(
        _("Contact info"),
        description=
        _("How registrants can get in touch with somebody for extra information"
          ))
    moderation_enabled = BooleanField(
        _("Moderated"),
        widget=SwitchWidget(),
        description=_("If enabled, registrations require manager approval"))
    require_login = BooleanField(
        _("Only logged-in users"),
        widget=SwitchWidget(),
        description=_("Users must be logged in to register"))
    require_user = BooleanField(
        _("Registrant must have account"),
        widget=SwitchWidget(),
        description=_(
            "Registrations emails must be associated with an Indico account"))
    limit_registrations = BooleanField(
        _("Limit registrations"),
        widget=SwitchWidget(),
        description=_("Whether there is a limit of registrations"))
    registration_limit = IntegerField(
        _("Capacity"), [
            HiddenUnless('limit_registrations'),
            DataRequired(),
            NumberRange(min=1)
        ],
        description=_("Maximum number of registrations"))
    modification_mode = IndicoEnumSelectField(
        _("Modification allowed"),
        enum=ModificationMode,
        description=_("Will users be able to modify their data? When?"))
    publish_registrations_enabled = BooleanField(
        _('Publish registrations'),
        widget=SwitchWidget(),
        description=_("Registrations from this form will be displayed in the "
                      "event page"))
    publish_registration_count = BooleanField(
        _("Publish number of registrations"),
        widget=SwitchWidget(),
        description=_("Number of registered participants will be displayed in "
                      "the event page"))
    publish_checkin_enabled = BooleanField(
        _('Publish check-in status'),
        widget=SwitchWidget(),
        description=_(
            "Check-in status will be shown publicly on the event page"))
    base_price = DecimalField(
        _('Registration fee'),
        [NumberRange(min=0),
         Optional(), _check_if_payment_required],
        filters=[lambda x: x if x is not None else 0],
        widget=NumberInput(step='0.01'),
        description=_("A fixed fee all users have to pay when registering."))
    currency = SelectField(_('Currency'), [DataRequired()],
                           description=_('The currency for new registrations'))
    notification_sender_address = StringField(_('Notification sender address'),
                                              [IndicoEmail()],
                                              filters=[lambda x: (x or None)])
    message_pending = TextAreaField(
        _("Message for pending registrations"),
        description=_("Text included in emails sent to pending registrations"))
    message_unpaid = TextAreaField(
        _("Message for unpaid registrations"),
        description=_("Text included in emails sent to unpaid registrations"))
    message_complete = TextAreaField(
        _("Message for complete registrations"),
        description=_(
            "Text included in emails sent to complete registrations"))
    manager_notifications_enabled = BooleanField(
        _('Enabled'),
        widget=SwitchWidget(),
        description=_("Enable notifications to managers about registrations"))
    manager_notification_recipients = EmailListField(
        _('List of recipients'), [
            HiddenUnless('manager_notifications_enabled', preserve_data=True),
            DataRequired()
        ],
        description=_("Email addresses that will receive notifications"))

    def __init__(self, *args, **kwargs):
        self.event = kwargs.pop('event')
        super(IndicoForm, self).__init__(*args, **kwargs)
        self._set_currencies()
        self.notification_sender_address.description = _(
            'Email address set as the sender of all '
            'notifications sent to users. If empty, '
            'then {0} is used.'.format(config.NO_REPLY_EMAIL))

    def _set_currencies(self):
        currencies = [(c['code'], '{0[code]} ({0[name]})'.format(c))
                      for c in payment_settings.get('currencies')]
        self.currency.choices = sorted(currencies, key=lambda x: x[1].lower())
Ejemplo n.º 3
0
class CategorySettingsForm(IndicoForm):
    BASIC_FIELDS = ('title', 'description', 'timezone', 'lecture_theme',
                    'meeting_theme', 'visibility', 'suggestions_disabled',
                    'event_creation_notification_emails', 'notify_managers')
    EVENT_HEADER_FIELDS = ('event_message_mode', 'event_message')

    title = StringField(_("Title"), [DataRequired()])
    description = IndicoMarkdownField(_("Description"))
    timezone = IndicoTimezoneSelectField(
        _("Timezone"), [DataRequired()],
        description=_(
            "Default timezone event lists will show up in. It will also be "
            "used as a default for new events."))
    lecture_theme = IndicoThemeSelectField(
        _("Theme for Lectures"), [DataRequired()],
        event_type=EventType.lecture,
        description=_("Default timetable theme used for lecture events"))
    meeting_theme = IndicoThemeSelectField(
        _("Theme for Meetings"), [DataRequired()],
        event_type=EventType.meeting,
        description=_("Default timetable theme used for meeting events"))
    visibility = SelectField(
        _("Event visibility"), [Optional()],
        coerce=lambda x: None if x == '' else int(x),
        description=
        _("""From which point in the category tree contents will be visible from """
          """(number of categories upwards). Applies to "Today's events" and """
          """Calendar. If the category is moved, this number will be preserved."""
          ))
    suggestions_disabled = BooleanField(
        _('Disable Suggestions'),
        widget=SwitchWidget(),
        description=_(
            "Enable this if you don't want Indico to suggest this category as"
            " a possible addition to a user's favourites."))
    event_message_mode = IndicoEnumSelectField(
        _("Message Type"),
        enum=EventMessageMode,
        default=EventMessageMode.disabled,
        description=_(
            "This message will show up at the top of every event page "
            "in this category"))
    event_message = IndicoMarkdownField(_("Content"))
    notify_managers = BooleanField(
        _("Notify managers"),
        widget=SwitchWidget(),
        description=
        _("Whether to send email notifications to all managers of this category "
          "when an event is created inside it or in any of its subcategories."
          ))
    event_creation_notification_emails = EmailListField(
        _("Notification E-mails"),
        description=_("List of emails that will receive a notification "
                      "every time a new event is created inside the "
                      "category or one of its subcategories. "
                      "One email address per line."))

    def __init__(self, *args, **kwargs):
        super(CategorySettingsForm, self).__init__(*args, **kwargs)
        category = kwargs.pop('category')
        self.visibility.choices = get_visibility_options(category,
                                                         allow_invisible=False)

        # Check if category visibility would be affected by any of the parents
        real_horizon = category.real_visibility_horizon
        own_horizon = category.own_visibility_horizon
        if real_horizon and real_horizon.is_descendant_of(own_horizon):
            self.visibility.warning = _(
                "This category's visibility is currently limited by that of '{}'."
            ).format(real_horizon.title)
Ejemplo n.º 4
0
class AddTemplateForm(IndicoForm):
    title = StringField(_('Title'), [DataRequired()])
    type = IndicoEnumSelectField(_('Template'), enum=TemplateType, default=TemplateType.poster)
    is_clonable = BooleanField(_('Allow cloning'), widget=SwitchWidget(), default=True,
                               description=_("Allow cloning this template in subcategories and events"))
Ejemplo n.º 5
0
class ConferenceLayoutForm(LoggedLayoutForm):
    is_searchable = BooleanField(
        _("Enable search"),
        widget=SwitchWidget(),
        description=_("Enable search within the event"))
    show_nav_bar = BooleanField(
        _("Show navigation bar"),
        widget=SwitchWidget(),
        description=_("Show the navigation bar at the top"))
    show_banner = BooleanField(
        _("\"Now happening\""),
        widget=SwitchWidget(),
        description=_(
            "Show a banner with the current entries from the timetable"))
    show_social_badges = BooleanField(_("Show social badges"),
                                      widget=SwitchWidget())
    name_format = IndicoEnumSelectField(
        _('Name format'),
        enum=NameFormat,
        none=_('Inherit from user preferences'),
        description=_('Format in which names are displayed'))

    # Style
    header_text_color = StringField(_("Text colour"),
                                    widget=ColorPickerWidget())
    header_background_color = StringField(_("Background colour"),
                                          widget=ColorPickerWidget())

    # Announcement
    announcement = StringField(
        _("Announcement"),
        [UsedIf(lambda form, field: form.show_announcement.data)],
        description=_("Short message shown below the title"))
    show_announcement = BooleanField(
        _("Show announcement"),
        widget=SwitchWidget(),
        description=_("Show the announcement message"))

    # Timetable
    timetable_by_room = BooleanField(
        _("Group by room"),
        widget=SwitchWidget(),
        description=_("Group the entries of the timetable by room by default"))
    timetable_detailed = BooleanField(
        _("Show detailed view"),
        widget=SwitchWidget(),
        description=_("Show the detailed view of the timetable by default."))
    timetable_theme = SelectField(_('Theme'), [Optional()],
                                  coerce=lambda x: x or None)
    # Themes
    use_custom_css = BooleanField(
        _("Use custom CSS"),
        widget=SwitchWidget(),
        description=_(
            "Use a custom CSS file as a theme for the conference page. Deactivate "
            "this option to reveal the available Indico themes."))
    theme = SelectField(
        _("Theme"),
        [Optional(), HiddenUnless('use_custom_css', False)],
        coerce=lambda x: (x or None),
        description=_(
            "Currently selected theme of the conference page. Click on the Preview button to "
            "preview and select a different one."))

    def __init__(self, *args, **kwargs):
        self.event = kwargs.pop('event')
        super(ConferenceLayoutForm, self).__init__(*args, **kwargs)
        self.timetable_theme.choices = [
            ('', _('Default'))
        ] + _get_timetable_theme_choices(self.event)
        self.theme.choices = _get_conference_theme_choices()

    def validate_use_custom_css(self, field):
        if field.data and not self.event.has_stylesheet:
            raise ValidationError(
                _('Cannot enable custom stylesheet unless there is one.'))
Ejemplo n.º 6
0
class CategoryProtectionForm(IndicoForm):
    permissions = PermissionsField(_('Permissions'), object_type='category')
    protection_mode = IndicoProtectionField(
        _('Protection mode'),
        protected_object=lambda form: form.protected_object)
    own_no_access_contact = StringField(
        _('No access contact'),
        description=_(
            'Contact information shown when someone lacks access to the '
            'category'))
    visibility = SelectField(
        _('Event visibility'), [Optional()],
        coerce=lambda x: None if x == '' else int(x),
        description=
        _('''From which point in the category tree contents will be visible from '''
          '''(number of categories upwards). Applies to "Today's events" and '''
          '''Calendar. If the category is moved, this number will be preserved.'''
          ))
    event_creation_mode = IndicoEnumSelectField(
        _('Event creation mode'),
        enum=EventCreationMode,
        default=EventCreationMode.restricted,
        description=_(
            'Specify who can create events in the category and '
            'whether they need to be approved. Regardless of this '
            'setting, users cannot create/propose events unless they '
            'have at least read access to the category.'))

    def __init__(self, *args, **kwargs):
        self.protected_object = self.category = kwargs.pop('category')
        super().__init__(*args, **kwargs)
        self._init_visibility()

    def _init_visibility(self):
        self.visibility.choices = get_visibility_options(self.category,
                                                         allow_invisible=False)
        # Check if category visibility would be affected by any of the parents
        real_horizon = self.category.real_visibility_horizon
        own_horizon = self.category.own_visibility_horizon
        if real_horizon and real_horizon.is_descendant_of(own_horizon):
            self.visibility.warning = _(
                "This category's visibility is currently limited by that of '{}'."
            ).format(real_horizon.title)

    def validate_permissions(self, field):
        for principal_fossil, permissions in field.data:
            principal = principal_from_identifier(
                principal_fossil['identifier'],
                allow_external_users=True,
                allow_groups=True,
                allow_networks=True,
                allow_category_roles=True,
                category_id=self.category.id)
            if isinstance(principal, IPNetworkGroup
                          ) and set(permissions) - {READ_ACCESS_PERMISSION}:
                msg = _('IP networks cannot have management permissions: {}'
                        ).format(principal.name)
                raise ValidationError(msg)
            if FULL_ACCESS_PERMISSION in permissions and len(permissions) != 1:
                # when full access permission is set, discard rest of permissions
                permissions[:] = [FULL_ACCESS_PERMISSION]
Ejemplo n.º 7
0
class AbstractSubmissionSettingsForm(IndicoForm):
    """Settings form for abstract submission."""

    announcement = IndicoMarkdownField(_('Announcement'), editor=True)
    allow_multiple_tracks = BooleanField(
        _('Multiple tracks'),
        widget=SwitchWidget(),
        description=_("Allow the selection of multiple tracks"))
    tracks_required = BooleanField(
        _('Require tracks'),
        widget=SwitchWidget(),
        description=_("Make the track selection mandatory"))
    contrib_type_required = BooleanField(
        _('Require contrib. type'),
        widget=SwitchWidget(),
        description=_("Make the selection of a contribution type mandatory"))
    allow_attachments = BooleanField(
        _('Allow attachments'),
        widget=SwitchWidget(),
        description=_("Allow files to be attached to the abstract"))
    copy_attachments = BooleanField(
        _('Copy attachments'), [HiddenUnless('allow_attachments')],
        widget=SwitchWidget(),
        description=_(
            "Copy attachments to the contribution when accepting an abstract"))
    allow_speakers = BooleanField(
        _('Allow speakers'),
        widget=SwitchWidget(),
        description=_("Allow the selection of the abstract speakers"))
    speakers_required = BooleanField(
        _('Require a speaker'), [HiddenUnless('allow_speakers')],
        widget=SwitchWidget(),
        description=_(
            "Make the selection of at least one author as speaker mandatory"))
    allow_editing = IndicoEnumSelectField(
        _('Allow editing'),
        enum=AllowEditingType,
        sorted=True,
        description=_("Specify who will be able to edit the abstract"))
    contribution_submitters = IndicoEnumSelectField(
        _('Contribution submitters'),
        enum=SubmissionRightsType,
        sorted=True,
        description=_("Specify who will get contribution submission rights "
                      "once an abstract has been accepted"))
    authorized_submitters = PrincipalListField(
        _("Authorized submitters"),
        event=lambda form: form.event,
        allow_external_users=True,
        allow_groups=True,
        allow_event_roles=True,
        allow_category_roles=True,
        description=_("These users may always submit abstracts, "
                      "even outside the regular submission period."))
    submission_instructions = IndicoMarkdownField(
        _('Instructions'),
        editor=True,
        description=_("These instructions will be displayed right before the "
                      "submission form"))

    @generated_data
    def announcement_render_mode(self):
        return RenderMode.markdown

    def __init__(self, *args, **kwargs):
        self.event = kwargs.pop('event')
        super().__init__(*args, **kwargs)

    def validate_contrib_type_required(self, field):
        if field.data and not self.event.contribution_types.count():
            raise ValidationError(
                _('The event has no contribution types defined.'))
Ejemplo n.º 8
0
class PluginSettingsForm(VCPluginSettingsFormBase):
    _fieldsets = [
        (_('API Credentials'), ['api_key', 'api_secret', 'webhook_token']),
        (_('Zoom Account'), [
            'user_lookup_mode', 'email_domains', 'authenticators',
            'enterprise_domain', 'allow_webinars', 'phone_link'
        ]),
        (_('Room Settings'), [
            'mute_audio', 'mute_host_video', 'mute_participant_video',
            'join_before_host', 'waiting_room'
        ]),
        (_('Notifications'),
         ['creation_email_footer', 'send_host_url', 'notification_emails']),
        (_('Access'), ['managers', 'acl'])
    ]

    api_key = StringField(_('API Key'), [DataRequired()])

    api_secret = IndicoPasswordField(_('API Secret'), [DataRequired()],
                                     toggle=True)

    webhook_token = IndicoPasswordField(
        _('Webhook Token'),
        toggle=True,
        description=_("Specify Zoom's webhook token if you want live updates"))

    user_lookup_mode = IndicoEnumSelectField(
        _('User lookup mode'), [DataRequired()],
        enum=UserLookupMode,
        description=_('Specify how Indico should look up the zoom user that '
                      'corresponds to an Indico user.'))

    email_domains = TextListField(
        _('E-mail domains'), [
            HiddenUnless('user_lookup_mode', UserLookupMode.email_domains),
            DataRequired()
        ],
        description=
        _('List of e-mail domains which can use the Zoom API. Indico attempts '
          'to find Zoom accounts using all email addresses of a user which use '
          'those domains.'))

    authenticators = TextListField(
        _('Indico identity providers'), [
            HiddenUnless('user_lookup_mode', UserLookupMode.authenticators),
            DataRequired()
        ],
        description=
        _('Identity providers from which to get usernames. '
          'Indico queries those providers using the email addresses of the user '
          'and attempts to find Zoom accounts having an email address with the '
          'format username@enterprise-domain.'))

    enterprise_domain = StringField(
        _('Enterprise domain'), [
            HiddenUnless('user_lookup_mode', UserLookupMode.authenticators),
            DataRequired()
        ],
        description=_(
            'The domain name used together with the usernames from the Indico '
            'identity provider'))

    allow_webinars = BooleanField(
        _('Allow Webinars (Experimental)'),
        widget=SwitchWidget(),
        description=_(
            'Allow webinars to be created through Indico. Use at your own risk.'
        ))

    mute_audio = BooleanField(
        _('Mute audio'),
        widget=SwitchWidget(),
        description=_('Participants will join the VC room muted by default '))

    mute_host_video = BooleanField(
        _('Mute video (host)'),
        widget=SwitchWidget(),
        description=_('The host will join the VC room with video disabled'))

    mute_participant_video = BooleanField(
        _('Mute video (participants)'),
        widget=SwitchWidget(),
        description=_(
            'Participants will join the VC room with video disabled'))

    join_before_host = BooleanField(
        _('Join Before Host'),
        widget=SwitchWidget(),
        description=_(
            'Allow participants to join the meeting before the host starts the '
            'meeting. Only used for scheduled or recurring meetings.'))

    waiting_room = BooleanField(
        _('Waiting room'),
        widget=SwitchWidget(),
        description=_(
            'Participants may be kept in a waiting room by the host'))

    creation_email_footer = TextAreaField(
        _('Creation email footer'),
        widget=CKEditorWidget(),
        description=_(
            'Footer to append to emails sent upon creation of a VC room'))

    send_host_url = BooleanField(
        _('Send host URL'),
        widget=SwitchWidget(),
        description=_(
            'Whether to send an e-mail with the Host URL to the meeting host upon '
            'creation of a meeting'))

    phone_link = URLField(
        _('Join via phone'), [Optional(), URL()],
        description=_('Link to instructions on joining a meeting via phone'))

    def validate_authenticators(self, field):
        invalid = set(field.data) - set(multipass.identity_providers)
        if invalid:
            raise ValidationError(
                _('Invalid identity providers: {}').format(
                    escape(', '.join(invalid))))