def test_get_event_person_edit(db, dummy_event, dummy_user): data = { 'email': '*****@*****.**', 'firstName': 'John', 'familyName': 'Doe', 'affiliation': 'ACME Inc.' } person_1 = get_event_person(dummy_event, dict(data, _type='Avatar', id=dummy_user.id)) assert person_1.id is None assert person_1.user == dummy_user db.session.add(person_1) db.session.flush() person_2 = get_event_person( dummy_event, dict(data, _type='EventPerson', id=person_1.id)) assert person_2 == person_1 person_3 = get_event_person( dummy_event, dict(data, _type='PersonLink', personId=person_1.id)) assert person_3 == person_1 with pytest.raises(ValueError): get_event_person(dummy_event, dict(data, _type='UnsupportedPersonType'))
def test_get_event_person(db, dummy_event, dummy_user): data = { 'email': '*****@*****.**', 'firstName': 'John', 'familyName': 'Doe', 'affiliation': 'ACME Inc.' } person_1 = get_event_person(dummy_event, data) # Person doesn't exist in the DB assert person_1.id is None # User neither assert person_1.user is None # save in the DB for later db.session.add(person_1) db.session.flush() data = { 'email': '*****@*****.**', 'firstName': 'Sea', 'familyName': 'Pig', 'affiliation': 'ACME Inc.' } person_2 = get_event_person(dummy_event, data) # Person not in the DB either assert person_2.id is None # User exists, however (matched by e-mail) assert person_2.user == dummy_user assert person_2.full_name == 'Guinea Pig' db.session.add(person_2) db.session.flush() person = get_event_person(dummy_event, data) # Retrieved person should now be in the DB assert person.id == person_2.id # User for whom there is already an EventPerson in this event data = { 'email': '*****@*****.**', 'firstName': 'JOHN', 'familyName': 'DOE', 'affiliation': 'ACME' } person_3 = get_event_person(dummy_event, data) # We should get the first person assert person_3.id == person_1.id assert person_3.user is None assert person_3.full_name == 'John Doe' data = { 'firstName': 'Foo', 'familyName': 'Bar' } person_4 = get_event_person(dummy_event, data) # We should get a new person assert person_4.id is None assert person_4.user is None assert person_4.email == '' assert person_4.full_name == 'Foo Bar'
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 _convert_data(self, data): result = [] for person_data in data: person = get_event_person(person_data, create_untrusted_persons=self.create_untrusted_persons, allow_pending=self.allow_external, allow_emails=self.allow_emails, allow_networks=self.allow_networks, existing_data=self.object_data) self.event_person_conversions[person] = data result.append(person) return map(get_event_person, data)
def test_get_event_person_edit(db, dummy_event, dummy_user): data = { 'email': '*****@*****.**', 'firstName': 'John', 'familyName': 'Doe', 'affiliation': 'ACME Inc.' } person_1 = get_event_person(dummy_event, dict(data, _type='Avatar', id=dummy_user.id)) assert person_1.id is None assert person_1.user == dummy_user db.session.add(person_1) db.session.flush() person_2 = get_event_person(dummy_event, dict(data, _type='EventPerson', id=person_1.id)) assert person_2 == person_1 person_3 = get_event_person(dummy_event, dict(data, _type='PersonLink', personId=person_1.id)) assert person_3 == person_1 with pytest.raises(ValueError): get_event_person(dummy_event, dict(data, _type='UnsupportedPersonType'))
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
def import_contributions_from_csv(event, f): """Import timetable contributions from a CSV file into an event.""" reader = csv.reader(f.read().splitlines()) contrib_data = [] for num_row, row in enumerate(reader, 1): try: start_dt, duration, title, first_name, last_name, affiliation, email = \ [to_unicode(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].viewitems(): all_changes[key].append(val) email = speaker_data['email'] if not email: continue # set the information of the speaker person = get_event_person(event, { 'firstName': speaker_data['first_name'], 'familyName': speaker_data['last_name'], 'affiliation': speaker_data['affiliation'], 'email': email }) 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
def import_contributions_from_csv(event, f): """Import timetable contributions from a CSV file into an event.""" reader = csv.reader(f) contributions = [] all_changes = defaultdict(list) for num_row, row in enumerate(reader, 1): try: start_dt, duration, title, first_name, last_name, affiliation, email = row 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 {}: can't parse date: \"{}\"").format( num_row, start_dt)) try: parsed_duration = timedelta( minutes=int(duration)) if duration else None except ValueError: raise UserValueError( _("Row {}: can't parse duration: {}").format( num_row, duration)) if not title: raise UserValueError( _("Row {}: contribution title is required").format(num_row)) with track_time_changes() as changes: contribution = create_contribution( event, { 'start_dt': parsed_start_dt, 'duration': parsed_duration or timedelta(minutes=20), 'title': title }, extend_parent=True) contributions.append(contribution) for key, val in changes[event].viewitems(): all_changes[key].append(val) if not email: continue # set the information of the speaker person = get_event_person( event, { 'firstName': first_name, 'familyName': last_name, 'affiliation': affiliation, 'email': email }) link = ContributionPersonLink(person=person, is_speaker=True) link.populate_from_dict({ 'first_name': first_name, 'last_name': last_name, 'affiliation': affiliation, 'email': email }) contribution.person_links.append(link) return contributions, all_changes
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