예제 #1
0
 def _get_person_link(self, data, extra_data=None):
     extra_data = extra_data or {}
     person = get_event_person(self.event, data, create_untrusted_persons=self.create_untrusted_persons,
                               allow_external=True)
     person_data = {'title': next((x.value for x in UserTitle if data.get('title') == orig_string(x.title)),
                                  UserTitle.none),
                    'first_name': data.get('firstName', ''), 'last_name': data['familyName'],
                    'affiliation': data.get('affiliation', ''), 'address': data.get('address', ''),
                    'phone': data.get('phone', ''), 'display_order': data['displayOrder']}
     person_data.update(extra_data)
     person_link = None
     if self.object and inspect(person).persistent:
         person_link = self.person_link_cls.find_first(person=person, object=self.object)
     if not person_link:
         person_link = self.person_link_cls(person=person)
     person_link.populate_from_dict(person_data)
     email = data.get('email', '').lower()
     if email != person_link.email:
         if not self.event or not self.event.persons.filter_by(email=email).first():
             person_link.person.email = email
             person_link.person.user = get_user_by_email(email)
             if inspect(person).persistent:
                 signals.event.person_updated.send(person_link.person)
         else:
             raise UserValueError(_('There is already a person with the email {}').format(email))
     return person_link
예제 #2
0
파일: timeline.py 프로젝트: mkopcic/indico
    def _process(self):
        if self.editable:
            raise UserValueError(_('Editable already exists'))

        args = parser.parse({
            'files':
            EditingFilesField(self.event,
                              self.contrib,
                              self.editable_type,
                              required=True)
        })
        service_url = editing_settings.get(self.event, 'service_url')
        initial_state = InitialRevisionState.new if service_url else InitialRevisionState.ready_for_review

        editable = create_new_editable(self.contrib, self.editable_type,
                                       session.user, args['files'],
                                       initial_state)
        if service_url:
            try:
                service_handle_new_editable(editable, session.user)
            except ServiceRequestFailed:
                raise ServiceUnavailable(
                    _('Submission failed, please try again later.'))

        return '', 201
예제 #3
0
 def _reschedule_duration(self):
     for entry, successor in window(self._entries):
         duration = successor.start_dt - entry.start_dt - self.gap
         if duration <= timedelta(0):
             raise UserValueError(_("The chosen time gap would result in an entry with a duration of less than a "
                                    "minute. Please choose a smaller gap between entries."))
         entry.object.duration = duration
예제 #4
0
    def create_form(self,
                    event,
                    existing_vc_room=None,
                    existing_event_vc_room=None):
        """Override the default room form creation mechanism."""

        if existing_vc_room and request.method != 'POST':
            try:
                self.refresh_room(existing_vc_room, event)
            except VCRoomNotFoundError as exc:
                raise UserValueError(str(exc))
            except VCRoomError:
                # maybe a temporary issue - we just keep going and fail when saving in
                # case it's something more persistent
                pass

        form = super().create_form(
            event,
            existing_vc_room=existing_vc_room,
            existing_event_vc_room=existing_event_vc_room)

        if existing_vc_room:
            form.host_choice.render_kw = {'disabled': True}
            form.host_user.render_kw = {'disabled': True}
            if self.settings.get('allow_webinars'):
                # if we're editing a VC room, we will not allow the meeting type to be changed
                form.meeting_type.render_kw = {'disabled': True}

                if form.data['meeting_type'] == 'webinar':
                    # webinar hosts cannot be changed through the API
                    form.host_choice.render_kw = {'disabled': True}
                    form.host_user.render_kw = {'disabled': True}
        elif not form.is_submitted():
            form.password.data = gen_random_password()
        return form
