Exemplo n.º 1
0
class AccessControlListField(PrincipalListField):
    widget = JinjaWidget('forms/principal_list_widget.html',
                         single_kwargs=True,
                         acl=True)

    def __init__(self, *args, **kwargs):
        # The text of the link that changes the protection mode of the object to protected
        self.default_text = kwargs.pop('default_text')
        super(AccessControlListField, self).__init__(*args, **kwargs)
Exemplo n.º 2
0
class OverrideMultipleItemsField(HiddenField):
    """A field similar to `MultipleItemsField` which allows the user to override some values.

    :param fields: a list of ``(fieldname, title)`` tuples. Should match
                   the fields of the corresponding `MultipleItemsField`.
    :param field_data: the data from the corresponding `MultipleItemsField`.
    :param unique_field: the name of the field which is unique among all rows
    :param edit_fields: a set containing the field names which can be edited

    If you decide to use this field, please consider adding support
    for `uuid_field` here!
    """

    widget = JinjaWidget('forms/override_multiple_items_widget.html')

    def __init__(self, *args, **kwargs):
        self.fields = kwargs.pop('fields')
        self.field_data = kwargs.pop('field_data', None)  # usually set after creating the form instance
        self.unique_field = kwargs.pop('unique_field')
        self.edit_fields = set(kwargs.pop('edit_fields'))
        super(OverrideMultipleItemsField, self).__init__(*args, **kwargs)

    def process_formdata(self, valuelist):
        if is_preprocessed_formdata(valuelist):
            self.data = valuelist[0]
        elif valuelist:
            self.data = json.loads(valuelist[0])

    def pre_validate(self, form):
        valid_keys = {x[self.unique_field] for x in self.field_data}
        for key, values in self.data.items():
            if key not in valid_keys:
                # e.g. a row removed from field_data that had a value before
                del self.data[key]
                continue
            if values.viewkeys() > self.edit_fields:
                # e.g. a field that was editable before
                self.data[key] = {k: v for k, v in values.iteritems() if k in self.edit_fields}
        # Remove anything empty
        for key, values in self.data.items():
            for field, value in values.items():
                if not value:
                    del values[field]
            if not self.data[key]:
                del self.data[key]

    def _value(self):
        return self.data or {}

    def get_overridden_value(self, row, name):
        """Utility for the widget to get the entered value for an editable field"""
        key = self.get_row_key(row)
        return self._value().get(key, {}).get(name, '')

    def get_row_key(self, row):
        """Utility for the widget to get the unique value for a row"""
        return row[self.unique_field]
Exemplo n.º 3
0
class PrincipalListField(HiddenField):
    """A field that lets you select a list Indico user/group ("principal")

    :param groups: If groups should be selectable.
    :param allow_networks: If ip networks should be selectable.
    :param allow_emails: If emails should be allowed.
    :param allow_external: If "search users with no indico account"
                           should be available.  Selecting such a user
                           will automatically create a pending user once
                           the form is submitted, even if other fields
                           in the form fail to validate!
    """

    widget = JinjaWidget('forms/principal_list_widget.html', single_kwargs=True)

    def __init__(self, *args, **kwargs):
        self.allow_emails = kwargs.pop('allow_emails', False)
        self.groups = kwargs.pop('groups', False)
        self.allow_networks = kwargs.pop('allow_networks', False)
        self.ip_networks = []
        if self.allow_networks:
            self.ip_networks = map(serialize_ip_network_group, IPNetworkGroup.query.filter_by(hidden=False))
        # Whether it is allowed to search for external users with no indico account
        self.allow_external = kwargs.pop('allow_external', False)
        # Whether the add user dialog is opened immediately when the field is displayed
        self.open_immediately = kwargs.pop('open_immediately', False)
        self._event = kwargs.pop('event')(kwargs['_form']) if 'event' in kwargs else None
        super(PrincipalListField, self).__init__(*args, **kwargs)

    def _convert_principal(self, principal):
        return principal_from_fossil(principal, allow_pending=self.allow_external,
                                     allow_emails=self.allow_emails, allow_networks=self.allow_networks,
                                     existing_data=self.object_data, event=self._event)

    def process_formdata(self, valuelist):
        if valuelist:
            self.data = {self._convert_principal(x) for x in json.loads(valuelist[0])}

    def pre_validate(self, form):
        if not self.groups and any(isinstance(p, GroupProxy) for p in self._get_data()):
            raise ValueError('You cannot select groups')

    def _value(self):
        from indico.modules.events.models.persons import PersonLinkBase

        def key(obj):
            if isinstance(obj, PersonLinkBase):
                return obj.display_full_name.lower()
            name = obj.display_full_name if isinstance(obj, User) else obj.name
            return obj.principal_type, name.lower()

        principals = sorted(self._get_data(), key=key)
        return map(serialize_principal, principals)

    def _get_data(self):
        return sorted(self.data) if self.data else []
