From bb0bd4d31fd7a276afb807001db2cf19f2a7584d Mon Sep 17 00:00:00 2001 From: Guille Date: Fri, 14 Jun 2024 06:37:01 +0200 Subject: [PATCH] Add glb workflow --- bootstrap.py | 2 + hub_api/workflow/glb.py | 105 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 hub_api/workflow/glb.py diff --git a/bootstrap.py b/bootstrap.py index a340ea6..27138f1 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -22,6 +22,7 @@ from hub_api.persistence.retrofit_results import RetrofitResults from hub_api.workflow.insel_montly_energy_balance import InselMonthlyEnergyBalance from hub_api.workflow.costs import Costs from hub_api.workflow.energy_plus import EnergyPlus +from hub_api.workflow.glb import Glb from hub_api.energy_plus.idf_generator import IdfGenerator from hub_api.config import Config @@ -48,6 +49,7 @@ api.add_resource(IdfGenerator, '/v1.4/energy-plus/idf-generator') # workflows api.add_resource(Costs, '/v1.4/workflow/costs') api.add_resource(EnergyPlus, '/v1.4/workflow/energy-plus') +api.add_resource(Glb, '/v1.4/workflow/glb') api.add_resource(InselMonthlyEnergyBalance, '/v1.4/workflow/insel-monthly-energy-balance') yml_path = Path('./docs/openapi-specs.yml').resolve() diff --git a/hub_api/workflow/glb.py b/hub_api/workflow/glb.py new file mode 100644 index 0000000..51a8870 --- /dev/null +++ b/hub_api/workflow/glb.py @@ -0,0 +1,105 @@ +import glob +import json +import os +import shutil +import zipfile +from pathlib import Path + +from flask import Response, request, send_file, make_response +from flask_restful import Resource +from hub.exports.exports_factory import ExportsFactory +from hub.imports.geometry_factory import GeometryFactory +from werkzeug.utils import secure_filename + +from hub_api.config import Config +from hub_api.helpers.session_helper import refresh_session + + +class Glb(Resource, Config): + def __init__(self): + super().__init__() + self._extensions = ['.geojson', '.gml'] + self._tmp_path = (Path(__file__).parent / 'tmp').resolve() + self._response_path = (Path(__file__).parent.parent / 'response_files').resolve() + self._city = None + + def _allowed_extensions(self, filename): + self._file_extension = Path(filename).suffix + return self._file_extension in self._extensions + + def _geojson(self, file_path): + try: + height_field = request.form.get('height_field') + year_of_construction_field = request.form.get('year_of_construction_field') + function_field = request.form.get('function_field') + function_dictionary = self._dictionaries[request.form.get('function_to_hub')] + return GeometryFactory('geojson', + path=file_path, + height_field=height_field, + year_of_construction_field=year_of_construction_field, + function_field=function_field, + function_to_hub=function_dictionary).city + except KeyError: + return None + + def _citygml(self, file_path): + try: + year_of_construction_field = request.form.get('year_of_construction_field') + function_field = request.form.get('function_field') + function_dictionary = self._dictionaries[request.form.get('function_dictionary_name')] + hub_crs = request.form.get('hub_crs') + return GeometryFactory('citygml', + path=file_path, + year_of_construction_field=year_of_construction_field, + function_field=function_field, + function_to_hub=function_dictionary, + hub_crs=hub_crs).city + except KeyError: + return None + + def post(self): + """ + API call for performing the monthly energy balance workflow + """ + session_id = request.headers.get('session-id', None) + token = request.headers.get('token', None) + application_uuid = request.headers.get('application-uuid', None) + _session = refresh_session(session_id, token, application_uuid) + if _session is None: + return Response(json.dumps({'error': 'unauthorized'}), status=403) + else: + response_token = {'token': _session['token']} + tmp_path = (self._tmp_path / token).resolve() + response_path = (self._response_path / session_id).resolve() + try: + os.mkdir(tmp_path) + except FileExistsError: + pass + try: + os.mkdir(response_path) + except FileExistsError: + pass + geometry_file = request.files['geometry_file'] + if not self._allowed_extensions(geometry_file.filename): + shutil.rmtree(tmp_path) + return Response(json.dumps({'error': 'Unsupported media type'}), status=415, headers=response_token) + filename = secure_filename(geometry_file.filename) + file_path = os.path.join(tmp_path, filename) + geometry_file.save(file_path) + if self._file_extension == '.geojson': + self._city = self._geojson(file_path) + else: + self._city = self._citygml(file_path) + if self._city is None: + shutil.rmtree(tmp_path) + return Response(json.dumps({'error': 'Bad request'}), status=400, headers=response_token) + ExportsFactory('glb', self._city, tmp_path).export() + result_files = glob.glob(f'{tmp_path}/*.glb') + result_zip = (response_path / f'{token}.zip').resolve() + with zipfile.ZipFile(result_zip, 'w') as zf: + for result_file in result_files: + zf.write(result_file, Path(result_file).name) + shutil.rmtree(tmp_path) + response = make_response(send_file(result_zip)) + response.headers['token'] = token + return response