def _clone_registrations(self, old_form, new_form, field_data_map): registration_attrs = get_simple_column_attrs(Registration) - {'uuid', 'ticket_uuid'} for old_registration in old_form.registrations: if old_registration.is_deleted: continue new_registration = Registration(user=old_registration.user, registration_form=new_form, **{attr: getattr(old_registration, attr) for attr in registration_attrs}) reg_data_attrs = get_simple_column_attrs(RegistrationData) - {'storage_file_id', 'storage_backend', 'size'} for old_registration_data in old_registration.data: new_registration_data = RegistrationData(registration=new_registration, **{attr: getattr(old_registration_data, attr) for attr in reg_data_attrs}) new_registration_data.field_data = field_data_map[old_registration_data.field_data] if old_registration_data.storage_file_id is not None: with old_registration_data.open() as fd: new_registration_data.save(fd) db.session.flush() signals.event.registration_state_updated.send(new_registration)
def _checkParams(self, params): RHManageRegFormsBase._checkParams(self, params) self.field_data = ( RegistrationData.find( RegistrationData.registration_id == request.view_args["registration_id"], RegistrationData.field_data_id == request.view_args["field_data_id"], RegistrationData.filename != None, ) # noqa .options(joinedload("registration").joinedload("registration_form")) .one() )
def _migrate_participant_status(self, old_part, registration): if not self.status_used: return if old_part._status not in {'added', 'pending'}: status_info = self.status_map[old_part._status] data = {status_info['uuid']: 1} caption = status_info['caption'] else: data = None caption = '' if not self.quiet and data: self.print_info('%[red]STATUS%[reset] %[cyan]{}'.format(caption)) registration.data.append( RegistrationData(field_data=self.status_field.current_data, data=data))
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.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) 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) 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', f'Registration modified: {registration.full_name}', session.user, data={'Email': registration.email})
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() signals.event.registration_created.send(registration, management=management) 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}, meta={'registration_id': registration.id}) return registration
def test_multi_choice_field_process_form_data_old_version(multi_choice_field): # reg linked to old version, price changed in new version, nothing changed # in this case everything should remain linked to the old version old_version = multi_choice_field.current_data old_data = RegistrationData(field_data=old_version, data={ _id(2): 1, _id(3): 1 }) multi_choice_field.versioned_data = _update_data( multi_choice_field.versioned_data, {_id(3): { 'price': 1000 }}) form_data = {_id(2): 1, _id(3): 1} assert multi_choice_field.field_impl.process_form_data( None, form_data, old_data) == {}
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 test_multi_choice_field_process_form_data_item_removed_deselected( multi_choice_field): # reg linked to old version, one selected item removed from there and deselected # since all other items are available in the latest version we upgrade to it old_version = multi_choice_field.current_data old_data = RegistrationData(field_data=old_version, data={ _id(1): 1, _id(2): 1 }) multi_choice_field.versioned_data = _update_data( multi_choice_field.versioned_data, {_id(1): None}) form_data = {_id(2): 1} rv = multi_choice_field.field_impl.process_form_data( None, form_data, old_data) assert rv['field_data'] == multi_choice_field.current_data assert rv['data'] == form_data
def test_multi_choice_field_process_form_data_only_new(multi_choice_field): # reg linked to old version, but all old items deselected # field data should be upgraded to the current version old_version = multi_choice_field.current_data old_data = RegistrationData(field_data=old_version, data={ _id(1): 1, _id(2): 1 }) multi_choice_field.versioned_data = _update_data( multi_choice_field.versioned_data, { _id(1): None, _id(4): {} }) form_data = {_id(4): 1} rv = multi_choice_field.field_impl.process_form_data( None, form_data, old_data) assert rv['field_data'] == multi_choice_field.current_data assert rv['data'] == form_data
def test_multi_choice_field_process_form_data_mixed(multi_choice_field): # reg linked to old version, a currently selected item was deleted and a new item is selected # field data should be upgraded to a new version containing both the new items and the deleted one old_version = multi_choice_field.current_data old_data = RegistrationData(field_data=old_version, data={_id(1): 1}) multi_choice_field.versioned_data = _update_data( multi_choice_field.versioned_data, { _id(1): None, _id(4): {} }) form_data = {_id(1): 1, _id(4): 1} rv = multi_choice_field.field_impl.process_form_data( None, form_data, old_data) assert rv['field_data'] not in { multi_choice_field.current_data, old_version } assert rv['data'] == form_data combined = multi_choice_field.versioned_data['choices'] + [ old_version.versioned_data['choices'][0] ] _assert_same_choices(rv['field_data'].versioned_data['choices'], combined)
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 test_multi_choice_field_process_form_data_mixed_price_change( multi_choice_field): # reg linked to old version, a currently selected item had its price changed and a new item is selected # field data should be upgraded to a new version containing both the new items and the old-priced one old_version = multi_choice_field.current_data old_data = RegistrationData(field_data=old_version, data={_id(3): 1}) multi_choice_field.versioned_data = _update_data( multi_choice_field.versioned_data, { _id(3): { 'price': 1000 }, _id(4): {} }) form_data = {_id(3): 1, _id(4): 1} rv = multi_choice_field.field_impl.process_form_data( None, form_data, old_data) assert rv['field_data'] not in { multi_choice_field.current_data, old_version } assert rv['data'] == form_data old_choices = old_version.versioned_data['choices'] new_choices = multi_choice_field.versioned_data['choices'] combined = new_choices[:2] + [old_choices[2]] + [new_choices[-1]] _assert_same_choices(rv['field_data'].versioned_data['choices'], combined)
def _get_registration_data(self, field): registration_ids = [r.id for r in field.registration_form.active_registrations] field_data_ids = [data.id for data in field.data_versions] return RegistrationData.find_all(RegistrationData.registration_id.in_(registration_ids), RegistrationData.field_data_id.in_(field_data_ids), RegistrationData.data != {})
def test_multi_choice_field_process_form_data_current_version(multi_choice_field): # nothing changed old_data = RegistrationData(field_data=multi_choice_field.current_data, data={_id(1): 1, _id(2): 1}) form_data = {_id(1): 1, _id(2): 1} assert multi_choice_field.field_impl.process_form_data(None, form_data, old_data) == {}
def _get_registration_data(self, field): registration_ids = [r.id for r in field.registration_form.active_registrations] field_data_ids = [data.id for data in field.data_versions] return RegistrationData.find_all(RegistrationData.registration_id.in_(registration_ids), RegistrationData.field_data_id.in_(field_data_ids), RegistrationData.data != {})
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})