diff options
Diffstat (limited to 'ishtar_common')
| -rw-r--r-- | ishtar_common/forms.py | 27 | ||||
| -rw-r--r-- | ishtar_common/forms_common.py | 252 | 
2 files changed, 179 insertions, 100 deletions
| diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 0f1263bef..c560dc5ec 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -681,7 +681,9 @@ class IshtarForm(forms.Form, BSForm):      # to manage translation      def __init__(self, *args, **kwargs): -        super(IshtarForm, self).__init__(*args, **kwargs) +        self._headers = {}  # used for dynamic headers +        self._types = []  # used for dynamic types +        super().__init__(*args, **kwargs)          profile = None          if self.PROFILE_FILTER or self.SITE_KEYS:              profile = models.get_current_profile() @@ -694,8 +696,6 @@ class IshtarForm(forms.Form, BSForm):                              self.fields.pop(field_key)          if getattr(self, "confirm", False):              return -        for field in self.TYPES: -            self._init_type(field)          if self.SITE_KEYS:              field_keys = list(self.fields.keys())              for site_key in list(self.SITE_KEYS.keys()): @@ -722,8 +722,14 @@ class IshtarForm(forms.Form, BSForm):                      continue                  for option, value in options.items():                      setattr(self.fields[field_name].widget, option, value) +        self._init_types()          self._post_init() +    def _init_types(self): +        type_lst = self._types or self.TYPES +        for field in type_lst: +            self._init_type(field) +      def _init_type(self, field):          if field.key not in self.fields:              return @@ -731,6 +737,8 @@ class IshtarForm(forms.Form, BSForm):          self.fields[field.key].help_text = field.get_help()      def get_headers(self): +        if self._headers: +            return self._headers          return self.HEADERS      def headers(self, key): @@ -775,10 +783,11 @@ class IshtarForm(forms.Form, BSForm):          conditional_fields = self.CONDITIONAL_FIELDS          if hasattr(self, "get_conditional_fields"):              conditional_fields = self.get_conditional_fields() -        if not conditional_fields or not self.TYPES: +        type_lst = self._types or self.TYPES +        if not conditional_fields or not type_lst:              return -        type_dict = dict([(typ.key, typ.model) for typ in self.TYPES]) +        type_dict = dict([(typ.key, typ.model) for typ in type_lst])          html = ""          for condition, target_names in conditional_fields:              condition_field, condition_attr, condition_val = condition @@ -851,12 +860,13 @@ class IshtarForm(forms.Form, BSForm):              all_values,          ) = self.get_conditional_filter_fields() -        types = [typ.key for typ in self.TYPES] +        type_lst = self._types or self.TYPES +        type_lst = [typ.key for typ in type_lst]          html = ""          outputs = set()          for input_key in conditional_fields: -            if input_key not in types: +            if input_key not in type_lst:                  continue              name = input_key              if self.prefix: @@ -1159,7 +1169,8 @@ class ManageOldType(IshtarForm):                          self.init_data[k].append(val)          self.init_data = MultiValueDict(self.init_data)          super(ManageOldType, self).__init__(*args, **kwargs) -        for field in self.TYPES: +        type_lst = self._types or self.TYPES +        for field in type_lst:              self._init_type(field)      def _init_type(self, field): diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index 1b59206a6..3e3488ae9 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -30,13 +30,16 @@ from urllib.parse import urlparse, quote  import zipfile  from django import forms +from django.apps import apps  from django.conf import settings  from django.contrib.auth import password_validation  from django.contrib.auth.models import User -from django.contrib.auth.forms import UsernameField, \ -    AuthenticationForm as AuthAuthenticationForm, \ -    PasswordChangeForm as AuthPasswordChangeForm, \ -    SetPasswordForm as AuthSetPasswordForm +from django.contrib.auth.forms import ( +    UsernameField, +    AuthenticationForm as AuthAuthenticationForm, +    PasswordChangeForm as AuthPasswordChangeForm, +    SetPasswordForm as AuthSetPasswordForm, +)  from django.core import validators  from django.core.exceptions import ObjectDoesNotExist  from django.core.files import File @@ -73,8 +76,12 @@ from .forms import (      LockForm,  )  from ishtar_common.data_importer import ImporterError -from ishtar_common.utils import is_downloadable, clean_session_cache, max_size_help, \ -    reverse_coordinates +from ishtar_common.utils import ( +    is_downloadable, +    clean_session_cache, +    max_size_help, +    reverse_coordinates, +)  from archaeological_operations.models import Operation, OperationType  from archaeological_context_records.models import ContextRecord @@ -138,14 +145,15 @@ def get_person_field(label=_("Person"), required=True, person_types=None):  class AuthenticationForm(AuthAuthenticationForm): -    username = UsernameField(widget=forms.TextInput( -        attrs={'autofocus': True, 'class': 'no-append'}) +    username = UsernameField( +        widget=forms.TextInput(attrs={"autofocus": True, "class": "no-append"})      )      password = forms.CharField(          label=_("Password"),          strip=False,          widget=forms.PasswordInput( -            attrs={'autocomplete': 'off', 'data-toggle': 'password'}) +            attrs={"autocomplete": "off", "data-toggle": "password"} +        ),      ) @@ -154,14 +162,16 @@ class SetPasswordForm(AuthSetPasswordForm):          label=_("New password"),          strip=False,          help_text=password_validation.password_validators_help_text_html(), -        widget=forms.PasswordInput(attrs={'autocomplete': 'off', -                                          'data-toggle': 'password'}), +        widget=forms.PasswordInput( +            attrs={"autocomplete": "off", "data-toggle": "password"} +        ),      )      new_password2 = forms.CharField(          label=_("New password confirmation"),          strip=False, -        widget=forms.PasswordInput(attrs={'autocomplete': 'off', -                                          'data-toggle': 'password'}), +        widget=forms.PasswordInput( +            attrs={"autocomplete": "off", "data-toggle": "password"} +        ),      ) @@ -169,9 +179,9 @@ class PasswordChangeForm(SetPasswordForm, AuthPasswordChangeForm):      old_password = forms.CharField(          label=_("Old password"),          strip=False, -        widget=forms.PasswordInput(attrs={'autofocus': True, 'autocomplete': 'off', -                                          'data-toggle': 'password'}), - +        widget=forms.PasswordInput( +            attrs={"autofocus": True, "autocomplete": "off", "data-toggle": "password"} +        ),      ) @@ -246,9 +256,9 @@ class BaseImportForm(IshtarForm, forms.ModelForm):      def _filter_importer_type(self):          self.fields["importer_type"].choices = [("", "--")] + [              (imp.pk, imp.name) -            for imp in models.ImporterType.objects.filter(available=True, -                                                          is_import=True, -                                                          type=self.importer_type) +            for imp in models.ImporterType.objects.filter( +                available=True, is_import=True, type=self.importer_type +            )          ]      def _filter_group(self, user): @@ -294,9 +304,9 @@ class BaseImportForm(IshtarForm, forms.ModelForm):      def clean(self):          data = self.cleaned_data          if ( -                data.get("conservative_import", None) -                and data.get("importer_type") -                and not data.get("importer_type").unicity_keys +            data.get("conservative_import", None) +            and data.get("importer_type") +            and not data.get("importer_type").unicity_keys          ):              raise forms.ValidationError(                  _( @@ -363,13 +373,13 @@ class NewImportForm(BaseImportForm):                  zf.testzip()              except zipfile.BadZipFile:                  raise forms.ValidationError( -                    _("\"Associated images\" field must be a valid zip file.") +                    _('"Associated images" field must be a valid zip file.')                  )          self._clean_csv(is_csv=True)          archive_required = self._need_archive(data)          if archive_required and ( -                not data.get("imported_images", None) and -                not data.get("imported_images_link", None) +            not data.get("imported_images", None) +            and not data.get("imported_images_link", None)          ):              raise forms.ValidationError(_("This importer need a document archive."))          return data @@ -448,7 +458,9 @@ class NewImportGISForm(BaseImportForm):                          raise forms.ValidationError("")              except forms.ValidationError:                  raise forms.ValidationError( -                    _("GIS file must be a zip containing a ShapeFile or GeoPackage file.") +                    _( +                        "GIS file must be a zip containing a ShapeFile or GeoPackage file." +                    )                  )          return value @@ -624,39 +636,70 @@ class TargetKeyForm(forms.ModelForm):  class PreImportForm(IshtarForm):      def __init__(self, *args, **kwargs): -        self.HEADERS = {} +        self._headers = {} +        self._types = []          self.import_item = kwargs.pop("import_item")          super().__init__(*args, **kwargs) -        readonly = self.import_item.state not in ("C", "AP", "A") +        readonly = self.import_item.state not in ("C", "AP", "A")          for column in self.column_query.order_by("col_number"):              q = column.targets              if not q.count():                  continue              target = q.all()[0] -            field_name, widget_name = FORMATER_WIDGETS_DCT[target.formater_type.formater_type] +            field_name, widget_name = FORMATER_WIDGETS_DCT[ +                target.formater_type.formater_type +            ]              attrs = {                  "label": column.label,                  "required": column.required,              } -            q = models.ImportColumnValue.objects.filter(column=column, -                                                        import_item=self.import_item) +            q = models.ImportColumnValue.objects.filter( +                column=column, import_item=self.import_item +            )              if q.count(): -                attrs["initial"] = q.all()[0].value +                value = q.all()[0].value +                if target.formater_type.many_split: +                    if value.startswith("['") and value.endswith("']"): +                        value = value[2:-2].split("', '") +                    else: +                        value = "" +                attrs["initial"] = value              if column.description:                  attrs["help_text"] = column.description              if widget_name:                  attrs["widget"] = getattr(forms, widget_name)              key = f"col_{- column.col_number}" -            self.fields[key] = getattr(forms, field_name)( -                **attrs -            ) +            form_field = getattr(forms, field_name) +            if field_name == "ChoiceField": +                if not target.formater_type.options: +                    continue +                options = target.formater_type.options.split(".") +                if len(options) == 1: +                    app = "ishtar_common" +                else: +                    app = options[0] +                model_name = options[-1] +                try: +                    model = apps.get_model(app, model_name) +                except LookupError: +                    continue +                if target.formater_type.many_split: +                    form_field = widgets.Select2MultipleField +                self._types.append( +                    FieldType(key, model, is_multiple=bool(target.formater_type.many_split)) +                ) +            self.fields[key] = form_field(**attrs)              if readonly:                  self.fields[key].widget.attrs["readonly"] = True -            if not self.HEADERS: -                self.HEADERS[key] = FormHeader(self.import_item) +            if not self._headers: +                self._headers[key] = FormHeader(self.import_item)                  if self.import_item.importer_type.pre_import_message: -                    self.HEADERS[key].help_message = self.import_item.importer_type.pre_import_message +                    self._headers[ +                        key +                    ].help_message = self.import_item.importer_type.pre_import_message +        self._init_types() +        self._post_init()      @property      def column_query(self): @@ -668,8 +711,7 @@ class PreImportForm(IshtarForm):              if key not in self.cleaned_data:                  continue              col_value, __ = models.ImportColumnValue.objects.get_or_create( -                column=column, -                import_item=self.import_item +                column=column, import_item=self.import_item              )              col_value.value = self.cleaned_data[key]              col_value.save() @@ -736,7 +778,9 @@ class OrganizationForm(ManageOldType, NewItemForm):          )          if dct["precise_town_id"]:              try: -                dct["precise_town_id"] = models.Town.objects.get(pk=dct["precise_town_id"]).pk +                dct["precise_town_id"] = models.Town.objects.get( +                    pk=dct["precise_town_id"] +                ).pk              except models.Town.DoesNotExist:                  dct.pop("precise_town_id")          if not item: @@ -1334,14 +1378,18 @@ class AccountForm(IshtarForm):      hidden_password = forms.CharField(          label=_("New password"),          max_length=128, -        widget=forms.PasswordInput(attrs={'autocomplete': 'off', 'data-toggle': 'password'}), +        widget=forms.PasswordInput( +            attrs={"autocomplete": "off", "data-toggle": "password"} +        ),          required=False,          validators=[validators.MinLengthValidator(4)],      )      hidden_password_confirm = forms.CharField(          label=_("New password (confirmation)"),          max_length=128, -        widget=forms.PasswordInput(attrs={'autocomplete': 'off', 'data-toggle': 'password'}), +        widget=forms.PasswordInput( +            attrs={"autocomplete": "off", "data-toggle": "password"} +        ),          required=False,      ) @@ -1396,9 +1444,7 @@ class AccountForm(IshtarForm):                      _("You must provide a correct " "password.")                  )          # check username unicity -        q = User.objects.filter( -            username=cleaned_data.get("username") -        ) +        q = User.objects.filter(username=cleaned_data.get("username"))          if cleaned_data.get("pk"):              q = q.exclude(ishtaruser__person__pk=cleaned_data.get("pk"))          if q.count(): @@ -1442,10 +1488,7 @@ class ProfileFormsetBase(FormSetWithDeleteSwitches):          for data in self.cleaned_data:              if not data.get("profile_type", None):                  continue -            value = ( -                data.get("profile_type", None), -                data.get("name", None) -            ) +            value = (data.get("profile_type", None), data.get("name", None))              if value in values:                  raise forms.ValidationError(_("Choose different name for profiles."))              values.append(value) @@ -2338,8 +2381,7 @@ class DocumentSelect(HistorySelect):          validators=[models.valid_id(Operation)],      )      operations__operation_type = forms.ChoiceField( -        label=_("Operation - type"), -        choices=[] +        label=_("Operation - type"), choices=[]      )      operations__year = forms.IntegerField(label=_("Operation - year"))      context_record = forms.IntegerField( @@ -2823,13 +2865,17 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):          label=_("Import key"),          required=False,          disabled=True, -        help_text=_("An update via import corresponding to the source element and " -                    "this key will overwrite the data."), +        help_text=_( +            "An update via import corresponding to the source element and " +            "this key will overwrite the data." +        ),      )      source_content_type_id = forms.IntegerField( -        label="", required=True, widget=forms.HiddenInput, disabled=True) +        label="", required=True, widget=forms.HiddenInput, disabled=True +    )      source_id = forms.IntegerField( -        label="", required=True, widget=forms.HiddenInput, disabled=True) +        label="", required=True, widget=forms.HiddenInput, disabled=True +    )      data_type = widgets.ModelChoiceField(          model=models.GeoDataType, label=_("Data type"), choices=[], required=False      ) @@ -2840,7 +2886,8 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):          model=models.GeoProviderType, label=_("Provider"), choices=[], required=False      )      buffer = forms.FloatField( -        label=_("Buffer"), required=False, +        label=_("Buffer"), +        required=False,          widget=widgets.MeterCentimeterWidget,      )      buffer_type = widgets.ModelChoiceField( @@ -2848,15 +2895,18 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):      )      comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False)      estimated_error_x = forms.FloatField( -        label=_("Estimated error for X"), required=False, +        label=_("Estimated error for X"), +        required=False,          widget=widgets.MeterCentimeterWidget,      )      estimated_error_y = forms.FloatField( -        label=_("Estimated error for Y"), required=False, +        label=_("Estimated error for Y"), +        required=False,          widget=widgets.MeterCentimeterWidget,      )      estimated_error_z = forms.FloatField( -        label=_("Estimated error for Z"), required=False, +        label=_("Estimated error for Z"), +        required=False,          widget=widgets.MeterCentimeterWidget,      ) @@ -2869,12 +2919,21 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):      class Meta:          model = models.GeoVectorData -        exclude = ["need_update", "imports", "cached_x", "cached_y", "cached_z", -                   "source_content_type", "timestamp_label", "timestamp_geo"] +        exclude = [ +            "need_update", +            "imports", +            "cached_x", +            "cached_y", +            "cached_z", +            "source_content_type", +            "timestamp_label", +            "timestamp_geo" +        ]      HEADERS = {          "related_items_ishtar_common_town": FormHeader( -            _("Related items"), collapse=True), +            _("Related items"), collapse=True +        ),          "name": FormHeader(_("Metadata")),          "geo_field": FormHeader(_("Geography")),          "buffer": FormHeader(_("Buffer"), collapse=True), @@ -2911,8 +2970,9 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):          if "too_many" in kwargs:              self.too_many = kwargs.pop("too_many")          self.user = None -        self.geom_type = kwargs.pop("geom_type") \ -            if kwargs.get("geom_type", None) else None +        self.geom_type = ( +            kwargs.pop("geom_type") if kwargs.get("geom_type", None) else None +        )          if kwargs.get("user", None):              self.user = kwargs.pop("user")          instance = kwargs.get("instance", False) @@ -2923,10 +2983,12 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):          super().__init__(*args, **kwargs)          if back_url:              self.fields["back_url"] = forms.CharField( -                label="", required=False, widget=forms.HiddenInput, initial=back_url) +                label="", required=False, widget=forms.HiddenInput, initial=back_url +            )          if find_id:              self.fields["find_id"] = forms.CharField( -                label="", required=False, widget=forms.HiddenInput, initial=find_id) +                label="", required=False, widget=forms.HiddenInput, initial=find_id +            )          if not self.fields["import_key"].initial:              self.fields.pop("import_key")          if not self.source_content_type: @@ -2951,7 +3013,7 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):                  for field_key, label in main_items_fields[related_key]:                      disabled = False                      if kwargs.get("initial", None) and kwargs["initial"].get( -                            field_key, False +                        field_key, False                      ):                          disabled = True                      fields[field_key] = forms.BooleanField( @@ -2976,9 +3038,12 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):          extra_geo = ["buffer", "buffer_type"]          if self.geom_type == "coordinates":              geo_keys = [ -                "x", "estimated_error_x", -                "y", "estimated_error_y", -                "z", "estimated_error_z", +                "x", +                "estimated_error_x", +                "y", +                "estimated_error_y", +                "z", +                "estimated_error_z",                  "spatial_reference_system",              ]          base_widget_attrs = {} @@ -3038,16 +3103,22 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):                      if map_srid == 4326:                          widget = widgets.ReversedOSMWidget                      self.fields[keys[0]].widget = widget( -                        attrs={"map_srid": map_srid, -                               "geom_type": geom.geom_type, -                               "cols": True}) +                        attrs={ +                            "map_srid": map_srid, +                            "geom_type": geom.geom_type, +                            "cols": True, +                        } +                    )                      self.fields.pop("spatial_reference_system")                      geo_keys = keys[:]                  else:                      geo_keys = [ -                        "x", "estimated_error_x", -                        "y", "estimated_error_y", -                        "z", "estimated_error_z", +                        "x", +                        "estimated_error_x", +                        "y", +                        "estimated_error_y", +                        "z", +                        "estimated_error_z",                          "spatial_reference_system",                      ]                  for geo_fields in self.GEO_FIELDS: @@ -3074,21 +3145,17 @@ class GISForm(forms.ModelForm, CustomForm, ManageOldType):      def clean(self):          cleaned_data = self.cleaned_data -        if cleaned_data.get("buffer", None) \ -                and not cleaned_data.get("buffer_type", None): -            raise forms.ValidationError( -                _("If you set a buffer set a buffer type.") -            ) -        if cleaned_data.get("buffer_type", None) \ -                and not cleaned_data.get("buffer", None): -            raise forms.ValidationError( -                _("If you set a buffer type set a buffer.") -            ) +        if cleaned_data.get("buffer", None) and not cleaned_data.get( +            "buffer_type", None +        ): +            raise forms.ValidationError(_("If you set a buffer set a buffer type.")) +        if cleaned_data.get("buffer_type", None) and not cleaned_data.get( +            "buffer", None +        ): +            raise forms.ValidationError(_("If you set a buffer type set a buffer."))          if cleaned_data.get("point_3d"):              if "z" not in cleaned_data: -                raise forms.ValidationError( -                    _("A value is expected for Z.") -                ) +                raise forms.ValidationError(_("A value is expected for Z."))              value = cleaned_data["point_3d"].ewkt              if "POINT Z" not in value:                  value = value.replace("POINT", "POINT Z") @@ -3154,7 +3221,7 @@ class PreGISForm(IshtarForm):              ("multi_points", _("Multi-points")),              ("multi_line", _("Multi-lines")),              ("multi_polygon", _("Multi-polygons")), -        ) +        ),      )      HEADERS = {          "geom_type": FormHeader(_("Type")), @@ -3167,4 +3234,5 @@ class PreGISForm(IshtarForm):          super().__init__(*args, **kwargs)          if back_url:              self.fields["back_url"] = forms.CharField( -                label="", required=False, widget=forms.HiddenInput, initial=back_url) +                label="", required=False, widget=forms.HiddenInput, initial=back_url +            ) | 
