#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2010-2017 Étienne Loks # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # See the file COPYING for details. import json from jinja2 import TemplateSyntaxError from django.conf import settings from django.core.urlresolvers import reverse from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.shortcuts import render, redirect from django.views.generic import RedirectView from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy from archaeological_operations import models from archaeological_operations import forms from archaeological_operations import wizards from ishtar_common.forms import ClosingDateFormSelection, FinalForm, FinalDeleteForm from ishtar_common.models import ( get_current_profile, IshtarSiteProfile, DocumentTemplate, ) from ishtar_common.utils import put_session_message, check_rights_condition from ishtar_common.views import ( gen_generate_doc, QAItemEditForm, QABaseLockView, wizard_is_available, QAItemForm, IshtarMixin, LoginRequiredMixin, ) from ishtar_common.views_item import get_item, show_item, revert_item, new_qa_item from ishtar_common.wizards import SearchWizard def autocomplete_patriarche(request): if ( not request.user.has_perm("ishtar_common.view_operation", models.Operation) and not request.user.has_perm( "ishtar_common.view_own_operation", models.Operation ) and not request.user.ishtaruser.has_right( "operation_search", session=request.session ) ): return HttpResponse(content_type="text/plain") if not request.GET.get("term"): return HttpResponse(content_type="text/plain") q = request.GET.get("term") query = Q() for q in q.split(" "): query &= Q(code_patriarche__startswith=q) limit = 15 operations = models.Operation.objects.filter(query).order_by("code_patriarche")[ :limit ] data = json.dumps( [ {"id": operation.code_patriarche, "value": operation.code_patriarche} for operation in operations ] ) return HttpResponse(data, content_type="text/plain") def autocomplete_archaeologicalsite(request): if not request.user.has_perm( "archaeological_operations.view_archaeologicalsite", models.ArchaeologicalSite ) and not request.user.has_perm( "archaeological_operations.view_own_archaeologicalsite", models.ArchaeologicalSite, ): return HttpResponse(content_type="text/plain") if not request.GET.get("term"): return HttpResponse(content_type="text/plain") q = request.GET.get("term") query = Q() for q in q.split(" "): qt = Q(reference__icontains=q) | Q(name__icontains=q) query = query & qt limit = 15 sites = ( models.ArchaeologicalSite.objects.filter(query) .distinct() .order_by("reference")[:limit] ) data = json.dumps([{"id": site.pk, "value": str(site)[:60]} for site in sites]) return HttpResponse(data, content_type="text/plain") new_archaeologicalsite = new_qa_item( models.ArchaeologicalSite, forms.ArchaeologicalSiteForm, many=True, page_name=_("New archaeological site"), ) def autocomplete_operation(request): # person_types = request.user.ishtaruser.person.person_type if ( not request.user.has_perm("ishtar_common.view_operation", models.Operation) and not request.user.has_perm( "ishtar_common.view_own_operation", models.Operation ) and not request.user.ishtaruser.has_right( "operation_search", session=request.session ) ): return HttpResponse(content_type="text/plain") if not request.GET.get("term"): return HttpResponse(content_type="text/plain") q = request.GET.get("term") query = Q() for q in q.split(" "): extra = Q(towns__name__icontains=q) | Q(common_name__icontains=q) try: int(q) extra = extra | Q(year=q) | Q(operation_code=q) except ValueError: pass if settings.COUNTRY == "fr": if q.startswith("OA"): q = q[2:] try: int(q) extra |= Q(code_patriarche__contains=q) except ValueError: pass query = query & extra limit = 15 operations = models.Operation.objects.filter(query).distinct()[:limit] data = json.dumps( [{"id": operation.pk, "value": str(operation)} for operation in operations] ) return HttpResponse(data, content_type="text/plain") def get_available_operation_code(request, year=None): if not request.user.has_perm( "ishtar_common.view_operation", models.Operation ) and not request.user.has_perm( "ishtar_common.view_own_operation", models.Operation ): return HttpResponse(content_type="text/plain") data = json.dumps({"id": models.Operation.get_available_operation_code(year)}) return HttpResponse(data, content_type="text/plain") get_operation = get_item( models.Operation, "get_operation", "operation", search_form=forms.OperationSelect ) show_operation = show_item(models.Operation, "operation") revert_operation = revert_item(models.Operation) get_administrativeactop = get_item( models.AdministrativeAct, "get_administrativeactop", "administrativeactop", base_request={"operation__pk__isnull": False}, ) get_administrativeact = get_item( models.AdministrativeAct, "get_administrativeact", "administrativeact" ) show_administrativeact = show_item(models.AdministrativeAct, "administrativeact") def dashboard_operation(request, *args, **kwargs): """ Operation dashboard """ dct = {"dashboard": models.OperationDashboard()} return render(request, "ishtar/dashboards/dashboard_operation.html", dct) operation_search_wizard = wizards.OperationSearch.as_view( [("general-operation_search", forms.OperationFormSelection)], label=_("Operation search"), url_name="operation_search", ) wizard_steps = [ ("filechoice-operation_creation", forms.OperationFormFileChoice), ("general-operation_creation", forms.OperationFormGeneral), ("judiciary-operation_creation", forms.CourtOrderedSeizureForm), ("collaborators-operation_creation", forms.CollaboratorForm), ("archaeologicalsite-operation_creation", forms.ArchaeologicalSiteFormSet), ("preventive-operation_creation", forms.OperationFormPreventive), ("preventivediag-operation_creation", forms.OperationFormPreventiveDiag), ("townsgeneral-operation_creation", forms.TownFormset), ("towns-operation_creation", forms.SelectedTownFormset), ("parcelsgeneral-operation_creation", forms.SelectedParcelGeneralFormSet), ("parcels-operation_creation", forms.SelectedParcelFormSet), ("remains-operation_creation", forms.RemainForm), ("periods-operation_creation", forms.PeriodForm), ("relations-operation_creation", forms.RecordRelationsFormSet), ("abstract-operation_creation", forms.OperationFormAbstract), ("final-operation_creation", FinalForm), ] def get_check_files_for_operation(other_check=None): def func(self): if not get_current_profile().files or not check_rights_condition(["view_file"])( self ): return False if not other_check: return True return other_check(self) return func check_files_for_operation = get_check_files_for_operation() ope_crea_condition_dict = { "filechoice-operation_creation": check_files_for_operation, "judiciary-operation_creation": wizards.is_judiciary( "general-operation_creation", models.OperationType, "operation_type", ), "preventive-operation_creation": get_check_files_for_operation( wizards.is_preventive( "general-operation_creation", models.OperationType, "operation_type", "prev_excavation", ) ), "preventivediag-operation_creation": get_check_files_for_operation( wizards.is_preventive( "general-operation_creation", models.OperationType, "operation_type", "arch_diagnostic", ) ), "townsgeneral-operation_creation": wizards.has_associated_file( "filechoice-operation_creation", negate=True ), "towns-operation_creation": wizards.has_associated_file( "filechoice-operation_creation" ), "parcelsgeneral-operation_creation": wizards.has_associated_file( "filechoice-operation_creation", negate=True ), "parcels-operation_creation": wizards.has_associated_file( "filechoice-operation_creation" ), } operation_creation_wizard = wizards.OperationWizard.as_view( wizard_steps, label=_("New operation"), condition_dict=ope_crea_condition_dict, url_name="operation_creation", ) operation_modif_wizard_steps = [ ("selec-operation_modification", forms.OperationFormSelection), ("general-operation_modification", forms.OperationFormModifGeneral), ("judiciary-operation_modification", forms.CourtOrderedSeizureForm), ("collaborators-operation_modification", forms.CollaboratorForm), ("archaeologicalsite-operation_modification", forms.ArchaeologicalSiteFormSet), ("preventive-operation_modification", forms.OperationFormPreventive), ("preventivediag-operation_modification", forms.OperationFormPreventiveDiag), ("towns-operation_modification", forms.SelectedTownFormset), ("townsgeneral-operation_modification", forms.TownFormset), ("parcels-operation_modification", forms.SelectedParcelFormSet), ("parcelsgeneral-operation_modification", forms.SelectedParcelGeneralFormSet), ("remains-operation_modification", forms.RemainForm), ("periods-operation_modification", forms.PeriodForm), ("relations-operation_modification", forms.RecordRelationsFormSet), ("abstract-operation_modification", forms.OperationFormAbstract), ("final-operation_modification", FinalForm), ] ope_modif_condition_dict = { "preventive-operation_modification": get_check_files_for_operation( wizards.is_preventive( "general-operation_modification", models.OperationType, "operation_type", "prev_excavation", ) ), "preventivediag-operation_modification": get_check_files_for_operation( wizards.is_preventive( "general-operation_modification", models.OperationType, "operation_type", "arch_diagnostic", ) ), "judiciary-operation_modification": wizards.is_judiciary( "general-operation_modification", models.OperationType, "operation_type", ), "townsgeneral-operation_modification": wizards.has_associated_file( "general-operation_modification", negate=True ), "towns-operation_modification": wizards.has_associated_file( "general-operation_modification" ), "parcelsgeneral-operation_modification": wizards.has_associated_file( "general-operation_modification", negate=True ), "parcels-operation_modification": wizards.has_associated_file( "general-operation_modification" ), } operation_modification_wizard = wizards.OperationModificationWizard.as_view( operation_modif_wizard_steps, label=_("Operation modification"), condition_dict=ope_modif_condition_dict, url_name="operation_modification", ) def operation_modify(request, pk): if not wizard_is_available( operation_modification_wizard, request, models.Operation, pk ): return HttpResponseRedirect("/") wizard_url = "operation_modification" wizards.OperationModificationWizard.session_set_value( request, "selec-" + wizard_url, "pk", pk, reset=True ) return redirect(reverse(wizard_url, kwargs={"step": "general-" + wizard_url})) def operation_add(request, file_id): operation_creation_wizard(request) wizards.OperationWizard.session_set_value( request, "filechoice-operation_creation", "associated_file", file_id, reset=True ) return redirect( reverse("operation_creation", kwargs={"step": "general-operation_creation"}) ) operation_closing_steps = [ ("selec-operation_closing", forms.OperationFormSelection), ("date-operation_closing", ClosingDateFormSelection), ("final-operation_closing", forms.FinalOperationClosingForm), ] operation_closing_wizard = wizards.OperationClosingWizard.as_view( operation_closing_steps, label=_("Operation closing"), url_name="operation_closing", ) operation_deletion_steps = [ ("selec-operation_deletion", forms.OperationFormMultiSelection), ("final-operation_deletion", forms.OperationDeletionForm), ] operation_deletion_wizard = wizards.OperationDeletionWizard.as_view( operation_deletion_steps, label=_("Operation deletion"), url_name="operation_deletion", ) def operation_delete(request, pk): if not wizard_is_available( operation_deletion_wizard, request, models.Operation, pk ): return HttpResponseRedirect("/") wizard_url = "operation_deletion" wizards.OperationDeletionWizard.session_set_value( request, "selec-" + wizard_url, "pks", pk, reset=True ) return redirect(reverse(wizard_url, kwargs={"step": "final-" + wizard_url})) # archaeological sites def site_extra_context(request, item): return {"SITE_LABEL": IshtarSiteProfile.get_default_site_label()} get_site = get_item( models.ArchaeologicalSite, "get_site", "site", search_form=forms.SiteSelect ) show_site = show_item(models.ArchaeologicalSite, "site", extra_dct=site_extra_context) revert_site = revert_item(models.ArchaeologicalSite) site_search_wizard = wizards.SiteSearch.as_view( [("general-site_search", forms.SiteFormSelection)], url_name="site_search", ) site_creation_steps = [ ("general-site_creation", forms.SiteForm), ("towns-site_creation", forms.SiteTownFormset), ("underwater-site_creation", forms.SiteUnderwaterForm), ("final-site_creation", FinalForm), ] site_creation_wizard = wizards.SiteWizard.as_view( site_creation_steps, condition_dict={"underwater-site_creation": forms.check_underwater_module}, url_name="site_creation", ) site_modification_steps = [ ("selec-site_modification", forms.SiteFormSelection), ("general-site_modification", forms.SiteForm), ("towns-site_modification", forms.SiteTownFormset), ("underwater-site_modification", forms.SiteUnderwaterForm), ("final-site_modification", FinalForm), ] site_modification_wizard = wizards.SiteModificationWizard.as_view( site_modification_steps, condition_dict={"underwater-site_modification": forms.check_underwater_module}, url_name="site_modification", ) def site_modify(request, pk): if not wizard_is_available( site_modification_wizard, request, models.ArchaeologicalSite, pk ): return HttpResponseRedirect("/") wizard_url = "site_modification" wizards.SiteModificationWizard.session_set_value( request, "selec-" + wizard_url, "pk", pk, reset=True ) return redirect(reverse(wizard_url, kwargs={"step": "general-" + wizard_url})) site_deletion_steps = [ ("selec-site_deletion", forms.SiteFormMultiSelection), ("final-site_deletion", FinalDeleteForm), ] site_deletion_wizard = wizards.SiteDeletionWizard.as_view( site_deletion_steps, label=_("Site deletion"), url_name="site_deletion", ) def site_delete(request, pk): if not wizard_is_available( site_deletion_wizard, request, models.ArchaeologicalSite, pk ): return HttpResponseRedirect("/") wizard_url = "site_deletion" wizards.SiteDeletionWizard.session_set_value( request, "selec-" + wizard_url, "pks", pk, reset=True ) return redirect(reverse(wizard_url, kwargs={"step": "final-" + wizard_url})) operation_administrativeactop_search_wizard = wizards.SearchWizard.as_view( [ ( "general-operation_administrativeactop_search", forms.AdministrativeActOpeFormSelection, ) ], label=_("Administrative act search"), url_name="operation_administrativeactop_search", ) administrativeactop_steps = [ ("selec-operation_administrativeactop", forms.OperationFormSelection), ("administrativeact-operation_administrativeactop", forms.AdministrativeActOpeForm), ("final-operation_administrativeactop", FinalForm), ] operation_administrativeactop_wizard = wizards.OperationAdministrativeActWizard.as_view( administrativeactop_steps, label=_("Operation: new administrative act"), url_name="operation_administrativeactop", ) operation_administrativeactop_modification_wizard = ( wizards.OperationEditAdministrativeActWizard.as_view( [ ( "selec-operation_administrativeactop_modification", forms.AdministrativeActOpeFormSelection, ), ( "administrativeact-operation_administrativeactop_modification", forms.AdministrativeActOpeModifForm, ), ("final-operation_administrativeactop_modification", FinalForm), ], label=_("Operation: administrative act modification"), url_name="operation_administrativeactop_modification", ) ) def operation_administrativeactop_modify(request, pk): if not wizard_is_available( operation_administrativeactop_modification_wizard, request, models.AdministrativeAct, pk, ): return HttpResponseRedirect("/") wizard_url = "operation_administrativeactop_modification" wizards.OperationEditAdministrativeActWizard.session_set_value( request, "selec-" + wizard_url, "pk", pk, reset=True ) return redirect( reverse(wizard_url, kwargs={"step": "administrativeact-" + wizard_url}) ) operation_administrativeactop_deletion_wizard = ( wizards.AdministrativeActDeletionWizard.as_view( [ ( "selec-operation_administrativeactop_deletion", forms.AdministrativeActOpeFormSelection, ), ( "final-operation_administrativeactop_deletion", forms.FinalAdministrativeActDeleteForm, ), ], label=_("Operation: administrative act deletion"), url_name="operation_administrativeactop_deletion", ) ) def operation_administrativeactop_delete(request, pk): if not wizard_is_available( operation_administrativeactop_deletion_wizard, request, models.AdministrativeAct, pk, ): return HttpResponseRedirect("/") wizard_url = "operation_administrativeactop_deletion" wizards.AdministrativeActDeletionWizard.session_set_value( request, "selec-" + wizard_url, "pk", pk, reset=True ) return redirect(reverse(wizard_url, kwargs={"step": "final-" + wizard_url})) administrativact_register_wizard = SearchWizard.as_view( [ ( "general-administrativact_register", forms.AdministrativeActRegisterFormSelection, ) ], label=pgettext_lazy("admin act register", "Register"), url_name="administrativact_register", ) generatedoc_administrativeactop = gen_generate_doc(models.AdministrativeAct) def administrativeactfile_document( request, file=False, treatment=False, treatment_file=False ): search_form = forms.AdministrativeActOpeFormSelection document_type = "O" if file: from archaeological_files.forms import AdministrativeActFileFormSelection search_form = AdministrativeActFileFormSelection document_type = "F" elif treatment: from archaeological_finds.forms import AdministrativeActTreatmentFormSelection search_form = AdministrativeActTreatmentFormSelection document_type = "T" elif treatment_file: from archaeological_finds.forms import ( AdministrativeActTreatmentFileFormSelection, ) search_form = AdministrativeActTreatmentFileFormSelection document_type = "TF" if not request.user.has_perm("view_administrativeact", models.AdministrativeAct): return HttpResponse(content_type="text/plain") dct = {} DocumentGenerationAdminActForm = forms.DocumentGenerationAdminActForm if request.POST: dct["search_form"] = search_form(request.POST) dct["template_form"] = DocumentGenerationAdminActForm( document_type=document_type ) c_object = None try: if dct["search_form"].is_valid(): c_object = DocumentGenerationAdminActForm._associated_model.objects.get( pk=dct["search_form"].cleaned_data.get("pk") ) except DocumentGenerationAdminActForm._associated_model.DoesNotExist: pass if c_object: dct["template_form"] = DocumentGenerationAdminActForm( request.POST, document_type=document_type, obj=c_object ) if dct["template_form"].is_valid(): try: return generatedoc_administrativeactop( request, dct["search_form"].cleaned_data.get("pk"), dct["template_form"].cleaned_data.get("document_template"), ) except TemplateSyntaxError: dct["search_form"] = search_form() try: template = DocumentTemplate.objects.get( pk=dct["template_form"].cleaned_data.get( "document_template" ) ).name except DocumentTemplate.DoesNotExist: template = "" dct["template_form"] = DocumentGenerationAdminActForm( document_type=document_type ) dct["template_error"] = str( _( 'Syntax error on the source template "{}" - ' "contact your administrator and ask him to check " "the syntax of this document." ) ).format(template) else: dct["search_form"] = search_form() dct["template_form"] = DocumentGenerationAdminActForm( document_type=document_type ) return render(request, "ishtar/administrativeact_document.html", dct) def autocomplete_administrativeact(request): if not request.user.has_perm( "archaeological_operations.view_administrativeact", models.AdministrativeAct ) and not request.user.has_perm( "archaeological_operations.view_own_administrativeact", models.AdministrativeAct ): return HttpResponse(content_type="text/plain") if not request.GET.get("term"): return HttpResponse(content_type="text/plain") q = request.GET.get("term") query = Q() for q in q.split(" "): qt = Q(act_type__label__icontains=q) | Q(towns_label=q) try: if len(q) == 4: qt |= Q(year=int(q)) qt |= Q(index=int(q)) except ValueError: pass query = query & qt limit = 15 items = ( models.AdministrativeAct.objects.filter(query) .order_by("year", "index") .distinct()[:limit] ) data = json.dumps( [{"id": item.pk, "value": str(item)[:80] + " (...)"} for item in items] ) return HttpResponse(data, content_type="text/plain") def reset_wizards(request): for wizard_class, url_name in ( (wizards.OperationWizard, "operation_creation"), (wizards.OperationModificationWizard, "operation_modification"), (wizards.OperationClosingWizard, "operation_closing"), (wizards.OperationDeletionWizard, "operation_deletion_wizard"), (wizards.OperationAdministrativeActWizard, "operation_administrativeactop"), ( wizards.OperationEditAdministrativeActWizard, "operation_administrativeactop_modification", ), ( wizards.AdministrativeActDeletionWizard, "operation_administrativeactop_deletion", ), ): wizard_class.session_reset(request, url_name) class QAOperationForm(QAItemEditForm): model = models.Operation form_class = forms.QAOperationFormMulti class QAOperationLockView(QABaseLockView): model = models.Operation base_url = "operation-qa-lock" class QASiteLockView(QABaseLockView): model = models.ArchaeologicalSite base_url = "site-qa-lock" class QAOperationdDuplicateFormView(QAItemForm): template_name = "ishtar/forms/qa_operation_duplicate.html" model = models.Operation page_name = _("Duplicate") form_class = forms.QAOperationDuplicateForm base_url = "operation-qa-duplicate" def get_form_kwargs(self): kwargs = super(QAOperationdDuplicateFormView, self).get_form_kwargs() kwargs["user"] = self.request.user return kwargs def form_valid(self, form): form.save() return HttpResponseRedirect(reverse("success")) def get_context_data(self, **kwargs): data = super(QAOperationdDuplicateFormView, self).get_context_data(**kwargs) data["action_name"] = _("Duplicate") return data class QAArchaeologicalSiteDuplicateFormView(QAItemForm): template_name = "ishtar/forms/qa_site_duplicate.html" model = models.ArchaeologicalSite page_name = _("Duplicate") form_class = forms.QAArchaeologicalSiteDuplicateForm base_url = "site-qa-duplicate" def get_form_kwargs(self): kwargs = super(QAArchaeologicalSiteDuplicateFormView, self).get_form_kwargs() kwargs["user"] = self.request.user return kwargs def form_valid(self, form): form.save() return HttpResponseRedirect(reverse("success")) def get_context_data(self, **kwargs): data = super(QAArchaeologicalSiteDuplicateFormView, self).get_context_data( **kwargs ) data["action_name"] = _("Duplicate") return data class QAArchaeologicalSiteForm(QAItemEditForm): model = models.ArchaeologicalSite form_class = forms.QAArchaeologicalSiteFormMulti class GenerateStatsOperation(IshtarMixin, LoginRequiredMixin, RedirectView): model = models.Operation def get_redirect_url(self, *args, **kwargs): return ( reverse("display-item", args=[self.model.SLUG, self.item.pk]) + "#statistics" ) def get(self, request, *args, **kwargs): self.item = self.model.objects.get(pk=kwargs["pk"]) self.item._get_or_set_stats("_nb_acts", update=True) self.item._get_or_set_stats("_nb_indexed_acts", update=True) self.item._get_or_set_stats("_nb_context_records", update=True) self.item._get_or_set_stats( "_nb_context_records_by_type", update=True, expected_type=list ) self.item._get_or_set_stats( "_nb_context_records_by_periods", update=True, expected_type=list ) self.item._get_or_set_stats("_nb_finds", update=True) self.item._get_or_set_stats( "_nb_finds_by_material_type", update=True, expected_type=list ) self.item._get_or_set_stats( "_nb_finds_by_types", update=True, expected_type=list ) self.item._get_or_set_stats( "_nb_finds_by_periods", update=True, expected_type=list ) self.item._get_or_set_stats("_nb_documents", update=True) self.item._get_or_set_stats( "_nb_documents_by_types", update=True, expected_type=list ) self.item._get_or_set_stats("_nb_stats_finds_by_ue", update=True) return super(GenerateStatsOperation, self).get(request, *args, **kwargs)