diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2024-10-23 18:51:15 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2025-02-19 14:43:48 +0100 |
commit | 6f59b9e36a0971b3deb44562062a878eb26beedf (patch) | |
tree | e22db164f77fc0ba6e30a539350bb5a37f36f5a6 /ishtar_common/models.py | |
parent | be063a7032971db7c00a160595e69e1e67dd2c9f (diff) | |
download | Ishtar-6f59b9e36a0971b3deb44562062a878eb26beedf.tar.bz2 Ishtar-6f59b9e36a0971b3deb44562062a878eb26beedf.zip |
✨ permissions refactoring: generate permissions, adapt permissions checks
Diffstat (limited to 'ishtar_common/models.py')
-rw-r--r-- | ishtar_common/models.py | 154 |
1 files changed, 124 insertions, 30 deletions
diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 8fcb9edbb..0c92f2f10 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -27,6 +27,7 @@ from bs4 import BeautifulSoup import bleach import copy import datetime +from guardian.models import UserObjectPermission import inspect from importlib import import_module from jinja2 import TemplateSyntaxError, UndefinedError @@ -297,7 +298,7 @@ class ValueGetter: def _get_values_update_sub_filter(self, filtr, prefix): if not filtr: return - return [k[len(prefix) :] for k in filtr if k.startswith(prefix)] + return [k[len(prefix):] for k in filtr if k.startswith(prefix)] def get_extra_values(self, prefix="", no_values=False, filtr=None, **kwargs): return {} @@ -3540,6 +3541,81 @@ class UserProfile(models.Model): new_item.external_sources.add(src) return new_item + def _generate_permission(self, ishtar_user, content_type, permission_request): + item_ids = [] + model_class = content_type.model_class() + if permission_request.include_associated_items: + item_ids += model_class.filter( + ishtar_users__pk=ishtar_user.pk + ).values_list("pk", flat=True) + if permission_request.include_upstream_items: + # TODO.... + item_ids += model_class.get_ids_from_upper_permissions(ishtar_user.user_ptr.pk) + if permission_request.request or permission_request.limit_to_attached_areas: + # TODO + pass + query = model_class.objects + return item_ids + + def generate_permission(self, content_type): + ishtar_user = self.person.ishtaruser + + # add base permissions + for group in self.profile_type.groups.all(): + for perm in group.permissions.all(): + ishtar_user.user_ptr.user_permissions.add(perm) + q_has_perm = self.profile_type.groups.filter( + permissions__content_type=content_type, + permissions__codename__contains="_own_" + ) + if not q_has_perm.count(): # no permission to generate + return + + permissions = [] + for group in q_has_perm.all(): + permissions += list(group.permissions.values_list("pk", flat=True)) + q_req = self.profile_type.permission_requests.filter( + model=content_type, active=True + ) + item_ids = [] + if not q_req.count(): + # TODO v5: delete old behaviour + """ + print(f"WARNING: no permission request for content {content_type.name} and profile {self}") + print("Using old behaviour") + """ + model_class = content_type.model_class() + query = model_class.get_owns(user=ishtar_user, query=True, no_auth_check=True) + if query: + item_ids = list( + model_class.objects.filter(query).values_list("pk", flat=True) + ) + else: + for perm_request in q_req.all(): + item_ids += self._generate_permission( + ishtar_user, content_type, perm_request + ) + user_id = ishtar_user.user_ptr.pk + object_permissions = [] + item_ids = list(set(item_ids)) + permissions = list(set(permissions)) + for permission_id in permissions: + exclude = list(UserObjectPermission.objects.filter( + content_type_id=content_type.pk, permission_id=permission_id, + user_id=user_id + ).values_list("object_pk", flat=True)) + object_permissions += [ + UserObjectPermission( + object_pk=str(item_id), + content_type_id=content_type.pk, + permission_id=permission_id, + user_id=user_id + ) + for item_id in item_ids if str(item_id) not in exclude + ] + if object_permissions: + UserObjectPermission.objects.bulk_create(object_permissions) + def save( self, force_insert=False, @@ -3692,8 +3768,8 @@ class IshtarUser(FullSearch): _("Advanced shortcut menu"), default=False ) # latest news read by the user - latest_news_version = models.CharField(_("Latest news version"), default="", blank=True, - max_length=20) + latest_news_version = models.CharField(_("Latest news version"), default="", + blank=True, max_length=20) display_news = models.BooleanField(_("Display news"), default=True) display_forum_entries = models.BooleanField(_("Display forum entries"), default=True) @@ -3787,32 +3863,43 @@ class IshtarUser(FullSearch): if obj: return self.user_ptr.has_perm(permission, obj) return self.user_ptr.has_perm(permission) - """ - res = ( - bool( - self.profiles.filter( - current=True, profile_type__txt_idx=permission - ).count() - ) - or bool( - self.profiles.filter( - current=True, - profile_type__groups__permissions__codename=permission, - ).count() - ) - or bool( - self.ishtaruser.user_ptr.groups.filter( - permissions__codename__in=[permission] - ).count() - ) - or bool( - self.ishtaruser.user_ptr.user_permissions.filter( - codename__in=[permission] - ).count() - ) - ) - return res - """ + + def generate_permission(self): + # models to treat first in this order to manage cascade permissions + model_names = [ + ("archaeological_operations", "operation"), + ("archaeological_context_records", "contextrecord"), + ("archaeological_warehouse", "warehouse"), + ("archaeological_finds", "treatment"), + ("archaeological_warehouse", "container"), + ("archaeological_finds", "find"), + ] + # cascade permission to treat at the end + last_model_names = [ + ("ishtar_common", "document"), + ("ishtar_common", "geovectordata"), + ("ishtar_common", "import"), + ] + for ct in ContentType.objects.all(): + name = (ct.app_label, ct.model) + klass = ct.model_class() + if not klass or not getattr(klass, "SHOW_URL", None) \ + or name in model_names \ + or name in last_model_names: + continue + model_names.append(name) + model_names += last_model_names + content_types = [ + ContentType.objects.get(app_label=app, model=model_name) + for app, model_name in model_names + ] + # clean all permission first + UserObjectPermission.objects.filter(user_id=self.pk).delete() + self.user_ptr.user_permissions.clear() + + for ct in content_types: + for profile in self.person.profiles.all(): + profile.generate_permission(ct) def full_label(self): return self.person.full_label() @@ -5014,7 +5101,14 @@ class Document( def get_query_owns(cls, ishtaruser): query_own_list = [] for rel_model in cls.RELATED_MODELS: - klass = getattr(cls, rel_model).remote_field.related_model + r = getattr(cls, rel_model) + if hasattr(r, "remote_field"): + r = getattr(cls, rel_model).remote_field + else: + r = getattr(cls, rel_model).rel + klass = r.related_model + if not hasattr(klass, "_get_query_owns_dicts"): + continue q_own_dct = klass._get_query_owns_dicts(ishtaruser) if q_own_dct: query_own_list.append((rel_model + "__", q_own_dct)) |