Esempio n. 1
0
class NewsSettingsForm(fossirForm):
    show_recent = BooleanField(
        'Show headlines',
        widget=SwitchWidget(),
        description=_(
            'Whether to show the latest news headlines on the fossir home page.'
        ))
    max_entries = IntegerField(
        _('Max. headlines'),
        [HiddenUnless('show_recent'),
         DataRequired(),
         NumberRange(min=1)],
        description=
        _("The maximum number of news headlines to show on the fossir home page."
          ))
    max_age = IntegerField(
        _('Max. age'),
        [HiddenUnless('show_recent'),
         InputRequired(),
         NumberRange(min=0)],
        description=_(
            "The maximum age in days for news to show up on the fossir home page. "
            "Setting it to 0 will show news no matter how old they are."))
    new_days = IntegerField(
        _('"New" threshold'),
        [InputRequired(), NumberRange(min=0)],
        description=_(
            'The maximum age in days for news to be considered "new". Setting it to 0 '
            'will disable the "new" label altogether.'))
Esempio n. 2
0
class AttachmentPackageForm(fossirForm):
    added_since = fossirDateField(
        _('Added Since'), [Optional()],
        description=_('Include only attachments uploaded after this date'))

    filter_type = fossirRadioField(_('Include'), [DataRequired()])

    sessions = fossirSelectMultipleCheckboxField(
        _('Sessions'),
        [HiddenUnless('filter_type', 'sessions'),
         DataRequired()],
        description=_('Include materials from selected sessions'),
        coerce=int)
    contributions = fossirSelectMultipleCheckboxField(
        _('Contributions'),
        [HiddenUnless('filter_type', 'contributions'),
         DataRequired()],
        description=_('Include materials from selected contributions'),
        coerce=int)
    dates = fossirSelectMultipleCheckboxField(
        _('Events scheduled on'),
        [HiddenUnless('filter_type', 'dates'),
         DataRequired()],
        description=_(
            'Include materials from sessions/contributions scheduled '
            'on the selected dates'))
Esempio n. 3
0
class TimetablePDFExportForm(fossirForm):
    _pdf_options_fields = {'pagesize', 'fontsize', 'firstPageNumber'}

    advanced = BooleanField(_("Advanced timetable"),
                            widget=SwitchWidget(),
                            description=_("Advanced customization options"))
    document_settings = fossirSelectMultipleCheckboxBooleanField(
        _('Document settings'), [HiddenUnless('advanced')],
        choices=_DOCUMENT_SETTINGS_CHOICES)
    contribution_info = fossirSelectMultipleCheckboxBooleanField(
        _('Contributions related info'), [HiddenUnless('advanced')],
        choices=_CONTRIBUTION_CHOICES)
    session_info = fossirSelectMultipleCheckboxBooleanField(
        _('Sessions related info'), [HiddenUnless('advanced')],
        choices=_SESSION_CHOICES)
    visible_entries = fossirSelectMultipleCheckboxBooleanField(
        _('Breaks and contributions'), [HiddenUnless('advanced')],
        choices=_VISIBLE_ENTRIES_CHOICES)
    other = fossirSelectMultipleCheckboxBooleanField(_('Miscellaneous'),
                                                     choices=_OTHER_CHOICES)
    pagesize = SelectField(_('Page size'),
                           choices=[('A0', 'A0'), ('A1', 'A1'), ('A2', 'A2'),
                                    ('A3', 'A3'), ('A4', 'A4'), ('A5', 'A5'),
                                    ('Letter', 'Letter')],
                           default='A4')
    fontsize = SelectField(_('Font size'),
                           choices=[('xxx-small', _('xxx-small')),
                                    ('xx-small', _('xx-small')),
                                    ('x-small', _('x-small')),
                                    ('smaller', _('smaller')),
                                    ('small', _('small')),
                                    ('normal', _('normal')),
                                    ('large', _('large')),
                                    ('larger', _('larger'))],
                           default='normal')
    firstPageNumber = IntegerField(_('Number for the first page'),
                                   [NumberRange(min=1)],
                                   default=1,
                                   widget=NumberInput(step=1))
    submitted = HiddenField()

    def is_submitted(self):
        return 'submitted' in request.args

    @property
    def data_for_format(self):
        if not self.advanced.data:
            fields = ('visible_entries', )
        else:
            fields = set(
                get_form_field_names(TimetablePDFExportForm)
            ) - self._pdf_options_fields - {'csrf_token', 'advanced'}
        data = {}
        for fieldname in fields:
            data.update(getattr(self, fieldname).data)
        return data
