diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2024-11-06 12:50:59 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2025-02-19 14:43:49 +0100 |
commit | 6a26d7e015b00039f2c6754d828d79915fdc1c23 (patch) | |
tree | 74ca481e52d5f14e6270c1d26e33bbd775cd6a02 | |
parent | dd7a0780afceb515959896c5826515bc5ce0efd8 (diff) | |
download | Ishtar-6a26d7e015b00039f2c6754d828d79915fdc1c23.tar.bz2 Ishtar-6a26d7e015b00039f2c6754d828d79915fdc1c23.zip |
✨ permissions refactoring: forms - permission filter (mainly used by search tables)
-rw-r--r-- | ishtar_common/forms.py | 72 | ||||
-rw-r--r-- | ishtar_common/forms_common.py | 27 | ||||
-rw-r--r-- | ishtar_common/templates/blocks/DataTables.html | 9 | ||||
-rw-r--r-- | ishtar_common/views_item.py | 13 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 2 | ||||
-rw-r--r-- | ishtar_common/wizards.py | 8 |
6 files changed, 97 insertions, 34 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index e5ffeefb5..ca9f37623 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -109,7 +109,24 @@ class FloatField(forms.FloatField): return super(FloatField, self).clean(value) -class FinalForm(forms.Form): +class FormPermissionForm: + """ + Modification, deletion kwargs (for permissions) + """ + + def __init__(self, *args, **kwargs): + if "modification" in kwargs: + self.form_permission = "modification" + kwargs.pop("modification") + elif "deletion" in kwargs: + self.form_permission = "deletion" + kwargs.pop("deletion") + else: + self.form_permission = "view" + super().__init__(*args, **kwargs) + + +class FinalForm(FormPermissionForm, forms.Form): final = True form_label = _("Confirm") @@ -142,7 +159,11 @@ JSON_VALUE_TYPES_FIELDS = { } -class BSForm: +class BSForm(FormPermissionForm): + """ + Bootstrap decoration + """ + def _post_init(self): for k in self.fields: widget = self.fields[k].widget @@ -179,6 +200,11 @@ class BSForm: class CustomForm(BSForm): + """ + Manage: + - form custom fields. + - user kwargs + """ form_admin_name = "" form_slug = "" need_user_for_initialization = True @@ -422,17 +448,23 @@ class CustomForm(BSForm): return sorted(customs, key=lambda x: x[1]) -class CustomFormSearch(forms.Form): +class CustomFormSearch(FormPermissionForm, forms.Form): + """ + Manage: + - user kwargs + - modification, deletion kwargs (for permissions) + """ need_user_for_initialization = True def __init__(self, *args, **kwargs): user = None if "user" in kwargs: user = kwargs.pop("user") - super(CustomFormSearch, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.request_user = user if user and "pk" in self.fields: self.fields["pk"].widget.user = user + self.fields["pk"].widget.form_permission = self.form_permission class LockForm(object): @@ -674,7 +706,7 @@ class FormHeader(object): ) -class IshtarForm(forms.Form, BSForm): +class IshtarForm(BSForm, forms.Form): TYPES = [] # FieldType list CONDITIONAL_FIELDS = [] # dynamic conditions on field display # can be dynamic with "get_conditional_fields" @@ -694,20 +726,11 @@ class IshtarForm(forms.Form, BSForm): profile = models.get_current_profile() if self.PROFILE_FILTER: - for profile_key in self.PROFILE_FILTER: - if not getattr(profile, profile_key): - for field_key in self.PROFILE_FILTER[profile_key]: - if field_key in self.fields.keys(): - self.fields.pop(field_key) + self._profile_filter(profile) if getattr(self, "confirm", False): return if self.SITE_KEYS: - field_keys = list(self.fields.keys()) - for site_key in list(self.SITE_KEYS.keys()): - if site_key in field_keys: - self.fields[site_key].label = profile.get_site_label( - self.SITE_KEYS[site_key] - ) + self._site_keys(profile) user = getattr(self, "user", None) ishtar_user = None if user: @@ -730,6 +753,21 @@ class IshtarForm(forms.Form, BSForm): self._init_types() self._post_init() + def _profile_filter(self, profile): + for profile_key in self.PROFILE_FILTER: + if not getattr(profile, profile_key): + for field_key in self.PROFILE_FILTER[profile_key]: + if field_key in self.fields.keys(): + self.fields.pop(field_key) + + def _site_keys(self, profile): + field_keys = list(self.fields.keys()) + for site_key in list(self.SITE_KEYS.keys()): + if site_key in field_keys: + self.fields[site_key].label = profile.get_site_label( + self.SITE_KEYS[site_key] + ) + def _init_types(self): type_lst = self._types or self.TYPES for field in type_lst: @@ -1123,7 +1161,7 @@ def get_form_selection( attrs["SEARCH_AND_SELECT"] = True if not base_form_select: - base_form_select = forms.Form + base_form_select = (FormPermissionForm, forms.Form) if not isinstance(base_form_select, (tuple, list)): base_form_select = (base_form_select,) return type(class_name, base_form_select, attrs) diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index e7e6a334d..cb7eb761a 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -56,23 +56,24 @@ from .models_imports import FORMATER_WIDGETS_DCT from . import widgets from ishtar_common.templatetags.link_to_window import simple_link_to_window from .forms import ( - FinalForm, - FormSet, - reverse_lazy, - name_validator, - TableSelect, - ManageOldType, CustomForm, + CustomFormSearch, FieldType, + file_size_validator, + FinalForm, FormHeader, + FormPermissionForm, FormSetWithDeleteSwitches, - file_size_validator, + FormSet, HistorySelect, - CustomFormSearch, - QAForm, - IshtarForm, - MultiSearchForm, LockForm, + ManageOldType, + MultiSearchForm, + name_validator, + IshtarForm, + QAForm, + reverse_lazy, + TableSelect, ) from ishtar_common.data_importer import ImporterError from ishtar_common.utils import ( @@ -84,7 +85,7 @@ from ishtar_common.utils import ( reverse_coordinates, ) -from archaeological_operations.models import Operation, OperationType +from archaeological_operations.models import Operation from archaeological_context_records.models import ContextRecord from archaeological_finds.models import Find, FindBasket from archaeological_warehouse.models import Container @@ -1621,7 +1622,7 @@ ProfileFormset.form_slug = "profiles" ProfileFormset.NO_CUSTOM_FORM = True -class FinalAccountForm(forms.Form): +class FinalAccountForm(FormPermissionForm, forms.Form): final = True form_label = _("Confirm") send_password = forms.BooleanField( diff --git a/ishtar_common/templates/blocks/DataTables.html b/ishtar_common/templates/blocks/DataTables.html index e0836bcd8..6e2b01d7a 100644 --- a/ishtar_common/templates/blocks/DataTables.html +++ b/ishtar_common/templates/blocks/DataTables.html @@ -142,6 +142,9 @@ stats_submit_search = function(){ datatable_submit_search = function(not_submited){ var data = search_get_query_data(query_vars, "{{name}}"); + {% if form_permission %} + if (data) data += "&"; + data += "form_permission={{form_permission}}";{% endif %} var mygrid = jQuery("#grid_{{name}}"); var url = ""; if (!not_submited){ @@ -174,7 +177,11 @@ datatable_submit_search = function(not_submited){ update_submit_args = function(source_cls){ if (!source_cls) source_cls = "sources-default"; let data = search_get_query_data(query_vars, "{{name}}"); - let extra = "?submited=1&" + data; + let extra = "?submited=1"; + {% if form_permission %} + if (data) data += "&"; + data += "form_permission={{form_permission}}";{% endif %} + extra += "&" + data; let csv_url = "{{source}}csv" + extra; $("." + source_cls + " .{{sname}}-csv").attr("href", csv_url); let csv_full_url = "{{source_full}}csv?submited=1&" + data; diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py index 7b10974db..0619f8f8a 100644 --- a/ishtar_common/views_item.py +++ b/ishtar_common/views_item.py @@ -2496,12 +2496,19 @@ def get_item( query_own = model.get_query_owns(q.all()[0]) print(query_own) # TODO - get old request to transform them """ - if own_key: + if not own_key: + form_permission = dct_request_items.get("form_permission", "view") + if form_permission == "modification": + own_key = "change_own" + elif form_permission == "deletion": + own_key = "delete_own" + else: + own_key = "view_own" + if own_key in dct_request_items: user_pk = dct_request_items[own_key] - codename = f"{own_key}_{model._meta.model_name}" else: user_pk = request.user.pk if request else ishtaruser.pk - codename = f"view_own_{model._meta.model_name}" + codename = f"{own_key}_{model._meta.model_name}" q = UserObjectPermission.objects.filter( user_id=user_pk, permission__codename=codename, diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index cb112b22b..e131521e0 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -1202,6 +1202,7 @@ class DataTable(Select2Media, forms.RadioSelect): self.gallery = gallery self.map = map self.external_sources = None + self.form_permission = "view" if self.col_prefix and not self.col_prefix.endswith("__"): self.col_prefix += "__" @@ -1314,6 +1315,7 @@ class DataTable(Select2Media, forms.RadioSelect): "col_names": col_names, "extra_cols": extra_cols, "source": source, + "form_permission": self.form_permission, "col_idx": col_idx, "no_result": str(_("No results")), "loading": str(_("Loading...")), diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index 697c51156..e6cda14cf 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -1420,6 +1420,14 @@ class Wizard(IshtarWizard): self._current_object = current_obj return current_obj + def get_form_kwargs(self, step=None): + kwargs = super().get_form_kwargs(step) + if self.modification: + kwargs["modification"] = True + elif self.deletion: + kwargs["deletion"] = True + return kwargs + def get_form_initial(self, step, data=None): current_obj = self.get_current_object() current_step = self.steps.current |