Beispiel #1
0
 def validate_body(self, field):
     missing = get_missing_placeholders('cern-access-email',
                                        field.data,
                                        regform=self.regform,
                                        registration=None)
     if missing:
         raise ValidationError(
             _('Missing placeholders: {}').format(', '.join(missing)))
Beispiel #2
0
class RegistrationFormPersonalDataForm(AccessIdentityDataForm):
    request_cern_access = BooleanField(_('Request access to the CERN site'), widget=SwitchWidget())

    @classmethod
    def _add_fields_hidden_unless(cls):
        for field_name in ('birth_date', 'nationality', 'birth_place'):
            inject_validators(RegistrationFormPersonalDataForm, field_name,
                              [UsedIf(lambda form, field: form.request_cern_access.data)], early=True)
Beispiel #3
0
 def _print_badge_template(self, template, regform, **kwargs):
     access_tpl = self.settings.get('access_ticket_template')
     if not access_tpl:
         return
     if template == access_tpl or template.backside_template == access_tpl:
         if (not regform.cern_access_request or
                 (regform.cern_access_request and
                     regform.cern_access_request.request_state != CERNAccessRequestState.active)):
             raise Forbidden(_('This badge cannot be printed because it uses the CERN access ticket '
                               'template without an active CERN access request'))
Beispiel #4
0
 def __init__(self, *args, **kwargs):
     reset_text = (Markup('<a id="reset-cern-access-email">{}</a><br>')
                   .format(_('Click here to reset subject and body to the default text.')))
     super(GrantAccessEmailForm, self).__init__(*args, recipients=[], **kwargs)
     self.body.description = reset_text + render_placeholder_info('cern-access-email', regform=self.regform,
                                                                  registration=None)
     del self.cc_addresses
     del self.copy_for_sender
     del self.attach_ticket
     del self.recipients
Beispiel #5
0
class GrantAccessEmailForm(EmailRegistrantsForm):
    save_default = BooleanField(_("Save as default"), widget=SwitchWidget(),
                                description=_("Save this email's content as the default that will be used the next "
                                              "time a CERN access request is sent for a registrant in this event."))

    def __init__(self, *args, **kwargs):
        reset_text = (Markup('<a id="reset-cern-access-email">{}</a><br>')
                      .format(_('Click here to reset subject and body to the default text.')))
        super(GrantAccessEmailForm, self).__init__(*args, recipients=[], **kwargs)
        self.body.description = reset_text + render_placeholder_info('cern-access-email', regform=self.regform,
                                                                     registration=None)
        del self.cc_addresses
        del self.copy_for_sender
        del self.attach_ticket
        del self.recipients

    def validate_body(self, field):
        missing = get_missing_placeholders('cern-access-email', field.data, regform=self.regform, registration=None)
        if missing:
            raise ValidationError(_('Missing placeholders: {}').format(', '.join(missing)))
Beispiel #6
0
class AccessIdentityDataForm(IndicoForm):
    birth_date = IndicoDateField(_('Birth date'), [DataRequired()])
    nationality = SelectField(_('Country of birth'), [DataRequired()])
    birth_place = StringField(_('Place of birth'), [DataRequired()])
    by_car = BooleanField(_('Are you bringing your own car?'), [Optional()], widget=SwitchWidget())
    license_plate = StringField(
        _('License plate'),
        [
            HiddenUnless('by_car'),
            Length(min=3),
            IndicoRegexp(r'^[0-9A-Za-z]+([- ][ ]*[0-9A-Za-z]+)*$',
                         message=_('Wrong format. Only letters and numbers separated by dashes (-) or spaces allowed'))
        ]
    )

    def __init__(self, *args, **kwargs):
        super(AccessIdentityDataForm, self).__init__(*args, **kwargs)
        self.nationality.choices = [('', '')] + sorted(get_countries().iteritems(), key=itemgetter(1))

    def validate_birth_date(self, field):
        if field.data > datetime.now().date():
            raise ValidationError(_('The specified date is in the future'))

    def validate_license_plate(self, field):
        if self.by_car.data and not sanitize_license_plate(field.data):
            raise ValidationError(_('Please insert a valid license plate number!'))
