230 lines
9.8 KiB
Python
230 lines
9.8 KiB
Python
# mi_proyecto/pdf/views.py
|
|
# dpsk - 2026
|
|
import io
|
|
from pathlib import Path
|
|
from django.http import HttpResponse
|
|
from django.template.loader import render_to_string
|
|
from weasyprint import HTML
|
|
from arches.app.models.resource import Resource
|
|
from django.contrib.auth.models import Group
|
|
from datetime import datetime
|
|
from zoneinfo import ZoneInfo
|
|
from functools import reduce
|
|
from operator import getitem
|
|
from pypdf import PdfReader, PdfWriter
|
|
import urllib.parse
|
|
import requests
|
|
import base64
|
|
import json
|
|
import ast
|
|
|
|
def static_map_view(geojson_colec, sat_map):
|
|
|
|
geojson_dict = ast.literal_eval(geojson_colec)
|
|
if sat_map:
|
|
for geo in geojson_dict['features'] :
|
|
if geo['geometry'].get('type') == 'Polygon':
|
|
geo['properties'] = {
|
|
"stroke": "#00ffff",
|
|
"stroke-width": 2,
|
|
"stroke-opacity": 0.8,
|
|
"fill": "#00ffff",
|
|
"fill-opacity": 0.3
|
|
}
|
|
elif geo['geometry'].get('type') == 'Point':
|
|
geo['properties'] = {
|
|
"marker-color": "#ff0000",
|
|
"marker-size": "small"
|
|
}
|
|
elif geo['geometry'].get('type') == 'LineString':
|
|
geo['properties'] = {
|
|
"stroke": "#0000ff",
|
|
"stroke-width": 2,
|
|
"stroke-opacity": 0.8
|
|
}
|
|
|
|
geojson_string = json.dumps(geojson_dict, separators=(',', ':'))
|
|
encoded_geojson = urllib.parse.quote(geojson_string)
|
|
|
|
username = "mapbox"
|
|
if sat_map:
|
|
style_id = "satellite-streets-v12" # streets-v12 | outdoors-v11 | satellite-streets-v12
|
|
else:
|
|
style_id = "light-v11"
|
|
|
|
width, height = 340, 340
|
|
|
|
# Procedimiento pendiente para extraer el token desde la configuración del sistema
|
|
access_token = 'pk.eyJ1IjoianNidXJnb3N2IiwiYSI6ImNsaWhoN3ZtMTBxeHUzZm1xaGM0cGpxOXIifQ.ki3vldVB5MwZMqDSpLSjLg'
|
|
|
|
mapbox_url = (
|
|
f"https://api.mapbox.com/styles/v1/{username}/{style_id}/static/"
|
|
f"geojson({encoded_geojson})/auto/{width}x{height}"
|
|
f"?access_token={access_token}"
|
|
)
|
|
|
|
response = requests.get(mapbox_url)
|
|
|
|
return base64.b64encode(response.content).decode('utf-8')
|
|
|
|
def ajustar_medios(resource_media_rel, medios_list):
|
|
medios = []
|
|
img=["image/bmp", "image/gif", "image/jpg", "image/jpeg", "image/png", "image/tif", "image/tiff"]
|
|
no_imagen_principal = True
|
|
try:
|
|
if isinstance(medios_list, list) :
|
|
for rel in resource_media_rel['related_resources']:
|
|
if isinstance(medios_list[0], dict) :
|
|
medio=next((item for item in medios_list if item['@value'] == rel['displayname']), None)
|
|
else:
|
|
medio = None
|
|
for til in rel['tiles']:
|
|
for dato in til['data']:
|
|
if isinstance(til['data'][dato], list):
|
|
for dat in til['data'][dato]:
|
|
idx = " - " + str(dat['index'] +1) if len(til['data'][dato])>1 else ""
|
|
if medio is not None and isinstance(medio, dict):
|
|
medio_nuevo = {'tipo': val for key, val in medio.items() if "Tipo" in key}
|
|
else:
|
|
if dat['type'] in img and no_imagen_principal:
|
|
medio_nuevo = {'tipo':'Imagen principal'}
|
|
no_imagen_principal = False
|
|
else:
|
|
medio_nuevo = {'tipo':'Medio'}
|
|
medio_nuevo.update({'@value':rel['displayname']+idx, 'file':dat['name'], 'url': dat['url'], 'formato':dat['type']})
|
|
medios.append(medio_nuevo)
|
|
|
|
# Reordenamos para que el primer medio de la lista sea de tipo Imagen principal o al menos del tipo imagen
|
|
medios.sort(key=lambda item: item.get('formato') not in img)
|
|
medios.sort(key=lambda item: item.get('tipo') != 'Imagen principal')
|
|
|
|
except:
|
|
pass
|
|
return medios
|
|
|
|
def find_key_path(data, target_key, current_path=None):
|
|
if current_path is None:
|
|
current_path = []
|
|
|
|
# Verifica si es diccionario válido
|
|
if isinstance(data, dict):
|
|
for key, value in data.items():
|
|
# si la clave buscada está en el nivel actual del diccionario.
|
|
if key == target_key:
|
|
return current_path + [key]
|
|
|
|
# Profundiza en el rastreo mientras agrega la clave actual a la ruta.
|
|
path = find_key_path(value, target_key, current_path + [key])
|
|
if path:
|
|
return path
|
|
# En caso de que la clave esté dentro de una lista
|
|
elif isinstance(data, list):
|
|
for index, item in enumerate(data):
|
|
path = find_key_path(item, target_key, current_path + [index])
|
|
if path:
|
|
return path
|
|
return None
|
|
|
|
def strdict_to_dict(strdict):
|
|
""" Representación de texto de un diccionario a formato json """
|
|
value = {}
|
|
try:
|
|
if isinstance(strdict, str):
|
|
value = json.dumps(ast.literal_eval(strdict))
|
|
except:
|
|
pass
|
|
return value
|
|
|
|
def export_resource_pdf(request, resourceid, printubic, satmap, printimgs, printpdfs):
|
|
resource = Resource.objects.get(pk=resourceid)
|
|
resource_data = resource.to_json()
|
|
|
|
# Corrección de medios relacionados, se normalizan claves y se adicionan propiedades
|
|
ruta_medios = find_key_path( resource_data, "Medio de información")
|
|
|
|
if ruta_medios is not None:
|
|
valor_medios=reduce(lambda dict_layer, key: dict_layer[key], ruta_medios, resource_data)
|
|
resource_rel=resource.get_related_resources(user=request.user,resourceinstance_graphid='6afc4e9e-727e-4152-8084-309267752650')
|
|
#resource_data["Información gráfica"]["Medio de información"] = ajustar_medios(resource_rel)
|
|
reduce(getitem, ruta_medios[:-1], resource_data)[ruta_medios[-1]] = ajustar_medios(resource_rel,valor_medios)
|
|
|
|
# Cambio de datos gis en texto a formato json
|
|
|
|
ruta_gis = find_key_path( resource_data, "Coordenadas / Geometría")
|
|
if ruta_gis is not None:
|
|
valor_gis=reduce(lambda dict_layer, key: dict_layer[key], ruta_gis, resource_data)["@value"]
|
|
reduce(getitem, ruta_gis[:-1], resource_data)[ruta_gis[-1]]["@value"] = strdict_to_dict(valor_gis)
|
|
|
|
# Extracción del identificador de grupo ETA
|
|
eta_group=""
|
|
ruta_meta_iden = find_key_path( resource_data, "Meta identificación")
|
|
if ruta_meta_iden is not None:
|
|
meta_iden=json.loads(strdict_to_dict(reduce(lambda dict_layer, key: dict_layer[key], ruta_meta_iden, resource_data)))
|
|
eta_group=str(Group.objects.get(pk=meta_iden["grp_eta"])).upper()
|
|
|
|
# Fecha del informe
|
|
sprpcb_url=request.build_absolute_uri('/')[:-1]
|
|
fecha=datetime.now(ZoneInfo("America/La_Paz"))
|
|
|
|
map_img = None
|
|
|
|
if ruta_gis is not None and bool(int(printubic)) :
|
|
if reduce(getitem, ruta_gis[:-1], resource_data)[ruta_gis[-1]]["@value"] :
|
|
map_img = static_map_view(reduce(getitem, ruta_gis[:-1], resource_data)[ruta_gis[-1]]["@value"], bool(int(satmap)))
|
|
|
|
resources = [{
|
|
'resourceinstanceid': str(resource.resourceinstanceid),
|
|
'graph_id': str(resource.graph_id),
|
|
'displayname': resource.displayname,
|
|
'resource': resource_data,
|
|
'sprpcb_url': sprpcb_url,
|
|
'fecha': fecha,
|
|
'eta_group': eta_group,
|
|
'print_ubic': bool(int(printubic)),
|
|
'print_imgs': bool(int(printimgs)),
|
|
'print_pdfs': bool(int(printpdfs)),
|
|
'map_img': map_img
|
|
}]
|
|
|
|
context = {'resources': resources}
|
|
|
|
match str(resource.graph_id):
|
|
case "72420da0-db59-4048-aea2-03b0bc5cdcdf": # Actores
|
|
context["resources"][0]["grafo"]="Organizaciones y personas"
|
|
nombre_pdf = f'Actor_{resourceid}'
|
|
html_string = render_to_string('reports/actor_pdf_report.html', context)
|
|
case '8ea3bf67-89ce-474c-b3cb-6dd5ee3d6198': # Bienes inmuebles
|
|
context["resources"][0]["grafo"]="Patrimonio material - Bienes inmuebles"
|
|
html_string = render_to_string('reports/bim_pdf_report.html', context)
|
|
nombre_pdf = f'bienes_inmuebles_{resourceid}'
|
|
case '10b03fec-4d85-11ee-a708-ffcd06c08a5d': # Bienes muebles
|
|
context["resources"][0]["grafo"]="Patrimonio material - Bienes muebles"
|
|
html_string = render_to_string('reports/bm_pdf_report.html', context)
|
|
nombre_pdf = f'bienes_muebles_{resourceid}'
|
|
case "9b0e22c7-5c56-4be6-aa89-ae2632ba28e8": # Inmaterial
|
|
context["resources"][0]["grafo"]="Patrimonio Inmaterial"
|
|
html_string = render_to_string('reports/pi_pdf_report.html', context)
|
|
nombre_pdf = f'Inmaterial_{resourceid}'
|
|
|
|
gen_pdf_file = HTML(string=html_string, base_url=request.build_absolute_uri("/")).write_pdf()
|
|
|
|
merger = PdfWriter()
|
|
merger.append(PdfReader(io.BytesIO(gen_pdf_file)))
|
|
|
|
root_path = Path(__file__).resolve().parent.parent
|
|
|
|
if ruta_medios is not None and bool(int(printpdfs)) :
|
|
for medio in reduce(getitem, ruta_medios[:-1], resource_data)[ruta_medios[-1]] :
|
|
if medio['formato'] == 'application/pdf' :
|
|
merger.append(PdfReader(f'{root_path}/uploadedfiles/{medio["file"]}'))
|
|
output_buffer = io.BytesIO()
|
|
merger.write(output_buffer)
|
|
merger.close()
|
|
else:
|
|
output_buffer = io.BytesIO()
|
|
merger.write(output_buffer)
|
|
merger.close()
|
|
|
|
response = HttpResponse(output_buffer.getvalue(), content_type='application/pdf')
|
|
response['Content-Disposition'] = f'attachment; filename="{nombre_pdf}.pdf"'
|
|
return response |