Exemplo n.º 4
0
class PermissionsField(JSONField):
    from indico.modules.categories.models.categories import Category
    widget = JinjaWidget('forms/permissions_widget.html', single_kwargs=True, acl=True)

    type_mapping = {
        'event': Event,
        'session': Session,
        'contribution': Contribution,
        'category': Category
    }

    def __init__(self, *args, **kwargs):
        self.object_type = kwargs.pop('object_type')
        super().__init__(*args, **kwargs)
        self.ip_networks = list(map(serialize_ip_network_group, IPNetworkGroup.query.filter_by(hidden=False)))

    @property
    def event(self):
        return self.get_form().event

    @property
    def category(self):
        if self.object_type == 'category':
            return self.get_form().category
        return self.event.category

    @property
    def event_roles(self):
        return [serialize_event_role(role) for role in sorted(self.event.roles, key=attrgetter('code'))]

    @property
    def category_roles(self):
        from indico.modules.categories.models.roles import CategoryRole
        from indico.modules.categories.util import serialize_category_role
        category_roles = CategoryRole.get_category_roles(self.category)
        return [serialize_category_role(role, legacy=True) for role in category_roles]

    @property
    def registration_forms(self):
        if not self.event.has_feature('registration'):
            return []
        registration_forms = self.event.registration_forms
        return [serialize_registration_form(regform) for regform in registration_forms]

    @property
    def permissions_info(self):
        return get_permissions_info(PermissionsField.type_mapping[self.object_type])[0]

    @property
    def hidden_permissions_info(self):
        all_permissions = get_available_permissions(PermissionsField.type_mapping[self.object_type])
        visible_permissions = get_permissions_info(PermissionsField.type_mapping[self.object_type])[0]
        return {k: all_permissions[k].friendly_name for k in set(all_permissions) - set(visible_permissions)}

    def _value(self):
        return self.data if self.data else []
