From edb2e21927649df757de85ab63cea5f09b4abd44 Mon Sep 17 00:00:00 2001 From: Francisco Sandoval Date: Sat, 13 Jan 2024 14:47:36 -0300 Subject: [PATCH] se agrega endpoint que procesa archivo zip --- docs/rest/upload.rest | 26 +++++++++ project/api/urls.py | 3 +- project/api/views/upload.py | 111 ++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 docs/rest/upload.rest create mode 100644 project/api/views/upload.py diff --git a/docs/rest/upload.rest b/docs/rest/upload.rest new file mode 100644 index 0000000..ddcbdba --- /dev/null +++ b/docs/rest/upload.rest @@ -0,0 +1,26 @@ + +@server = http://localhost:4000/api +@token = {{login.response.body.$.token}} + +### +# @name login +POST {{server}}/auth/ +Content-Type: application/json + +{ + "username": "usuario1", + "password": "usuario1" +} + +### +POST {{server}}/upload/zip/ +Authorization: Bearer {{token}} +Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW + +------WebKitFormBoundary7MA4YWxkTrZu0gW +Content-Disposition: form-data; name="filezip"; filename="Gran Concepción20230727.zip" +Content-Type: application/zip + +< ./Gran Concepción20230727.zip +------WebKitFormBoundary7MA4YWxkTrZu0gW-- +### diff --git a/project/api/urls.py b/project/api/urls.py index 700b560..a616f3b 100755 --- a/project/api/urls.py +++ b/project/api/urls.py @@ -6,7 +6,7 @@ from api.views import mapa, linea, letrero_lur, operador from api.views import paradero_imagen, linea_paradero from api.views import dispositivo from api.views import rol_linea -# from api.views import proto +from api.views import upload router = routers.DefaultRouter() router.register('aplicaciones', aplicacion.AplicacionViewSet) @@ -36,4 +36,5 @@ urlpatterns = [ path('mapas/paraderos/', mapa.paraderos, name='mapa-paraderos'), path('mapas/rutas/', mapa.rutas, name='mapa-rutas'), path('paraderos/info-public//', paradero.info_public, name='paradero-infopublic'), + path('upload/zip/', upload.upload_zip, name='upload_zip'), ] diff --git a/project/api/views/upload.py b/project/api/views/upload.py new file mode 100644 index 0000000..8eaf196 --- /dev/null +++ b/project/api/views/upload.py @@ -0,0 +1,111 @@ + +from django.views.decorators.csrf import csrf_exempt +from django.http import JsonResponse +from rest_framework.decorators import action +from django.db import connection +import tempfile +import threading +import time +import shutil +import logging +import zipfile +import os +import csv + + +@csrf_exempt +@action(detail=False, methods=['post']) +def upload_zip(request): + + if request.method == 'POST': + filezip = request.FILES['filezip'] + + if filezip.closed == False and hasattr(filezip,'temporary_file_path'): + hilo = threading.Thread(target=procesa_zip, args=(filezip,)) + hilo.start() + return JsonResponse({ + 'ok': True, + 'message': 'Procesando archivo zip' + }) + + return JsonResponse({ + 'ok': False, + 'message': 'Error en archivo zip enviado' + }) + +def procesa_zip(file_upload): + carpeta_destino = tempfile.gettempdir() + # shutil.copy(filezip.temporary_file_path(), carpeta_destino) + + # descomprimir archivo zip + archivo_zip = zipfile.ZipFile(file_upload.temporary_file_path(), "r") + password='' + try: + # Extraer todos los archivos del archivo ZIP + archivo_zip.extractall(pwd=password, path=carpeta_destino) + print("Archivos extraídos con éxito", flush=True) + except Exception as e: + print("Error al extraer archivos:", e, flush=True) + finally: + archivo_zip.close() + + # Lista de archivos GTFS para cargar en la base de datos + gtfs_files = [ + "agency.txt", + "calendar.txt", + "feed_info.txt", + "routes.txt", + "shapes.txt", + "stops.txt", + "stop_times.txt", + "trips.txt" + ] + + # Crear las tablas en el esquema y cargar los datos + cur = connection.cursor() + for file in gtfs_files: + filepath = os.path.join(carpeta_destino, file) + if os.path.exists(filepath): + create_and_load_table(filepath, file, cur) + os.remove(filepath) + + cur.close() + connection.commit() + + # for i in range(10): + # time.sleep(1) + # print('.', end='', flush=True) + + print('==============', flush=True) + print(f'fin proceso archivo: {archivo_zip}', flush=True) + + + +# Función para crear la definición de la tabla como texto y cargar los datos +def create_and_load_table(filepath, file_name, cursor): + with open(filepath, 'r', encoding='utf-8-sig') as file: + reader = csv.reader(file) + columns = next(reader) + + table_name = "z_"+file_name.replace('.txt', '') + column_definitions = ',\n'.join([f"{column_name} TEXT" for column_name in columns]) + + create_table = f"CREATE TABLE IF NOT EXISTS {table_name} (\n{column_definitions}\n);" + cursor.execute(create_table) + print(f'SQL> {create_table}', flush=True) + print('', flush=True) + + truncate_table = f"truncate table {table_name}; commit;" + cursor.execute(truncate_table) + print(f'SQL> {truncate_table}', flush=True) + print('', flush=True) + + file.seek(0) + next(reader) + + insert_query = f"COPY {table_name} ({', '.join(columns)}) FROM STDIN WITH CSV" + cursor.copy_expert(sql=insert_query, file=file) + print(f'SQL> {insert_query}', flush=True) + print('', flush=True) + + \ No newline at end of file