Beispiel #7
0
 def _process(self):
     if not self.registrations:
         raise NoReportError.wrap_exc(BadRequest(_("The selected registrants have been removed.")))
     registration = self.registrations[0]
     email_body = replace_placeholders('cern-access-email', request.form['body'], regform=self.regform,
                                       registration=registration)
     email_subject = replace_placeholders('cern-access-email', request.form['subject'], regform=self.regform,
                                          registration=registration)
     tpl = get_template_module('cern_access:emails/identity_data_form_email.html', registration=registration,
                               email_subject=email_subject, email_body=email_body)
     html = render_template('events/registration/management/email_preview.html', subject=tpl.get_subject(),
                            body=tpl.get_body())
     return jsonify(html=html)
 def _process(self):
     access_request = self.registration.cern_access_request
     if not access_request or access_request.has_identity_info:
         raise UserValueError(_('The personal data for this registrant has already been entered'))
     form = AccessIdentityDataForm()
     if form.validate_on_submit():
         form.populate_obj(access_request)
         db.session.flush()
         send_ticket(self.registration)
         return jsonify_data(html=render_plugin_template('cern_access_status.html', registration=self.registration,
                                                         header=False))
     return jsonify_template('identity_data_form_management.html', render_plugin_template, form=form,
                             registration=self.registration)
Beispiel #9
0
def _send_adams_http_request(method, data):
    from indico_cern_access.plugin import CERNAccessPlugin

    url = CERNAccessPlugin.settings.get('adams_url')
    credentials = (CERNAccessPlugin.settings.get('username'), CERNAccessPlugin.settings.get('password'))
    request_headers = {'Content-Type': 'application/json'}

    try:
        r = requests.request(method, url, data=json.dumps(data), headers=request_headers, auth=credentials)
        r.raise_for_status()
    except requests.exceptions.RequestException:
        CERNAccessPlugin.logger.exception('Request to ADAMS failed (%r)', data)
        raise AdamsError(_('Sending request to ADAMS failed'))
    return r.status_code == requests.codes.all_ok
Beispiel #10
0
    def _form_validated(self, form, **kwargs):
        """
        Forbid to disable the tickets when access to CERN is requested and
        to use CERN access ticket template with regforms without active CERN access request.
        """
        if not isinstance(form, TicketsForm):
            return

        regform = RegistrationForm.get_or_404(request.view_args['reg_form_id'])
        if regform.cern_access_request and regform.cern_access_request.is_active and not form.tickets_enabled.data:
            err = _('This form is used to grant CERN site access so ticketing must be enabled')
            form.tickets_enabled.errors.append(err)
            return False
        access_tpl = self.settings.get('access_ticket_template')
        ticket_template = DesignerTemplate.get_or_404(form.ticket_template_id.data)
        if not access_tpl:
            return
        if ticket_template == access_tpl or ticket_template.backside_template == access_tpl:
            if (not regform.cern_access_request or
                    (regform.cern_access_request and
                        regform.cern_access_request.request_state != CERNAccessRequestState.active)):
                form.ticket_template_id.errors.append(_('The selected template can only be used with an '
                                                        'active CERN access request'))
                return False
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
 def validate_birth_date(self, field):
     if field.data > datetime.now().date():
         raise ValidationError(_('The specified date is in the future'))
 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.'
               ))
class CERNAccessRequestState(RichIntEnum):
    __titles__ = [_('Not requested'), _('Accepted'), _('Withdrawn')]
    not_requested = 0
    active = 1
    withdrawn = 2
