summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2024-10-29 17:50:49 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2025-02-19 14:43:49 +0100
commit547a20789faf6bbc9979357c7f65cbe61e56ed07 (patch)
tree5ede13492f49434468607950769266d643333d11
parentfcc0bb255730d43ec2cff78fb8b948d6322a8b68 (diff)
downloadIshtar-547a20789faf6bbc9979357c7f65cbe61e56ed07.tar.bz2
Ishtar-547a20789faf6bbc9979357c7f65cbe61e56ed07.zip
✨ permissions refactoring: link items to user QA forms
-rw-r--r--archaeological_context_records/models.py10
-rw-r--r--archaeological_context_records/urls.py7
-rw-r--r--archaeological_files/models.py35
-rw-r--r--archaeological_files/urls.py9
-rw-r--r--archaeological_finds/models_finds.py8
-rw-r--r--archaeological_finds/urls.py7
-rw-r--r--archaeological_operations/models.py20
-rw-r--r--archaeological_operations/tests.py24
-rw-r--r--archaeological_operations/urls.py13
-rw-r--r--archaeological_warehouse/models.py19
-rw-r--r--archaeological_warehouse/urls.py13
-rw-r--r--ishtar_common/forms_common.py30
-rw-r--r--ishtar_common/views.py22
13 files changed, 198 insertions, 19 deletions
diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py
index 1bb09717d..21cc507c1 100644
--- a/archaeological_context_records/models.py
+++ b/archaeological_context_records/models.py
@@ -795,6 +795,13 @@ class ContextRecord(
"archaeological_context_records.change_own_contextrecord"
],
)
+ QA_LINK = QuickAction(
+ url="contextrecord-qa-link",
+ icon_class="fa fa-link",
+ text=_("Link to account"),
+ target="many",
+ rights=["ishtaradmin"],
+ )
QA_EDIT = QuickAction(
url="contextrecord-qa-bulk-update",
icon_class="fa fa-pencil",
@@ -807,7 +814,6 @@ class ContextRecord(
)
QUICK_ACTIONS = [
QA_EDIT,
- QA_LOCK,
QuickAction(
url="contextrecord-qa-duplicate",
icon_class="fa fa-clone",
@@ -818,6 +824,8 @@ class ContextRecord(
"archaeological_context_records.change_own_contextrecord"
],
),
+ QA_LOCK,
+ QA_LINK,
]
SERIALIZE_EXCLUDE = MainItem.SERIALIZE_EXCLUDE + ["contextrecord"]
SERIALIZE_PROPERTIES = MainItem.SERIALIZE_PROPERTIES + [
diff --git a/archaeological_context_records/urls.py b/archaeological_context_records/urls.py
index 338f5bb2a..c4d6e05bc 100644
--- a/archaeological_context_records/urls.py
+++ b/archaeological_context_records/urls.py
@@ -21,6 +21,7 @@ from django.conf.urls import url
from django.urls import path
from ishtar_common.utils import check_permissions
+from ishtar_common.views import QALinkView
from archaeological_context_records import models, views, views_api
# be careful: each check_permissions must be relevant with ishtar_menu
@@ -177,6 +178,12 @@ urlpatterns = [
kwargs={"model": models.ContextRecord},
),
url(
+ r"^contextrecord-qa-link/(?P<pks>[0-9-]+)?/$",
+ QALinkView.as_view(),
+ name="contextrecord-qa-link",
+ kwargs={"model": models.ContextRecord, "url": "contextrecord-qa-link"},
+ ),
+ url(
r"^contextrecord-qa-duplicate/(?P<pks>[0-9-]+)?/$",
check_permissions(["archaeological_context_records.change_contextrecord",
"archaeological_context_records.change_own_contextrecord"])(
diff --git a/archaeological_files/models.py b/archaeological_files/models.py
index b3815c95d..04481889f 100644
--- a/archaeological_files/models.py
+++ b/archaeological_files/models.py
@@ -45,26 +45,27 @@ from ishtar_common.utils import (
)
from ishtar_common.models import (
+ BaseHistorizedItem,
+ CompleteIdentifierItem,
+ DashboardFormItem,
Department,
+ Document,
+ DocumentItem,
GeneralType,
GlobalVar,
- BaseHistorizedItem,
- Imported,
- OwnPerms,
- Person,
- Organization,
- Town,
- DashboardFormItem,
HistoricalRecords,
- ValueGetter,
+ HistoryModel,
+ Imported,
MainItem,
OperationType,
+ Organization,
+ OwnPerms,
+ Person,
post_save_cache,
- Document,
- HistoryModel,
+ QuickAction,
SearchVectorConfig,
- DocumentItem,
- CompleteIdentifierItem,
+ Town,
+ ValueGetter,
)
from archaeological_operations.models import (
@@ -619,6 +620,16 @@ class File(
HISTORICAL_M2M = ["towns", "departments"]
SERIALIZE_PROPERTIES = ["external_id"]
+ QA_LINK = QuickAction(
+ url="file-qa-link",
+ icon_class="fa fa-link",
+ text=_("Link to account"),
+ target="many",
+ rights=["ishtaradmin"],
+ )
+ QUICK_ACTIONS = [
+ QA_LINK
+ ]
# fields
year = models.IntegerField(_("Year"), default=get_current_year)
diff --git a/archaeological_files/urls.py b/archaeological_files/urls.py
index 4b50047a6..4c278e0be 100644
--- a/archaeological_files/urls.py
+++ b/archaeological_files/urls.py
@@ -21,7 +21,8 @@ from django.conf.urls import url
from django.urls import path
from ishtar_common.utils import check_permissions
-from archaeological_files import views, views_api
+from ishtar_common.views import QALinkView
+from archaeological_files import views, views_api, models
from archaeological_operations.views import administrativeactfile_document
# be carreful: each check_permissions must be relevant with ishtar_menu
@@ -29,6 +30,12 @@ from archaeological_operations.views import administrativeactfile_document
# forms:
urlpatterns = [
url(
+ r"^file-qa-link/(?P<pks>[0-9-]+)?/$",
+ QALinkView.as_view(),
+ name="file-qa-link",
+ kwargs={"model": models.File, "url": "file-qa-link"},
+ ),
+ url(
r"file_administrativeactfile_search/(?P<step>.+)?$",
check_permissions(["archaeological_operations.change_administrativeact"])(
views.file_administrativeactfile_search_wizard
diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py
index ece7d08b8..e224dc48c 100644
--- a/archaeological_finds/models_finds.py
+++ b/archaeological_finds/models_finds.py
@@ -1867,6 +1867,13 @@ class Find(
rights=["archaeological_finds.change_find",
"archaeological_finds.change_own_find"],
)
+ QA_LINK = QuickAction(
+ url="find-qa-link",
+ icon_class="fa fa-link",
+ text=_("Link to account"),
+ target="many",
+ rights=["ishtaradmin"],
+ )
QA_LOCK = QuickAction(
url="find-qa-lock",
icon_class="fa fa-lock",
@@ -1921,6 +1928,7 @@ class Find(
is_popup=False,
),
QA_LOCK,
+ QA_LINK
]
UP_MODEL_QUERY = {
"operation": (
diff --git a/archaeological_finds/urls.py b/archaeological_finds/urls.py
index ba10750d2..c7d8356ce 100644
--- a/archaeological_finds/urls.py
+++ b/archaeological_finds/urls.py
@@ -22,6 +22,7 @@ from django.urls import path
from ishtar_common.utils import check_permissions, get_urls_for_model
+from ishtar_common.views import QALinkView
from archaeological_finds import views
from archaeological_finds import views_api
from archaeological_operations.views import administrativeactfile_document
@@ -275,6 +276,12 @@ urlpatterns = [
kwargs={"model": models.Find},
),
url(
+ r"^find-qa-link/(?P<pks>[0-9-]+)?/$",
+ QALinkView.as_view(),
+ name="find-qa-link",
+ kwargs={"model": models.Find, "url": "find-qa-link"},
+ ),
+ url(
r"^treatment_creation/(?P<step>.+)?$",
check_permissions(
["archaeological_finds.change_find",
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py
index 9e43f264b..debc26d8b 100644
--- a/archaeological_operations/models.py
+++ b/archaeological_operations/models.py
@@ -584,6 +584,13 @@ class ArchaeologicalSite(
"archaeological_operations.change_own_archaeologicalsite"
],
)
+ QA_LINK = QuickAction(
+ url="site-qa-link",
+ icon_class="fa fa-link",
+ text=_("Link to account"),
+ target="many",
+ rights=["ishtaradmin"],
+ )
QA_EDIT = QuickAction(
url="site-qa-bulk-update",
icon_class="fa fa-pencil",
@@ -596,7 +603,6 @@ class ArchaeologicalSite(
)
QUICK_ACTIONS = [
QA_EDIT,
- QA_LOCK,
QuickAction(
url="site-add-operation",
icon_class="fa fa-plus",
@@ -615,6 +621,8 @@ class ArchaeologicalSite(
"archaeological_operations.change_own_archaeologicalsite"
],
),
+ QA_LOCK,
+ QA_LINK
]
objects = SiteManager()
@@ -1478,9 +1486,15 @@ class Operation(
"archaeological_operations.change_own_operation"
],
)
+ QA_LINK = QuickAction(
+ url="operation-qa-link",
+ icon_class="fa fa-link",
+ text=_("Link to account"),
+ target="many",
+ rights=["ishtaradmin"],
+ )
QUICK_ACTIONS = [
QA_EDIT,
- QA_LOCK,
QuickAction(
url="operation-qa-duplicate",
icon_class="fa fa-clone",
@@ -1491,6 +1505,8 @@ class Operation(
"archaeological_operations.change_own_operation"
],
),
+ QA_LOCK,
+ QA_LINK,
]
UP_MODEL_QUERY = {
diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py
index 18d927d06..41d4a8611 100644
--- a/archaeological_operations/tests.py
+++ b/archaeological_operations/tests.py
@@ -4784,6 +4784,30 @@ class OperationQATest(OperationInitTest, TestCase):
Permission.objects.get(codename="change_operation")
)
+ def test_link(self):
+ c = Client()
+ op0, op1 = self.operations[0], self.operations[1]
+ pks = "{}-{}".format(op0.pk, op1.pk)
+ url = reverse("operation-qa-link", args=[pks])
+
+ response = c.get(url)
+ self.assertEqual(response.status_code, 404)
+
+ c.login(username=self.username, password=self.password)
+ response = c.get(reverse("operation-qa-link", args=[pks]))
+
+ self.assertEqual(response.status_code, 200)
+ q_link = models.Operation.objects.filter(ishtar_users__pk__isnull=False)
+ self.assertEqual(q_link.count(), 0)
+
+ response = c.post(url, {"action": "link", "account": self.user.pk})
+ self.assertRedirects(response, "/success/")
+ self.assertEqual(q_link.count(), 2)
+
+ response = c.post(url, {"action": "unlink", "account": self.user.pk})
+ self.assertRedirects(response, "/success/")
+ self.assertEqual(q_link.count(), 0)
+
def test_lock(self):
c = Client()
op0, op1 = self.operations[0], self.operations[1]
diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py
index ba96c64b2..29b68a349 100644
--- a/archaeological_operations/urls.py
+++ b/archaeological_operations/urls.py
@@ -21,6 +21,7 @@ from django.conf.urls import url
from django.urls import path, register_converter
from ishtar_common import urls_converters
+from ishtar_common.views import QALinkView
from ishtar_common.utils import check_permissions
from archaeological_operations import views
from archaeological_operations import views_api
@@ -394,6 +395,12 @@ urlpatterns = [
kwargs={"model": models.Operation},
),
url(
+ r"^operation-qa-link/(?P<pks>[0-9-]+)?/$",
+ QALinkView.as_view(),
+ name="operation-qa-link",
+ kwargs={"model": models.Operation, "url": "operation-qa-link"},
+ ),
+ url(
r"^site-qa-duplicate/(?P<pks>[0-9-]+)?/$",
check_permissions(
["archaeological_operations.change_archaeologicalsite",
@@ -408,6 +415,12 @@ urlpatterns = [
kwargs={"model": models.ArchaeologicalSite},
),
url(
+ r"^site-qa-link/(?P<pks>[0-9-]+)?/$",
+ QALinkView.as_view(),
+ name="site-qa-link",
+ kwargs={"model": models.ArchaeologicalSite, "url": "site-qa-link"},
+ ),
+ url(
r"^site-qa-bulk-update/(?P<pks>[0-9-]+)?/$",
check_permissions(
["archaeological_operations.change_archaeologicalsite",
diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py
index 5a854c079..099d6a641 100644
--- a/archaeological_warehouse/models.py
+++ b/archaeological_warehouse/models.py
@@ -394,9 +394,17 @@ class Warehouse(
"archaeological_warehouse.change_own_warehouse"
],
)
+ QA_LINK = QuickAction(
+ url="warehouse-qa-link",
+ icon_class="fa fa-link",
+ text=_("Link to account"),
+ target="many",
+ rights=["ishtaradmin"],
+ )
QUICK_ACTIONS = [
- QA_LOCK,
QA_EDIT,
+ QA_LOCK,
+ QA_LINK
]
objects = UUIDModelManager()
@@ -1137,7 +1145,14 @@ class Container(
"archaeological_warehouse.change_own_container"
],
)
- QUICK_ACTIONS = [QA_EDIT, QA_MOVE, QA_LOCK]
+ QA_LINK = QuickAction(
+ url="container-qa-link",
+ icon_class="fa fa-link",
+ text=_("Link to account"),
+ target="many",
+ rights=["ishtaradmin"],
+ )
+ QUICK_ACTIONS = [QA_EDIT, QA_MOVE, QA_LOCK, QA_LINK]
BASE_QUERY_LOCATION = "container_tree_child__container_parent"
SERIALIZE_CALL = {
diff --git a/archaeological_warehouse/urls.py b/archaeological_warehouse/urls.py
index 669732a57..78bc5945c 100644
--- a/archaeological_warehouse/urls.py
+++ b/archaeological_warehouse/urls.py
@@ -21,6 +21,7 @@ from django.conf.urls import url
from django.urls import path
from ishtar_common.utils import check_permissions
+from ishtar_common.views import QALinkView
from archaeological_warehouse import models, views, views_api
@@ -150,6 +151,12 @@ urlpatterns = [
kwargs={"model": models.Warehouse},
),
url(
+ r"^warehouse-qa-link/(?P<pks>[0-9-]+)?/$",
+ QALinkView.as_view(),
+ name="warehouse-qa-link",
+ kwargs={"model": models.Warehouse, "url": "warehouse-qa-link"},
+ ),
+ url(
r"^warehouse-qa-bulk-update/(?P<pks>[0-9-]+)?/$",
check_permissions([
"archaeological_warehouse.change_warehouse",
@@ -248,6 +255,12 @@ urlpatterns = [
kwargs={"model": models.Container},
),
url(
+ r"^container-qa-link/(?P<pks>[0-9-]+)?/$",
+ QALinkView.as_view(),
+ name="container-qa-link",
+ kwargs={"model": models.Container, "url": "container-qa-link"},
+ ),
+ url(
r"container-merge/(?:(?P<page>\d+)/)?$",
views.container_merge,
name="container_merge",
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 734707419..e7e6a334d 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -2833,6 +2833,36 @@ class QALockForm(forms.Form):
item.save()
+class QALinkForm(forms.Form):
+ action = forms.ChoiceField(
+ label=_("Action"),
+ choices=(("link", _("Link items")), ("unlink", _("Unlink items")))
+ )
+ account = forms.IntegerField(
+ widget=widgets.JQueryAutoComplete(
+ reverse_lazy(
+ 'autocomplete-user',
+ ),
+ associated_model=User),
+ label=_("User"))
+
+ def __init__(self, *args, **kwargs):
+ self.items = kwargs.pop("items")
+ super().__init__(*args, **kwargs)
+
+ def save(self, items, user):
+ try:
+ ishtar_user = models.IshtarUser.objects.get(pk=self.cleaned_data["account"])
+ except models.IshtarUser.DoesNotExist:
+ return
+ if self.cleaned_data["action"] == "link":
+ for item in items:
+ item.ishtar_users.add(ishtar_user)
+ else:
+ for item in items:
+ item.ishtar_users.remove(ishtar_user)
+
+
class SourceDeletionForm(FinalForm):
confirm_msg = " "
confirm_end_msg = _("Would you like to delete this documentation?")
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index f01e848a0..03b029fe2 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -3121,7 +3121,10 @@ class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
def pre_dispatch(self, request, *args, **kwargs):
if not self.model:
- raise NotImplementedError("No attribute model defined.")
+ if "model" in kwargs:
+ self.model = kwargs["model"]
+ else:
+ raise NotImplementedError("No attribute model defined.")
pks = [int(pk) for pk in kwargs.get("pks").split("-")]
self.items = list(self.model.objects.filter(pk__in=pks))
if not self.items:
@@ -3252,6 +3255,23 @@ class QABaseLockView(QAItemForm):
return HttpResponseRedirect(reverse("success"))
+class QALinkView(QAItemForm):
+ form_class = forms.QALinkForm
+ page_name = _("Link items")
+ icon = "fa fa-link"
+
+ def pre_dispatch(self, request, *args, **kwargs):
+ self.base_url = kwargs["url"]
+ super().pre_dispatch(request, *args, **kwargs)
+ if not request.user.ishtaruser.is_ishtaradmin:
+ url = reverse("qa-not-available")
+ return HttpResponseRedirect(url)
+
+ def form_valid(self, form):
+ form.save(self.items, self.request.user)
+ return HttpResponseRedirect(reverse("success"))
+
+
class QAOrganizationForm(QAItemEditForm):
model = models.Organization
form_class = forms.QAOrganizationFormMulti