diff options
Diffstat (limited to 'archaeological_operations')
-rw-r--r-- | archaeological_operations/forms.py | 68 | ||||
-rw-r--r-- | archaeological_operations/models.py | 12 | ||||
-rw-r--r-- | archaeological_operations/urls.py | 7 | ||||
-rw-r--r-- | archaeological_operations/views.py | 128 |
4 files changed, 162 insertions, 53 deletions
diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index d3c797ff2..9cc73e63b 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -20,6 +20,7 @@ """ Operations forms definitions """ +from copy import copy import datetime from collections import OrderedDict from itertools import groupby @@ -371,12 +372,13 @@ class ParcelFormSet(FormSet): class RecordRelationsForm(ManageOldType): base_model = 'right_relation' - ERROR_MISSING = _("You should select an operation.") current_model = models.RelationType current_related_model = models.Operation - associated_models = {'right_record': models.Operation, 'relation_type': models.RelationType} + ERROR_MISSING = _("You should select an operation.") + ERROR_SAME = _("An operation cannot be related to herself.") + pk = forms.IntegerField(required=False, widget=forms.HiddenInput) relation_type = forms.ChoiceField(label=_("Relation type"), choices=[], required=False) @@ -391,23 +393,20 @@ class RecordRelationsForm(ManageOldType): self.left_record = None if 'left_record' in kwargs: self.left_record = kwargs.pop('left_record') + if "data" in kwargs: + kwargs["data"] = copy(kwargs["data"]) + # clean data if not "real" data + prefix_value = kwargs['prefix'] + '-relation_type' + if not [k for k in kwargs['data'].keys() + if k.startswith(prefix_value) and kwargs['data'][k]]: + kwargs.pop('data') + if 'files' in kwargs: + kwargs.pop('files') super().__init__(*args, **kwargs) self.fields['relation_type'].choices = \ self.current_model.get_types( initial=self.init_data.get('relation_type')) - @classmethod - def _format_lst(cls, current): - nc = [] - for rel, ope in sorted(current): - if not nc or nc[-1][0] != rel: - nc.append([rel, []]) - nc[-1][1].append(ope) - rendered = ";".join( - ["{}{} {}".format(rel, _(":"), " ; ".join(opes)) - for rel, opes in nc]) - return rendered - def clean(self): cleaned_data = self.cleaned_data if (cleaned_data.get('relation_type', None) and @@ -420,42 +419,9 @@ class RecordRelationsForm(ManageOldType): if self.left_record and \ str(cleaned_data.get('right_record', None)) == str( self.left_record.pk): - raise forms.ValidationError( - _("An operation cannot be related to herself.")) + raise forms.ValidationError(self.ERROR_SAME) return cleaned_data - @classmethod - def get_formated_datas(cls, cleaned_datas): - result, current, deleted = [], [], [] - for data in cleaned_datas: - if not data: - continue - try: - relation_type = cls.current_model.objects.get( - pk=data.get('relation_type')) - except cls.current_model.DoesNotExist: - continue - try: - right_record = cls.current_related_model.objects.get( - pk=data.get('right_record')) - except cls.current_related_model.DoesNotExist: - continue - values = [str(relation_type), right_record.reference] - if data.get('DELETE'): - deleted.append(values) - else: - current.append(values) - if current: - nc = [] - for rel, ope in sorted(current): - if not nc or nc[-1][0] != rel: - nc.append([rel, []]) - nc[-1][1].append(ope) - result.append((_("Current relations"), cls._format_lst(current))) - if deleted: - result.append((_("Deleted relations"), " ; ".join(deleted))) - return result - class RecordRelationsFormSetBase(FormSet): delete_widget = forms.CheckboxInput @@ -478,9 +444,9 @@ class RecordRelationsFormSetBase(FormSet): RecordRelationsFormSet = formset_factory( RecordRelationsForm, can_delete=True, formset=RecordRelationsFormSetBase) -RecordRelationsFormSet.form_label = _("Relations") -RecordRelationsFormSet.form_admin_name = _("Operation - 080 - Relations") -RecordRelationsFormSet.form_slug = "operation-080-relations" +RecordRelationsFormSet.form_label = _("Operations - Relations") +RecordRelationsFormSet.form_admin_name = _("Operation - Relations") +RecordRelationsFormSet.form_slug = "operation-relations" class OperationSelect(GeoItemSelect): diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 4220e6cc2..d17e529a7 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -2017,6 +2017,18 @@ class Operation( False, ), ] + if can_edit_operation and not is_locked: + actions += [ + ( + reverse("operation-relation-modify", args=[self.pk]), + _("Modify relations"), + "fa fa-retweet", + _("relations"), + "", + True, + ), + ] + if can_edit_operation: actions += [ ( diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py index 05c03bc51..b87d6c5fd 100644 --- a/archaeological_operations/urls.py +++ b/archaeological_operations/urls.py @@ -305,6 +305,13 @@ urlpatterns = [ name="operation-parcels-modify", ), url( + r"^operation-relations-modify/(?P<pk>.+)/$", + check_rights(["change_operation", "change_own_operation"])( + views.operation_modify_relations + ), + name="operation-relation-modify", + ), + url( r"^operation-qa-bulk-update/(?P<pks>[0-9-]+)?/$", check_rights(["change_operation", "change_own_operation"])( views.QAOperationForm.as_view() diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index 028f311e6..93fb1864b 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -21,6 +21,7 @@ import json from jinja2 import TemplateSyntaxError from django.conf import settings +from django.core.exceptions import PermissionDenied from django.db.models import Q from django.forms.utils import ErrorDict, ErrorList from django.http import HttpResponse, HttpResponseRedirect, Http404 @@ -204,7 +205,6 @@ wizard_steps = [ ("judiciary-operation_creation", forms.CourtOrderedSeizureForm), ("preventive-operation_creation", forms.OperationFormPreventive), ("preventivediag-operation_creation", forms.OperationFormPreventiveDiag), - ("relations-operation_creation", forms.RecordRelationsFormSet), ("final-operation_creation", FinalForm), ] @@ -269,7 +269,6 @@ operation_modif_wizard_steps = [ ("judiciary-operation_modification", forms.CourtOrderedSeizureForm), ("preventive-operation_modification", forms.OperationFormPreventive), ("preventivediag-operation_modification", forms.OperationFormPreventiveDiag), - ("relations-operation_modification", forms.RecordRelationsFormSet), ("final-operation_modification", FinalForm), ] @@ -500,6 +499,131 @@ operation_modify_parcels = get_parcel_modify( ) +RELATION_FORMSET_EXTRA_FORM = 3 + + +def get_relation_modify(model, model_relation, url_name, formset_class, filter_operations=False): + def _modify_relation(request, pk, current_right=None): + try: + item = model.objects.get(pk=pk) + except model.DoesNotExist: + raise Http404() + if "_own_" in current_right: + if not item.is_own(request.user): + raise PermissionDenied() + relations = model_relation.objects.filter(left_record_id=pk).all() + + items, current_items = [], [] + if filter_operations: + items = [ + (item.id, str(item)) + for item in model.objects.filter(operation=item.operation).all() + ] + current_items = [item[0] for item in items] + + initial = [] + for relation in relations: + initial.append({ + "pk": relation.pk, + "right_record": relation.right_record_id, + "relation_type": relation.relation_type_id, + }) + if filter_operations and relation.right_record_id not in current_items: + items.append((relation.right_record_id, str(relation.right_record))) + data = { + 'form-TOTAL_FORMS': len(initial) + RELATION_FORMSET_EXTRA_FORM, + 'form-INITIAL_FORMS': 0, + 'form-MIN_NUM_FORMS': 0, + 'form-MAX_NUM_FORMS': 100, + } + if filter_operations: + data["CURRENT_ITEMS"] = items + if request.method == 'POST': + new_data = dict(request.POST) + new_data = {k: new_data[k][0] for k in new_data} # convert POST to classic dict + + # remove empty lines and get deleted + no_values = list(range(data["form-TOTAL_FORMS"])) + deleted = {} + for k, value in list(new_data.items()): + if not value or not k.startswith("form-"): + continue + try: + form_number = int(k.split("-")[1]) + except (ValueError, IndexError) as __: + continue + if k.endswith("-DELETE"): + if new_data.get(f"form-{form_number}-pk", None): + deleted[form_number] = new_data[f"form-{form_number}-pk"] + if form_number not in no_values: # put it back in no values + no_values.append(form_number) + else: + new_data.pop(k) + elif form_number in no_values and form_number not in deleted: + no_values.pop(no_values.index(form_number)) + for no_value in no_values: + for k in list(new_data.keys()): + if k.startswith(f"form-{no_value}-"): + new_data.pop(k) + data["form-TOTAL_FORMS"] = data["form-TOTAL_FORMS"] - len(no_values) + + new_data.update(data) + formset = formset_class(data=new_data) + + if formset.is_valid(): + is_valid = True + # delete + for deleted_id in deleted.values(): + try: + model_relation.objects.get(pk=deleted_id).delete() + except model_relation.DoesNotExist: + continue + + for idx_form, data in enumerate(formset.cleaned_data): + if not data.get('right_record') or not data.get('relation_type'): + continue + + if data.get("pk"): + try: + current_relation = model_relation.objects.get(pk=data.get("pk")) + except model_relation.DoesNotExist: + continue + not_deleted_or_associated = True + for key, value in data.items(): + if key == "DELETE" and value is True: + current_relation.delete() + not_deleted_or_associated = False + + if not_deleted_or_associated: + current_relation.right_record_id = data.get("right_record") + current_relation.relation_type_id = data.get("relation_type") + current_relation.save() + else: + model_relation.objects.create( + **{ + "left_record_id": item.pk, + "right_record_id": data.get("right_record"), + "relation_type_id": data.get("relation_type"), + } + ) + if is_valid: + return redirect(reverse(url_name, args=[pk])) + else: + formset = formset_class(initial=initial, data=data) + + return render(request, 'ishtar/forms/modify_relations.html', { + 'formset': formset, + "url": reverse(url_name, args=[pk]) + }) + return _modify_relation + + +operation_modify_relations = get_relation_modify( + models.Operation, models.RecordRelations, + "operation-relation-modify", forms.RecordRelationsFormSet +) + + # archaeological sites |