예제 #5
0
 def _process(self):
     data = request.json
     required_keys = {'contribution_ids', 'day'}
     allowed_keys = required_keys | {'session_block_id'}
     if set(data.viewkeys()) > allowed_keys:
         raise BadRequest('Invalid keys found')
     elif required_keys > set(data.viewkeys()):
         raise BadRequest('Required keys missing')
     entries = []
     day = dateutil.parser.parse(data['day']).date()
     query = Contribution.query.with_parent(self.event).filter(
         Contribution.id.in_(data['contribution_ids']))
     with track_time_changes(auto_extend='end',
                             user=session.user) as changes:
         for contribution in query:
             start_dt = find_next_start_dt(
                 contribution.duration,
                 obj=self.session_block or self.event,
                 day=None if self.session_block else day,
                 force=True)
             entry = self._schedule(contribution, start_dt)
             if entry.end_dt.astimezone(entry.event.tzinfo).date() > day:
                 raise UserValueError(
                     _("Contribution '{}' could not be scheduled since it doesn't fit on this day."
                       ).format(contribution.title))
             entries.append(entry)
     notifications = get_time_changes_notifications(
         changes, tzinfo=self.event.tzinfo)
     return jsonify_data(update=serialize_entry_update(
         entries[0], session_=self.session) if entries else None,
                         notifications=notifications,
                         flash=False)
예제 #6
0
    def _process_DELETE(self):
        if EditingRevisionFile.query.with_parent(self.file_type).has_rows():
            raise UserValueError(_('Cannot delete file type which already has files'))

        review_conditions = editing_settings.get(self.event, self.editable_type.name + '_review_conditions')
        if any(self.file_type.id in cond for cond in review_conditions.values()):
            raise UserValueError(_('Cannot delete file type which is used in a review condition'))
        if self.file_type.publishable:
            is_last = not (EditingFileType.query
                           .with_parent(self.event)
                           .filter(EditingFileType.publishable, EditingFileType.id != self.file_type.id)
                           .has_rows())
            if is_last:
                raise UserValueError(_('Cannot delete the only publishable file type'))
        delete_file_type(self.file_type)
        return '', 204
예제 #7
0
 def _get_person_link(self, data, extra_data=None):
     extra_data = extra_data or {}
     person = self._get_event_person(data)
     person_data = {
         'title':
         next((x.value for x in UserTitle if data.get('title') == x.title),
              UserTitle.none),
         'first_name':
         data.get('firstName', ''),
         'last_name':
         data['familyName'],
         'affiliation':
         data.get('affiliation', ''),
         'address':
         data.get('address', ''),
         'phone':
         data.get('phone', '')
     }
     person_data.update(extra_data)
     person_link = None
     if self.object and inspect(person).persistent:
         person_link = self.person_link_cls.find_first(person=person,
                                                       object=self.object)
     if not person_link:
         person_link = self.person_link_cls(person=person)
     person_link.populate_from_dict(person_data)
     email = data.get('email', '').lower()
     if email != person_link.email:
         if not self.event.persons.filter_by(email=email).first():
             person_link.person.email = email
         else:
             raise UserValueError(
                 _('There is already a person with the email {}').format(
                     email))
     return person_link
예제 #8
0
 def _process_args(self):
     self.backend_name = request.view_args['backend']
     try:
         self.backend = current_plugin.backend_classes[self.backend_name]
     except KeyError:
         raise NotFound
     if self.backend.unique and LiveSyncAgent.query.filter_by(backend_name=self.backend_name).has_rows():
         raise UserValueError(_('This backend is already in use'))
예제 #9
0
 def _process(self, id):
     last_rev = self.contrib.paper.get_last_revision()
     if last_rev:
         found = next((f for f in last_rev.files if f.id == id), None)
         if found:
             with found.open() as stream:
                 return self._save_file(found, stream)
     raise UserValueError(_('No such file was found within the paper'))
예제 #10
0
 def _process(self):
     language = request.form['lang']
     if language not in get_all_locales():
         raise UserValueError('Invalid language')
     session.lang = language
     if session.user:
         session.user.settings.set('lang', language)
     return '', 204
예제 #11
0
    def _process(self):
        if self.editable:
            raise UserValueError(_('Editable already exists'))

        args = parser.parse({
            'files': EditingFilesField(self.event, self.contrib, required=True)
        })

        create_new_editable(self.contrib, self.editable_type, session.user, args['files'])
        return '', 201