Exemplo n.º 5
0
class OccurrencesField(JSONField):
    """
    A field that lets you select multiple occurrences consisting of a
    start date/time and a duration.
    """

    widget = JinjaWidget('forms/occurrences_widget.html', single_line=True)
    CAN_POPULATE = True

    def __init__(self, *args, **kwargs):
        self._timezone = kwargs.pop('timezone', None)
        self.default_time = kwargs.pop('default_time', time(0, 0))
        self.default_duration = kwargs.pop('default_duration', timedelta())
        kwargs.setdefault('default', [])
        super(OccurrencesField, self).__init__(*args, **kwargs)

    def process_formdata(self, valuelist):
        def _deserialize(occ):
            try:
                dt = dateutil.parser.parse('{} {}'.format(
                    occ['date'], occ['time']))
            except ValueError:
                raise ValueError('Invalid date/time: {} {}'.format(
                    escape(occ['date']), escape(occ['time'])))
            return localize_as_utc(
                dt, self.timezone), timedelta(minutes=occ['duration'])

        self.data = []
        super(OccurrencesField, self).process_formdata(valuelist)
        self.data = map(_deserialize, self.data)

    def _value(self):
        def _serialize(occ):
            if isinstance(occ, dict):
                # raw data from the client
                return occ
            dt = occ[0].astimezone(pytz.timezone(self.timezone))
            return {
                'date': dt.date().isoformat(),
                'time': dt.time().isoformat()[:-3],  # hh:mm only
                'duration': int(occ[1].total_seconds() // 60)
            }

        return json.dumps(map(_serialize, self.data))

    @property
    def timezone_field(self):
        field = getattr(self.get_form(), 'timezone', None)
        return field if isinstance(field, SelectField) else None

    @property
    def timezone(self):
        if self.timezone_field:
            return self.timezone_field.data
        else:
            return getattr(self.get_form(), 'timezone', session.tzinfo.zone)
Exemplo n.º 6
0
class IndicoMarkdownField(TextAreaField):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault(
            'description',
            _("You can use Markdown or basic HTML formatting tags."))
        super(IndicoMarkdownField, self).__init__(*args, **kwargs)

    widget = JinjaWidget('forms/markdown_widget.html',
                         single_kwargs=True,
                         rows=5)
Exemplo n.º 7
0
class IndicoDateField(DateField):
    widget = JinjaWidget('forms/date_widget.html',
                         single_line=True,
                         single_kwargs=True)

    def __init__(self, *args, **kwargs):
        super(IndicoDateField, self).__init__(*args,
                                              parse_kwargs={'dayfirst': True},
                                              display_format='%d/%m/%Y',
                                              **kwargs)
Exemplo n.º 8
0
class IndicoStaticTextField(Field):
    """Returns an html element with text taken from this field's value"""
    widget = JinjaWidget('forms/static_text_widget.html')

    def __init__(self, *args, **kwargs):
        self.text_value = kwargs.pop('text')
        super(IndicoStaticTextField, self).__init__(*args, **kwargs)

    def _value(self):
        return self.text_value
Exemplo n.º 9
0
class PrincipalListField(HiddenField):
    """A field that lets you select a list of principals.

    Principals are users or other objects represending users such as
    groups or roles that can be added to ACLs.

    :param allow_external_users: If "search users with no indico account"
                                 should be available. Selecting such a user
                                 will automatically create a pending user once
                                 the form is submitted, even if other fields
                                 in the form fail to validate!
    :param allow_groups: If groups should be selectable.
    :param allow_event_roles: If event roles should be selectable.
    :param allow_category_roles: If category roles should be selectable.
    :param allow_registration_forms: If registration form associated
                                     to an event should be selectable.
    :param allow_emails: If the field should allow bare emails. Those are not
                         selectable in the widget, but may be added to an ACL
                         through other means.
    """

    widget = JinjaWidget('forms/principal_list_widget.html', single_kwargs=True)

    def __init__(self, *args, **kwargs):
        self.allow_external_users = kwargs.pop('allow_external_users', False)
        self.allow_groups = kwargs.pop('allow_groups', False)
        self.allow_event_roles = kwargs.pop('allow_event_roles', False)
        self.allow_category_roles = kwargs.pop('allow_category_roles', False)
        self.allow_registration_forms = kwargs.pop('allow_registration_forms', False)
        self.allow_emails = kwargs.pop('allow_emails', False)
        self._event = kwargs.pop('event')(kwargs['_form']) if 'event' in kwargs else None
        super().__init__(*args, **kwargs)

    def _convert_principal(self, principal):
        event_id = self._event.id if self._event else None
        return principal_from_identifier(principal, event_id=event_id, allow_groups=self.allow_groups,
                                         allow_external_users=self.allow_external_users,
                                         allow_event_roles=self.allow_event_roles,
                                         allow_category_roles=self.allow_category_roles,
                                         allow_registration_forms=self.allow_registration_forms,
                                         allow_emails=self.allow_emails)

    def process_formdata(self, valuelist):
        if valuelist:
            self._submitted_data = json.loads(valuelist[0])
            self.data = {self._convert_principal(x) for x in self._submitted_data}

    def _value(self):
        try:
            return self._submitted_data
        except AttributeError:
            return [x.identifier for x in self._get_data()]

    def _get_data(self):
        return sorted(self.data, key=attrgetter('identifier')) if self.data else []
Exemplo n.º 10
0
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
Exemplo n.º 11
0
class TrackRoleField(JSONField):
    """A field that stores a list of e-mail template rules."""

    CAN_POPULATE = True
    widget = JinjaWidget('events/abstracts/forms/track_role_widget.html')

    @property
    def users(self):
        return {
            user_id: _serialize_user(user)
            for user_id, user in _get_users_in_roles(self.data)
        }

    @property
    def role_data(self):
        conveners = set()
        reviewers = set()

        # Handle global reviewers/conveners
        role_data = self.data.pop('*')
        global_conveners = _get_users(role_data['convener'])
        global_reviewers = _get_users(role_data['reviewer'])
        conveners |= global_conveners
        reviewers |= global_reviewers

        track_dict = {
            track.id: track
            for track in Track.query.with_parent(self.event).filter(
                Track.id.in_(self.data))
        }
        user_dict = dict(_get_users_in_roles(self.data))

        track_roles = {}
        # Update track-specific reviewers/conveners
        for track_id, roles in self.data.viewitems():
            track = track_dict[int(track_id)]
            track_roles[track] = defaultdict(set)
            for role_id, user_ids in roles.viewitems():
                users = {user_dict[user_id] for user_id in user_ids}
                track_roles[track][role_id] = users
                if role_id == 'convener':
                    conveners |= users
                elif role_id == 'reviewer':
                    reviewers |= users

        return {
            'track_roles': track_roles,
            'global_conveners': global_conveners,
            'global_reviewers': global_reviewers,
            'all_conveners': conveners,
            'all_reviewers': reviewers
        }

    def _value(self):
        return super(TrackRoleField, self)._value() if self.data else '[]'
Exemplo n.º 12
0
class SessionBlockPersonLinkListField(PersonLinkListFieldBase):
    person_link_cls = SessionBlockPersonLink
    linked_object_attr = 'session_block'
    widget = JinjaWidget('events/sessions/forms/session_person_link_widget.html')

    def _serialize_person_link(self, principal, extra_data=None):
        extra_data = extra_data or {}
        return dict(extra_data, **serialize_person_link(principal))

    def _convert_data(self, data):
        return list({self._get_person_link(x) for x in data})
Exemplo n.º 13
0
class PrincipalListField(HiddenField):
    """A field that lets you select a list Indico user/group ("principal")

    :param groups: If groups should be selectable.
    :param allow_external: If "search users with no indico account"
                           should be available.  Selecting such a user
                           will automatically create a pending user once
                           the form is submitted, even if other fields
                           in the form fail to validate!
    """

    widget = JinjaWidget('forms/principal_list_widget.html',
                         single_kwargs=True)

    def __init__(self, *args, **kwargs):
        self.allow_emails = kwargs.pop('allow_emails', False)
        self.groups = kwargs.pop('groups', False)
        # Whether it is allowed to search for external users with no indico account
        self.allow_external = kwargs.pop('allow_external', False)
        super(PrincipalListField, self).__init__(*args, **kwargs)

    def _convert_principal(self, principal):
        return principal_from_fossil(principal,
                                     allow_pending=self.allow_external,
                                     legacy=False,
                                     allow_emails=self.allow_emails)

    def process_formdata(self, valuelist):
        if valuelist:
            self.data = {
                self._convert_principal(x)
                for x in json.loads(valuelist[0])
            }

    def pre_validate(self, form):
        if not self.groups and any(
                isinstance(p, GroupProxy) for p in self._get_data()):
            raise ValueError(u'You cannot select groups')

    def _serialize_principal(self, principal):
        if principal.principal_type == PrincipalType.email:
            return principal.fossilize()
        elif principal.principal_type == PrincipalType.user:
            return serialize_user(principal)
        else:
            return serialize_group(principal)

    def _value(self):
        principals = sorted(self._get_data(), key=lambda x: x.name.lower())
        return map(self._serialize_principal, principals)

    def _get_data(self):
        return sorted(self.data) if self.data else []
Exemplo n.º 14
0
class PrincipalField(PrincipalListField):
    """A field that lets you select an Indico user/group ("principal")"""

    widget = JinjaWidget('forms/principal_widget.html', single_line=True)

    def _get_data(self):
        return [] if self.data is None else [self.data]

    def process_formdata(self, valuelist):
        if valuelist:
            data = map(self._convert_principal, json.loads(valuelist[0]))
            self.data = None if not data else data[0]
Exemplo n.º 15
0
class AbstractPersonLinkListField(PersonLinkListFieldBase):
    """A field to configure a list of abstract persons"""

    person_link_cls = AbstractPersonLink
    linked_object_attr = 'abstract'
    default_sort_alpha = False
    create_untrusted_persons = True
    widget = JinjaWidget(
        'events/contributions/forms/contribution_person_link_widget.html',
        allow_empty_email=True)

    def __init__(self, *args, **kwargs):
        self.author_types = AuthorType.serialize()
        self.allow_authors = True
        self.allow_submitters = False
        self.show_empty_coauthors = kwargs.pop('show_empty_coauthors', True)
        self.default_author_type = kwargs.pop('default_author_type',
                                              AuthorType.none)
        self.default_is_submitter = False
        self.default_is_speaker = False
        self.require_primary_author = True
        self.sort_by_last_name = True
        self.disable_user_search = kwargs.pop('disable_user_search', False)
        super(AbstractPersonLinkListField, self).__init__(*args, **kwargs)

    def _convert_data(self, data):
        return list({self._get_person_link(x) for x in data})

    @no_autoflush
    def _get_person_link(self, data):
        extra_data = {
            'author_type': data.pop('authorType', self.default_author_type),
            'is_speaker': data.pop('isSpeaker', self.default_is_speaker)
        }
        return super(AbstractPersonLinkListField,
                     self)._get_person_link(data, extra_data)

    def _serialize_person_link(self, principal, extra_data=None):
        extra_data = extra_data or {}
        data = dict(extra_data, **serialize_person_link(principal))
        data['isSpeaker'] = principal.is_speaker
        data['authorType'] = principal.author_type.value
        return data

    def pre_validate(self, form):
        super(AbstractPersonLinkListField, self).pre_validate(form)
        for person_link in self.data:
            if not self.allow_authors and person_link.author_type != AuthorType.none:
                if not self.object_data or person_link not in self.object_data:
                    person_link.author_type = AuthorType.none
            if person_link.author_type == AuthorType.none and not person_link.is_speaker:
                raise ValueError(
                    _("{} has no role").format(person_link.full_name))
Exemplo n.º 16
0
class ContributionPersonLinkListField(PersonLinkListFieldBase):
    """A field to configure a list of contribution persons"""

    person_link_cls = ContributionPersonLink
    linked_object_attr = 'contrib'
    widget = JinjaWidget(
        'events/contributions/forms/contribution_person_link_widget.html',
        allow_empty_email=True)

    def __init__(self, *args, **kwargs):
        self.author_types = AuthorType.serialize()
        self.allow_authors = kwargs.pop(
            'allow_authors', kwargs['_form'].event.type == 'conference')
        self.allow_submitters = kwargs.pop('allow_submitters', True)
        self.show_empty_coauthors = kwargs.pop('show_empty_coauthors', True)
        self.default_author_type = kwargs.pop('default_author_type',
                                              AuthorType.none)
        self.default_is_submitter = kwargs.pop('default_is_submitter', True)
        self.default_is_speaker = True
        super(ContributionPersonLinkListField, self).__init__(*args, **kwargs)

    def _convert_data(self, data):
        return {
            self._get_person_link(x): x.pop('isSubmitter',
                                            self.default_is_submitter)
            for x in data
        }

    @no_autoflush
    def _get_person_link(self, data):
        extra_data = {
            'author_type': data.pop('authorType', self.default_author_type),
            'is_speaker': data.pop('isSpeaker', self.default_is_speaker)
        }
        return super(ContributionPersonLinkListField,
                     self)._get_person_link(data, extra_data)

    def _serialize_person_link(self, principal, extra_data=None):
        is_submitter = self.data[principal] if self.get_form().is_submitted(
        ) else None
        return serialize_contribution_person_link(principal,
                                                  is_submitter=is_submitter)

    def pre_validate(self, form):
        super(ContributionPersonLinkListField, self).pre_validate(form)
        for person_link in self.data:
            if not self.allow_authors and person_link.author_type != AuthorType.none:
                if not self.object_data or person_link not in self.object_data:
                    person_link.author_type = AuthorType.none
            if person_link.author_type == AuthorType.none and not person_link.is_speaker:
                raise ValueError(
                    _("{} has no role").format(person_link.full_name))
Exemplo n.º 17
0
class EventPersonLinkListField(PersonLinkListFieldBase):
    """A field to manage event's chairpersons."""

    person_link_cls = EventPersonLink
    linked_object_attr = 'event'
    widget = JinjaWidget('forms/person_link_widget.html')

    @property
    def roles(self):
        return [{
            'name': 'submitter',
            'label': _('Submitter'),
            'icon': 'paperclip',
            'default': self.default_is_submitter
        }]

    def __init__(self, *args, **kwargs):
        self.default_is_submitter = kwargs.pop('default_is_submitter', True)
        self.empty_message = _('There are no chairpersons')
        event_type = kwargs.pop('event_type', None)
        super().__init__(*args, **kwargs)
        if not event_type and self.object:
            event_type = self.object.event.type_
        if event_type == EventType.lecture:
            self.empty_message = _('There are no speakers')

    def _convert_data(self, data):
        return {
            self._get_person_link(x): 'submitter' in x.get('roles', [])
            for x in data
        }

    def _serialize_person_link(self, principal):
        from indico.modules.events.persons.schemas import PersonLinkSchema
        data = PersonLinkSchema().dump(principal)
        data['roles'] = []
        if (self.get_form().is_submitted()
                and self.data[principal]) or (principal.event
                                              and principal.is_submitter):
            data['roles'].append('submitter')
        return data

    def pre_validate(self, form):
        super().pre_validate(form)
        persons = set()
        for person_link in self.data:
            if person_link.person in persons:
                raise ValueError(
                    _("Person with email '{}' is duplicated").format(
                        person_link.person.email))
            persons.add(person_link.person)
Exemplo n.º 18
0
class IndicoProtectionField(IndicoEnumRadioField):
    widget = JinjaWidget('forms/protection_widget.html', single_kwargs=True)
    radio_widget = JinjaWidget('forms/radio_buttons_widget.html',
                               orientation='horizontal',
                               single_kwargs=True)

    def __init__(self, *args, **kwargs):
        self.protected_object = kwargs.pop('protected_object')(kwargs['_form'])
        get_acl_message_url = kwargs.pop('acl_message_url', None)
        self.acl_message_url = get_acl_message_url(
            kwargs['_form']) if get_acl_message_url else None
        self.can_inherit_protection = self.protected_object.protection_parent is not None
        if not self.can_inherit_protection:
            kwargs['skip'] = {ProtectionMode.inheriting}
        super(IndicoProtectionField, self).__init__(*args,
                                                    enum=ProtectionMode,
                                                    **kwargs)

    def render_protection_message(self):
        from indico.modules.categories.models.categories import Category
        protected_object = self.get_form().protected_object
        if hasattr(protected_object, 'get_non_inheriting_objects'):
            non_inheriting_objects = protected_object.get_non_inheriting_objects(
            )
        else:
            non_inheriting_objects = []
        if isinstance(protected_object.protection_parent, Event):
            parent_type = _('Event')
        elif isinstance(protected_object.protection_parent, Category):
            parent_type = _('Category')
        else:
            parent_type = _('Session')
        rv = render_template('_protection_info.html',
                             field=self,
                             protected_object=protected_object,
                             parent_type=parent_type,
                             non_inheriting_objects=non_inheriting_objects)
        return Markup(rv)
Exemplo n.º 19
0
class IndicoDurationField(Field):
    widget = JinjaWidget('forms/duration_widget.html',
                         single_line=True,
                         single_kwargs=True)

    def _value(self):
        if self.data is None:
            return 0
        else:
            return int(self.data.total_seconds())

    def process_formdata(self, valuelist):
        if valuelist:
            self.data = timedelta(seconds=int(valuelist[0]))
Exemplo n.º 20
0
class SubContributionPersonLinkListField(ContributionPersonLinkListField):
    """A field to configure a list of subcontribution persons."""

    person_link_cls = SubContributionPersonLink
    linked_object_attr = 'subcontrib'
    widget = JinjaWidget('forms/person_link_widget.html', allow_empty_email=True)

    def _serialize_person_link(self, principal):
        from indico.modules.events.persons.schemas import PersonLinkSchema
        data = PersonLinkSchema().dump(principal)
        data['roles'] = []
        if principal.is_speaker:
            data['roles'].append('speaker')
        return data
Exemplo n.º 21
0
class _MultiChoiceQuerySelectMultipleFieldGrouped(IndicoQuerySelectMultipleField):
    widget = JinjaWidget('events/abstracts/forms/checkbox_group_grouped_widget.html')

    def __init__(self, *args, **kwargs):
        self.get_group = kwargs.pop('get_group', lambda x: x)
        super(_MultiChoiceQuerySelectMultipleFieldGrouped, self).__init__(*args, **kwargs)

    def get_grouped_choices(self):
        return groupby(list(self.iter_choices()), key=lambda x: x[3:])  # group by (group, group label)

    def iter_choices(self):
        for pk, obj in self._get_object_list():
            yield (pk, self.get_label(obj), obj in self.data, self.get_group(obj),
                   self.get_label(self.get_group(obj)) if self.get_group(obj) else None)
Exemplo n.º 22
0
class IndicoStaticTextField(Field):
    """Return an html element with text taken from this field's value."""

    widget = JinjaWidget('forms/static_text_widget.html')

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

    def process_data(self, data):
        self.text_value = self.data = str(data)

    def _value(self):
        return self.text_value
Exemplo n.º 23
0
class MultiStringField(HiddenField):
    """A field with multiple input text fields.

    :param field: A tuple ``(fieldname, title)`` where the title is used in the
                  placeholder.
    :param uuid_field: If set, each item will have a UUID assigned and
                       stored in the field specified here.
    :param unique: Whether the values should be unique.
    :param sortable: Whether items should be sortable.
    """

    widget = JinjaWidget('forms/multiple_text_input_widget.html',
                         single_line=True)

    def __init__(self, *args, **kwargs):
        self.field_name, self.field_caption = kwargs.pop('field')
        self.sortable = kwargs.pop('sortable', False)
        self.unique = kwargs.pop('unique', False)
        self.uuid_field = kwargs.pop('uuid_field', None)
        super(MultiStringField, self).__init__(*args, **kwargs)

    def process_formdata(self, valuelist):
        if is_preprocessed_formdata(valuelist):
            self.data = valuelist[0]
        elif valuelist:
            self.data = json.loads(valuelist[0])
            if self.uuid_field:
                for item in self.data:
                    if self.uuid_field not in item:
                        item[self.uuid_field] = unicode(uuid.uuid4())

    def pre_validate(self, form):
        if not all(isinstance(item, dict) for item in self.data):
            raise ValueError('Invalid data. Expected list of dicts.')
        if self.unique:
            unique_values = {item[self.field_name] for item in self.data}
            if len(unique_values) != len(self.data):
                raise ValueError('Items must be unique')
        if self.uuid_field:
            unique_uuids = {
                uuid.UUID(item[self.uuid_field], version=4)
                for item in self.data
            }
            if len(unique_uuids) != len(self.data):
                raise ValueError('UUIDs must be unique')
        if not all(item[self.field_name].strip() for item in self.data):
            raise ValueError('Empty items are not allowed')

    def _value(self):
        return self.data or []
Exemplo n.º 24
0
class _SingleChoiceQuerySelectMultipleFieldGrouped(_SingleChoiceQuerySelectMultipleField):
    widget = JinjaWidget('events/abstracts/forms/select_grouped_widget.html')

    def __init__(self, *args, **kwargs):
        self.get_group = kwargs.pop('get_group', lambda x: x)
        super().__init__(*args, **kwargs)

    def get_grouped_choices(self):
        return groupby(list(self.iter_choices()), key=lambda x: x[3:])  # group by (group, group label)

    def iter_choices(self):
        yield ('__None', self.blank_text, self.data is None, None, None)
        for pk, obj in self._get_object_list():
            yield (pk, self.get_label(obj), obj in self.data, self.get_group(obj),
                   self.get_label(self.get_group(obj)) if self.get_group(obj) else None)
Exemplo n.º 25
0
class IndicoDurationField(Field):
    widget = JinjaWidget('forms/duration_widget.html', single_line=True, single_kwargs=True)

    def _value(self):
        if self.data is None:
            return 0
        else:
            return int(self.data.total_seconds())

    def process_formdata(self, valuelist):
        if valuelist:
            self.data = timedelta(seconds=int(valuelist[0]))
            if self.data.total_seconds() % 60:
                Logger.get('forms').warning('Duration with seconds submitted')
                raise ValueError('Duration cannot contain seconds')
Exemplo n.º 26
0
class PermissionsField(JSONField):
    widget = JinjaWidget('forms/permissions_widget.html', single_kwargs=True, acl=True)

    def __init__(self, *args, **kwargs):
        super(PermissionsField, self).__init__(*args, **kwargs)
        self.ip_networks = map(serialize_ip_network_group, IPNetworkGroup.query.filter_by(hidden=False))
        self.permissions_info = get_permissions_info(Event)[0]

    @property
    def event(self):
        return self.get_form().event

    @property
    def roles(self):
        return [serialize_role(role) for role in sorted(self.get_form().event.roles, key=attrgetter('code'))]

    def _value(self):
        return self.data if self.data else '[]'
Exemplo n.º 27
0
class PermissionsField(JSONField):
    from indico.modules.categories.models.categories import Category
    widget = JinjaWidget('forms/permissions_widget.html', single_kwargs=True, acl=True)

    type_mapping = {
        'event': Event,
        'session': Session,
        'contribution': Contribution,
        'category': Category
    }

    def __init__(self, *args, **kwargs):
        self.object_type = kwargs.pop('object_type')
        super(PermissionsField, self).__init__(*args, **kwargs)
        self.ip_networks = map(serialize_ip_network_group, IPNetworkGroup.query.filter_by(hidden=False))

    @property
    def event(self):
        return self.get_form().event

    @property
    def category(self):
        if self.object_type == 'category':
            return self.get_form().category
        return self.event.category

    @property
    def event_roles(self):
        return [serialize_event_role(role) for role in sorted(self.event.roles, key=attrgetter('code'))]

    @property
    def category_roles(self):
        from indico.modules.categories.util import serialize_category_role
        from indico.modules.categories.models.roles import CategoryRole
        category_roles = CategoryRole.get_category_roles(self.category)
        return [serialize_category_role(role, legacy=True) for role in category_roles]

    @property
    def permissions_info(self):
        return get_permissions_info(PermissionsField.type_mapping[self.object_type])[0]

    def _value(self):
        return self.data if self.data else []
Exemplo n.º 28
0
class EmailRuleListField(JSONField):
    """A field that stores a list of e-mail template rules."""

    CAN_POPULATE = True
    widget = JinjaWidget('events/abstracts/forms/rule_list_widget.html')
    accepted_condition_types = (StateCondition, TrackCondition,
                                ContributionTypeCondition)

    @classproperty
    @classmethod
    def condition_class_map(cls):
        return {r.name: r for r in cls.accepted_condition_types}

    @property
    def condition_choices(self):
        return {
            c.name: {
                'title':
                c.description,
                'labelText':
                c.label_text,
                'options':
                list(c.get_available_values(event=self.event).viewitems()),
                'compatibleWith':
                c.compatible_with,
                'required':
                c.required
            }
            for c in self.accepted_condition_types
        }

    def pre_validate(self, form):
        super(EmailRuleListField, self).pre_validate(form)
        if not all(self.data):
            raise ValueError(_('Rules may not be empty'))
        if any('*' in crit for rule in self.data
               for crit in rule.itervalues()):
            # '*' (any) rules should never be included in the JSON, and having
            # such an entry would result in the rule never passing.
            raise ValueError('Unexpected "*" criterion')

    def _value(self):
        return super(EmailRuleListField, self)._value() if self.data else '[]'
Exemplo n.º 29
0
class CategoryField(HiddenField):
    """WTForms field that lets you select a category.

    :param require_event_creation_rights: Whether to allow selecting
                                          only categories where the
                                          user can create events.
    """

    widget = JinjaWidget('forms/category_picker_widget.html')

    def __init__(self, *args, **kwargs):
        self.navigator_category_id = 0
        self.require_event_creation_rights = kwargs.pop(
            'require_event_creation_rights', False)
        super().__init__(*args, **kwargs)

    def process_data(self, value):
        if not value:
            self.data = None
            return
        self.data = value
        self.navigator_category_id = value.id

    def process_formdata(self, valuelist):
        from indico.modules.categories import Category
        if valuelist:
            try:
                category_id = int(json.loads(valuelist[0])['id'])
            except KeyError:
                self.data = None
            else:
                self.data = Category.get(category_id, is_deleted=False)

    def _value(self):
        return {
            'id': self.data.id,
            'title': self.data.title
        } if self.data else {}

    def _get_data(self):
        return self.data
Exemplo n.º 30
0
class EditableFileField(FileField):
    """A dropzone field that displays its current state and keeps track of deletes."""

    widget = JinjaWidget('forms/dropzone_widget.html', editable=True)

    def __init__(self, *args, **kwargs):
        self.get_metadata = kwargs.pop('get_metadata', get_file_metadata)
        self.added_only = kwargs.pop('added_only', False)
        super().__init__(*args, **kwargs)
        self.widget_options['editable'] = True

    def process_formdata(self, valuelist):
        uploaded = []
        deleted = []

        for value in valuelist:
            if isinstance(value, FileStorage):
                uploaded.append(value)
            else:
                deleted = json.loads(value)
        if not self.allow_multiple_files:
            uploaded = uploaded[0] if uploaded else None
            deleted = deleted[0] if deleted else None
        self.data = uploaded if self.added_only else {
            'added': uploaded,
            'deleted': deleted
        }

    def _value(self):
        # If form validation fails we still have the dict from `process_formdata`
        # in `self.data` which cannot be serialized so we fallback to the default
        # data (if there is any, i.e. if we were editing something)
        # It would be cleaner to still take e.g. 'deleted' into account and
        # save/restore the selected files with JavaScript but in most cases our
        # client-side validation should not fail anyway...
        data = self.object_data if isinstance(self.data, dict) else self.data
        if self.allow_multiple_files:
            return [self.get_metadata(f) for f in data] if data else []
        else:
            return self.get_metadata(data) if data else None