summaryrefslogtreecommitdiff
path: root/ishtar_common/models.py
diff options
context:
space:
mode:
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
commit6f59b9e36a0971b3deb44562062a878eb26beedf (patch)
treee22db164f77fc0ba6e30a539350bb5a37f36f5a6 /ishtar_common/models.py
parentbe063a7032971db7c00a160595e69e1e67dd2c9f (diff)
downloadIshtar-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.py154
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))