Beispiel #15
0
class PluginSettingsForm(IndicoForm):
    adams_url = URLField(_('ADaMS URL'), [DataRequired()],
                         description=_('The URL of the ADaMS REST API'))
    username = StringField(
        _('Username'), [DataRequired()],
        description=_('The login used to authenticate with ADaMS service'))
    password = IndicoPasswordField(
        _('Password'), [DataRequired()],
        description=_('The password used to authenticate with ADaMS service'))
    secret_key = IndicoPasswordField(
        _('Secret key'), [DataRequired()],
        description=_('Secret key to sign ADaMS requests'))
    authorized_users = PrincipalListField(
        _('Authorized users'),
        allow_groups=True,
        description=_('List of users/groups who can send requests'))
    excluded_categories = MultipleItemsField('Excluded categories',
                                             fields=[{
                                                 'id': 'id',
                                                 'caption': 'Category ID'
                                             }])
    access_ticket_template = QuerySelectField(
        _("Access ticket template"),
        allow_blank=True,
        blank_text=_("No access ticket selected"),
        get_label='title',
        description=_("Ticket template allowing access to CERN"))
    earliest_start_dt = IndicoDateTimeField(
        _("Earliest start date"), [Optional()],
        default_time=time(0, 0),
        description=_(
            "The earliest date an event can start to qualify for CERN "
            "access badges"))
    delete_personal_data_after = TimeDeltaField(
        _('Delete personal data'), [DataRequired()],
        units=('days', ),
        description=_(
            'Personal data will be deleted once the event has '
            'finished and the duration specified here has been '
            'exceeded. Once the data has been deleted, access badges '
            'will not be accessible anymore.'))
    api_username = StringField(_('Username'), [DataRequired()],
                               description=_('The username to access the API'))
    api_password = IndicoPasswordField(
        _('Password'), [DataRequired()],
        toggle=True,
        description=_('The password to access the API'))

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.access_ticket_template.query = (DesignerTemplate.query.filter(
            DesignerTemplate.category_id == 0,
            DesignerTemplate.type == TemplateType.badge).order_by(
                db.func.lower(DesignerTemplate.title)))
Beispiel #16
0
class CERNAccessRequestDefinition(RequestDefinitionBase):
    name = 'cern-access'
    title = _('CERN Visitor Badges')
    form = CERNAccessForm

    @classmethod
    def create_form(cls, event, existing_request=None):
        default_data = cls.form_defaults
        if existing_request:
            default_data = dict(existing_request.data)
            if default_data['start_dt_override']:
                default_data['start_dt_override'] = dateutil.parser.parse(
                    default_data['start_dt_override'])
            if default_data['end_dt_override']:
                default_data['end_dt_override'] = dateutil.parser.parse(
                    default_data['end_dt_override'])
        with plugin_context(cls.plugin):
            return cls.form(prefix='request-',
                            obj=FormDefaults(default_data),
                            event=event,
                            request=existing_request)

    @classmethod
    def render_form(cls, event, **kwargs):
        from indico_cern_access.plugin import CERNAccessPlugin
        kwargs['user_authorized'] = is_authorized_user(session.user)
        kwargs['category_blacklisted'] = is_category_blacklisted(
            event.category)
        kwargs['event_too_early'] = is_event_too_early(event)
        kwargs['earliest_start_dt'] = CERNAccessPlugin.settings.get(
            'earliest_start_dt')
        return super(CERNAccessRequestDefinition,
                     cls).render_form(event, **kwargs)

    @classmethod
    def can_be_managed(cls, user):
        return False

    @classmethod
    def send(cls, req, data):
        check_access(req)
        start_dt = data['start_dt_override'] or req.event.start_dt
        end_dt = data['end_dt_override'] or req.event.end_dt
        if data['start_dt_override']:
            data['start_dt_override'] = data['start_dt_override'].isoformat()
        if data['end_dt_override']:
            data['end_dt_override'] = data['end_dt_override'].isoformat()
        times_changed = False
        if req.id is not None:
            old_start_dt, old_end_dt = get_access_dates(req)
            if old_start_dt != start_dt or old_end_dt != end_dt:
                times_changed = True
        super(CERNAccessRequestDefinition, cls).send(req, data)
        update_access_request(req)
        req.state = RequestState.accepted
        if times_changed:
            handle_event_time_update(req.event)

    @classmethod
    def withdraw(cls, req, notify_event_managers=False):
        check_access(req)
        withdraw_event_access_request(req)
        super(CERNAccessRequestDefinition,
              cls).withdraw(req, notify_event_managers)
Beispiel #17
0
 def validate_license_plate(self, field):
     if self.by_car.data and not sanitize_license_plate(field.data):
         raise ValidationError(_('Please insert a valid license plate number!'))
Beispiel #18
0
class RegformDataMode(RichIntEnum):
    __titles__ = [_('No'), _('Yes'), _('Yes (required)')]
    after_registration = 0
    during_registration = 1
    during_registration_required = 2