Esempio n. 4
0
class NewBookingConfirmForm(NewBookingPeriodForm):
    room_usage = RadioField(
        [DataRequired()],
        choices=[('current_user', _("I'll be using the room myself")),
                 ('other_user', _("I'm booking the room for someone else"))])
    booked_for_user = PrincipalField(
        _('User'), [HiddenUnless('room_usage', 'other_user'),
                    DataRequired()],
        allow_external=True)
    booking_reason = TextAreaField(_('Reason'), [DataRequired()])
    uses_vc = BooleanField(_('I will use videoconference equipment'))
    used_equipment = fossirQuerySelectMultipleCheckboxField(
        _('VC equipment'), get_label=lambda x: x.name)
    needs_vc_assistance = BooleanField(
        _('Request assistance for the startup of the videoconference session. '
          'This support is usually performed remotely.'))
    needs_assistance = BooleanField(
        _('Request personal assistance for meeting startup'))
    submit_book = SubmitField(_('Create booking'))
    submit_prebook = SubmitField(_('Create pre-booking'))

    def validate_used_equipment(self, field):
        if field.data and not self.uses_vc.data:
            raise ValidationError(_('Videoconference equipment is not used.'))
        elif not field.data and self.uses_vc.data:
            raise ValidationError(
                _('Please select the type of videoconference that you will use.'
                  ))

    def validate_needs_vc_assistance(self, field):
        if field.data and not self.uses_vc.data:
            raise ValidationError(_('Videoconference equipment is not used.'))
Esempio n. 5
0
class TicketsForm(fossirForm):
    tickets_enabled = BooleanField(
        _('Enable Tickets'),
        widget=SwitchWidget(),
        description=_(
            'Create tickets for registrations using this registration form.'))
    ticket_on_email = BooleanField(
        _('Send with an e-mail'),
        [HiddenUnless('tickets_enabled', preserve_data=True)],
        widget=SwitchWidget(),
        description=_(
            'Attach PDF ticket to the email sent to a user after completing '
            'their registration.'))
    ticket_on_event_page = BooleanField(
        _('Download from event homepage'),
        [HiddenUnless('tickets_enabled', preserve_data=True)],
        widget=SwitchWidget(),
        description=_('Allow users to download their ticket from the '
                      'conference homepage.'))
    ticket_on_summary_page = BooleanField(
        _('Download from summary page'),
        [HiddenUnless('tickets_enabled', preserve_data=True)],
        widget=SwitchWidget(),
        description=_(
            'Allow users to download their ticket from the registration '
            'summary page.'))

    ticket_template_id = SelectField(
        _('Ticket template'),
        [HiddenUnless('tickets_enabled', preserve_data=True),
         Optional()],
        coerce=int)

    def __init__(self, *args, **kwargs):
        event = kwargs.pop('event')
        super(TicketsForm, self).__init__(*args, **kwargs)
        default_tpl = get_default_template_on_category(event.category)
        all_templates = set(
            event.designer_templates) | get_inherited_templates(event)
        badge_templates = [
            (tpl.id, tpl.title) for tpl in all_templates
            if tpl.type == TemplateType.badge and tpl != default_tpl
        ]
        # Show the default template first
        badge_templates.insert(0, (default_tpl.id, '{} ({})'.format(
            default_tpl.title, _('Default category template'))))
        self.ticket_template_id.choices = badge_templates
Esempio n. 6
0
class SectionForm(fossirForm):
    display_as_section = BooleanField(
        _("Display as section"),
        widget=SwitchWidget(),
        default=True,
        description=_(
            "Whether this is going to be displayed as a section or standalone")
    )
    title = StringField(_('Title'), [
        HiddenUnless('display_as_section', preserve_data=True),
        DataRequired()
    ],
                        description=_("The title of the section."))
    description = TextAreaField(
        _('Description'),
        [HiddenUnless('display_as_section', preserve_data=True)],
        description=_("The description text of the section."))
