Exemple #1
0
def create_personal_data_fields(regform):
    """Creates the special section/fields for personal data."""
    section = next((s for s in regform.sections
                    if s.type == RegistrationFormItemType.section_pd), None)
    if section is None:
        section = RegistrationFormPersonalDataSection(
            registration_form=regform, title='Personal Data')
        missing = set(PersonalDataType)
    else:
        existing = {
            x.personal_data_type
            for x in section.children
            if x.type == RegistrationFormItemType.field_pd
        }
        missing = set(PersonalDataType) - existing
    for pd_type, data in PersonalDataType.FIELD_DATA:
        if pd_type not in missing:
            continue
        field = RegistrationFormPersonalDataField(
            registration_form=regform,
            personal_data_type=pd_type,
            is_required=pd_type.is_required)
        if not data.get('is_enabled', True):
            field.position = data['position']
        for key, value in data.iteritems():
            setattr(field, key, value)
        field.data, versioned_data = field.field_impl.process_field_data(
            data.pop('data', {}))
        field.current_data = RegistrationFormFieldData(
            versioned_data=versioned_data)
        section.children.append(field)
Exemple #2
0
 def _clone_form_items(self, old_form, new_form, clone_all_revisions):
     old_sections = RegistrationFormSection.find(
         RegistrationFormSection.registration_form_id == old_form.id)
     items_attrs = get_simple_column_attrs(RegistrationFormSection)
     for old_section in old_sections:
         new_section = RegistrationFormSection(
             **{attr: getattr(old_section, attr)
                for attr in items_attrs})
         for old_item in old_section.children:
             new_item = RegistrationFormItem(
                 parent=new_section,
                 registration_form=new_form,
                 **{attr: getattr(old_item, attr)
                    for attr in items_attrs})
             if new_item.is_field:
                 if clone_all_revisions:
                     self._clone_all_field_versions(old_item, new_item)
                 else:
                     field_data = RegistrationFormFieldData(
                         field=new_item,
                         versioned_data=old_item.versioned_data)
                     new_item.current_data = field_data
                     self._field_data_map[
                         old_item.current_data] = field_data
             new_section.children.append(new_item)
         new_form.form_items.append(new_section)
         db.session.flush()
Exemple #3
0
 def _clone_all_field_versions(self, old_item, new_item):
     for old_version in old_item.data_versions:
         new_version = RegistrationFormFieldData(versioned_data=old_version.versioned_data, field=new_item)
         if old_version.id == old_item.current_data_id:
             new_item.current_data = new_version
         new_item.data_versions.append(new_version)
         self._field_data_map[old_version] = new_version
Exemple #4
0
    def process_form_data(self, registration, value, old_data=None, billable_items_locked=False, new_data_version=None):
        # always store no-option as empty dict
        if value is None:
            value = {}

        return_value = {}
        has_old_data = old_data is not None and old_data.data is not None

        if has_old_data:
            # in case nothing changed we can skip all checks
            if old_data.data == value:
                return {}

            selected_choice_hashes = {c['id']: _hashable_choice(c)
                                      for c in old_data.field_data.versioned_data['choices']
                                      if c['id'] in value}
            selected_choice_hashes.update({c['id']: _hashable_choice(c)
                                           for c in self.form_item.versioned_data['choices']
                                           if c['id'] in value and c['id'] not in selected_choice_hashes})
            selected_choice_hashes = set(selected_choice_hashes.values())
            existing_version_hashes = {c['id']: _hashable_choice(c)
                                       for c in old_data.field_data.versioned_data['choices']}
            latest_version_hashes = {c['id']: _hashable_choice(c) for c in self.form_item.versioned_data['choices']}
            deselected_ids = old_data.data.keys() - value.keys()
            modified_deselected = any(latest_version_hashes.get(id_) != existing_version_hashes.get(id_)
                                      for id_ in deselected_ids)
            if selected_choice_hashes <= set(latest_version_hashes.values()):
                # all choices available in the latest version - upgrade to that version
                return_value['field_data'] = self.form_item.current_data
            elif not modified_deselected and selected_choice_hashes <= set(existing_version_hashes.values()):
                # all choices available in the previously selected version - stay with it
                return_value['field_data'] = old_data.field_data
            else:
                # create a new version containing selected choices from the previously
                # selected version and everything else from the latest version
                new_choices = []
                used_ids = set()
                for choice in old_data.field_data.versioned_data['choices']:
                    # copy all old choices that are currently selected
                    if choice['id'] in value:
                        used_ids.add(choice['id'])
                        new_choices.append(choice)
                for choice in self.form_item.versioned_data['choices']:
                    # copy all new choices unless we already got them from the old version
                    if choice['id'] not in used_ids:
                        used_ids.add(choice['id'])
                        new_choices.append(choice)
                new_choices_hash = {_hashable_choice(x) for x in new_choices}
                for data_version in self.form_item.data_versions:
                    if {_hashable_choice(x) for x in data_version.versioned_data['choices']} == new_choices_hash:
                        break
                else:
                    data_version = RegistrationFormFieldData(field=self.form_item,
                                                             versioned_data={'choices': new_choices})
                return_value['field_data'] = data_version
            new_choices = return_value['field_data'].versioned_data['choices']

        if not billable_items_locked:
            processed_data = super().process_form_data(registration, value, old_data, False,
                                                       return_value.get('field_data'))
            return {key: return_value.get(key, value) for key, value in processed_data.items()}
        # XXX: This code still relies on the client sending data for the disabled fields.
        # This is pretty ugly but especially in case of non-billable extra slots it makes
        # sense to keep it like this.  If someone tampers with the list of billable fields
        # we detect it any reject the change to the field's data anyway.
        if has_old_data:
            old_choices_mapping = {x['id']: x for x in old_data.field_data.versioned_data['choices']}
            new_choices_mapping = {x['id']: x for x in new_choices}
            old_billable = {uuid: num for uuid, num in old_data.data.items()
                            if old_choices_mapping[uuid]['is_billable'] and old_choices_mapping[uuid]['price']}
            new_billable = {uuid: num for uuid, num in value.items()
                            if new_choices_mapping[uuid]['is_billable'] and new_choices_mapping[uuid]['price']}
        if has_old_data and old_billable != new_billable:
            # preserve existing data
            return return_value
        else:
            # nothing price-related changed
            # TODO: check item prices (in case there's a change between old/new version)
            # for now we simply ignore field changes in this case (since the old/new price
            # check in the base method will fail)
            processed_data = super().process_form_data(registration, value, old_data, True,
                                                       return_value.get('field_data'))
            return {key: return_value.get(key, value) for key, value in processed_data.items()}