Beispiel #19
0
class PluginSettingsForm(IndicoForm):
    adams_url = URLField(_('ADaMS URL'), [DataRequired()],
                         description=_('The URL of the ADaMS REST API'))
    username = StringField(
        _('Username'), [DataRequired()],
        description=_('The login used to authenticate with ADaMS service'))
    password = IndicoPasswordField(
        _('Password'), [DataRequired()],
        description=_('The password used to authenticate with ADaMS service'))
    secret_key = IndicoPasswordField(
        _('Secret key'), [DataRequired()],
        description=_('Secret key to sign ADaMS requests'))
    authorized_users = PrincipalListField(
        _('Authorized users'),
        groups=True,
        description=_('List of users/groups who can send requests'))
    excluded_categories = MultipleItemsField('Excluded categories',
                                             fields=[{
                                                 'id': 'id',
                                                 'caption': 'Category ID'
                                             }])
    access_ticket_template = QuerySelectField(
        _("Access ticket template"),
        allow_blank=True,
        blank_text=_("No access ticket selected"),
        get_label='title',
        description=_("Ticket template allowing access to CERN"))
    earliest_start_dt = IndicoDateTimeField(
        _("Earliest start date"), [Optional()],
        default_time=time(0, 0),
        description=_(
            "The earliest date an event can start to qualify for CERN "
            "access badges"))

    def __init__(self, *args, **kwargs):
        super(PluginSettingsForm, self).__init__(*args, **kwargs)
        self.access_ticket_template.query = (DesignerTemplate.query.filter(
            DesignerTemplate.category_id == 0,
            DesignerTemplate.type == TemplateType.badge).order_by(
                db.func.lower(DesignerTemplate.title)))
Beispiel #20
0
class CERNAccessRequestDefinition(RequestDefinitionBase):
    name = 'cern-access'
    title = _('CERN Visitor Badges')
    form = CERNAccessForm
    form_defaults = {
        'during_registration': True,
        'during_registration_preselected': False,
        'during_registration_required': False
    }

    @classmethod
    def create_form(cls, event, existing_request=None):
        default_data = cls.form_defaults
        if existing_request:
            default_data = dict(existing_request.data)
            if default_data['start_dt_override']:
                default_data['start_dt_override'] = dateutil.parser.parse(
                    default_data['start_dt_override'])
            if default_data['end_dt_override']:
                default_data['end_dt_override'] = dateutil.parser.parse(
                    default_data['end_dt_override'])
        with plugin_context(cls.plugin):
            return cls.form(prefix='request-',
                            obj=FormDefaults(default_data),
                            event=event,
                            request=existing_request)

    @classmethod
    def render_form(cls, event, **kwargs):
        from indico_cern_access.plugin import CERNAccessPlugin
        kwargs['user_authorized'] = is_authorized_user(session.user)
        kwargs['category_blacklisted'] = is_category_blacklisted(
            event.category)
        kwargs['event_too_early'] = is_event_too_early(event)
        kwargs['earliest_start_dt'] = CERNAccessPlugin.settings.get(
            'earliest_start_dt')
        return super(CERNAccessRequestDefinition,
                     cls).render_form(event, **kwargs)

    @classmethod
    def can_be_managed(cls, user):
        return False

    @classmethod
    def send(cls, req, data):
        check_access(req)
        start_dt = data['start_dt_override'] or req.event.start_dt
        end_dt = data['end_dt_override'] or req.event.end_dt
        if data['start_dt_override']:
            data['start_dt_override'] = data['start_dt_override'].isoformat()
        if data['end_dt_override']:
            data['end_dt_override'] = data['end_dt_override'].isoformat()
        times_changed = False
        if req.id is not None:
            old_start_dt, old_end_dt = get_access_dates(req)
            if old_start_dt != start_dt or old_end_dt != end_dt:
                times_changed = True
        super(CERNAccessRequestDefinition, cls).send(req, data)
        update_access_request(req)
        req.state = RequestState.accepted
        if times_changed:
            handle_event_time_update(req.event)

        link = "https://indico-user-docs.web.cern.ch/indico-user-docs/cern/cern_access/#granting-access-to-participants"
        message = _(
            'Please note that even though your request has been accepted, you still have to '
            'request badges for each one of your participants. {link}More details here.{endlink}'
        ).format(link='<a href="{}">'.format(link), endlink='</a>')
        flash(Markup(message), 'warning')

    @classmethod
    def withdraw(cls, req, notify_event_managers=False):
        withdraw_event_access_request(req)
        super(CERNAccessRequestDefinition,
              cls).withdraw(req, notify_event_managers)