import os import requests from django.conf import settings from django.core.paginator import Paginator from django.db import models from django.db.models.functions import Lower from django.http import HttpResponse, JsonResponse from django.shortcuts import get_object_or_404, render from django_downloadview import ObjectDownloadView from django_http_exceptions import HTTPExceptions from guardian.shortcuts import get_objects_for_user from .models import Contract, ContractFile class ContractFileDownloadView(ObjectDownloadView): model = ContractFile file_field = "file" attachment = False def get_queryset(self, *args, **kwargs): queryset = super().get_queryset(*args, **kwargs) if not self.current_user.has_perm("contracts.view_confidential"): queryset = queryset.filter(is_public=True) return queryset def get(self, request, *args, **kwargs): self.current_user = request.user return super().get(request, *args, **kwargs) def get_base_context(request) -> dict: return { "site_url": settings.SITE_URL, "user": request.user, } def get_pagination(request, objects) -> tuple: paginator = Paginator(objects, 25) page = paginator.get_page(request.GET.get("page")) return page, paginator def get_paginated_contracts(request, filter=None, annotations=None) -> tuple: if filter is None: filter = models.Q() filter = filter & models.Q(status=Contract.StatusTypes.APPROVED) if not request.user.has_perm("contracts.view_confidential"): additional_filter = models.Q(is_public=True) if not request.user.is_anonymous: additional_filter = additional_filter | models.Q(created_by=request.user) filter = filter & additional_filter contracts = get_objects_for_user(request.user, "contracts.view_contract") if annotations is not None: contracts = contracts.annotate(**annotations) contracts = contracts.filter(filter).order_by("-valid_start_date").all() page, paginator = get_pagination(request, contracts) return page, paginator def index(request): page, paginator = get_paginated_contracts(request) return render( request, "contracts/index.html", { **get_base_context(request), "title": "Seznam smluv", "description": "", "page": page, "paginator": paginator, "settings": Contract.settings, }, ) def view_contract(request, id: int): filter = models.Q(status=Contract.StatusTypes.APPROVED) if not request.user.has_perm("contracts.view_confidential"): filter = filter & ( models.Q(is_public=True) | ( models.Q(created_by=request.user) if not request.user.is_anonymous else models.Value(True) ) ) contract = get_object_or_404( (get_objects_for_user(request.user, "contracts.view_contract").filter(filter)), id=id, ) return render( request, "contracts/view_contract.html", { **get_base_context(request), "title": contract.name, "description": contract.summary, "contract": contract, }, ) def search(request): original_query = request.GET.get("q", default="") query = original_query.lower() if query.isnumeric(): number_query = int(query) else: number_query = 0 page = paginator = None title = "Vyhledávání" if query: filter = models.Q( models.Q(lower_name__contains=query) | models.Q(lower_summary__contains=query) | models.Q( models.Q(contractee_signatures__contractee__ico_number=number_query) | models.Q(signee_signatures__signee__ico_number=number_query) ) | models.Q( models.Q(contractee_signatures__contractee__name_lower__contains=query) | models.Q(signee_signatures__signee__name_lower__contains=query) ) | models.Q( models.Q( contractee_signatures__representatives__name_lower__contains=query ) | models.Q( signee_signatures__representatives__name_lower__contains=query ) ) ) annotations = { "lower_name": Lower("name"), "lower_summary": Lower("summary"), "contractee_signatures__contractee__name_lower": Lower( "contractee_signatures__contractee__name" ), "signee_signatures__signee__name_lower": Lower( "signee_signatures__signee__name" ), "contractee_signatures__representatives__name_lower": Lower( "contractee_signatures__representatives__name" ), "signee_signatures__representatives__name_lower": Lower( "signee_signatures__representatives__name" ), } # WARNING: PostgreSQL-dependent page, paginator = get_paginated_contracts( request, filter, annotations, ) return render( request, "contracts/search.html", { **get_base_context(request), "title": title, "description": "", "page": page, "paginator": paginator, "query": original_query, }, ) # BEGIN Filtered contract + submodel views def view_contract_filing_area(request, id: int): filing_area = get_object_or_404( get_objects_for_user(request.user, "contracts.view_contractfilingarea"), id=id ) contracts_page, contracts_paginator = get_paginated_contracts( request, models.Q(filing_area=filing_area) ) return render( request, "contracts/view_contract_filing_area.html", { **get_base_context(request), "title": filing_area.name, "description": ( f"Spisovna smluv - {filing_area.name}, " f"zodpovědná osoba {filing_area.person_responsible}" ), "filing_area": filing_area, "contracts_page": contracts_page, "contracts_paginator": contracts_paginator, }, ) def view_contract_issue(request, id: int): issue = get_object_or_404( get_objects_for_user(request.user, "contracts.view_contractissue"), id=id ) contracts_page, contracts_paginator = get_paginated_contracts( request, models.Q(issues=issue) ) return render( request, "contracts/view_contract_issue.html", { **get_base_context(request), "title": issue.name, "description": f"Problém se smlouvami - {issue.name}", "issue": issue, "contracts_page": contracts_page, "contracts_paginator": contracts_paginator, }, ) def view_contract_type(request, id: int): type_ = get_object_or_404( get_objects_for_user(request.user, "contracts.view_contracttype"), id=id ) contracts_page, contracts_paginator = get_paginated_contracts( request, models.Q(types=type_) ) return render( request, "contracts/view_contract_type.html", { **get_base_context(request), "title": type_.name, "description": f"Typ smluv - {type_.name}", "type": type_, "contracts_page": contracts_page, "contracts_paginator": contracts_paginator, }, ) def view_contractee(request, id: int): contractee = get_object_or_404( get_objects_for_user(request.user, "contracts.view_contractee"), id=id ) contracts_page, contracts_paginator = get_paginated_contracts( request, models.Q(contractee_signatures__contractee=contractee) ) return render( request, "contracts/view_contractee.html", { **get_base_context(request), "title": contractee.name, "description": f"Naše smluvní strana - {contractee.name}", "contractee": contractee, "contracts_page": contracts_page, "contracts_paginator": contracts_paginator, }, ) def view_signee(request, id: int): signee = get_object_or_404( get_objects_for_user(request.user, "contracts.view_signee"), id=id ) contracts_page, contracts_paginator = get_paginated_contracts( request, models.Q(signee_signatures__signee=signee) ) return render( request, "contracts/view_signee.html", { **get_base_context(request), "title": signee.name, "description": f"Jiná smluvní strana - {signee.name}", "signee": signee, "contracts_page": contracts_page, "contracts_paginator": contracts_paginator, }, ) # END Filtered contract + submodel views # BEGIN Submodel listing views def view_contract_filing_areas(request): filing_areas = get_objects_for_user( request.user, "contracts.view_contractfilingarea", ).order_by("name") page, paginator = get_pagination(request, filing_areas) return render( request, "contracts/view_contract_filing_areas.html", { **get_base_context(request), "title": "Spisovny", "description": "Seznam fyzických spisoven, kde jsou ukládány smlouvy.", "page": page, "paginator": paginator, }, ) def view_contract_issues(request): issues = get_objects_for_user( request.user, "contracts.view_contractissue", ).order_by("name") page, paginator = get_pagination(request, issues) return render( request, "contracts/view_contract_issues.html", { **get_base_context(request), "title": ( "Poznámky" if (request.user.is_anonymous or not request.user.can_view_confidential) else "Problémy" ), "description": ( "Poznámky ke smlouvám." if (request.user.is_anonymous or not request.user.can_view_confidential) else "Problémy se smlouvami." ), "page": page, "paginator": paginator, }, ) def view_contract_types(request): types = get_objects_for_user( request.user, "contracts.view_contracttype", ).order_by("name") page, paginator = get_pagination(request, types) return render( request, "contracts/view_contract_types.html", { **get_base_context(request), "title": "Typy", "description": "Typy smluv.", "page": page, "paginator": paginator, }, ) def view_contractees(request): contractees = get_objects_for_user( request.user, "contracts.view_contractee", ) page, paginator = get_pagination(request, contractees) return render( request, "contracts/view_contractees.html", { **get_base_context(request), "title": "Naše smluvní strany", "description": "Naše smluvní strany.", "page": page, "paginator": paginator, }, ) def view_signees(request): contractees = get_objects_for_user( request.user, "contracts.view_signee", ) page, paginator = get_pagination(request, contractees) return render( request, "contracts/view_signees.html", { **get_base_context(request), "title": "Jiné smluvní strany", "description": "Jiné smluvní strany.", "page": page, "paginator": paginator, }, ) # END Submodel listing views # Basic contract view API def view_contract_json(request, id: int): filter = models.Q(status=Contract.StatusTypes.APPROVED) if not request.user.has_perm("contracts.view_confidential"): filter = filter & ( models.Q(is_public=True) | ( models.Q(created_by=request.user) if not request.user.is_anonymous else models.Value(True) ) ) contract = get_object_or_404( (get_objects_for_user(request.user, "contracts.view_contract").filter(filter)), id=id, ) return JsonResponse({ "id": contract.id, "created_by": { "id": contract.created_by_id, "username": contract.created_by.username, }, "created_on": contract.created_on, "updated_on": contract.updated_on, "status": contract.status, "name": contract.name, "id_number": contract.id_number, "types": [ { "id": type.id, "name": type.name } for type in contract.types.all() ], "summary": contract.summary, "valid_start_date": contract.valid_start_date, "valid_end_date": contract.valid_end_date, "is_valid": contract.is_valid, "is_public": contract.is_public, "publishing_rejection_comment": contract.publishing_rejection_comment, "paper_form_state": contract.paper_form_state, "paper_form_person_responsible": contract.paper_form_person_responsible, "tender_url": contract.tender_url, "issues": [ { "id": issue.id, "name": issue.name } for issue in contract.issues.all() ] }) # ARES CORS proxy def get_ares_info(request, ico: int): if not request.user.is_staff: raise HTTPExceptions.FORBIDDEN ares_info = requests.get( f"https://ares.gov.cz/ekonomicke-subjekty-v-be/rest/ekonomicke-subjekty/{ico}" ) return HttpResponse( content=ares_info.content, status=ares_info.status_code, content_type=ares_info.headers.get("Content-Type"), ) def handle_404(request, exception): path = os.path.normpath(request.get_full_path()) archive_url = f"https://smlouvy-archiv.pirati.cz{path}" archive_response = requests.get(archive_url) # Quick dirty check for whether the page found is an actual contract was_found = archive_response.ok and "Datum podpisu" in str(archive_response.content) return render( request, "contracts/404.html", { **get_base_context(request), "title": "Stránka nenalezena", "description": "", "archive_page_exists": was_found, "archive_url": archive_url, }, )