예제 #12
0
 def _process_POST(self):
     f = request.files['photo']
     try:
         photo = Image.open(f)
     except OSError:
         raise UserValueError(
             _('You cannot upload this file as a room picture.'))
     if photo.format.lower() not in {'jpeg', 'png', 'gif'}:
         raise UserValueError(
             _('The file has an invalid format ({format}).').format(
                 format=photo.format))
     if photo.mode != 'RGB':
         photo = photo.convert('RGB')
     image_bytes = BytesIO()
     photo.save(image_bytes, 'JPEG')
     image_bytes.seek(0)
     self.room.photo = Photo(data=image_bytes.read())
     token = build_rooms_spritesheet()
     return jsonify(rooms_sprite_token=str(token))
예제 #13
0
 def _process(self):
     if not self.registrations:
         raise UserValueError(_("The selected registrants have been removed."))
     registration = self.registrations[0]
     email_body = replace_placeholders('registration-email', request.form['body'], regform=self.regform,
                                       registration=registration)
     tpl = get_template_module('events/registration/emails/custom_email.html', email_subject=request.form['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)
예제 #14
0
def import_registrations_from_csv(regform, fileobj, skip_moderation=True, notify_users=False):
    """Import event registrants from a CSV file into a form."""
    with csv_text_io_wrapper(fileobj) as ftxt:
        reader = csv.reader(ftxt.read().splitlines())
    reg_data = (db.session.query(Registration.user_id, Registration.email)
                .with_parent(regform)
                .filter(Registration.is_active)
                .all())
    registered_user_ids = {rd.user_id for rd in reg_data if rd.user_id is not None}
    registered_emails = {rd.email for rd in reg_data}
    used_emails = set()
    email_row_map = {}
    todo = []
    for row_num, row in enumerate(reader, 1):
        try:
            first_name, last_name, affiliation, position, phone, email = [value.strip() for value in row]
            email = email.lower()
        except ValueError:
            raise UserValueError(_('Row {}: malformed CSV data - please check that the number of columns is correct')
                                 .format(row_num))

        if not email:
            raise UserValueError(_('Row {}: missing e-mail address').format(row_num))
        if not validate_email(email):
            raise UserValueError(_('Row {}: invalid e-mail address').format(row_num))
        if not first_name or not last_name:
            raise UserValueError(_('Row {}: missing first or last name').format(row_num))
        if email in registered_emails:
            raise UserValueError(_('Row {}: a registration with this email already exists').format(row_num))

        user = get_user_by_email(email)
        if user and user.id in registered_user_ids:
            raise UserValueError(_('Row {}: a registration for this user already exists').format(row_num))
        if email in used_emails:
            raise UserValueError(_('Row {}: email address is not unique').format(row_num))
        if conflict_row_num := email_row_map.get(email):
            raise UserValueError(_('Row {}: email address belongs to the same user as in row {}')
                                 .format(row_num, conflict_row_num))

        used_emails.add(email)
        if user:
            email_row_map.update((e, row_num) for e in user.all_emails)

        todo.append({
            'email': email,
            'first_name': first_name.title(),
            'last_name': last_name.title(),
            'affiliation': affiliation,
            'phone': phone,
            'position': position
        })
예제 #15
0
 def _process_POST(self):
     data = dict({'background_position': 'stretch', 'items': []}, **request.json['template'])
     self.validate_json(TEMPLATE_DATA_JSON_SCHEMA, data)
     invalid_placeholders = {x['type'] for x in data['items']} - set(get_placeholder_options()) - {'fixed'}
     if invalid_placeholders:
         raise UserValueError('Invalid item types: {}'.format(', '.join(invalid_placeholders)))
     update_template(self.template, title=request.json['title'], data=data,
                     backside_template_id=request.json['backside_template_id'],
                     is_clonable=request.json['is_clonable'],
                     clear_background=request.json['clear_background'])
     flash(_("Template successfully saved."), 'success')
     return jsonify_data()
예제 #16
0
파일: roles.py 프로젝트: imfht/flaskapps
    def import_members_from_csv(self, f):
        with csv_text_io_wrapper(f) as ftxt:
            reader = csv.reader(ftxt.read().splitlines())

        emails = set()
        for num_row, row in enumerate(reader, 1):
            if len(row) != 1:
                raise UserValueError(_('Row {}: malformed CSV data').format(num_row))
            email = row[0].strip().lower()

            if email and not validate_email(email):
                raise UserValueError(_('Row {row}: invalid email address: {email}').format(row=num_row, email=email))
            if email in emails:
                raise UserValueError(_('Row {}: email address is not unique').format(num_row))
            emails.add(email)

        users = set(User.query.filter(~User.is_deleted, User.all_emails.in_(emails)))
        users_emails = {user.email for user in users}
        unknown_emails = emails - users_emails
        new_members = users - self.role.members
        return new_members, users, unknown_emails
예제 #17
0
 def _process(self):
     new_start_dt = self.event.tzinfo.localize(
         dateutil.parser.parse(request.form.get('startDate'))).astimezone(utc)
     new_end_dt = self.event.tzinfo.localize(dateutil.parser.parse(request.form.get('endDate'))).astimezone(utc)
     new_duration = new_end_dt - new_start_dt
     is_session_block = self.entry.type == TimetableEntryType.SESSION_BLOCK
     tzinfo = self.event.tzinfo
     if is_session_block and new_end_dt.astimezone(tzinfo).date() != self.entry.start_dt.astimezone(tzinfo).date():
         raise UserValueError(_('Session block cannot span more than one day'))
     with track_time_changes(auto_extend=True, user=session.user) as changes:
         update_timetable_entry_object(self.entry, {'duration': new_duration})
         if is_session_block:
             self.entry.move(new_start_dt)
         if not is_session_block:
             update_timetable_entry(self.entry, {'start_dt': new_start_dt})
     if is_session_block and self.entry.children:
         if new_end_dt < max(self.entry.children, key=attrgetter('end_dt')).end_dt:
             raise UserValueError(_('Session block cannot be shortened this much because contributions contained '
                                    "wouldn't fit."))
     notifications = get_time_changes_notifications(changes, tzinfo=self.event.tzinfo, entry=self.entry)
     return jsonify_data(update=serialize_entry_update(self.entry, session_=self.session),
                         notifications=notifications)
예제 #18
0
 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)
예제 #19
0
    def _process(self, source):
        self.user.picture_source = source

        if source == ProfilePictureSource.standard:
            self.user.picture = None
            self.user.picture_metadata = None
            logger.info('Profile picture of user %s removed by %s', self.user,
                        session.user)
            return '', 204

        if source == ProfilePictureSource.custom:
            f = request.files['picture']
            try:
                pic = Image.open(f)
            except OSError:
                raise UserValueError(
                    _('You cannot upload this file as profile picture.'))
            if pic.format.lower() not in {'jpeg', 'png', 'gif', 'webp'}:
                raise UserValueError(
                    _('The file has an invalid format ({format}).').format(
                        format=pic.format))
            if pic.mode not in ('RGB', 'RGBA'):
                pic = pic.convert('RGB')
            pic = square(pic)
            if pic.height > 256:
                pic = pic.resize((256, 256), resample=Image.BICUBIC)
            image_bytes = BytesIO()
            pic.save(image_bytes, 'PNG')
            image_bytes.seek(0)
            set_user_avatar(self.user, image_bytes.read(), f.filename)
        else:
            content, lastmod = get_gravatar_for_user(
                self.user, source == ProfilePictureSource.identicon, 256)
            set_user_avatar(self.user, content, source.name, lastmod)

        logger.info('Profile picture of user %s updated by %s', self.user,
                    session.user)
        return '', 204
예제 #20
0
파일: util.py 프로젝트: javfg/indico
def import_registrations_from_csv(regform,
                                  fileobj,
                                  skip_moderation=True,
                                  notify_users=False):
    """Import event registrants from a CSV file into a form."""
    columns = [
        'first_name', 'last_name', 'affiliation', 'position', 'phone', 'email'
    ]
    user_records = import_user_records_from_csv(fileobj, columns=columns)

    reg_data = (db.session.query(
        Registration.user_id, Registration.email).with_parent(regform).filter(
            Registration.is_active).all())
    registered_user_ids = {
        rd.user_id
        for rd in reg_data if rd.user_id is not None
    }
    registered_emails = {rd.email for rd in reg_data}

    for row_num, record in enumerate(user_records, 1):
        if record['email'] in registered_emails:
            raise UserValueError(
                _('Row {}: a registration with this email already exists').
                format(row_num))

        user = get_user_by_email(record['email'])
        if user and user.id in registered_user_ids:
            raise UserValueError(
                _('Row {}: a registration for this user already exists').
                format(row_num))

    return [
        create_registration(regform,
                            data,
                            notify_user=notify_users,
                            skip_moderation=skip_moderation)
        for data in user_records
    ]
예제 #21
0
파일: util.py 프로젝트: kuba111333/indico
def import_registrations_from_csv(regform,
                                  fileobj,
                                  skip_moderation=True,
                                  notify_users=False):
    """Import event registrants from a CSV file into a form."""
    with csv_text_io_wrapper(fileobj) as ftxt:
        reader = csv.reader(ftxt.read().splitlines())
    query = db.session.query(Registration.email).with_parent(regform).filter(
        Registration.is_active)
    registered_emails = {email for (email, ) in query}
    used_emails = set()
    todo = []
    for row_num, row in enumerate(reader, 1):
        try:
            first_name, last_name, affiliation, position, phone, email = [
                value.strip() for value in row
            ]
            email = email.lower()
        except ValueError:
            raise UserValueError(
                _('Row {}: malformed CSV data - please check that the number of columns is correct'
                  ).format(row_num))

        if not email:
            raise UserValueError(
                _('Row {}: missing e-mail address').format(row_num))
        if not validate_email(email):
            raise UserValueError(
                _('Row {}: invalid e-mail address').format(row_num))
        if not first_name or not last_name:
            raise UserValueError(
                _('Row {}: missing first or last name').format(row_num))
        if email in registered_emails:
            raise UserValueError(
                _('Row {}: a registration with this email already exists').
                format(row_num))
        if email in used_emails:
            raise UserValueError(
                _('Row {}: email address is not unique').format(row_num))

        used_emails.add(email)
        todo.append({
            'email': email,
            'first_name': first_name.title(),
            'last_name': last_name.title(),
            'affiliation': affiliation,
            'phone': phone,
            'position': position
        })
    return [
        create_registration(regform,
                            data,
                            notify_user=notify_users,
                            skip_moderation=skip_moderation) for data in todo
    ]
예제 #22
0
 def adjust_payment_form_data(self, data):
     data['postfinance_methods'] = get_payment_methods(data['event'], data['currency'])
     data['selected_method'] = selected_method = request.args.get('postfinance_method', '')
     base_amount = data['amount']
     if selected_method:
         method = get_payment_method(data['event'], data['currency'], selected_method)
         if method is None:
             raise UserValueError(_('Invalid currency'))
         modifier = Decimal(1 / (1 - method['fee'] / 100))
         data['amount'] = base_amount * modifier
         data['fee'] = data['amount'] - base_amount
         data['form_data'] = self._generate_form_data(data['amount'], data)
     else:
         data['form_data'] = None
         data['fee'] = None
         if data['event_settings']['apply_fees']:  # we don't know the final price
             data['amount'] = None
예제 #23
0
def move_timetable_entry(entry, parent=None, day=None):
    """Move the `entry` to another session or top-level timetable

    :param entry: `TimetableEntry` to be moved
    :param parent: If specified then the entry will be set as a child
                         of parent
    :param day: If specified then the entry will be moved to the
                        top-level timetable on this day
    """
    if bool(parent) + bool(day) != 1:
        raise TypeError("Wrong number of arguments")

    from indico.modules.events.contributions.operations import update_contribution

    updates = {}
    contrib_update_data = {}
    if day:
        new_start_dt = entry.start_dt.replace(day=day.day, month=day.month)
        updates['start_dt'] = new_start_dt
        updates['parent'] = None
        contrib_update_data = {'session_id': None, 'session_block_id': None}
    elif parent:
        new_start_dt = find_latest_entry_end_dt(
            parent.object) or parent.start_dt
        tz = entry.event.tzinfo
        if (new_start_dt + entry.duration
            ).astimezone(tz).date() != parent.start_dt.astimezone(tz).date():
            raise UserValueError(
                _('Session block cannot span more than one day'))
        updates['parent'] = parent
        updates['start_dt'] = new_start_dt
        contrib_update_data = {
            'session': parent.session_block.session,
            'session_block': parent.session_block
        }

    update_timetable_entry(entry, updates)
    if entry.type == TimetableEntryType.CONTRIBUTION:
        update_contribution(entry.object, contrib_update_data)
    if parent and entry.end_dt > parent.end_dt:
        duration = parent.object.duration + (entry.end_dt - parent.end_dt)
        update_session_block(parent.object, {'duration': duration})
예제 #24
0
    def _generate_form_data(self, amount, data):
        if amount is None:
            return {}
        registration = data['registration']
        personal_data = registration.get_personal_data()
        event = data['event']
        currency = data['currency']
        seed = data['settings']['hash_seed_{}'.format(currency.lower())]
        shop_id = data['settings']['shop_id_{}'.format(currency.lower())]
        method = get_payment_method(event, currency, data['selected_method'])
        if method is None:
            raise UserValueError(_('Invalid currency'))
        template_page = ''  # yes, apparently it's supposed to be empty..
        template_hash = sha512((seed + template_page).encode('utf-8')).hexdigest()
        order_id = self._get_order_id(data)
        locator = registration.locator.uuid

        address = re.sub(r'(\r?\n)+', ', ', personal_data.get('address', ''))
        form_data = {
            'PSPID': shop_id,
            'ORDERID': order_id,
            'AMOUNT': int(amount * 100),
            'CURRENCY': currency,
            'LANGUAGE': session.lang,
            'CN': unicode_to_ascii(remove_accents(registration.full_name[:35], False)),
            'EMAIL': registration.email[:50],
            'OWNERADDRESS': address[:35],
            'OWNERTELNO': personal_data.get('phone', '')[:30],
            'TP': template_page + '&hash=' + template_hash,
            'PM': method['type'],
            'BRAND': method['name'],
            'PARAMVAR': data['settings']['server_url_suffix'],
            'HOMEURL': url_for('event_registration.display_regform', locator, _external=True),
            'ACCEPTURL': url_for_plugin('payment_cern.success', locator, _external=True),
            'CANCELURL': url_for_plugin('payment_cern.cancel', locator, _external=True),
            'DECLINEURL': url_for_plugin('payment_cern.decline', locator, _external=True),
            'EXCEPTIONURL': url_for_plugin('payment_cern.uncertain', locator, _external=True),
            'BACKURL': url_for('payment.event_payment', locator, _external=True)
        }

        form_data['SHASIGN'] = create_hash(seed, form_data)
        return form_data
예제 #25
0
    def _process(self):
        new_identifier = session.user.identifier
        if new_identifier == self.vc_room.data['host'] or new_identifier in self.vc_room.data['alternative_hosts']:
            flash(_('You were already an (alternative) host of this meeting'), 'warning')
            return jsonify(success=False)

        try:
            self.plugin.refresh_room(self.vc_room, self.event)
            self.vc_room.data['alternative_hosts'].append(new_identifier)
            flag_modified(self.vc_room, 'data')
            self.plugin.update_room(self.vc_room, self.event)
        except VCRoomNotFoundError as exc:
            db.session.rollback()
            raise UserValueError(str(exc)) from exc
        except VCRoomError:
            db.session.rollback()
            raise
        else:
            flash(_("You are now an alternative host of room '{room}'").format(room=self.vc_room.name), 'success')
        return jsonify(success=True)
예제 #26
0
파일: util.py 프로젝트: javfg/indico
def import_user_records_from_csv(fileobj, columns):
    """Parse and do basic validation of user data from a CSV file.

    :param fileobj: the CSV file to be read
    :param columns: A list of column names, 'first_name', 'last_name', & 'email' are compulsory.
    :return: A list dictionaries each representing one row,
             the keys of which are given by the column names.
    """
    with csv_text_io_wrapper(fileobj) as ftxt:
        reader = csv.reader(ftxt.read().splitlines())
    used_emails = set()
    email_row_map = {}
    user_records = []
    for row_num, row in enumerate(reader, 1):
        values = [value.strip() for value in row]
        if len(columns) != len(values):
            raise UserValueError(
                _('Row {}: malformed CSV data - please check that the number of columns is correct'
                  ).format(row_num))
        record = dict(zip(columns, values))

        if not record['email']:
            raise UserValueError(
                _('Row {}: missing e-mail address').format(row_num))
        record['email'] = record['email'].lower()

        if not validate_email(record['email']):
            raise UserValueError(
                _('Row {}: invalid e-mail address').format(row_num))
        if not record['first_name'] or not record['last_name']:
            raise UserValueError(
                _('Row {}: missing first or last name').format(row_num))
        record['first_name'] = record['first_name'].title()
        record['last_name'] = record['last_name'].title()

        if record['email'] in used_emails:
            raise UserValueError(
                _('Row {}: email address is not unique').format(row_num))
        if conflict_row_num := email_row_map.get(record['email']):
            raise UserValueError(
                _('Row {}: email address belongs to the same user as in row {}'
                  ).format(row_num, conflict_row_num))

        used_emails.add(record['email'])
        if user := get_user_by_email(record['email']):
            email_row_map.update((e, row_num) for e in user.all_emails)
예제 #27
0
 def _process(self):
     dialog = request.args.get('dialog') == '1'
     form = TestForm(prefix='dlg-' if dialog else '', csrf_enabled=False)
     data = {}
     if form.validate_on_submit():
         _send_email(form.with_event.data)
         data = form.data
     elif form.is_submitted():
         data = form.errors
     if dialog:
         if form.validate_on_submit():
             if form.check.data:
                 raise ValueError('You are full of fail (or ValueErrors)')
             if form.check2.data:
                 raise UserValueError('You sent us failing garbage')
             if form.check3.data:
                 raise Forbidden('You shall not pass')
             if form.check4.data:
                 raise NotFound('Keep going, nothing to see here...')
             return jsonify_data(flash=False, html=json.dumps(data))
         return jsonify_form(form)
         # return jsonify_form(form, form_header_kwargs={'action': '/robots.txt'})
     else:
         return WPTest.render_template('test.html', form=form, data=data)
예제 #28
0
 def _check_access(self):
     RHContributionEditableBase._check_access(self)
     if not self._check_revision_access():
         raise UserValueError(
             _('You cannot perform this action on this revision'))
예제 #29
0
def import_contributions_from_csv(event, f):
    """Import timetable contributions from a CSV file into an event."""
    with csv_text_io_wrapper(f) as ftxt:
        reader = csv.reader(ftxt.read().splitlines())

    contrib_data = []
    for num_row, row in enumerate(reader, 1):
        try:
            start_dt, duration, title, first_name, last_name, affiliation, email = (
                value.strip() for value in row)
            email = email.lower()
        except ValueError:
            raise UserValueError(
                _('Row {}: malformed CSV data - please check that the number of columns is correct'
                  ).format(num_row))
        try:
            parsed_start_dt = event.tzinfo.localize(
                dateutil.parser.parse(start_dt)) if start_dt else None
        except ValueError:
            raise UserValueError(
                _('Row {row}: can\'t parse date: "{date}"').format(
                    row=num_row, date=start_dt))

        try:
            parsed_duration = timedelta(
                minutes=int(duration)) if duration else None
        except ValueError:
            raise UserValueError(
                _("Row {row}: can't parse duration: {duration}").format(
                    row=num_row, duration=duration))

        if not title:
            raise UserValueError(
                _('Row {}: contribution title is required').format(num_row))

        if email and not validate_email(email):
            raise UserValueError(
                _('Row {row}: invalid email address: {email}').format(
                    row=num_row, email=email))

        contrib_data.append({
            'start_dt':
            parsed_start_dt,
            'duration':
            parsed_duration or timedelta(minutes=20),
            'title':
            title,
            'speaker': {
                'first_name': first_name,
                'last_name': last_name,
                'affiliation': affiliation,
                'email': email
            }
        })

    # now that we're sure the data is OK, let's pre-allocate the friendly ids
    # for the contributions in question
    Contribution.allocate_friendly_ids(event, len(contrib_data))
    contributions = []
    all_changes = defaultdict(list)

    for contrib_fields in contrib_data:
        speaker_data = contrib_fields.pop('speaker')

        with track_time_changes() as changes:
            contribution = create_contribution(event,
                                               contrib_fields,
                                               extend_parent=True)

        contributions.append(contribution)
        for key, val in changes[event].items():
            all_changes[key].append(val)

        email = speaker_data['email']
        if not email:
            continue

        # set the information of the speaker
        person = get_event_person(event, speaker_data)
        link = ContributionPersonLink(person=person, is_speaker=True)
        link.populate_from_dict({
            'first_name': speaker_data['first_name'],
            'last_name': speaker_data['last_name'],
            'affiliation': speaker_data['affiliation']
        })
        contribution.person_links.append(link)

    return contributions, all_changes
예제 #30
0
파일: util.py 프로젝트: qroques/indico
def track_time_changes(auto_extend=False, user=None):
    """Track time changes of event objects.

    This provides a list of changes while the context manager was
    active and also triggers `times_changed` signals.

    If the code running inside the ``with`` block of this context
    manager raises an exception, no signals will be triggered.

    :param auto_extend: Whether entry parents will get their boundaries
                        automatically extended or not. Passing ``'start'`` will
                        extend only start datetime, ``'end'`` to extend only
                        end datetime.
    :param user: The `User` that will trigger time changes.
    """
    if auto_extend:
        assert user is not None
    if 'old_times' in g:
        raise RuntimeError('time change tracking may not be nested')
    g.old_times = defaultdict(dict)
    changes = defaultdict(dict)
    try:
        yield changes
    except:
        del g.old_times
        raise
    else:
        if auto_extend:
            by_start = auto_extend in (True, 'start')
            by_end = auto_extend in (True, 'end')
            initial_changes = set(g.old_times)
            # g.old_times changes during iteration
            for obj in list(g.old_times):
                if not isinstance(obj, Event):
                    obj.extend_parent(by_start=by_start, by_end=by_end)
            cascade_changes = set(g.old_times) - initial_changes
            for obj in cascade_changes:
                if isinstance(obj, Event):
                    if not obj.can_manage(user):
                        # TODO: raise Forbidden exceptions after adding protection check in the UI
                        raise UserValueError(
                            _("Your action requires modification of event boundaries, but you are "
                              "not authorized to manage the event."))
                elif not obj.object.can_manage(user):
                    # TODO: raise Forbidden exceptions after adding protection check in the UI
                    raise UserValueError(
                        _("Your action requires modification of session block boundaries, but you are "
                          "not authorized to manage the session block."))
        old_times = g.pop('old_times')
        for obj, info in old_times.iteritems():
            if isinstance(obj, TimetableEntry):
                obj = obj.object
            if obj.start_dt != info['start_dt']:
                changes[obj]['start_dt'] = (info['start_dt'], obj.start_dt)
            if obj.duration != info['duration']:
                changes[obj]['duration'] = (info['duration'], obj.duration)
            if obj.end_dt != info['end_dt']:
                changes[obj]['end_dt'] = (info['end_dt'], obj.end_dt)
        for obj, obj_changes in changes.iteritems():
            entry = None if isinstance(obj, Event) else obj.timetable_entry
            signals.event.times_changed.send(type(obj),
                                             entry=entry,
                                             obj=obj,
                                             changes=obj_changes)