Esempio n. 7
0
 def _add_contrib_type_hidden_unless(cls):
     # In the bulk form we need to hide/disable the contrib type selector unless we want to
     # override the type specified in the abstract.  However, multiple HiddenUnless validators
     # are not supported in the client-side JS so we only add it to this form - it removes
     # inactive fields on the server side so it still works (the JavaScript picks up the last
     # HiddenUnless validator)
     inject_validators(BulkAbstractJudgmentForm, 'accepted_contrib_type',
                       [HiddenUnless('override_contrib_type')])
Esempio n. 8
0
class DeadlineForm(fossirForm):
    deadline = fossirDateTimeField(_("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)
Esempio n. 9
0
class MultiSelectConfigForm(object):
    options = MultiStringField(
        _('Options'), [DataRequired()],
        field=('option', _('option')),
        unique=True,
        uuid_field='id',
        sortable=True,
        description=_('Specify the answers the user can select'))
    min_choices = IntegerField(
        _("Minimum choices"),
        [HiddenUnless('is_required'),
         Optional(),
         NumberRange(min=0)],
        description=_("The minimum amount of options the user has to choose."))
    max_choices = IntegerField(
        _("Maximum choices"),
        [HiddenUnless('is_required'),
         Optional(),
         NumberRange(min=1)],
        description=_("The maximum amount of options the user may choose."))

    def _validate_min_max_choices(self):
        if (self.min_choices.data is not None
                and self.max_choices.data is not None
                and self.min_choices.data > self.max_choices.data):
            raise ValidationError(
                _('Maximum choices must be greater than minimum choices.'))

    def validate_min_choices(self, field):
        if field.data is None:
            return
        if field.data >= len(self.options.data):
            raise ValidationError(
                _("Minimum choices must be fewer than the total number of options."
                  ))

    def validate_max_choices(self, field):
        if field.data is None:
            return
        self._validate_min_max_choices()
        if field.data > len(self.options.data):
            raise ValidationError(
                _("Maximum choices must be fewer or equal than the total number of options."
                  ))
Esempio n. 10
0
class CloneRepeatUntilFormBase(CloneRepeatOnceForm):
    stop_criterion = fossirRadioField(
        _('Clone'), [DataRequired()],
        default='num_times',
        choices=(('day', _('Until a given day (inclusive)')),
                 ('num_times', _('A number of times'))))
    until_dt = fossirDateField(
        _('Day'), [HiddenUnless('stop_criterion', 'day'),
                   DataRequired()])
    num_times = IntegerField(_('Number of times'), [
        HiddenUnless('stop_criterion', 'num_times'),
        DataRequired(),
        NumberRange(1, 100, message=_("You can clone a maximum of 100 times"))
    ],
                             default=2)

    def __init__(self, event, **kwargs):
        kwargs['until_dt'] = (self._calc_start_dt(event) +
                              timedelta(days=14)).date()
        super(CloneRepeatUntilFormBase, self).__init__(event, **kwargs)
Esempio n. 11
0
 def __init__(self, *args, **kwargs):
     if config.LOCAL_IDENTITIES:
         for field in ('username', 'password', 'confirm_password'):
             inject_validators(self,
                               field, [HiddenUnless('create_identity')],
                               early=True)
     super(AdminAccountRegistrationForm, self).__init__(*args, **kwargs)
     del self.comment
     if not config.LOCAL_IDENTITIES:
         del self.username
         del self.password
         del self.confirm_password
         del self.create_identity
Esempio n. 12
0
class AbstractSubmissionSettingsForm(fossirForm):
    """Settings form for abstract submission"""

    announcement = fossirMarkdownField(_('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"))
    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"))
    authorized_submitters = PrincipalListField(
        _("Authorized submitters"),
        description=_("These users may always submit abstracts, even outside "
                      "the regular submission period."))
    submission_instructions = fossirMarkdownField(
        _('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(AbstractSubmissionSettingsForm, self).__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.'))
Esempio n. 13
0
class NewBookingSimpleForm(NewBookingConfirmForm):
    submit_check = SubmitField(_('Check conflicts'))
    booking_reason = TextAreaField(_('Reason'), [
        UsedIf(lambda form, field: not form.submit_check.data),
        DataRequired()
    ])
    room_usage = RadioField(
        validators=[
            UsedIf(lambda form, field: not form.submit_check.data),
            DataRequired()
        ],
        choices=[('current_user', _("I'll be using the room myself")),
                 ('other_user', _("I'm booking the room for someone else"))])
    booked_for_user = PrincipalField(_('User'), [
        UsedIf(lambda form, field: not form.submit_check.data),
        HiddenUnless('room_usage', 'other_user'),
        DataRequired()
    ],
                                     allow_external=True)
Esempio n. 14
0
class MenuBuiltinEntryForm(fossirForm):
    custom_title = BooleanField(_("Custom title"), widget=SwitchWidget())
    title = StringField(_("Title"),
                        [HiddenUnless('custom_title'),
                         DataRequired()])
    is_enabled = BooleanField(_("Show"), widget=SwitchWidget())

    def __init__(self, *args, **kwargs):
        entry = kwargs.pop('entry')
        super(MenuBuiltinEntryForm, self).__init__(*args, **kwargs)
        self.custom_title.description = _(
            "If you customize the title, that title is used regardless of the user's "
            "language preference.  The default title <strong>{title}</strong> is "
            "displayed in the user's language.").format(
                title=entry.default_data.title)

    def post_validate(self):
        if not self.custom_title.data:
            self.title.data = None
Esempio n. 15
0
class SingleChoiceConfigForm(object):
    display_type = fossirRadioField(
        _('Display type'), [DataRequired()],
        description=_(
            'Widget that will be used to render the available options'),
        choices=[('radio', _('Radio buttons')),
                 ('select', _('Drop-down list'))],
        default='radio')
    radio_display_type = fossirRadioField(
        _('Alignment'),
        [DataRequired(), HiddenUnless('display_type', 'radio')],
        description=_('The arrangement of the options'),
        choices=[('vertical', _('Vertical')), ('horizontal', _('Horizontal'))])
    options = MultiStringField(
        _('Options'), [DataRequired()],
        field=('option', _('option')),
        unique=True,
        uuid_field='id',
        sortable=True,
        description=_('Specify the options the user can choose from'))
Esempio n. 16
0
class SurveyForm(fossirForm):
    _notification_fields = ('notifications_enabled', 'notify_participants',
                            'start_notification_emails',
                            'new_submission_emails')

    title = StringField(_("Title"), [DataRequired()],
                        description=_("The title of the survey"))
    introduction = TextAreaField(
        _("Introduction"),
        description=_("An introduction to be displayed before the survey"))
    anonymous = BooleanField(
        _("Anonymous submissions"),
        widget=SwitchWidget(),
        description=_("User information will not be attached to submissions"))
    require_user = BooleanField(
        _("Only logged-in users"), [HiddenUnless('anonymous')],
        widget=SwitchWidget(),
        description=_(
            "Require users to be logged in for submitting the survey"))
    limit_submissions = BooleanField(
        _("Limit submissions"),
        widget=SwitchWidget(),
        description=_("Whether there is a submission cap"))
    submission_limit = IntegerField(
        _("Capacity"), [
            HiddenUnless('limit_submissions'),
            DataRequired(),
            NumberRange(min=1)
        ],
        description=_("Maximum number of submissions accepted"))
    private = BooleanField(
        _("Private survey"),
        widget=SwitchWidget(),
        description=_("Only selected people can answer the survey."))
    partial_completion = BooleanField(
        _('Partial completion'),
        widget=SwitchWidget(),
        description=_('Allow to save answers without submitting the survey.'))
    notifications_enabled = BooleanField(
        _('Enabled'),
        widget=SwitchWidget(),
        description=_(
            'Send email notifications for specific events related to the '
            'survey.'))
    notify_participants = BooleanField(
        _('Participants'),
        [HiddenUnless('notifications_enabled', preserve_data=True)],
        widget=SwitchWidget(),
        description=_(
            'Notify participants of the event when this survey starts.'))
    start_notification_emails = EmailListField(
        _('Start notification recipients'),
        [HiddenUnless('notifications_enabled', preserve_data=True)],
        description=_(
            'Email addresses to notify about the start of the survey'))
    new_submission_emails = EmailListField(
        _('New submission notification recipients'),
        [HiddenUnless('notifications_enabled', preserve_data=True)],
        description=_(
            'Email addresses to notify when a new submission is made'))

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

    def validate_title(self, field):
        query = (Survey.query.with_parent(self.event).filter(
            db.func.lower(Survey.title) == field.data.lower(),
            Survey.title != field.object_data, ~Survey.is_deleted))
        if query.count():
            raise ValidationError(
                _('There is already a survey named "{}" on this event'.format(
                    escape(field.data))))

    def post_validate(self):
        if not self.anonymous.data:
            self.require_user.data = True
Esempio n. 17
0
class BulkAbstractJudgmentForm(AbstractJudgmentFormBase):
    _order = ('judgment', 'accepted_track', 'override_contrib_type',
              'accepted_contrib_type', 'session', 'duplicate_of',
              'merged_into', 'merge_persons', 'judgment_comment',
              'send_notifications')

    judgment = HiddenEnumField(enum=AbstractAction,
                               skip={AbstractAction.change_tracks})
    abstract_id = HiddenFieldList()
    submitted = HiddenField()
    override_contrib_type = BooleanField(
        _("Override contribution type"),
        [HiddenUnless('judgment', AbstractAction.accept)],
        widget=SwitchWidget(),
        description=_(
            "Override the contribution type for all selected abstracts"))

    def __init__(self, *args, **kwargs):
        self.event = kwargs.pop('event')
        super(BulkAbstractJudgmentForm, self).__init__(*args, **kwargs)
        if self.accepted_track:
            self.accepted_track.description = _(
                "The abstracts will be accepted in this track")
        if self.accepted_contrib_type:
            self.accepted_contrib_type.description = _(
                "The abstracts will be converted into a contribution of this "
                "type")
        else:
            del self.override_contrib_type
        if self.session:
            self.session.description = _(
                "The generated contributions will be allocated in this session"
            )
        self.duplicate_of.description = _(
            "The selected abstracts will be marked as duplicate of the specified "
            "abstract")
        self.merged_into.description = _(
            "The selected abstracts will be merged into the specified abstract"
        )
        self.merge_persons.description = _(
            "Authors and speakers of the selected abstracts will be added to the "
            "specified abstract")
        self.duplicate_of.excluded_abstract_ids = set(kwargs['abstract_id'])
        self.merged_into.excluded_abstract_ids = set(kwargs['abstract_id'])
        if kwargs['judgment']:
            self._remove_unused_fields(kwargs['judgment'])

    def _remove_unused_fields(self, judgment):
        for field in list(self):
            validator = next(
                (v for v in field.validators
                 if isinstance(v, HiddenUnless) and v.field == 'judgment'),
                None)
            if validator is None:
                continue
            if not any(v.name == judgment for v in validator.value):
                delattr(self, field.name)

    def is_submitted(self):
        return super(BulkAbstractJudgmentForm,
                     self).is_submitted() and 'submitted' in request.form

    @classmethod
    def _add_contrib_type_hidden_unless(cls):
        # In the bulk form we need to hide/disable the contrib type selector unless we want to
        # override the type specified in the abstract.  However, multiple HiddenUnless validators
        # are not supported in the client-side JS so we only add it to this form - it removes
        # inactive fields on the server side so it still works (the JavaScript picks up the last
        # HiddenUnless validator)
        inject_validators(BulkAbstractJudgmentForm, 'accepted_contrib_type',
                          [HiddenUnless('override_contrib_type')])
Esempio n. 18
0
class AbstractReviewForm(fossirForm):
    """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)...")
                            })
    proposed_action = fossirEnumSelectField(_("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 = fossirQuerySelectMultipleCheckboxField(
        _("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_')
            }
        }
Esempio n. 19
0
class AbstractJudgmentFormBase(fossirForm):
    """Form base class for abstract judgment operations"""

    _order = ('judgment', 'accepted_track', 'accepted_contrib_type', 'session',
              'duplicate_of', 'merged_into', 'merge_persons',
              'judgment_comment', 'send_notifications')

    accepted_track = QuerySelectField(
        _("Track"), [HiddenUnless('judgment', AbstractAction.accept)],
        get_label='title',
        allow_blank=True,
        blank_text=_("Choose a track..."),
        description=_("The abstract will be accepted in this track"))
    accepted_contrib_type = QuerySelectField(
        _("Contribution type"),
        [HiddenUnless('judgment', AbstractAction.accept)],
        get_label=lambda x: x.name.title(),
        allow_blank=True,
        blank_text=_("You may choose a contribution type..."),
        description=_("The abstract will be converted "
                      "into a contribution of this type"))
    session = QuerySelectField(
        _("Session"), [HiddenUnless('judgment', AbstractAction.accept)],
        get_label='title',
        allow_blank=True,
        blank_text=_("You may choose a session..."),
        description=_(
            "The generated contribution will be allocated in this session"))
    duplicate_of = AbstractField(
        _("Duplicate of"), [
            HiddenUnless('judgment', AbstractAction.mark_as_duplicate),
            DataRequired()
        ],
        description=
        _("The current abstract will be marked as duplicate of the selected one"
          ),
        ajax_endpoint='abstracts.other_abstracts')
    merged_into = AbstractField(
        _("Merge into"),
        [HiddenUnless('judgment', AbstractAction.merge),
         DataRequired()],
        description=_(
            "The current abstract will be merged into the selected one"),
        ajax_endpoint='abstracts.other_abstracts')
    merge_persons = BooleanField(
        _("Merge persons"), [HiddenUnless('judgment', AbstractAction.merge)],
        description=_(
            "Authors and speakers of the current abstract will be added to the "
            "selected one"))
    judgment_comment = TextAreaField(
        _("Comment"),
        render_kw={'placeholder': _("Leave a comment for the submitter...")})
    # TODO: show only if notifications apply?
    send_notifications = BooleanField(_("Send notifications to submitter"),
                                      default=True)

    def __init__(self, *args, **kwargs):
        super(AbstractJudgmentFormBase, self).__init__(*args, **kwargs)
        self.session.query = Session.query.with_parent(self.event).order_by(
            Session.title)
        if not self.session.query.count():
            del self.session
        self.accepted_track.query = Track.query.with_parent(
            self.event).order_by(Track.position)
        if not self.accepted_track.query.count():
            del self.accepted_track
        self.accepted_contrib_type.query = (ContributionType.query.with_parent(
            self.event).order_by(ContributionType.name))
        if not self.accepted_contrib_type.query.count():
            del self.accepted_contrib_type

    @property
    def split_data(self):
        abstract_data = self.data
        judgment_data = {
            'judgment': abstract_data.pop('judgment'),
            'send_notifications': abstract_data.pop('send_notifications'),
            'contrib_session': abstract_data.pop('session', None),
            'merge_persons': abstract_data.pop('merge_persons', None)
        }
        return judgment_data, abstract_data
Esempio n. 20
0
class AbstractReviewingSettingsForm(fossirForm):
    """Settings form for abstract reviewing"""

    RATING_FIELDS = ('scale_lower', 'scale_upper')

    scale_lower = IntegerField(
        _("Scale (from)"),
        [UsedIf(lambda form, field: not form.has_ratings),
         InputRequired()])
    scale_upper = IntegerField(
        _("Scale (to)"),
        [UsedIf(lambda form, field: not form.has_ratings),
         InputRequired()])
    allow_convener_judgment = BooleanField(
        _("Allow track conveners to judge"),
        widget=SwitchWidget(),
        description=_(
            "Enabling this allows track conveners to make a judgment "
            "such as accepting or rejecting an abstract."))
    allow_comments = BooleanField(
        _("Allow comments"),
        widget=SwitchWidget(),
        description=_(
            "Enabling this allows judges, conveners and reviewers to leave "
            "comments on abstracts."))
    allow_contributors_in_comments = BooleanField(
        _("Allow contributors in comments"),
        [HiddenUnless('allow_comments', preserve_data=True)],
        widget=SwitchWidget(),
        description=_("Enabling this allows submitters, authors, and "
                      "speakers to also participate in the comments."))
    abstract_review_questions = ReviewQuestionsField(
        _("Review questions"),
        question_model=AbstractReviewQuestion,
        extra_fields=[{
            'id': 'no_score',
            'caption': _("Exclude from score"),
            'type': 'checkbox'
        }])
    reviewing_instructions = fossirMarkdownField(
        _('Reviewing Instructions'),
        editor=True,
        description=_("These instructions will be displayed right before the "
                      "reviewing form."))
    judgment_instructions = fossirMarkdownField(
        _('Judgment Instructions'),
        editor=True,
        description=_("These instructions will be displayed right before the "
                      "decision box."))

    def __init__(self, *args, **kwargs):
        self.event = kwargs.pop('event')
        self.has_ratings = kwargs.pop('has_ratings', False)
        super(AbstractReviewingSettingsForm, self).__init__(*args, **kwargs)
        if self.has_ratings:
            self.scale_upper.warning = _(
                "Some reviewers have already submitted ratings so the scale cannot be changed "
                "anymore.")

    def validate_scale_upper(self, field):
        lower = self.scale_lower.data
        upper = self.scale_upper.data
        if lower is None or upper is None:
            return
        if lower >= upper:
            raise ValidationError(
                _("The scale's 'to' value must be greater than the 'from' value."
                  ))
        if upper - lower > 20:
            raise ValidationError(
                _("The difference between 'to' and' from' may not be greater than 20."
                  ))

    @property
    def data(self):
        data = super(AbstractReviewingSettingsForm, self).data
        if self.has_ratings:
            for key in self.RATING_FIELDS:
                del data[key]
        return data
Esempio n. 21
0
class ReminderForm(fossirForm):
    default_widget_attrs = {'absolute_time': {'placeholder': 'HH:MM'}}
    recipient_fields = {'recipients', 'send_to_participants'}
    schedule_fields = {'schedule_type', 'absolute_date', 'absolute_time', 'relative_delta'}
    schedule_recipient_fields = recipient_fields | schedule_fields

    # Schedule
    schedule_type = fossirRadioField(_('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_date = fossirDateField(_('Date'), [HiddenUnless('schedule_type', 'absolute'), DataRequired()])
    absolute_time = TimeField(_('Time'), [HiddenUnless('schedule_type', 'absolute'), InputRequired()])
    # 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."))

    def __init__(self, *args, **kwargs):
        self.event = kwargs.pop('event')
        super(ReminderForm, self).__init__(*args, **kwargs)
        self.absolute_time.description = _("The event's timezone is {tz}.").format(tz=self.event.tzinfo)
        self.reply_to_address.choices = (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'))

    def validate_absolute_date(self, field):
        if self.schedule_type.data == 'absolute' and field.data < date.today():
            raise ValidationError(_('The specified date is in the past'))

    @generated_data
    def scheduled_dt(self):
        if self.schedule_type.data == 'absolute':
            if self.absolute_date.data is None or self.absolute_time.data is None:
                return None
            dt = datetime.combine(self.absolute_date.data, self.absolute_time.data)
            return self.event.tzinfo.localize(dt).astimezone(pytz.utc)
        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
Esempio n. 22
0
class ConferenceLayoutForm(fossirForm):
    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(on_label=_("ON"), off_label=_("OFF")),
        description=_(
            "Show a banner with the current entries from the timetable"))
    show_social_badges = BooleanField(_("Show social badges"),
                                      widget=SwitchWidget())

    # 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 fossir 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.'))
Esempio n. 23
0
class RegistrationFormForm(fossirForm):
    _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 fossir 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 = fossirEnumSelectField(
        _("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'),
                                              [fossirEmail()],
                                              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(fossirForm, 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())