summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/admin.py3
-rw-r--r--ishtar_common/models.py154
-rw-r--r--ishtar_common/models_common.py7
-rw-r--r--ishtar_common/utils.py14
-rw-r--r--ishtar_common/views_item.py1
-rw-r--r--ishtar_common/wizards.py36
6 files changed, 168 insertions, 47 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py
index f67a99e01..743d643a3 100644
--- a/ishtar_common/admin.py
+++ b/ishtar_common/admin.py
@@ -1655,6 +1655,9 @@ class ProfileTypeAdmin(GeneralTypeAdmin):
return Http404()
permissions_needed = set()
permissions_not_needed = set()
+ for model in ("basefind", "import", "biographicalnote"):
+ for perm_type in ("add", "change", "delete", "view"):
+ permissions_not_needed.add((perm_type, model))
for group in obj.groups.all():
for perm in group.permissions.all():
sp = perm.codename.split("_")
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))
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index e92d7d55d..28f5aba00 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -1629,13 +1629,14 @@ class BaseHistorizedItem(
)
}
- class Meta:
- abstract = True
-
@classmethod
def get_verbose_name(cls):
return cls._meta.verbose_name
+ @classmethod
+ def get_ids_from_upper_permissions(cls, user_id):
+ return []
+
def is_locked(self, user=None):
if not user:
return self.locked
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index 8de745874..09c470823 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -395,7 +395,8 @@ class OwnPerms:
"""
Check if the current object is owned by the user
"""
- print("ishtar_common/utils.py - 370 - DELETE")
+ print("ishtar_common/utils.py - 377 - DELETE")
+ raise
IshtarUser = apps.get_model("ishtar_common", "IshtarUser")
if isinstance(user, IshtarUser):
ishtaruser = user
@@ -467,13 +468,18 @@ class OwnPerms:
values=None,
get_short_menu_class=False,
menu_filtr=None,
+ no_auth_check=False,
+ query=False
):
"""
Get Own items
"""
+ return_query = query
+ query = None
if not replace_query:
replace_query = {}
- if hasattr(user, "is_authenticated") and not user.is_authenticated:
+ if hasattr(user, "is_authenticated") and not user.is_authenticated \
+ and not no_auth_check:
returned = cls.objects.filter(pk__isnull=True)
if values:
returned = []
@@ -502,6 +508,10 @@ class OwnPerms:
if values:
returned = []
return returned
+ if return_query:
+ if query:
+ return query
+ return replace_query
if query:
q = cls.objects.filter(query)
else: # replace_query
diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py
index a88cb48b3..64dee8872 100644
--- a/ishtar_common/views_item.py
+++ b/ishtar_common/views_item.py
@@ -12,7 +12,6 @@ import requests
# nosec: no user input used
import subprocess # nosec
from tempfile import NamedTemporaryFile
-import unidecode
from django.conf import settings
from django.contrib.auth.models import Permission
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index e41c4c811..1da9b9f4d 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -35,7 +35,7 @@ from formtools.wizard.views import (
from django.contrib.sites.models import Site
from django.core.exceptions import ObjectDoesNotExist
from django.core.files.images import ImageFile
-from django.core.files.storage import default_storage, FileSystemStorage
+from django.core.files.storage import FileSystemStorage
from django.core.mail import send_mail
from django.db.models.fields.files import FileField, ImageFieldFile
from django.db.models.fields.related import ManyToManyField
@@ -50,7 +50,7 @@ from django.utils.safestring import mark_safe
from ishtar_common import models, models_rest
from ishtar_common.forms import CustomForm, reverse_lazy
-from ishtar_common.utils import get_all_field_names, get_person_gdpr_log, MultiValueDict, \
+from ishtar_common.utils import get_all_field_names, get_person_gdpr_log, MultiValueDict,\
put_session_message
logger = logging.getLogger(__name__)
@@ -154,6 +154,7 @@ class Wizard(IshtarWizard):
label = ""
translated_keys = []
modification = None # True when the wizard modify an item
+ deletion = True # True on deletion
storage_name = "formtools.wizard.storage.session.SessionStorage"
wizard_done_template = "ishtar/wizard/wizard_done.html"
wizard_done_window = ""
@@ -211,16 +212,9 @@ class Wizard(IshtarWizard):
self.steps = StepsHelper(self)
current_object = self.get_current_object()
- ishtaruser = (
- request.user.ishtaruser if hasattr(request.user, "ishtaruser") else None
- )
-
# not the first step and current object is not owned
if self.steps and self.steps.first != step and current_object:
- is_own = current_object.is_own(
- ishtaruser, alt_query_own=self.alt_is_own_method
- )
- if not is_own:
+ if not self.verify_permission(request, current_object):
messages.add_message(
request,
messages.WARNING,
@@ -230,6 +224,23 @@ class Wizard(IshtarWizard):
return
return True
+ def verify_permission(self, request, current_object=None):
+ meta = self.model._meta
+ perm = f"{meta.app_label}."
+ if self.modification:
+ perm += "change"
+ elif self.deletion:
+ perm += "delete"
+ else:
+ perm += "add"
+ base_perm = f"{perm}_{meta.model_name}"
+ if request.user.has_perm(base_perm):
+ return True
+ if not current_object:
+ return False
+ own_perm = f"{perm}_own_{meta.model_name}"
+ return request.user.has_perm(own_perm, current_object)
+
def dispatch(self, request, *args, **kwargs):
self.current_right = kwargs.get("current_right", None)
step = kwargs.get("step", None)
@@ -241,7 +252,6 @@ class Wizard(IshtarWizard):
self.filter_owns_items = True
else:
self.filter_owns_items = False
-
return super(Wizard, self).dispatch(request, *args, **kwargs)
def get_prefix(self, request, *args, **kwargs):
@@ -1714,6 +1724,8 @@ class DocumentSearch(SearchWizard):
class DeletionWizard(Wizard):
+ deletion = True
+
def __init__(self, *args, **kwargs):
if (not hasattr(self, "fields") or not self.fields) and (
hasattr(self, "model") and hasattr(self.model, "TABLE_COLS")
@@ -1790,6 +1802,8 @@ class MultipleItemWizard(Wizard):
class MultipleDeletionWizard(MultipleItemWizard):
+ deletion = True
+
def __init__(self, *args, **kwargs):
if (not hasattr(self, "fields") or not self.fields) and (
hasattr(self, "model") and hasattr(self.model, "TABLE_COLS")