def _associate_users_by_email(self, event): # link objects to users by email where possible # event principals emails = [p.email for p in EventPrincipal.query.with_parent(event).filter_by(type=PrincipalType.email)] for user in User.query.filter(~User.is_deleted, User.all_emails.in_(emails)): EventPrincipal.replace_email_with_user(user, 'event') # session principals query = (SessionPrincipal.query .filter(SessionPrincipal.session.has(Session.event == event), SessionPrincipal.type == PrincipalType.email)) emails = [p.email for p in query] for user in User.query.filter(~User.is_deleted, User.all_emails.in_(emails)): SessionPrincipal.replace_email_with_user(user, 'session') # contribution principals query = (ContributionPrincipal.query .filter(ContributionPrincipal.contribution.has(Contribution.event == event), ContributionPrincipal.type == PrincipalType.email)) emails = [p.email for p in query] for user in User.query.filter(~User.is_deleted, User.all_emails.in_(emails)): ContributionPrincipal.replace_email_with_user(user, 'contribution') # event persons query = EventPerson.query.with_parent(event).filter(EventPerson.user_id.is_(None), EventPerson.email != '') for person in query: person.user = get_user_by_email(person.email) # registrations for registration in Registration.query.with_parent(event).filter(Registration.user_id.is_(None)): registration.user = get_user_by_email(registration.email)
def _synchronize_email(self, email, silent=False): from indico.modules.users import logger from indico.modules.users.tasks import update_gravatars from indico.modules.users.util import get_user_by_email if not validate_email(email, check_dns=False): logger.warning( 'Cannot sync email for %r to %r; address is invalid', self, email) if not silent: flash( _("Your email address could not be synchronized from '{old_value}' to " "'{new_value}' since the new email address is not valid." ).format(old_value=self.email, new_value=email), 'warning') return False if email not in self.secondary_emails: if other := get_user_by_email(email): logger.warning( 'Cannot sync email for %r to %r; already used by %r', self, email, other) if not silent: flash( _("Your email address could not be synchronized from '{old_value}' to " "'{new_value}' due to a conflict with another Indico profile." ).format(old_value=self.email, new_value=email), 'warning') return False self.secondary_emails.add(email) signals.users.email_added.send(self, email=email, silent=silent)
def _process(self): if self._getUser() is not None and self._getUser().isRegisteredInConf(self._conf): if ( not self._conf.getRegistrationForm().inRegistrationPeriod() and not self._conf.getRegistrationForm().inModificationPeriod() ): flash(_("Your modification could not be recorded since the modification period is over."), "error") return redirect(url_for("event.confRegistrationFormDisplay", self._conf)) else: rp = self._getUser().getRegistrantById(self._conf.getId()) # Check if the email matches an existing user params = self._getRequestParams() email = self._regForm.getPersonalData().getValueFromParams(params, "email") or "" user = get_user_by_email(email) if user: if not session.user: flash( _( "The provided email ({email}) is linked to an Indico account. Please sign in with it " "first." ).format(email=email), "error", ) return redirect(url_for("event.confRegistrationFormDisplay-modify", self._conf)) elif session.user != user: flash( _( "The provided email ({email}) is linked to another Indico account. Please sign in with " "it first." ).format(email=email), "error", ) return redirect(url_for("event.confRegistrationFormDisplay-modify", self._conf)) # check if the email is being changed by another one that already exists if email != rp.getEmail() and self._conf.hasRegistrantByEmail(email): raise FormValuesError( _('There is already a user with the email "{email}". ' "Please choose another one.").format( email or "--no email--" ) ) rp.setValues(self._getRequestParams(), self._getUser()) log_msg = u"User modified his registration data: {}" self._conf.log( EventLogRealm.participants, EventLogKind.positive, u"Registration", log_msg.format(to_unicode(rp.getFullName(title=False, firstNameFirst=True))), session.user, data={u"Indico user": u"{} ({})".format(user.full_name, user.id) if user else u"None"}, ) notify_registration_modification(self._conf, rp) flash(_(u"Your registration has been modified successfully."), "success") if rp.doPay(): self._redirect(urlHandlers.UHConfRegistrationFormCreationDone.getURL(rp)) else: self._redirect(urlHandlers.UHConfRegistrationForm.getURL(self._conf)) else: self._redirect(urlHandlers.UHConfRegistrationForm.getURL(self._conf))
def create_registration(regform, data, invitation=None, management=False, notify_user=True, skip_moderation=None): user = session.user if session else None registration = Registration(registration_form=regform, user=get_user_by_email(data['email']), base_price=regform.base_price, currency=regform.currency) if skip_moderation is None: skip_moderation = management for form_item in regform.active_fields: if form_item.parent.is_manager_only: value = form_item.field_impl.default_value else: value = data.get(form_item.html_field_name) data_entry = RegistrationData() registration.data.append(data_entry) for attr, value in form_item.field_impl.process_form_data(registration, value).items(): setattr(data_entry, attr, value) if form_item.type == RegistrationFormItemType.field_pd and form_item.personal_data_type.column: setattr(registration, form_item.personal_data_type.column, value) if invitation is None: # Associate invitation based on email in case the user did not use the link invitation = (RegistrationInvitation.query .filter_by(email=data['email'], registration_id=None) .with_parent(regform) .first()) if invitation: invitation.state = InvitationState.accepted invitation.registration = registration registration.sync_state(_skip_moderation=skip_moderation) db.session.flush() signals.event.registration_created.send(registration, management=management, data=data) notify_registration_creation(registration, notify_user) logger.info('New registration %s by %s', registration, user) registration.log(EventLogRealm.management if management else EventLogRealm.participants, EventLogKind.positive, 'Registration', f'New registration: {registration.full_name}', user, data={'Email': registration.email}) return registration
def modify_registration(registration, data, management=False, notify_user=True): old_price = registration.price personal_data_changes = {} regform = registration.registration_form data_by_field = registration.data_by_field if management or not registration.user: registration.user = get_user_by_email(data['email']) billable_items_locked = not management and registration.is_paid for form_item in regform.active_fields: field_impl = form_item.field_impl if management or not form_item.parent.is_manager_only: value = data.get(form_item.html_field_name) elif form_item.id not in data_by_field: # set default value for manager-only field if it didn't have one before value = field_impl.default_value else: # manager-only field that has data which should be preserved continue if form_item.id not in data_by_field: data_by_field[form_item.id] = RegistrationData( registration=registration, field_data=form_item.current_data) attrs = field_impl.process_form_data( registration, value, data_by_field[form_item.id], billable_items_locked=billable_items_locked) for key, val in attrs.iteritems(): setattr(data_by_field[form_item.id], key, val) if form_item.type == RegistrationFormItemType.field_pd and form_item.personal_data_type.column: key = form_item.personal_data_type.column if getattr(registration, key) != value: personal_data_changes[key] = value setattr(registration, key, value) registration.sync_state() db.session.flush() # sanity check if billable_items_locked and old_price != registration.price: raise Exception( "There was an error while modifying your registration (price mismatch: %s / %s)", old_price, registration.price) if personal_data_changes: signals.event.registration_personal_data_modified.send( registration, change=personal_data_changes) signals.event.registration_updated.send(registration, management=management) notify_registration_modification(registration, notify_user) logger.info('Registration %s modified by %s', registration, session.user) registration.log( EventLogRealm.management if management else EventLogRealm.participants, EventLogKind.change, 'Registration', 'Registration modified: {}'.format(registration.full_name), session.user, data={'Email': registration.email})
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.query.filter_by(person=person, object=self.object).first() 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
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
def create_registration(regform, data, invitation=None, management=False, notify_user=True, skip_moderation=None): user = session.user if session else None registration = Registration(registration_form=regform, user=get_user_by_email(data['email']), base_price=regform.base_price, currency=regform.currency) if skip_moderation is None: skip_moderation = management for form_item in regform.active_fields: if form_item.parent.is_manager_only: value = form_item.field_impl.default_value else: value = data.get(form_item.html_field_name) data_entry = RegistrationData() registration.data.append(data_entry) for attr, value in form_item.field_impl.process_form_data(registration, value).iteritems(): setattr(data_entry, attr, value) if form_item.type == RegistrationFormItemType.field_pd and form_item.personal_data_type.column: setattr(registration, form_item.personal_data_type.column, value) if invitation is None: # Associate invitation based on email in case the user did not use the link invitation = (RegistrationInvitation .find(email=data['email'], registration_id=None) .with_parent(regform) .first()) if invitation: invitation.state = InvitationState.accepted invitation.registration = registration registration.sync_state(_skip_moderation=skip_moderation) db.session.flush() notify_registration_creation(registration, notify_user) logger.info('New registration %s by %s', registration, user) regform.event.log(EventLogRealm.management if management else EventLogRealm.participants, EventLogKind.positive, 'Registration', 'New registration: {}'.format(registration.full_name), user, data={'Email': registration.email}) return registration
def create_registration(regform, data, invitation=None, management=False, notify_user=True): registration = Registration(registration_form=regform, user=get_user_by_email(data['email']), base_price=regform.base_price, currency=regform.currency) for form_item in regform.active_fields: if form_item.parent.is_manager_only: with db.session.no_autoflush: value = form_item.field_impl.default_value else: value = data.get(form_item.html_field_name) with db.session.no_autoflush: data_entry = RegistrationData() registration.data.append(data_entry) for attr, value in form_item.field_impl.process_form_data(registration, value).iteritems(): setattr(data_entry, attr, value) if form_item.type == RegistrationFormItemType.field_pd and form_item.personal_data_type.column: setattr(registration, form_item.personal_data_type.column, value) if invitation is None: # Associate invitation based on email in case the user did not use the link with db.session.no_autoflush: invitation = (RegistrationInvitation .find(email=data['email'], registration_id=None) .with_parent(regform) .first()) if invitation: invitation.state = InvitationState.accepted invitation.registration = registration registration.sync_state(_skip_moderation=management) db.session.flush() notify_registration_creation(registration, notify_user) logger.info('New registration %s by %s', registration, session.user) return registration
def get_authors_from_author_index(event, limit): """Fetch the authors of an event with the most contributions. An author is a ContributionParticipation object or an Avatar object. :param event: The event to fetch the author index from :param limit: The limit of the authors to be returned :return: A list of authors. """ author_index = event.getAuthorIndex() fav_users_emails = (set( itertools.chain.from_iterable( f.all_emails for f in session.user.favorite_users)) if session.user else []) sorted_authors = [ x[0] for x in sorted((p for p in author_index.getParticipations() if p[0].getEmail() not in fav_users_emails), key=len, reverse=True) ] authors = [] # Check if there is a corresponding Avatar for the specific user and use that. for author in sorted_authors[:limit]: user = get_user_by_email(author.getEmail()) authors.append(user.as_avatar if user else author) return authors
def process_alternative_hosts(emails): """Convert a comma-concatenated list of alternative host e-mails into a list of identifiers.""" from indico_vc_zoom.plugin import ZoomPlugin mode = ZoomPlugin.settings.get('user_lookup_mode') emails = re.findall(r'[^,;]+', emails) if mode in (UserLookupMode.all_emails, UserLookupMode.email_domains): users = {get_user_by_email(email) for email in emails} elif mode == UserLookupMode.authenticators: users = set() domain = ZoomPlugin.settings.get('enterprise_domain') usernames = { email.split('@')[0] for email in emails if email.endswith(f'@{domain}') } providers = ZoomPlugin.settings.get('authenticators') users = [] if providers and usernames: criteria = db.or_(((Identity.provider == provider) & (Identity.identifier == username)) for provider, username in itertools.product( providers, usernames)) users = [ identity.user for identity in Identity.query.filter(criteria) ] else: raise TypeError('invalid mode') return [u.identifier for u in users if u is not None]
def check_registration_email(regform, email, registration=None, management=False): """Checks whether an email address is suitable for registration. :param regform: The registration form :param email: The email address :param registration: The existing registration (in case of modification) :param management: If it's a manager adding a new registration """ email = email.lower().strip() user = get_user_by_email(email) email_registration = regform.get_registration(email=email) user_registration = regform.get_registration(user=user) if user else None if registration is not None: if email_registration and email_registration != registration: return dict(status='error', conflict='email-already-registered') elif user_registration and user_registration != registration: return dict(status='error', conflict='user-already-registered') elif user and registration.user and registration.user != user: return dict(status='warning' if management else 'error', conflict='email-other-user', user=user.full_name) elif not user and registration.user: return dict(status='warning' if management else 'error', conflict='email-no-user', user=registration.user.full_name) elif user: return dict(status='ok', user=user.full_name, self=(not management and user == session.user), same=(user == registration.user)) elif not validate_email(email): return dict(status='error', conflict='email-invalid') elif regform.require_user and (management or email != registration.email): return dict(status='warning' if management else 'error', conflict='no-user') else: return dict(status='ok', user=None) else: if email_registration: return dict(status='error', conflict='email-already-registered') elif user_registration: return dict(status='error', conflict='user-already-registered') elif user: return dict(status='ok', user=user.full_name, self=(not management and user == session.user), same=False) elif not validate_email(email): return dict(status='error', conflict='email-invalid') elif regform.require_user: return dict(status='warning' if management else 'error', conflict='no-user') else: return dict(status='ok', user=None)
def _process(self): canManageRegistration = self._conf.canManageRegistration(self._getUser()) if not canManageRegistration and not self._regForm.isActivated(): p = registrationForm.WPRegFormInactive(self, self._conf) return p.display() params = self._getRequestParams() email = self._regForm.getPersonalData().getValueFromParams(params, 'email') if email is None: raise FormValuesError(_("An email address has to be set in order to make the registration in the event.")) elif not validMail(email, False): raise FormValuesError(_("The given email address is not valid.")) # Check if the email matches an existing user user = get_user_by_email(email) avatar = user.as_avatar if user else None # Check if the user can register if not canManageRegistration: # normal user registering. Managers can. if self._conf.getRegistrationForm().isFull(): self._redirect(urlHandlers.UHConfRegistrationFormDisplay.getURL(self._conf)) return elif not self._conf.getRegistrationForm().inRegistrationPeriod(): flash(_("Your registration couldn't be recorded."), 'error') return redirect(url_for('event.confRegistrationFormDisplay', self._conf)) if user is None: if self._conf.hasRegistrantByEmail(email): raise FormValuesError("There is already a user with the email \"%s\". Please choose another one" % email) else: if avatar.isRegisteredInConf(self._conf) or self._conf.hasRegistrantByEmail(email): if canManageRegistration: raise FormValuesError("There is already a user with the email \"%s\". Please choose another one" % email) else: raise FormValuesError("You have already registered with the email address \"%s\". If you need to modify your registration, please contact the managers of the conference." % email) rp = registration.Registrant() self._conf.addRegistrant(rp, avatar) rp.setValues(self._getRequestParams(), avatar) if avatar is not None: rp.setAvatar(avatar) notify_registration_confirmation(self._conf, rp) self._conf.log(EventLogRealm.management if self.is_manager else EventLogRealm.participants, EventLogKind.positive, u'Registration', u'User registered: {}'.format(to_unicode(rp.getFullName(title=False, firstNameFirst=True))), session.user, data={u'Indico user': u'{} ({})'.format(user.full_name, user.id) if user else u'None'}) if self.is_manager: self._redirect(RHRegistrantListModif._uh.getURL(self._conf)) else: params = {} if not rp.doPay() or not payment_event_settings.get(self._conf, 'enabled'): flash(_(u"Your registration has been recorded successfully."), 'success') if not session.user or session.user != user: params.update(rp.getLocator(), **{'authkey': rp.getRandomId()}) else: params.update(self._conf.getLocator()) return redirect(url_for('event.confRegistrationFormDisplay', **params))
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)
def import_invitations_from_csv(regform, fileobj, email_from, email_subject, email_body, skip_moderation=True, skip_existing=False): """Import invitations from a CSV file. :return: A list of invitations and the number of skipped records which is zero if skip_existing=False """ columns = ['first_name', 'last_name', 'affiliation', '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} invited_emails = {inv.email for inv in regform.invitations} filtered_records = [] for row_num, user in enumerate(user_records, 1): if user['email'] in registered_emails: if skip_existing: continue raise UserValueError( _('Row {}: a registration with this email already exists'). format(row_num)) indico_user = get_user_by_email(user['email']) if indico_user and indico_user.id in registered_user_ids: if skip_existing: continue raise UserValueError( _('Row {}: a registration for this user already exists'). format(row_num)) if user['email'] in invited_emails: if skip_existing: continue raise UserValueError( _('Row {}: an invitation for this user already exists').format( row_num)) filtered_records.append(user) invitations = [ create_invitation(regform, user, skip_moderation, email_from, email_subject, email_body) for user in filtered_records ] skipped_records = len(user_records) - len(filtered_records) return invitations, skipped_records
def _parse_room_data(self, raw_data, coordinates, room_id): data = {} data['building'] = raw_data['BUILDING'] data['floor'] = raw_data['FLOOR'] data['number'] = raw_data['ROOM_NUMBER'] email = raw_data['RESPONSIBLE_EMAIL'] if not data['building'] or not data['floor'] or not data['number']: raise SkipRoom( 'Error in Foundation - No value for BUILDING or FLOOR or ROOM_NUMBER' ) email_warning = None if not email: email_warning = ( '[%s] No value for RESPONSIBLE_EMAIL in Foundation', room_id) user = None else: user = get_user_by_email(email, create_pending=True) if not user: email_warning = ( '[%s] Bad RESPONSIBLE_EMAIL in Foundation: no user found with email %s', email, room_id) data['owner'] = user data['verbose_name'] = (raw_data.get('FRIENDLY_NAME') or '').strip() or None data['capacity'] = int( raw_data['CAPACITY']) if raw_data['CAPACITY'] else None data['surface_area'] = int( raw_data['SURFACE']) if raw_data['SURFACE'] else None data['division'] = raw_data.get('DEPARTMENT') data['telephone'] = raw_data.get('TELEPHONE') or '' data['key_location'] = self._html_to_markdown( raw_data.get('WHERE_IS_KEY') or '') data['comments'] = self._html_to_markdown( raw_data.get('COMMENTS')) if raw_data.get('COMMENTS') else '' data['reservations_need_confirmation'] = raw_data[ 'BOOKINGS_NEED_CONFIRMATION'] != 'N' is_reservable = raw_data['IS_RESERVABLE'] != 'N' data[ 'protection_mode'] = ProtectionMode.public if is_reservable else ProtectionMode.protected site = raw_data.get('SITE') site_map = {'MEYR': 'Meyrin', 'PREV': 'Prevessin'} data['site'] = site_map.get(site, site) building_coordinates = coordinates.get(int(data['building'])) if building_coordinates: data['latitude'] = building_coordinates['latitude'] data['longitude'] = building_coordinates['longitude'] return data, email_warning
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 })
def modify_registration(registration, data, management=False, notify_user=True): old_price = registration.price personal_data_changes = {} regform = registration.registration_form data_by_field = registration.data_by_field if management or not registration.user: registration.user = get_user_by_email(data['email']) billable_items_locked = not management and registration.is_paid for form_item in regform.active_fields: field_impl = form_item.field_impl if management or not form_item.parent.is_manager_only: value = data.get(form_item.html_field_name) elif form_item.id not in data_by_field: # set default value for manager-only field if it didn't have one before value = field_impl.default_value else: # manager-only field that has data which should be preserved continue if form_item.id not in data_by_field: data_by_field[form_item.id] = RegistrationData(registration=registration, field_data=form_item.current_data) attrs = field_impl.process_form_data(registration, value, data_by_field[form_item.id], billable_items_locked=billable_items_locked) for key, val in attrs.iteritems(): setattr(data_by_field[form_item.id], key, val) if form_item.type == RegistrationFormItemType.field_pd and form_item.personal_data_type.column: key = form_item.personal_data_type.column if getattr(registration, key) != value: personal_data_changes[key] = value setattr(registration, key, value) registration.sync_state() db.session.flush() # sanity check if billable_items_locked and old_price != registration.price: raise Exception("There was an error while modifying your registration (price mismatch: %s / %s)", old_price, registration.price) if personal_data_changes: signals.event.registration_personal_data_modified.send(registration, change=personal_data_changes) signals.event.registration_updated.send(registration, management=management) notify_registration_modification(registration, notify_user) logger.info('Registration %s modified by %s', registration, session.user) regform.event.log(EventLogRealm.management if management else EventLogRealm.participants, EventLogKind.change, 'Registration', 'Registration modified: {}'.format(registration.full_name), session.user, data={'Email': registration.email})
def _getChairPersonsList(self): result = fossilize(self._conf.getChairList()) for chair in result: user = get_user_by_email(chair['email']) chair['showManagerCB'] = True chair['showSubmitterCB'] = True email_submitters = {x.email for x in self._conf.as_event.acl_entries if x.type == PrincipalType.email and x.has_management_role('submit', explicit=True)} if chair['email'] in email_submitters or (user and self._conf.as_event.can_manage(user, 'submit', explicit_role=True)): chair['showSubmitterCB'] = False email_managers = {x.email for x in self._conf.as_event.acl_entries if x.type == PrincipalType.email and x.has_management_role()} if chair['email'] in email_managers or (user and self._conf.as_event.can_manage(user, explicit_role=True)): chair['showManagerCB'] = False return result
def _update_managers(self, room, room_role_map, changes): new_managers = {room.owner} # add managers from aisroles (DKMs + DKAs) new_managers |= {get_user_by_email(email, create_pending=True) for email in room_role_map[(room.building, room.floor, room.number)]} new_managers.discard(None) # compute the "diff" and update the principals accordingly (ignore groups) current_managers = {p for p in room.get_manager_list() if not isinstance(p, GroupProxy)} for principal in current_managers - new_managers: changes.append(f'Manager removed: {principal}') room.update_principal(principal, full_access=False) for principal in new_managers - current_managers: changes.append(f'Manager added: {principal}') room.update_principal(principal, full_access=True)
def modify_registration(registration, data, management=False, notify_user=True): old_price = registration.price with db.session.no_autoflush: regform = registration.registration_form data_by_field = registration.data_by_field if management or not registration.user: registration.user = get_user_by_email(data['email']) billable_items_locked = not management and registration.is_paid for form_item in regform.active_fields: field_impl = form_item.field_impl if management or not form_item.parent.is_manager_only: value = data.get(form_item.html_field_name) elif form_item.id not in data_by_field: # set default value for manager-only field if it didn't have one before value = field_impl.default_value else: # manager-only field that has data which should be preserved continue if form_item.id not in data_by_field: data_by_field[form_item.id] = RegistrationData( registration=registration, field_data=form_item.current_data) attrs = field_impl.process_form_data( registration, value, data_by_field[form_item.id], billable_items_locked=billable_items_locked) for key, val in attrs.iteritems(): setattr(data_by_field[form_item.id], key, val) if form_item.type == RegistrationFormItemType.field_pd and form_item.personal_data_type.column: setattr(registration, form_item.personal_data_type.column, value) registration.sync_state() db.session.flush() # sanity check if billable_items_locked and old_price != registration.price: raise Exception( "There was an error while modifying your registration (price mismatch: %s / %s)", old_price, registration.price) notify_registration_modification(registration, notify_user) logger.info('Registration %s modified by %s', registration, session.user)
def get_authors_from_author_index(event, limit): """Fetch the authors of an event with the most contributions. An author is a ContributionParticipation object or an Avatar object. :param event: The event to fetch the author index from :param limit: The limit of the authors to be returned :return: A list of authors. """ author_index = event.getAuthorIndex() fav_users_emails = (set(itertools.chain.from_iterable(f.all_emails for f in session.user.favorite_users)) if session.user else []) sorted_authors = [x[0] for x in sorted((p for p in author_index.getParticipations() if p[0].getEmail() not in fav_users_emails), key=len, reverse=True)] authors = [] # Check if there is a corresponding Avatar for the specific user and use that. for author in sorted_authors[:limit]: user = get_user_by_email(author.getEmail()) authors.append(user.as_avatar if user else author) return authors
def modify_registration(registration, data, management=False, notify_user=True): old_price = registration.price with db.session.no_autoflush: regform = registration.registration_form data_by_field = registration.data_by_field if management or not registration.user: registration.user = get_user_by_email(data['email']) billable_items_locked = not management and registration.is_paid for form_item in regform.active_fields: field_impl = form_item.field_impl if management or not form_item.parent.is_manager_only: value = data.get(form_item.html_field_name) elif form_item.id not in data_by_field: # set default value for manager-only field if it didn't have one before value = field_impl.default_value else: # manager-only field that has data which should be preserved continue if form_item.id not in data_by_field: data_by_field[form_item.id] = RegistrationData(registration=registration, field_data=form_item.current_data) attrs = field_impl.process_form_data(registration, value, data_by_field[form_item.id], billable_items_locked=billable_items_locked) for key, val in attrs.iteritems(): setattr(data_by_field[form_item.id], key, val) if form_item.type == RegistrationFormItemType.field_pd and form_item.personal_data_type.column: setattr(registration, form_item.personal_data_type.column, value) registration.sync_state() db.session.flush() # sanity check if billable_items_locked and old_price != registration.price: raise Exception("There was an error while modifying your registration (price mismatch: %s / %s)", old_price, registration.price) notify_registration_modification(registration, notify_user) logger.info('Registration %s modified by %s', registration, session.user)
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 ]
def _parse_room_data(self, raw_data, coordinates): data = {} data['building'] = raw_data['BUILDING'] data['floor'] = raw_data['FLOOR'] data['number'] = raw_data['ROOM_NUMBER'] data['email'] = raw_data['RESPONSIBLE_EMAIL'] if not data['building'] or not data['floor'] or not data['number']: raise SkipRoom('Error in Foundation - No value for BUILDING or FLOOR or ROOM_NUMBER') if not data['email']: raise SkipRoom('Error in Foundation - No value for RESPONSIBLE_EMAIL') user = get_user_by_email(data['email'], create_pending=True) if not user: raise SkipRoom('Bad RESPONSIBLE_EMAIL in Foundation - No user found with email {}'.format(data['email'])) data['owner'] = user data['name'] = (raw_data.get('FRIENDLY_NAME') or '').strip() data['capacity'] = int(raw_data['CAPACITY']) if raw_data['CAPACITY'] else None data['surface_area'] = int(raw_data['SURFACE']) if raw_data['SURFACE'] else None data['division'] = raw_data.get('DEPARTMENT') data['telephone'] = raw_data.get('TELEPHONE') data['key_location'] = raw_data.get('WHERE_IS_KEY') data['comments'] = raw_data.get('COMMENTS') data['is_reservable'] = raw_data['IS_RESERVABLE'] != 'N' data['reservations_need_confirmation'] = raw_data['BOOKINGS_NEED_CONFIRMATION'] != 'N' site = raw_data.get('SITE') site_map = {'MEYR': 'Meyrin', 'PREV': 'Prevessin'} data['site'] = site_map.get(site, site) building_coordinates = coordinates.get(int(data['building'])) if building_coordinates: data['latitude'] = building_coordinates['latitude'] data['longitude'] = building_coordinates['longitude'] return data
def _process(self): if self._getUser() is not None and self._getUser().isRegisteredInConf(self._conf): if not self._conf.getRegistrationForm().inRegistrationPeriod() and not self._conf.getRegistrationForm().inModificationPeriod(): flash(_("Your modification could not be recorded since the modification period is over."), 'error') return redirect(url_for('event.confRegistrationFormDisplay', self._conf)) else: rp = self._getUser().getRegistrantById(self._conf.getId()) # Check if the email matches an existing user params = self._getRequestParams() email = self._regForm.getPersonalData().getValueFromParams(params, 'email') or '' user = get_user_by_email(email) if user: if not session.user: flash(_('The provided email ({email}) is linked to an Indico account. Please sign in with it ' 'first.').format(email=email), 'error') return redirect(url_for('event.confRegistrationFormDisplay-modify', self._conf)) elif session.user != user: flash(_('The provided email ({email}) is linked to another Indico account. Please sign in with ' 'it first.').format(email=email), 'error') return redirect(url_for('event.confRegistrationFormDisplay-modify', self._conf)) # check if the email is being changed by another one that already exists if email != rp.getEmail() and self._conf.hasRegistrantByEmail(email): raise FormValuesError(_("There is already a user with the email \"{email}\". " "Please choose another one.").format(email or "--no email--")) rp.setValues(self._getRequestParams(), self._getUser()) notify_registration_modification(self._conf, rp) flash(_(u"Your registration has been modified successfully."), 'success') if rp.doPay(): self._redirect(urlHandlers.UHConfRegistrationFormCreationDone.getURL(rp)) else: self._redirect(urlHandlers.UHConfRegistrationForm.getURL(self._conf)) else: self._redirect(urlHandlers.UHConfRegistrationForm.getURL(self._conf))
def _process(self): canManageRegistration = self._conf.canManageRegistration(self._getUser()) if not canManageRegistration and not self._regForm.isActivated(): p = registrationForm.WPRegFormInactive(self, self._conf) return p.display() params = self._getRequestParams() email = self._regForm.getPersonalData().getValueFromParams(params, 'email') if email is None: raise FormValuesError(_("An email address has to be set in order to make the registration in the event.")) elif not validMail(email, False): raise FormValuesError(_("The given email address is not valid.")) # Check if the email matches an existing user user = get_user_by_email(email) avatar = user.as_avatar if user else None if user: if not session.user: flash(_('The provided email ({email}) is linked to an Indico account. Please sign in with it ' 'first.').format(email=email), 'error') return redirect(url_for('event.confRegistrationFormDisplay-creation', self._conf)) elif session.user != user: flash(_('The provided email ({email}) is linked to another Indico account. Please sign in with it ' 'first.').format(email=email), 'error') return redirect(url_for('event.confRegistrationFormDisplay-creation', self._conf)) # Check if the user can register if not canManageRegistration: # normal user registering. Managers can. if self._conf.getRegistrationForm().isFull(): self._redirect(urlHandlers.UHConfRegistrationFormDisplay.getURL(self._conf)) return elif not self._conf.getRegistrationForm().inRegistrationPeriod(): flash(_("Your registration couldn't be recorded."), 'error') return redirect(url_for('event.confRegistrationFormDisplay', self._conf)) if user is None: if self._conf.hasRegistrantByEmail(email): raise FormValuesError("There is already a user with the email \"%s\". Please choose another one" % email) else: if avatar.isRegisteredInConf(self._conf) or self._conf.hasRegistrantByEmail(email): if canManageRegistration: raise FormValuesError("There is already a user with the email \"%s\". Please choose another one" % email) else: raise FormValuesError("You have already registered with the email address \"%s\". If you need to modify your registration, please contact the managers of the conference." % email) rp = registration.Registrant() self._conf.addRegistrant(rp, avatar) rp.setValues(self._getRequestParams(), avatar) if avatar is not None: rp.setAvatar(avatar) notify_registration_confirmation(self._conf, rp) if canManageRegistration and user != session.user: self._redirect(RHRegistrantListModif._uh.getURL(self._conf)) else: params = {} if not rp.doPay() or not payment_event_settings.get(self._conf, 'enabled'): flash(_(u"Your registration has been recorded successfully."), 'success') if not session.user: params.update(rp.getLocator(), **{'authkey': rp.getRandomId()}) else: params.update(self._conf.getLocator()) return redirect(url_for('event.confRegistrationFormDisplay', **params))
def validate_email(self, field): if get_user_by_email(field.data): raise ValidationError( _('There is already a user with this email address'))
def get_user(email): if email not in user_cache: user_cache[email] = get_user_by_email(email) return user_cache[email]
def check_registration_email(regform, email, registration=None, management=False): """Check whether an email address is suitable for registration. :param regform: The registration form :param email: The email address :param registration: The existing registration (in case of modification) :param management: If it's a manager adding a new registration """ email = email.lower().strip() user = get_user_by_email(email) email_registration = regform.get_registration(email=email) user_registration = regform.get_registration(user=user) if user else None extra_checks = values_from_signal( signals.event.before_check_registration_email.send( regform, email=email, registration=registration, management=management, user=user, user_registration=user_registration, email_registration=email_registration), as_list=True) if extra_checks: return sorted( extra_checks, key=lambda x: ['error', 'warning', 'ok'].index(x['status']))[0] if registration is not None: if email_registration and email_registration != registration: return dict(status='error', conflict='email-already-registered') elif user_registration and user_registration != registration: return dict(status='error', conflict='user-already-registered') elif user and registration.user and registration.user != user: return dict(status='warning' if management else 'error', conflict='email-other-user', user=user.full_name) elif not user and registration.user: return dict(status='warning' if management else 'error', conflict='email-no-user', user=registration.user.full_name) elif user: return dict(status='ok', user=user.full_name, self=(not management and user == session.user), same=(user == registration.user)) email_err = validate_email_verbose(email) if email_err: return dict(status='error', conflict='email-invalid', email_error=email_err) if regform.require_user and (management or email != registration.email): return dict(status='warning' if management else 'error', conflict='no-user') else: return dict(status='ok', user=None) else: if email_registration: return dict(status='error', conflict='email-already-registered') elif user_registration: return dict(status='error', conflict='user-already-registered') elif user: return dict(status='ok', user=user.full_name, self=(not management and user == session.user), same=False) email_err = validate_email_verbose(email) if email_err: return dict(status='error', conflict='email-invalid', email_error=email_err) if regform.require_user: return dict(status='warning' if management else 'error', conflict='no-user') else: return dict(status='ok', user=None)
def modify_registration(registration, data, management=False, notify_user=True): old_data = snapshot_registration_data(registration) old_price = registration.price personal_data_changes = {} regform = registration.registration_form data_by_field = registration.data_by_field if 'email' in data and (management or not registration.user): registration.user = get_user_by_email(data['email']) billable_items_locked = not management and registration.is_paid for form_item in regform.active_fields: if form_item.is_purged: continue field_impl = form_item.field_impl has_data = form_item.html_field_name in data can_modify = management or not form_item.parent.is_manager_only if has_data and can_modify: value = data.get(form_item.html_field_name) elif not has_data and form_item.id not in data_by_field: # set default value for a field if it didn't have one before (including manager-only fields) value = field_impl.default_value else: # keep current value continue if form_item.id not in data_by_field: data_by_field[form_item.id] = RegistrationData( registration=registration, field_data=form_item.current_data) attrs = field_impl.process_form_data( registration, value, data_by_field[form_item.id], billable_items_locked=billable_items_locked) for key, val in attrs.items(): setattr(data_by_field[form_item.id], key, val) if form_item.type == RegistrationFormItemType.field_pd and form_item.personal_data_type.column: key = form_item.personal_data_type.column if getattr(registration, key) != value: personal_data_changes[key] = value setattr(registration, key, value) if not management and regform.needs_publish_consent: registration.consent_to_publish = data.get( 'consent_to_publish', RegistrationVisibility.nobody) registration.sync_state() db.session.flush() # sanity check if billable_items_locked and old_price != registration.price: raise Exception( 'There was an error while modifying your registration (price mismatch: %s / %s)', old_price, registration.price) if personal_data_changes: signals.event.registration_personal_data_modified.send( registration, change=personal_data_changes) signals.event.registration_updated.send(registration, management=management, data=data) new_data = snapshot_registration_data(registration) diff = diff_registration_data(old_data, new_data) notify_registration_modification(registration, notify_user, diff=diff, old_price=old_price) logger.info('Registration %s modified by %s', registration, session.user) registration.log( EventLogRealm.management if management else EventLogRealm.participants, LogKind.change, 'Registration', f'Registration modified: {registration.full_name}', session.user, data={'Email': registration.email})
class PersonLinkListFieldBase(PrincipalListField): #: class that inherits from `PersonLinkBase` person_link_cls = None #: name of the attribute on the form containing the linked object linked_object_attr = None #: If set to `True`, will be sorted alphabetically by default default_sort_alpha = True widget = None create_untrusted_persons = False def __init__(self, *args, **kwargs): super().__init__(*args, allow_groups=False, allow_external_users=True, **kwargs) self.object = getattr(kwargs['_form'], self.linked_object_attr, None) @property def event(self): # The event should be a property as it may only be available later, such as, in creation forms return getattr(self.get_form(), 'event', None) @property def has_predefined_affiliations(self): return Affiliation.query.filter(~Affiliation.is_deleted).has_rows() @no_autoflush def _get_person_link(self, data): from indico.modules.events.persons.schemas import PersonLinkSchema identifier = data.get('identifier') data = PersonLinkSchema(unknown=EXCLUDE).load(data) if identifier and identifier.startswith('ExternalUser:'******'external-user') external_user_data = cache.get( identifier.removeprefix('ExternalUser:'******'affiliation_data')) and data['affiliation'] == affiliation_data['name']): data['affiliation_link'] = Affiliation.get_or_create_from_data( affiliation_data) data['affiliation'] = data['affiliation_link'].name person = get_event_person( self.event, data, create_untrusted_persons=self.create_untrusted_persons, allow_external=True) person_link = None if self.object and inspect(person).persistent: person_link = self.person_link_cls.query.filter_by( person=person, object=self.object).first() if not person_link: person_link = self.person_link_cls(person=person) person_link.populate_from_dict( data, keys=('first_name', 'last_name', 'affiliation', 'affiliation_link', 'address', 'phone', '_title', 'display_order')) 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 {email}'). format(email=email)) return person_link