diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-09-10 18:02:50 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-09-10 18:02:50 +0200 |
commit | 0c185f1abbe9abe0d977e1b7d1d3f0440b8d6371 (patch) | |
tree | f84171501c3d98df394c94fcc6d32cc3dd5c6539 | |
parent | 389f86b06d5f6129614cb312c7034cdc4bb1b684 (diff) | |
download | Ishtar-0c185f1abbe9abe0d977e1b7d1d3f0440b8d6371.tar.bz2 Ishtar-0c185f1abbe9abe0d977e1b7d1d3f0440b8d6371.zip |
Locks: prevent edit actions
-rw-r--r-- | archaeological_context_records/forms.py | 10 | ||||
-rw-r--r-- | archaeological_context_records/views.py | 7 | ||||
-rw-r--r-- | archaeological_files/forms.py | 9 | ||||
-rw-r--r-- | archaeological_files/views.py | 28 | ||||
-rw-r--r-- | archaeological_finds/forms.py | 17 | ||||
-rw-r--r-- | archaeological_finds/models_finds.py | 3 | ||||
-rw-r--r-- | archaeological_finds/views.py | 10 | ||||
-rw-r--r-- | archaeological_operations/forms.py | 20 | ||||
-rw-r--r-- | archaeological_operations/views.py | 26 | ||||
-rw-r--r-- | archaeological_warehouse/forms.py | 15 | ||||
-rw-r--r-- | archaeological_warehouse/models.py | 5 | ||||
-rw-r--r-- | archaeological_warehouse/views.py | 38 | ||||
-rw-r--r-- | ishtar_common/forms.py | 8 | ||||
-rw-r--r-- | ishtar_common/models.py | 2 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/blocks/window_nav.html | 2 | ||||
-rw-r--r-- | ishtar_common/urls.py | 3 | ||||
-rw-r--r-- | ishtar_common/views.py | 15 |
17 files changed, 201 insertions, 17 deletions
diff --git a/archaeological_context_records/forms.py b/archaeological_context_records/forms.py index 6bbc3099c..375943c9c 100644 --- a/archaeological_context_records/forms.py +++ b/archaeological_context_records/forms.py @@ -133,7 +133,15 @@ class RecordFormSelection(CustomFormSearch): if 'pk' not in cleaned_data or not cleaned_data['pk']: raise forms.ValidationError(_(u"You should at least select one " u"context record.")) - return cleaned_data + pk = self.cleaned_data["pk"] + try: + cr = models.ContextRecord.objects.get(pk=pk) + except models.ContextRecord.DoesNotExist: + raise forms.ValidationError(_("Invalid selection.")) + if cr.locked: + raise forms.ValidationError(_("This context record is locked for " + "edition.")) + return self.cleaned_data class RecordFormGeneral(CustomForm, ManageOldType): diff --git a/archaeological_context_records/views.py b/archaeological_context_records/views.py index fe77150f6..794cb5592 100644 --- a/archaeological_context_records/views.py +++ b/archaeological_context_records/views.py @@ -144,6 +144,13 @@ def record_modify(request, pk): ) return HttpResponseRedirect("/") + q = models.ContextRecord.objects.filter(pk=pk) + if not q.count(): + raise Http404() + cr = q.all()[0] + if cr.locked: + raise Http404() + wizards.RecordModifWizard.session_set_value( request, 'selec-record_modification', 'pk', pk, reset=True) return redirect(reverse('record_modification', diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 8f18de29e..640e2cab1 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -140,7 +140,14 @@ class FileFormSelection(forms.Form): cleaned_data = self.cleaned_data if 'pk' not in cleaned_data or not cleaned_data['pk']: raise forms.ValidationError(_(u"You should select a file.")) - return cleaned_data + pk = self.cleaned_data["pk"] + try: + file = models.File.objects.get(pk=pk) + except models.File.DoesNotExist: + raise forms.ValidationError(_("Invalid selection.")) + if file.locked: + raise forms.ValidationError(_("This file is locked for edition.")) + return self.cleaned_data DATE_SOURCE = (('creation', _(u"Creation date")), diff --git a/archaeological_files/views.py b/archaeological_files/views.py index 50f3a86d2..e7307e882 100644 --- a/archaeological_files/views.py +++ b/archaeological_files/views.py @@ -22,16 +22,12 @@ import re from django.core.urlresolvers import reverse from django.db.models import Q -from django.http import HttpResponse -from django.shortcuts import redirect, render +from django.http import HttpResponse, Http404, HttpResponseRedirect +from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ from ishtar_common.views_item import get_item, show_item, revert_item -from archaeological_operations.models import Operation -from . import models - -from ishtar_common.wizards import SearchWizard from archaeological_operations.wizards import AdministrativeActDeletionWizard, \ is_preventive, is_not_preventive from .wizards import * @@ -41,6 +37,8 @@ from archaeological_operations.forms import FinalAdministrativeActDeleteForm from ishtar_common.forms import ClosingDateFormSelection from . import forms +from ishtar_common.utils import put_session_message + RE_YEAR_INDEX = re.compile(r"([1-2][0-9]{3})-([0-9]+)") # eg.: 2014-123 @@ -145,7 +143,23 @@ file_modification_wizard = FileModificationWizard.as_view( def file_modify(request, pk): - file_modification_wizard(request) + try: + file_modification_wizard(request) + except IndexError: # no step available + put_session_message( + request.session.session_key, + _(u"You don't have sufficient permissions to do this action."), + 'warning' + ) + return HttpResponseRedirect("/") + + q = models.File.objects.filter(pk=pk) + if not q.count(): + raise Http404() + item = q.all()[0] + if item.locked: + raise Http404() + FileModificationWizard.session_set_value( request, 'selec-file_modification', 'pk', pk, reset=True) return redirect(reverse('file_modification', diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py index f4b115492..4de4bdaf9 100644 --- a/archaeological_finds/forms.py +++ b/archaeological_finds/forms.py @@ -1239,6 +1239,7 @@ class FindFormSelection(CustomFormSearch): form_label = _("Find search") associated_models = {'pk': models.Find} currents = {'pk': models.Find} + pk_key = 'pk' pk = forms.IntegerField( label="", required=False, @@ -1249,6 +1250,22 @@ class FindFormSelection(CustomFormSearch): source_full=reverse_lazy('get-find-full')), validators=[valid_id(models.Find)]) + def clean(self): + pk = self.cleaned_data[self.pk_key] + if "," in pk: + pks = [k.strip() for k in pk.split(',')] + else: + pks = [pk] + for pk in pks: + try: + find = models.Find.objects.get(pk=pk) + except models.Find.DoesNotExist: + raise forms.ValidationError(_("Invalid selection.")) + if find.locked: + raise forms.ValidationError( + _("This find is locked for edition.")) + return self.cleaned_data + class FindFormSelectionWarehouseModule(FindFormSelection): pk = forms.IntegerField( diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py index 6914ff019..9b134bceb 100644 --- a/archaeological_finds/models_finds.py +++ b/archaeological_finds/models_finds.py @@ -1742,8 +1742,9 @@ class Find(BulkUpdatedItem, ValueGetter, DocumentItem, BaseHistorizedItem, # own basket actions = super(Find, self).get_extra_actions(request) + is_locked = getattr(self, "locked", False) can_edit_find = self.can_do(request, 'change_find') - if can_edit_find: + if can_edit_find and not is_locked: actions += [ (reverse("find-qa-duplicate", args=[self.pk]), _("Duplicate"), "fa fa-clone", "", "", True), diff --git a/archaeological_finds/views.py b/archaeological_finds/views.py index 763733bd9..e5119b9f3 100644 --- a/archaeological_finds/views.py +++ b/archaeological_finds/views.py @@ -333,6 +333,8 @@ def find_modify(request, pk): raise Http404() step = 'find-find_modification' find = q.all()[0] + if find.locked: + raise Http404() if find.base_finds.count() > 1: step = 'simplefind-find_modification' @@ -973,6 +975,14 @@ class QAFindTreatmentFormView(QAItemForm): page_name = _(u"Packaging") base_url = "find-qa-packaging" + def dispatch(self, request, *args, **kwargs): + returned = super(QAFindTreatmentFormView, self).dispatch( + request, *args, **kwargs) + for item in self.items: + if item.locked: + return HttpResponseRedirect(reverse("qa-not-available")) + return returned + def get_form_kwargs(self): kwargs = super(QAFindTreatmentFormView, self).get_form_kwargs() kwargs['user'] = self.request.user diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index 5cc544171..1e12c3614 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -616,7 +616,15 @@ class OperationFormSelection(CustomFormSearch): cleaned_data = self.cleaned_data if 'pk' not in cleaned_data or not cleaned_data['pk']: raise forms.ValidationError(_(u"You should select an operation.")) - return cleaned_data + pk = self.cleaned_data["pk"] + try: + item = models.Operation.objects.get(pk=pk) + except models.Operation.DoesNotExist: + raise forms.ValidationError(_("Invalid selection.")) + if item.locked: + raise forms.ValidationError(_("This operation is locked for " + "edition.")) + return self.cleaned_data class OperationCodeInput(forms.TextInput): @@ -1388,7 +1396,15 @@ class SiteFormSelection(IshtarForm): cleaned_data = self.cleaned_data if 'pk' not in cleaned_data or not cleaned_data['pk']: raise forms.ValidationError(_(u"You should select an item.")) - return cleaned_data + pk = self.cleaned_data["pk"] + try: + item = models.ArchaeologicalSite.objects.get(pk=pk) + except models.ArchaeologicalSite.DoesNotExist: + raise forms.ValidationError(_("Invalid selection.")) + if item.locked: + raise forms.ValidationError(_("This site is locked for " + "edition.")) + return self.cleaned_data class SiteForm(CustomForm, ManageOldType): diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index 4563f815e..d8d9f30d5 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -307,6 +307,14 @@ def operation_modify(request, pk): 'warning' ) return HttpResponseRedirect("/") + + q = models.Operation.objects.filter(pk=pk) + if not q.count(): + raise Http404() + item = q.all()[0] + if item.locked: + raise Http404() + OperationModificationWizard.session_set_value( request, 'selec-operation_modification', 'pk', pk, reset=True) return redirect(reverse('operation_modification', @@ -392,7 +400,23 @@ site_modification_wizard = SiteModificationWizard.as_view( def site_modify(request, pk): - site_modification_wizard(request) + try: + site_modification_wizard(request) + except IndexError: # no step available + put_session_message( + request.session.session_key, + _(u"You don't have sufficient permissions to do this action."), + 'warning' + ) + return HttpResponseRedirect("/") + + q = models.ArchaeologicalSite.objects.filter(pk=pk) + if not q.count(): + raise Http404() + item = q.all()[0] + if item.locked: + raise Http404() + SiteModificationWizard.session_set_value( request, 'selec-site_modification', 'pk', pk, reset=True) return redirect(reverse('site_modification', diff --git a/archaeological_warehouse/forms.py b/archaeological_warehouse/forms.py index 94d37d092..ecf040a7e 100644 --- a/archaeological_warehouse/forms.py +++ b/archaeological_warehouse/forms.py @@ -121,6 +121,21 @@ class WarehouseFormSelection(forms.Form): WarehouseSelect, models.Warehouse, gallery=True, map=True), validators=[valid_id(models.Warehouse)]) + def clean(self): + cleaned_data = self.cleaned_data + if 'pk' not in cleaned_data or not cleaned_data['pk']: + raise forms.ValidationError(_(u"You should select an item.")) + pk = self.cleaned_data["pk"] + try: + item = models.Warehouse.objects.get(pk=pk) + except models.Warehouse.DoesNotExist: + raise forms.ValidationError(_("Invalid selection.")) + print(item) + if item.locked: + raise forms.ValidationError(_("This warehouse is locked for " + "edition.")) + return self.cleaned_data + class WarehouseForm(CustomForm, ManageOldType, forms.Form): HEADERS = {} diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index 336046a86..a3cbf82e3 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -56,7 +56,8 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem, APP = "archaeological-warehouse" MODEL = "warehouse" SHOW_URL = 'show-warehouse' - TABLE_COLS = ['name', 'warehouse_type'] + TABLE_COLS = ['name', 'warehouse_type__label'] + NEW_QUERY_ENGINE = True BASE_SEARCH_VECTORS = [ SearchVectorConfig("name"), SearchVectorConfig("warehouse_type__label"), @@ -66,6 +67,7 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem, ] EXTRA_REQUEST_KEYS = { + "warehouse_type__label": "warehouse_type__label", # used by dynamic_table_documents "person_in_charge__pk": "person_in_charge__pk", } @@ -414,6 +416,7 @@ class Container(DocumentItem, LightHistorizedItem, QRCodeItem, GeoItem, APP = "archaeological-warehouse" MODEL = "container" SHOW_URL = 'show-container' + NEW_QUERY_ENGINE = True TABLE_COLS = ['reference', 'container_type__label', 'cached_location', 'cached_division', 'old_reference'] IMAGE_PREFIX = 'containers/' diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py index 85b5511ae..ecbcc3175 100644 --- a/archaeological_warehouse/views.py +++ b/archaeological_warehouse/views.py @@ -21,7 +21,7 @@ import json from django.core.urlresolvers import reverse from django.db.models import Q -from django.http import HttpResponse, Http404 +from django.http import HttpResponse, Http404, HttpResponseRedirect from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ @@ -42,6 +42,8 @@ from archaeological_warehouse.wizards import PackagingWizard, WarehouseSearch, \ ContainerSearch, ContainerWizard, ContainerModificationWizard, \ ContainerDeletionWizard +from ishtar_common.utils import put_session_message + get_container = get_item(models.Container, 'get_container', 'container', search_form=ContainerSelect) show_container = show_item(models.Container, 'container') @@ -146,6 +148,23 @@ warehouse_modification_wizard = WarehouseModificationWizard.as_view([ def warehouse_modify(request, pk): + try: + warehouse_modification_wizard(request) + except IndexError: # no step available + put_session_message( + request.session.session_key, + _(u"You don't have sufficient permissions to do this action."), + 'warning' + ) + return HttpResponseRedirect("/") + + q = models.Warehouse.objects.filter(pk=pk) + if not q.count(): + raise Http404() + item = q.all()[0] + if item.locked: + raise Http404() + WarehouseModificationWizard.session_set_value( request, 'selec-warehouse_modification', 'pk', pk, reset=True) return redirect( @@ -187,6 +206,23 @@ container_modification_wizard = ContainerModificationWizard.as_view([ def container_modify(request, pk): + try: + container_modification_wizard(request) + except IndexError: # no step available + put_session_message( + request.session.session_key, + _(u"You don't have sufficient permissions to do this action."), + 'warning' + ) + return HttpResponseRedirect("/") + + q = models.Container.objects.filter(pk=pk) + if not q.count(): + raise Http404() + item = q.all()[0] + if item.locked: + raise Http404() + ContainerModificationWizard.session_set_value( request, 'selec-container_modification', 'pk', pk, reset=True) return redirect( diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 1f4d50d60..a69c65f0e 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -735,6 +735,14 @@ def get_form_selection( if self._main_key not in cleaned_data \ or not cleaned_data[self._main_key]: raise forms.ValidationError(self._not_selected_error) + + pk = self.cleaned_data[self._main_key] + try: + item = model.objects.get(pk=pk) + except model.DoesNotExist: + raise forms.ValidationError(_("Invalid selection.")) + if hasattr(item, "locked") and item.locked: + raise forms.ValidationError(_("This item is locked for edition.")) return cleaned_data attrs['clean'] = clean attrs['SEARCH_AND_SELECT'] = True diff --git a/ishtar_common/models.py b/ishtar_common/models.py index bc9e68c02..f673aed85 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1825,7 +1825,7 @@ class DocumentItem(object): return actions can_add_doc = self.can_do(request, 'add_document') - if can_add_doc: + if can_add_doc and not getattr(self, "locked", False): actions = [ ( reverse("create-document") + "?{}={}".format( diff --git a/ishtar_common/templates/ishtar/blocks/window_nav.html b/ishtar_common/templates/ishtar/blocks/window_nav.html index d76ff49e1..19b70ccd6 100644 --- a/ishtar_common/templates/ishtar/blocks/window_nav.html +++ b/ishtar_common/templates/ishtar/blocks/window_nav.html @@ -44,7 +44,7 @@ {% endif %} <div class="btn-group btn-group-sm" role="group" aria-label="{% trans 'Actions' %}"> {% block extra_actions %}{% endblock %} - {% if modify_url %} + {% if modify_url and not item.locked %} <a class="btn btn-success wait-button" href='{% url modify_url item.pk %}' title="{% trans 'Modify' %}"> <i class="fa fa-pencil"></i> diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index 3667d46b2..13694b10f 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -291,6 +291,9 @@ urlpatterns += [ check_rights(['change_document', 'change_own_document'])( views.QADocumentForm.as_view()), name='document-qa-bulk-update-confirm', kwargs={"confirm": True}), + + url(r'^qa-not-available/$', views.QANotAvailable.as_view(), + name='qa-not-available'), ] urlpatterns += get_urls_for_model(models.Document, views) diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 2af082a0a..4ab94aae9 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -2110,6 +2110,17 @@ class AlertList(JSONResponseMixin, LoginRequiredMixin, return {'alerts': alerts} +class QANotAvailable(IshtarMixin, LoginRequiredMixin, TemplateView): + template_name = 'ishtar/forms/qa_message.html' + modal_size = "small" + + def get_context_data(self, **kwargs): + data = super(QANotAvailable, self).get_context_data(**kwargs) + data["page_name"] = _("Not available") + data['message'] = _("Action not available for these items.") + return data + + class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView): template_name = 'ishtar/forms/qa_form.html' model = None @@ -2168,6 +2179,10 @@ class QAItemEditForm(QAItemForm): self.confirm = kwargs.get('confirm', False) and True returned = super(QAItemEditForm, self).dispatch(request, *args, **kwargs) + if hasattr(self.model, "locked"): + for item in self.items: + if item.locked: + return HttpResponseRedirect(reverse("qa-not-available")) return returned def get_form_class(self): |