diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2024-09-16 12:45:00 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2024-09-16 12:46:09 +0200 |
commit | 12e9870e2aa0659de98a9122fbc4ab16b0877449 (patch) | |
tree | 36d375089b787fbc3649ad54bb9e7e3b2b5741e0 /archaeological_context_records | |
parent | db5ecbb7b69ff668ca005bd9535bf595b79e649e (diff) | |
download | Ishtar-12e9870e2aa0659de98a9122fbc4ab16b0877449.tar.bz2 Ishtar-12e9870e2aa0659de98a9122fbc4ab16b0877449.zip |
✨ Context records relations: remove form from the wizard to put in a specific form
Diffstat (limited to 'archaeological_context_records')
-rw-r--r-- | archaeological_context_records/forms.py | 80 | ||||
-rw-r--r-- | archaeological_context_records/models.py | 18 | ||||
-rw-r--r-- | archaeological_context_records/urls.py | 5 | ||||
-rw-r--r-- | archaeological_context_records/views.py | 122 | ||||
-rw-r--r-- | archaeological_context_records/wizards.py | 12 |
5 files changed, 186 insertions, 51 deletions
diff --git a/archaeological_context_records/forms.py b/archaeological_context_records/forms.py index 55f27ddcd..8d41a7888 100644 --- a/archaeological_context_records/forms.py +++ b/archaeological_context_records/forms.py @@ -21,6 +21,7 @@ Context records forms definitions """ from collections import OrderedDict +from copy import copy from itertools import groupby from bootstrap_datepicker.widgets import DateField @@ -464,37 +465,6 @@ DatingFormSet.form_admin_name = _("Context record - 030 - Dating") DatingFormSet.form_slug = "contextrecord-030-datings" -class RecordRelationsForm(OpeRecordRelationsForm): - current_model = models.RelationType - current_related_model = models.ContextRecord - associated_models = { - "right_record": models.ContextRecord, - "relation_type": models.RelationType, - } - right_record = forms.ChoiceField( - label=_("Context record"), choices=[], required=False - ) - - def __init__(self, *args, **kwargs): - crs = None - if "data" in kwargs and "CONTEXT_RECORDS" in kwargs["data"]: - crs = kwargs["data"]["CONTEXT_RECORDS"] - super(RecordRelationsForm, self).__init__(*args, **kwargs) - self.fields["relation_type"].choices = models.RelationType.get_types( - initial=self.init_data.get("relation_type") - ) - if crs: - self.fields["right_record"].choices = [("", "-" * 2)] + crs - - -RecordRelationsFormSet = formset_factory( - RecordRelationsForm, can_delete=True, formset=RecordRelationsFormSetBase -) -RecordRelationsFormSet.form_label = _("Relations") -RecordRelationsFormSet.form_admin_name = _("Context record - 050 - Relations") -RecordRelationsFormSet.form_slug = "contextrecord-050-recordrelations" - - class RecordFormInterpretation(CustomForm, ManageOldType): HEADERS = {} form_label = _("Interpretation") @@ -554,6 +524,54 @@ class RecordDeletionForm(FinalForm): confirm_end_msg = _("Would you like to delete this context record?") +class RecordRelationsForm(OpeRecordRelationsForm): + current_model = models.RelationType + current_related_model = models.ContextRecord + associated_models = { + "right_record": models.ContextRecord, + "relation_type": models.RelationType, + } + ERROR_MISSING = _("You should select a context record and a relation type.") + + right_record = forms.ChoiceField( + label=_("Context record"), choices=[], required=False + ) + + def __init__(self, *args, **kwargs): + crs = None + if "data" in kwargs and "CONTEXT_RECORDS" in kwargs["data"]: + kwargs["data"] = copy(kwargs["data"]) + crs = kwargs["data"].pop("CONTEXT_RECORDS") + # 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') + initial = kwargs.get("initial", {}) + if initial and initial.get("right_record", None): + if initial["right_record"] not in [cr_id for cr_id, cr_lbl in crs]: + try: + crs.append( + (initial["right_record"], + str(models.ContextRecord.objects.get(pk=initial["right_record"]))) + ) + except models.ContextRecord.DoesNotExist: + pass + super().__init__(*args, **kwargs) + if crs: + self.fields["right_record"].choices = [("", "-" * 2)] + crs + + +RecordRelationsFormSet = formset_factory( + RecordRelationsForm, can_delete=True, formset=RecordRelationsFormSetBase +) +RecordRelationsFormSet.form_label = _("Relations") +RecordRelationsFormSet.form_admin_name = _("Context record - 050 - Relations") +RecordRelationsFormSet.form_slug = "contextrecord-050-recordrelations" + + class QAOperationCR(IshtarForm): town = forms.ChoiceField(label=_("Town"), choices=[]) archaeological_site = forms.ChoiceField( diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index ee43183eb..3867997de 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -1056,9 +1056,10 @@ class ContextRecord( def get_extra_actions(self, request): # url, base_text, icon, extra_text, extra css class, is a quick action - actions = super(ContextRecord, self).get_extra_actions(request) + actions = super().get_extra_actions(request) + is_locked = hasattr(self, "is_locked") and self.is_locked(request.user) - # is_locked = hasattr(self, "is_locked") and self.is_locked(request.user) + can_edit_cr = self.can_do(request, "change_contextrecord") profile = get_current_profile() can_add_geo = profile.mapping and self.can_do(request, "add_geovectordata") if can_add_geo: @@ -1075,7 +1076,18 @@ class ContextRecord( False, ), ] - can_edit_cr = self.can_do(request, "change_contextrecord") + if can_edit_cr and not is_locked: + actions += [ + ( + reverse("context-record-relation-modify", args=[self.pk]), + _("Modify relations"), + "fa fa-retweet", + _("relations"), + "", + True, + ), + ] + if can_edit_cr: actions += [ ( diff --git a/archaeological_context_records/urls.py b/archaeological_context_records/urls.py index 446b3fbf9..5fd360fbb 100644 --- a/archaeological_context_records/urls.py +++ b/archaeological_context_records/urls.py @@ -150,6 +150,11 @@ urlpatterns = [ name="get-contextrecordrelationdetail", ), url( + r"^context-record-relations-modify/(?P<pk>.+)/$", + views.context_record_modify_relations, + name="context-record-relation-modify", + ), + url( r"^operation-qa-contextrecord/(?P<pks>[0-9]+)/$", check_rights(["add_contextrecord", "add_own_contextrecord"])( views.QAOperationContextRecordView.as_view() diff --git a/archaeological_context_records/views.py b/archaeological_context_records/views.py index 9d1d285e5..3695617f9 100644 --- a/archaeological_context_records/views.py +++ b/archaeological_context_records/views.py @@ -21,7 +21,7 @@ import json from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect, Http404 -from django.shortcuts import redirect +from django.shortcuts import render, redirect from django.urls import reverse from ishtar_common.utils import ugettext_lazy as _ from django.views.generic import RedirectView @@ -32,7 +32,6 @@ from archaeological_context_records import models from archaeological_operations.views import site_extra_context from archaeological_context_records import forms -from ishtar_common.utils import put_session_message from ishtar_common.views import ( IshtarMixin, @@ -42,7 +41,7 @@ from ishtar_common.views import ( wizard_is_available, QAItemEditForm, ) -from ishtar_common.views_item import display_item, get_item, show_item, revert_item +from ishtar_common.views_item import get_item, show_item, revert_item from archaeological_context_records import wizards show_contextrecord = show_item( @@ -122,7 +121,6 @@ record_creation_steps = [ ("general-record_creation", forms.RecordFormGeneral), ("datings-record_creation", forms.DatingFormSet), ("interpretation-record_creation", forms.RecordFormInterpretation), - ("relations-record_creation", forms.RecordRelationsFormSet), ("final-record_creation", forms.FinalForm), ] @@ -138,7 +136,6 @@ record_modification_steps = [ ("general-record_modification", forms.RecordFormGeneral), ("datings-record_modification", forms.DatingFormSet), ("interpretation-record_modification", forms.RecordFormInterpretation), - ("relations-record_modification", forms.RecordRelationsFormSet), ("final-record_modification", forms.FinalForm), ] @@ -196,6 +193,121 @@ def reset_wizards(request): wizard_class.session_reset(request, url_name) +RELATION_FORMSET_EXTRA_FORM = 3 + + +def get_relation_modify(model, model_relation, url_name): + def _modify_relation(request, pk): + formset_class = forms.RecordRelationsFormSet + item = model.objects.get(pk=pk) + relations = model_relation.objects.filter(left_record_id=pk).all() + + 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 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, + "CONTEXT_RECORDS": 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 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") and 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) + 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 + + +context_record_modify_relations = get_relation_modify( + models.ContextRecord, models.RecordRelations, "context-record-relation-modify" +) + + class GenerateRelationImage(IshtarMixin, LoginRequiredMixin, RedirectView): upper_model = models.Operation model = models.ContextRecord diff --git a/archaeological_context_records/wizards.py b/archaeological_context_records/wizards.py index e92d9587e..35b4e02b4 100644 --- a/archaeological_context_records/wizards.py +++ b/archaeological_context_records/wizards.py @@ -119,21 +119,9 @@ class RecordWizard(Wizard): else: current_object = self.get_current_object() data["context_record"] = current_object - elif step.startswith("relations") and hasattr(form, "management_form"): - data["CONTEXT_RECORDS"] = self.get_other_context_records() form = super(RecordWizard, self).get_form(step, data, files) return form - def get_other_context_records(self): - operation = self.get_current_operation() - if not operation: - return [] - q = models.ContextRecord.objects.filter(operation_id=operation.pk) - obj = self.get_current_object() - if obj and obj.pk: - q = q.exclude(pk=obj.pk) - return [(cr.pk, cr.cached_label) for cr in q.all()] - class RecordModifWizard(RecordWizard): modification = True |