From db443c559d0628ca03ce1a9cdd1e5cf5124f5e0b Mon Sep 17 00:00:00 2001 From: guille Date: Thu, 23 Feb 2023 04:18:46 -0500 Subject: [PATCH] Little cosmetic changes and delete useless information. --- bootstrap.py | 14 -- hub_api/catalogs/construction_catalog.py | 195 ----------------------- hub_api/catalogs/greenery_catalog.py | 178 --------------------- hub_api/catalogs/usage_catalog.py | 156 ------------------ hub_api/city_info.py | 2 + hub_api/config.py | 6 +- hub_api/helpers/auth.py | 79 --------- hub_api/helpers/session_helper.py | 6 +- tests/base_test.py | 58 ------- tests/test_service.sh | 125 --------------- tests/test_user.py | 124 -------------- utils/__init__.py | 3 - utils/hp_simulator.py | 43 ----- utils/misc.py | 45 ------ 14 files changed, 8 insertions(+), 1026 deletions(-) delete mode 100644 hub_api/catalogs/construction_catalog.py delete mode 100644 hub_api/catalogs/greenery_catalog.py delete mode 100644 hub_api/catalogs/usage_catalog.py delete mode 100644 hub_api/helpers/auth.py delete mode 100644 tests/base_test.py delete mode 100755 tests/test_service.sh delete mode 100644 tests/test_user.py delete mode 100644 utils/__init__.py delete mode 100644 utils/hp_simulator.py delete mode 100644 utils/misc.py diff --git a/bootstrap.py b/bootstrap.py index c935428..2d455e5 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -15,9 +15,6 @@ from flask_restful import Api import threading import hub_api.helpers.session_helper as sh -from hub_api.catalogs.construction_catalog import ConstructionCatalogEntry, ConstructionCatalogEntries, ConstructionCatalogNames -from hub_api.catalogs.greenery_catalog import GreeneryCatalogEntry, GreeneryCatalogEntries, GreeneryCatalogNames -from hub_api.catalogs.usage_catalog import UsageCatalogEntry, UsageCatalogEntries, UsageCatalogNames from hub_api.session import SessionStart, SessionEnd, KeepSessionAlive from hub_api.uptime import Uptime @@ -29,17 +26,6 @@ api = Api(app) api.add_resource(Uptime, '/v1.4/uptime') -# Catalogs. -api.add_resource(GreeneryCatalogEntry, '/v1.4/greenery-catalog/entry') -api.add_resource(GreeneryCatalogEntries, '/v1.4/greenery-catalog/entries') -api.add_resource(GreeneryCatalogNames, '/v1.4/greenery-catalog/names') -api.add_resource(ConstructionCatalogEntry, '/v1.4/construction-catalog/entry') -api.add_resource(ConstructionCatalogEntries, '/v1.4/construction-catalog/entries') -api.add_resource(ConstructionCatalogNames, '/v1.4/construction-catalog/names') -api.add_resource(UsageCatalogEntry, '/v1.4/usage-catalog/entry') -api.add_resource(UsageCatalogEntries, '/v1.4/usage-catalog/entries') -api.add_resource(UsageCatalogNames, '/v1.4/usage-catalog/names') - # Session api.add_resource(SessionStart, '/v1.4/session/start') api.add_resource(SessionEnd, '/v1.4/session/end') diff --git a/hub_api/catalogs/construction_catalog.py b/hub_api/catalogs/construction_catalog.py deleted file mode 100644 index 82ca05e..0000000 --- a/hub_api/catalogs/construction_catalog.py +++ /dev/null @@ -1,195 +0,0 @@ -""" -Construction catalog -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Project Author name guillermo.gutierrezmorote@concordia.ca -""" - -import json - -from flask import request, Response -from flask_restful import Resource -from hub.catalog_factories.data_models.construction.archetype import Archetype -from hub.catalog_factories.data_models.construction.construction import Construction -from hub.catalog_factories.data_models.construction.material import Material -from hub.catalog_factories.data_models.construction.window import Window -from hub_api.helpers.session_helper import refresh_session -from hub_api.helpers.auth import role_required -from hub.persistence.models import UserRoles - - -class ToJson: - @staticmethod - def archetype_to_json(archetype): - constructions = [] - for construction in archetype.constructions: - constructions.append(ToJson.construction_to_json(construction)) - dictionary = { - 'name': archetype.name, - 'function': archetype.function, - 'construction_period': archetype.construction_period, - 'average_storey_height': archetype.average_storey_height, - 'thermal_capacity': archetype.thermal_capacity, - 'extra_loses_due_to_thermal_bridges': archetype.extra_loses_due_to_thermal_bridges, - 'indirect_heated_ratio': archetype.indirect_heated_ratio, - 'infiltration_rate_for_ventilation_system_off': archetype.infiltration_rate_for_ventilation_system_off, - 'infiltration_rate_for_ventilation_system_on': archetype.infiltration_rate_for_ventilation_system_on, - 'constructions': constructions - } - return dictionary - - @staticmethod - def construction_to_json(construction): - layers = [] - for layer in construction.layers: - layers.append(ToJson.layer_to_json(layer)) - dictionary = {'name': construction.name, - 'type': construction.type, - 'layers': layers - } - if construction.window is not None: - dictionary['window_ratio'] = construction.window_ratio - dictionary['window'] = ToJson.window_to_json(construction.window) - return dictionary - - @staticmethod - def window_to_json(window): - if window is None: - return {} - dictionary = { - 'name': window.name, - 'frame_ratio': window.frame_ratio, - 'g_value': window.g_value, - 'overall_u_value': str(window.overall_u_value) - } - return dictionary - - @staticmethod - def layer_to_json(layer): - dictionary = {'name': layer.name, - 'thickness': layer.thickness, - 'material': ToJson.material_to_json(layer.material), - } - return dictionary - - @staticmethod - def material_to_json(material): - dictionary = {'id': material.id, - 'name': material.name, - 'solar_absorptance': material.solar_absorptance, - 'thermal_absorptance': material.thermal_absorptance, - 'visible_absorptance': material.visible_absorptance, - 'no_mass': str(material.no_mass), - 'thermal_resistance': '', - 'conductivity': '', - 'density': '', - 'specific_heat': '' - } - if material.no_mass: - dictionary['thermal_resistance'] = material.thermal_resistance - else: - dictionary['conductivity'] = material.conductivity - dictionary['density'] = material.density - dictionary['specific_heat'] = material.specific_heat - return dictionary - - -class ConstructionCatalogEntry(Resource): - def __init__(self): - pass - - @role_required([UserRoles.Admin.value, UserRoles.Hub_Reader.value]) - def post(self): - session = refresh_session(request) - if session is None: - return Response(json.dumps({'error': 'invalid session'}), status=401) - headers = session.headers - catalog = session.construction_catalog - name = None - if request.data == b'' or request.json['name'] is None: - response = {'error': 'Mandatory parameter "name" is missing'} - return Response(json.dumps(response), headers=headers, status=400) - try: - name = request.json['name'] - entry = catalog.get_entry(name) - output = {} - if isinstance(entry, Archetype): - output['archetypes'] = ToJson.archetype_to_json(entry) - if isinstance(entry, Construction): - output['constructions'] = ToJson.construction_to_json(entry) - if isinstance(entry, Material): - output['materials'] = ToJson.material_to_json(entry) - if isinstance(entry, Window): - output['windows'] = ToJson.window_to_json(entry) - return Response(json.dumps(output), headers=headers) - except IndexError: - response = {'error': f'Name "{name}" unknown'} - return Response(json.dumps(response), headers=headers, status=400) - - -class ConstructionCatalogEntries(Resource): - def __init__(self): - pass - - @role_required([UserRoles.Admin.value, UserRoles.Hub_Reader.value]) - def post(self): - session = refresh_session(request) - if session is None: - return Response(json.dumps({'error': 'invalid session'}), status=401) - headers = session.headers - catalog = session.construction_catalog - category = None - if request.data != b'': - category = request.json['category'] - output = {} - if category is None: - output = {'archetypes': [], 'constructions':[], 'materials':[], 'windows':[]} - content = catalog.entries() - for archetype in content.archetypes: - output['archetypes'].append(ToJson.archetype_to_json(archetype)) - for construction in content.constructions: - output['constructions'].append(ToJson.construction_to_json(construction)) - for material in content.materials: - output['materials'].append(ToJson.material_to_json(material)) - for window in content.windows: - output['windows'].append(ToJson.window_to_json(window)) - else: - try: - output[category] = [] - content = catalog.entries(category) - for entry in content: - if isinstance(entry, Archetype): - output[category].append(ToJson.archetype_to_json(entry)) - if isinstance(entry, Construction): - output[category].append(ToJson.construction_to_json(entry)) - if isinstance(entry, Material): - output[category].append(ToJson.material_to_json(entry)) - if isinstance(entry, Window): - output[category].append(ToJson.window_to_json(entry)) - except ValueError: - output = {'error': f'Category "{category}" unknown'} - return Response(json.dumps(output), headers=headers, status=400) - return Response(json.dumps(output), headers=headers) - - -class ConstructionCatalogNames(Resource): - def __init__(self): - pass - - @staticmethod - def post(): - session = refresh_session(request) - if session is None: - return Response(json.dumps({'error': 'invalid session'}), status=401) - headers = session.headers - catalog = session.construction_catalog - category = None - if request.data != b'': - category = request.json['category'] - if category is None: - return Response(json.dumps(catalog.names()), headers=headers) - else: - try: - return Response(json.dumps(catalog.names(category)), headers=headers) - except ValueError: - response = {'error': f'Category "{category}" unknown'} - return Response(json.dumps(response), headers=headers, status=400) diff --git a/hub_api/catalogs/greenery_catalog.py b/hub_api/catalogs/greenery_catalog.py deleted file mode 100644 index f87345a..0000000 --- a/hub_api/catalogs/greenery_catalog.py +++ /dev/null @@ -1,178 +0,0 @@ -""" -Greenery catalog -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Project Author name guillermo.gutierrezmorote@concordia.ca -""" - -import json -from flask import request, Response -from flask_restful import Resource -from hub.catalog_factories.data_models.greenery.plant import Plant -from hub.catalog_factories.data_models.greenery.soil import Soil -from hub.catalog_factories.data_models.greenery.vegetation import Vegetation -from hub_api.helpers.session_helper import refresh_session - - -class ToJson: - @staticmethod - def plant_to_json(plant, percentage=None): - dictionary = { - 'plant_percentage': percentage, - 'plant_name': plant.name, - 'plant_category': plant.category, - 'plant_height': plant.height, - 'plant_leaf_area_index': plant.leaf_area_index, - 'plant_leaf_reflectivity': plant.leaf_reflectivity, - 'plant_leaf_emissivity': plant.leaf_emissivity, - 'plant_minimal_stomatal_resistance': plant.minimal_stomatal_resistance, - 'plant_co2_sequestration': plant.co2_sequestration, - 'plant_grows_on': [] - } - if percentage is None: - dictionary.pop('plant_percentage') - soils = [] - for soil in plant.grows_on: - soil_dic = ToJson.soil_to_json(soil) - soils.append(soil_dic) - dictionary['plant_grows_on'] = soils - return dictionary - - @staticmethod - def soil_to_json(soil): - dictionary = {'soil_name': soil.name, - 'soil_roughness': str(soil.roughness), - 'soil_dry_conductivity': soil.dry_conductivity, - 'soil_dry_density': soil.dry_density, - 'soil_dry_specific_heat': soil.dry_specific_heat, - 'soil_thermal_absortance': soil.thermal_absorptance, - 'soil_solar_absortance': soil.solar_absorptance, - 'soil_visible_absortance': soil.visible_absorptance, - 'soil_saturation_volumetric_moisture_content': soil.saturation_volumetric_moisture_content, - 'soil_residual_volumetric_moisture_content': soil.residual_volumetric_moisture_content, - 'soil_initial_volumetric_moisture_content': soil.initial_volumetric_moisture_content - } - return dictionary - - @staticmethod - def vegetation_to_json(vegetation): - - dictionary = {'vegetation_name': vegetation.name, - 'vegetation_category': vegetation.category, - 'soil_thickness': vegetation.soil_thickness, - 'management': str(vegetation.management), - 'air_gap': vegetation.air_gap, - 'soil_name': vegetation.soil_name, - 'soil_roughness': str(vegetation.soil_roughness), - 'dry_soil_conductivity': vegetation.dry_soil_conductivity, - 'dry_soil_density': vegetation.dry_soil_density, - 'dry_soil_specific_heat': vegetation.dry_soil_specific_heat, - 'soil_thermal_absorptance': vegetation.soil_thermal_absorptance, - 'soil_solar_absorptance': vegetation.soil_solar_absorptance, - 'soil_visible_absorptance': vegetation.soil_visible_absorptance, - 'soil_saturation_volumetric_moisture_content': vegetation.soil_saturation_volumetric_moisture_content, - 'soil_residual_volumetric_moisture_content': vegetation.soil_residual_volumetric_moisture_content, - 'soil_initial_volumetric_moisture_content': vegetation.soil_initial_volumetric_moisture_content, - 'plant_percentages': [] - } - percentages = [] - for percentage in vegetation.plant_percentages: - percentage_dic = ToJson.plant_to_json(percentage, percentage.percentage) - percentages.append(percentage_dic) - dictionary['plant_percentages'] = percentages - return dictionary - - -class GreeneryCatalogEntry(Resource): - def __init__(self): - pass - - @staticmethod - def post(): - session = refresh_session(request) - if session is None: - return Response(json.dumps({'error': 'invalid session'}), status=401) - headers = session.headers - catalog = session.greenery_catalog - name = None - if request.data == b'' or request.json['name'] is None: - response = {'error': 'Mandatory parameter "name" is missing'} - return Response(json.dumps(response), headers=headers, status=400) - try: - name = request.json['name'] - entry = catalog.get_entry(name) - output = {} - if isinstance(entry, Vegetation): - output['vegetations'] = ToJson.vegetation_to_json(entry) - if isinstance(entry, Plant): - output['plants'] = ToJson.plant_to_json(entry) - if isinstance(entry, Soil): - output['soils'] = ToJson.soil_to_json(entry) - return Response(json.dumps(output), headers=headers) - except IndexError: - response = {'error': f'Name "{name}" unknown'} - return Response(json.dumps(response), headers=headers, status=400) - - -class GreeneryCatalogEntries(Resource): - def __init__(self): - pass - - @staticmethod - def post(): - session = refresh_session(request) - if session is None: - return Response(json.dumps({'error': 'invalid session'}), status=401) - headers = session.headers - catalog = session.greenery_catalog - category = None - if request.data != b'': - category = request.json['category'] - output = {} - if category is None: - content = catalog.entries() - output = {'vegetations': [], 'plants': [], 'soils': []} - for vegetation in content.vegetations: - output['vegetations'].append(ToJson.vegetation_to_json(vegetation)) - for plant in content.plants: - output['plants'].append(ToJson.plant_to_json(plant)) - for soil in content.soils: - output['soils'].append(ToJson.soil_to_json(soil)) - else: - try: - content = catalog.entries(category) - output[category] = [] - for entry in content: - if isinstance(entry, Vegetation): - output[category].append(ToJson.vegetation_to_json(entry)) - if isinstance(entry, Plant): - output[category].append(ToJson.plant_to_json(entry)) - if isinstance(entry, Soil): - output[category].append(ToJson.soil_to_json(entry)) - except ValueError: - output = {'error': f'Category "{category}" unknown'} - return Response(json.dumps(output), headers=headers, status=400) - return Response(json.dumps(output), headers=headers) - - -class GreeneryCatalogNames(Resource): - def __init__(self): - pass - - @staticmethod - def post(): - session = refresh_session(request) - if session is None: - return Response(json.dumps({'error': 'invalid session'}), status=401) - headers = session.headers - catalog = session.greenery_catalog - category = None - if request.data != b'': - category = request.json['category'] - if category is None: - return Response(json.dumps(catalog.names()), headers=headers) - else: - try: - return Response(json.dumps(catalog.names(category)), headers=headers) - except ValueError: - response = {'error': f'Category "{category}" unknown'} - return Response(json.dumps(response), headers=headers, status=400) diff --git a/hub_api/catalogs/usage_catalog.py b/hub_api/catalogs/usage_catalog.py deleted file mode 100644 index 026df07..0000000 --- a/hub_api/catalogs/usage_catalog.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -Construction catalog -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Project Author name guillermo.gutierrezmorote@concordia.ca -""" - -import json - -from flask import request, Response -from flask_restful import Resource - -from hub_api.helpers.session_helper import refresh_session - - -class ToJson: - @staticmethod - def usage_to_json(usage): - dictionary = { - 'usage': usage.usage, - 'hours_day': usage.hours_day, - 'days_year': usage.days_year, - 'mechanical_air_change': usage.mechanical_air_change if usage.mechanical_air_change is not None else '', - 'ventilation_rate': usage.ventilation_rate if usage.ventilation_rate is not None else '', - 'occupancy': ToJson.occupancy_to_json(usage.occupancy), - 'lighting': ToJson.lighting_to_json(usage.lighting), - 'appliances': ToJson.appliances_to_json(usage.appliances), - 'thermal_control': ToJson.thermal_control_to_json(usage.thermal_control) - } - return dictionary - - @staticmethod - def occupancy_to_json(occupancy): - dictionary = { - 'occupancy_density': occupancy.occupancy_density, - 'sensible_convective_internal_gain': occupancy.sensible_convective_internal_gain, - 'sensible_radiative_internal_gain': occupancy.sensible_radiative_internal_gain, - 'latent_internal_gain': occupancy.latent_internal_gain, - 'schedules': [] - } - for schedule in occupancy.schedules: - dictionary['schedules'].append(ToJson.schedule_to_json(schedule)) - return dictionary - - @staticmethod - def lighting_to_json(lighting): - dictionary = { - 'density': lighting.density, - 'convective_fraction': lighting.convective_fraction, - 'radiative_fraction': lighting.radiative_fraction, - 'latent_fraction': lighting.latent_fraction, - 'schedules': [] - } - for schedule in lighting.schedules: - dictionary['schedules'].append(ToJson.schedule_to_json(schedule)) - return dictionary - - @staticmethod - def appliances_to_json(appliances): - dictionary = { - 'density': appliances.density, - 'convective_fraction': appliances.convective_fraction, - 'radiative_fraction': appliances.radiative_fraction, - 'latent_fraction': appliances.latent_fraction, - 'schedules': [] - } - for schedule in appliances.schedules: - dictionary['schedules'].append(ToJson.schedule_to_json(schedule)) - return dictionary - - @staticmethod - def thermal_control_to_json(thermal_control): - dictionary = { - 'mean_heating_set_point': thermal_control.mean_heating_set_point, - 'heating_set_back': thermal_control.heating_set_back, - 'mean_cooling_set_point': thermal_control.mean_cooling_set_point, - 'hvac_availability_schedules': [], - 'heating_set_point_schedules': [], - 'cooling_set_point_schedules': [], - } - for schedule in thermal_control.hvac_availability_schedules: - dictionary['hvac_availability_schedules'].append(ToJson.schedule_to_json(schedule)) - for schedule in thermal_control.heating_set_point_schedules: - dictionary['heating_set_point_schedules'].append(ToJson.schedule_to_json(schedule)) - for schedule in thermal_control.cooling_set_point_schedules: - dictionary['cooling_set_point_schedules'].append(ToJson.schedule_to_json(schedule)) - return dictionary - - @staticmethod - def schedule_to_json(schedule): - schedule_dictionary = { - 'type': schedule.type, - 'data_type': schedule.data_type, - 'time_step': schedule.time_step, - 'time_range': schedule.time_range, - 'day_types': schedule.day_types, - 'values': schedule.values, - } - return schedule_dictionary - - -class UsageCatalogEntry(Resource): - def __init__(self): - pass - - @staticmethod - def post(): - session = refresh_session(request) - if session is None: - return Response(json.dumps({'error': 'invalid session'}), status=401) - headers = session.headers - catalog = session.usage_catalog - - name = None - if request.data == b'' or request.json['name'] is None: - response = {'error': 'Mandatory parameter "name" is missing'} - return Response(json.dumps(response), headers=headers, status=400) - try: - name = request.json['name'] - entry = catalog.get_entry(name) - output = {'usages': [ToJson.usage_to_json(entry)]} - return Response(json.dumps(output), headers=headers) - except IndexError: - response = {'error': f'Name "{name}" unknown'} - return Response(json.dumps(response), headers=headers, status=400) - - -class UsageCatalogEntries(Resource): - def __init__(self): - pass - - @staticmethod - def post(): - session = refresh_session(request) - if session is None: - return Response(json.dumps({'error': 'invalid session'}), status=401) - headers = session.headers - catalog = session.usage_catalog - output = {'usages': []} - content = catalog.entries() - for usage in content.usages: - output['usages'].append(ToJson.usage_to_json(usage)) - return Response(json.dumps(output), headers=headers) - - -class UsageCatalogNames(Resource): - def __init__(self): - pass - - @staticmethod - def post(): - session = refresh_session(request) - if session is None: - return Response(json.dumps({'error': 'invalid session'}), status=401) - headers = session.headers - catalog = session.usage_catalog - return Response(json.dumps(catalog.names()), headers=headers) diff --git a/hub_api/city_info.py b/hub_api/city_info.py index e0f3f3d..4d9c53a 100644 --- a/hub_api/city_info.py +++ b/hub_api/city_info.py @@ -32,6 +32,8 @@ class CityInfo(Resource, Config): window_type = 'unknown' building_dic = {} for building in city.buildings: + for internal_zone in building.internal_zones: + poly = internal_zone.polyhedron usages = [] # This is only valid for dompark project as all the building have the same usage if building.lower_corner[2] == 0: diff --git a/hub_api/config.py b/hub_api/config.py index 8b697b3..90aa21c 100644 --- a/hub_api/config.py +++ b/hub_api/config.py @@ -3,12 +3,12 @@ Config SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2023 Project Peter Yefi peteryefi@gmail.com """ +import pickle from pathlib import Path +from hub.city_model_structure.city import City from hub.exports.db_factory import DBFactory as CityExportFactory from hub.imports.db_factory import DBFactory -import os -import pickle class Config: @@ -23,7 +23,7 @@ class Config: self.import_db_factory = DBFactory(db_name=database_name, app_env=environment, dotenv_path=dotenv_path) - def get_city(self, city_id): + def get_city(self, city_id) -> City: city_obj = self.export_db_factory.get_city(city_id) city = pickle.loads(city_obj.city) for building in city.buildings: diff --git a/hub_api/helpers/auth.py b/hub_api/helpers/auth.py deleted file mode 100644 index 0a04845..0000000 --- a/hub_api/helpers/auth.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -HeatPump Service -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2023 Project Author Peter Yefi peteryefi@gmail.com -""" - -from datetime import datetime, timedelta, timezone -from typing import Dict -from jwt import JWT, jwk_from_pem -import os -from jwt.utils import get_int_from_datetime -from functools import wraps -from flask import request, g -from hub.hub_logger import logger -from hub.persistence.models import UserRoles -from jwt.exceptions import JWTException - -instance = JWT() - - -def generate_auth_token(user: Dict): - private_key = "{}/rsa.pem".format(os.path.expanduser('~')) - with open(private_key, 'rb') as fh: - signing_key = jwk_from_pem(fh.read()) - user['exp'] = get_int_from_datetime(datetime.now(timezone.utc) + timedelta(hours=24)) - user['iat'] = get_int_from_datetime(datetime.now(timezone.utc)) - return instance.encode(user, signing_key, alg='RS256') - - -def validate_auth_token(token: str): - public_key = "{}/rsa.pub".format(os.path.expanduser('~')) - with open(public_key, 'rb') as fh: - verifying_key = jwk_from_pem(fh.read()) - return instance.decode(token, verifying_key, do_time_check=True) - - -def role_required(roles: [str]): - def auth_module(user): - g.user = user - for role in roles: - if role == user['role']: - return True - return False - - """ - A wrapper to authorize specific roles for specific endpoints - :param roles: a list of roles allowed - :return: - """ - - def role_decorator(f): - @wraps(f) - def wrapper(*args, **kwargs): - try: - token = request.headers['Authorization'].split()[1] - user = validate_auth_token(token) - if user is None: - return {'messages': 'You have not been authenticated'}, 401 - allowed = auth_module(user['user']) - if user['user']['role'] == UserRoles.Admin.value and 'localhost' not in request.headers['Host']: - allowed = False - if not allowed: - return {'messages': 'You are not authorized'}, 403 - return f(*args, **kwargs) - except KeyError as err: - # logger Error - logger.error(err) - return {'messages': 'Invalid payload'}, 400 - except JWTException as err: - logger.error(err) - return {'messages': 'Invalid token'}, 401 - except Exception as err: - logger.error(err) - return {'messages': 'Sorry, an error occurred while processing your request'}, 500 - - return wrapper - - return role_decorator - diff --git a/hub_api/helpers/session_helper.py b/hub_api/helpers/session_helper.py index 50e79fc..cb69ca0 100644 --- a/hub_api/helpers/session_helper.py +++ b/hub_api/helpers/session_helper.py @@ -57,8 +57,8 @@ class SessionData: def session_garbage_collector(session_timeout_duration): - #loop through all sessions and remove expired sessions - while(True): + # loop through all sessions and remove expired sessions + while True: if bool(sessions): for session in list(sessions): _expire = datetime.datetime.strptime(sessions[session]['expire'], '%Y-%m-%d %H:%M:%S.%f') @@ -73,7 +73,7 @@ def _validate_session(session_id, token, application_uuid): if bool(sessions[session_id]) and sessions[session_id]['token'] == token and \ sessions[session_id]['application_uuid'] == application_uuid: return True - except: + except KeyError: return False diff --git a/tests/base_test.py b/tests/base_test.py deleted file mode 100644 index 627aef1..0000000 --- a/tests/base_test.py +++ /dev/null @@ -1,58 +0,0 @@ -import os -from unittest import TestCase -from bootstrap import app -from hub.persistence.base_repo import BaseRepo -from sqlalchemy import create_engine -from hub.persistence.models import City -from hub.persistence.models import User -from sqlalchemy.exc import ProgrammingError - - -# function to ensure tests run in order shown in fle -def arrange(): - order = {} - - def ordered(f): - order[f.__name__] = len(order) - return f - - def compare(a, b): - return [1, -1][order[a] < order[b]] - - return ordered, compare - - -class BaseTest(TestCase): - """ - Tests for payment resource - """ - - @classmethod - def setUpClass(cls): - os.environ['FLASK_DEBUG'] = 'testing' - cls.app = app - cls.client = cls.app.test_client() - - # Create test database - repo = BaseRepo(db_name='test_db', app_env='TEST', dotenv_path="{}/.env".format(os.path.expanduser('~'))) - eng = create_engine(f'postgresql://{repo.config.get_db_user()}@/{repo.config.get_db_user()}') - - try: - # delete test database if it exists - conn = eng.connect() - conn.execute('commit') - conn.execute('DROP DATABASE test_db') - conn.close() - except ProgrammingError as err: - print(f'Database does not exist. Nothing to delete') - - cnn = eng.connect() - cnn.execute('commit') - cnn.execute("CREATE DATABASE test_db") - cnn.close() - User.__table__.create(bind=repo.engine, checkfirst=True) - City.__table__.create(bind=repo.engine, checkfirst=True) - - @classmethod - def tearDownClass(cls) -> None: - pass diff --git a/tests/test_service.sh b/tests/test_service.sh deleted file mode 100755 index 8845ad1..0000000 --- a/tests/test_service.sh +++ /dev/null @@ -1,125 +0,0 @@ -#!/bin/bash -clear -printf 'Uptime:\n' -curl -i -X GET http://127.0.0.1:15789/v1.3/uptime -printf '\n\nSession start:\n' -curl -i -X PUT -H "Session: {'session_id': 'debug'}" http://127.0.0.1:15789/v1.3/session/start - -printf '\n\nRepeat session start:\n' -curl -i -X PUT -H "Session: {'session_id': 'debug'}" http://127.0.0.1:15789/v1.3/session/start - -printf '\n\nKeep session alive:\n' -curl -i -X PUT -H "Session: {'session_id': 'debug', 'token': 'debug'}" http://127.0.0.1:15789/v1.3/session/keep_alive - -printf '\n\nCity info:\n' -curl -i -X GET -H "Session: {'session_id': 'debug', 'token': 'debug'}" http://127.0.0.1:15789/v1.3/city_info - -printf '\n\nGreenery catalog entry without parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery-catalog/entry - -printf '\n\nGreenery catalog entry with wrong parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"name": "non_existing_name"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery-catalog/entry - -printf '\n\nGreenery catalog entry with correct parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"name": "grass"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery-catalog/entry - -printf '\n\nGreenery catalog names without parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery-catalog/names - -printf '\n\nGreenery catalog names with wrong parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"category": "non_existing_name"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery-catalog/names - -printf '\n\nGreenery catalog names with correct parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"category": "soils"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery-catalog/names - -printf '\n\nGreenery catalog entries without parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery-catalog/entries - -printf '\n\nGreenery catalog entries with wrong parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"category": "non_existing_category"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery-catalog/entries - -printf '\n\nGreenery catalog entries with correct parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"category": "vegetations"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery-catalog/entries - -printf '\n\nGeometry:\n' -curl -i -X GET -H "Session: {'session_id': 'debug', 'token': 'debug'}" http://127.0.0.1:15789/v1.3/geometry - -printf '\n\nHeat Pump:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"BuildingSuppTemp": 40, "EndYear": 2016, "FuelDensity": 0.717, "FuelEF": 1887, "FuelLHV": 47100, "FuelPrice": 0.3, "HPSupTemp": 60, "HeatPumpModel": "012", "HeatPumpType": "Air Source HP", "HoursOfStorageAtMaxDemand": 1, "MaximumHPEnergyInput": 8000, "SimType": 0, "StartYear": 2015, "TemperatureDifference": 15 }' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/heat-pump - -printf '\n\Material LCA Catalog:\n' -curl -i -X GET -H "Session: {'session_id': 'debug', 'token': 'debug'}" http://127.0.0.1:15789/v1.3/material_lca_catalog/entries - -printf '\n\Material LCA Calculations:\n' -curl -i -X GET -H "Session: {'session_id': 'debug', 'token': 'debug'}" http://127.0.0.1:15789/v1.3/material_lca_catalog/calculations - -printf '\n\nConstruction catalog entry without parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction-catalog/entry - -printf '\n\nConstruction catalog entry with wrong parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"name": "non_existing_name"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction-catalog/entry - -printf '\n\nConstruction catalog entry with correct parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"name": "189.1-2009 Nonres 4B Ext Wall Mass"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction-catalog/entry - -printf '\n\nConstruction catalog names without parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction-catalog/names - -printf '\n\nConstruction catalog names with wrong parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"category": "non_existing_name"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction-catalog/names - -printf '\n\nConstruction catalog names with correct parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"category": "materials"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction-catalog/names - -printf '\n\nConstruction catalog entries without parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction-catalog/entries - -printf '\n\nConstruction catalog entries with wrong parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"category": "non_existing_category"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction-catalog/entries - -printf '\n\nConstruction catalog entries with correct parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"category": "archetypes"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction-catalog/entries - -printf '\n\nSet Construction without building names:\n' -curl -i -X PUT -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"extra_loses_due_to_thermal_bridges":"0.15","indirect_heated_ratio":"0.15","infiltration_rate_for_ventilation_system_off":"0.5","infiltration_rate_for_ventilation_system_on":"0","constructions":[{"type":"Wall","layers":[{"thickness":"0.0253","material":{"solar_absorptance":"0.92","thermal_absorptance":"0.9","visible_absorptance":"0.92","no_mass":"False","thermal_resistance":"","conductivity":"0.6918","density":"1858","specific_heat":"837"}},{"thickness":"0.2033","material":{"solar_absorptance":"0.65","thermal_absorptance":"0.9","visible_absorptance":"0.65","no_mass":"False","thermal_resistance":"","conductivity":"1.7296","density":"2243","specific_heat":"837"}},{"thickness":"0.0338606","material":{"solar_absorptance":"0.5","thermal_absorptance":"0.9","visible_absorptance":"0.5","no_mass":"False","thermal_resistance":"","conductivity":"0.0432","density":"91","specific_heat":"837"}},{"thickness":"0.01271","material":{"solar_absorptance":"0.92","thermal_absorptance":"0.9","visible_absorptance":"0.92","no_mass":"False","thermal_resistance":"","conductivity":"0.16","density":"784.9","specific_heat":"830"}}],"window":{"frame_ratio":"0","g_value":"0.36","overall_u_value":"4.491833333333333"}},{"type":"Ground","layers":[{"thickness":"0.1016","material":{"solar_absorptance":"0.7","thermal_absorptance":"0.9","visible_absorptance":"0.7","no_mass":"False","thermal_resistance":"","conductivity":"1.311","density":"2240","specific_heat":"836.8"}},{"thickness":0,"material":{"solar_absorptance":"0.7","thermal_absorptance":"0.9","visible_absorptance":"0.8","no_mass":"True","thermal_resistance":"0.21648","conductivity":"","density":"","specific_heat":""}}]},{"type":"Roof","layers":[{"thickness":"0.0178","material":{"solar_absorptance":"0.78","thermal_absorptance":"0.9","visible_absorptance":"0.78","no_mass":"False","thermal_resistance":"","conductivity":"0.115","density":"513","specific_heat":"1255"}},{"thickness":"0.0254","material":{"solar_absorptance":"0.78","thermal_absorptance":"0.9","visible_absorptance":"0.78","no_mass":"False","thermal_resistance":"","conductivity":"0.1211","density":"593","specific_heat":"2510"}},{"thickness":"0.221604","material":{"solar_absorptance":"0.7","thermal_absorptance":"0.9","visible_absorptance":"0.7","no_mass":"False","thermal_resistance":"","conductivity":"0.049","density":"265","specific_heat":"836.8"}},{"thickness":"0.01271","material":{"solar_absorptance":"0.92","thermal_absorptance":"0.9","visible_absorptance":"0.92","no_mass":"False","thermal_resistance":"","conductivity":"0.16","density":"784.9","specific_heat":"830"}}],"window":{"frame_ratio":"0","g_value":"0.36","overall_u_value":"4.491833333333333"}}]}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction - -printf '\n\nSet Construction:\n' -curl -i -X PUT -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"building_names":["Dompark"], "extra_loses_due_to_thermal_bridges":"0.15","indirect_heated_ratio":"0.15","infiltration_rate_for_ventilation_system_off":"0.5","infiltration_rate_for_ventilation_system_on":"0","constructions": [{"name": "189.1-2009 Res 4B Ext Wall Steel-Framed", "type": "Wall", "layers": [{"name": "Layer 1", "thickness": 0, "material": {"id": "12", "name": "MAT-SHEATH", "solar_absorptance": "0.7", "thermal_absorptance": "0.9", "visible_absorptance": "0.7", "no_mass": "True", "thermal_resistance": "0.36256", "conductivity": "", "density": "", "specific_heat": ""}}, {"name": "Layer 2", "thickness": "0.118387", "material": {"id": "3", "name": "Floor Insulation [4]", "solar_absorptance": "0.7", "thermal_absorptance": "0.9", "visible_absorptance": "0.7", "no_mass": "False", "thermal_resistance": "", "conductivity": "0.045", "density": "265", "specific_heat": "836.8"}}, {"name": "Layer 3", "thickness": "0.01271", "material": {"id": "7", "name": "1/2IN Gypsum", "solar_absorptance": "0.92", "thermal_absorptance": "0.9", "visible_absorptance": "0.92", "no_mass": "False", "thermal_resistance": "", "conductivity": "0.16", "density": "784.9", "specific_heat": "830"}}], "window_ratio": "0.3", "window": {"name": "189.1-2009 Nonres 4B Window Nonmetal framing", "frame_ratio": "0", "g_value": "0.35", "overall_u_value": "2.379966666666667"}}, {"name": "189.1-2009 Nonres 4B Ext Slab Unheated - 4in Slab with Carpet", "type": "Ground", "layers": [{"name": "Layer 1", "thickness": "0.1016", "material": {"id": "1", "name": "MAT-CC05 8 HW CONCRETE", "solar_absorptance": "0.7", "thermal_absorptance": "0.9", "visible_absorptance": "0.7", "no_mass": "False", "thermal_resistance": "", "conductivity": "1.311", "density": "2240", "specific_heat": "836.8"}}, {"name": "Layer 2", "thickness": 0, "material": {"id": "16", "name": "CP02 CARPET PAD", "solar_absorptance": "0.7", "thermal_absorptance": "0.9", "visible_absorptance": "0.8", "no_mass": "True", "thermal_resistance": "0.21648", "conductivity": "", "density": "", "specific_heat": ""}}]}, {"name": "189.1-2009 Nonres 4B Roof IEAD", "type": "Roof", "layers": [{"name": "Layer 1", "thickness": "0.0095", "material": {"id": "15", "name": "Roof Membrane", "solar_absorptance": "0.7", "thermal_absorptance": "0.9", "visible_absorptance": "0.7", "no_mass": "False", "thermal_resistance": "", "conductivity": "0.16", "density": "1121.29", "specific_heat": "1460"}}, {"name": "Layer 2", "thickness": "0.210538", "material": {"id": "11", "name": "Roof Insulation [23]", "solar_absorptance": "0.7", "thermal_absorptance": "0.9", "visible_absorptance": "0.7", "no_mass": "False", "thermal_resistance": "", "conductivity": "0.049", "density": "265", "specific_heat": "836.8"}}, {"name": "Layer 3", "thickness": "0.001524", "material": {"id": "14", "name": "Metal Decking", "solar_absorptance": "0.7", "thermal_absorptance": "0.9", "visible_absorptance": "0.3", "no_mass": "False", "thermal_resistance": "", "conductivity": "45.006", "density": "7680", "specific_heat": "418.4"}}]}]}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/construction - -printf '\n\nEnergy Demand:\n' -curl -i -X GET -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/energy-demand - -printf '\n\nUsage catalog entry without parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/usage-catalog/entry - -printf '\n\nUsage catalog entry with wrong parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"name": "non_existing_name"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/usage-catalog/entry - -printf '\n\nUsage catalog entry with correct parameter:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"name": "BA Automotive Facility"}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/usage-catalog/entry - -printf '\n\nUsage catalog names:\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/usage-catalog/names - -printf '\n\nUsage catalog entries :\n' -curl -i -X POST -H "Session: {'session_id': 'debug', 'token': 'debug'}" -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/usage-catalog/entries - -printf '\n\nSet Greenery with missing parameters:\n' -curl -i -X PUT --header "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"vegetation": {"vegetation_name": "Grass", "soil_thickness": "0.2", "air_gap": "0.0", "soil_name": "Loamy sand", "soil_roughness": "MediumRough", "dry_soil_conductivity": "0.35", "dry_soil_density": "1100", "dry_soil_specific_heat": "1200", "soil_thermal_absorptance": "0.9", "soil_solar_absorptance": "0.7", "soil_visible_absorptance": "0.75", "soil_saturation_volumetric_moisture_content": "0.41", "soil_residual_volumetric_moisture_content": "0.057", "plant_percentages": [{"plant_percentage": "100", "plant_name": "Lawn", "plant_height": "0.06", "plant_leaf_area_index": "1.4", "plant_leaf_reflectivity": "0.1", "plant_leaf_emissivity": "0.9", "plant_minimal_stomatal_resistance": "50", "plant_co2_sequestration": "0", "plant_grows_on": [{"soil_name": "Loam", "soil_roughness": "MediumRough", "soil_dry_conductivity": "0.67", "soil_dry_density": "1100", "soil_dry_specific_heat": "900", "soil_thermal_absortance": "0.9", "soil_solar_absortance": "0.7", "soil_visible_absortance": "0.75", "soil_saturation_volumetric_moisture_content": "0.43", "soil_residual_volumetric_moisture_content": "0.078", "soil_initial_volumetric_moisture_content": "0.1"}]}]}}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery - -printf '\n\nSet Greenery:\n' -curl -i -X PUT --header "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"building_names":["Dompark"], "greenery_percentage":"30", "vegetation": {"vegetation_name": "Grass", "soil_thickness": "0.2", "air_gap": "0.0", "soil_name": "Loamy sand", "soil_roughness": "MediumRough", "dry_soil_conductivity": "0.35", "dry_soil_density": "1100", "dry_soil_specific_heat": "1200", "soil_thermal_absorptance": "0.9", "soil_solar_absorptance": "0.7", "soil_visible_absorptance": "0.75", "soil_saturation_volumetric_moisture_content": "0.41", "soil_residual_volumetric_moisture_content": "0.057", "plant_percentages": [{"plant_percentage": "100", "plant_name": "Lawn", "plant_height": "0.06", "plant_leaf_area_index": "1.4", "plant_leaf_reflectivity": "0.1", "plant_leaf_emissivity": "0.9", "plant_minimal_stomatal_resistance": "50", "plant_co2_sequestration": "0", "plant_grows_on": [{"soil_name": "Loam", "soil_roughness": "MediumRough", "soil_dry_conductivity": "0.67", "soil_dry_density": "1100", "soil_dry_specific_heat": "900", "soil_thermal_absortance": "0.9", "soil_solar_absortance": "0.7", "soil_visible_absortance": "0.75", "soil_saturation_volumetric_moisture_content": "0.43", "soil_residual_volumetric_moisture_content": "0.078", "soil_initial_volumetric_moisture_content": "0.1"}]}]}}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/greenery - -printf '\n\nSet Usages with missing parameters:\n' -curl -i -X PUT --header "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"building_names":["Dompark"],"usages":[{"name": "BA Convention Center"}, {"name": "BA Multifamily", "percentage": "0.2"}, {"name": "BA Office", "percentage": "0.75"}]}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/usage - -printf '\n\nSet Usages:\n' -curl -i -X PUT --header "Session: {'session_id': 'debug', 'token': 'debug'}" -d '{"building_names":["Dompark"],"usages":[{"name": "BA Convention Center", "percentage": "0.05"}, {"name": "BA Multifamily", "percentage": "0.2"}, {"name": "BA Office", "percentage": "0.75"}]}' -H "Content-Type: application/json" http://127.0.0.1:15789/v1.3/usage - -printf '\n\nSession end:\n' -curl -i -X PUT -H "Session: {'session_id': 'debug', 'token': 'debug'}" http://127.0.0.1:15789/v1.3/session/end - -printf '\n\nRepeat session end:\n' -curl -i -X PUT -H "Session: {'session_id': 'debug', 'token': 'debug'}" http://127.0.0.1:15789/v1.3/session/end - -printf '\n' diff --git a/tests/test_user.py b/tests/test_user.py deleted file mode 100644 index 0993b24..0000000 --- a/tests/test_user.py +++ /dev/null @@ -1,124 +0,0 @@ -import json -from .base_test import BaseTest, arrange -import unittest -from hub_api.helpers.auth import generate_auth_token - -ordered, compare = arrange() -unittest.defaultTestLoader.sortTestMethodsUsing = compare - - -class UserTest(BaseTest): - """ - Tests for User API endpoints - """ - - @classmethod - def setUpClass(cls): - # Call setUp from parent - super().setUpClass() - cls.user_dict = {"user": { - "name": "Test User", - "email": "testuser@gmail.com", - "password": "TestUser@12345", - "role": "Admin", - }} - cls.token = generate_auth_token(cls.user_dict) - - @ordered - def test_create_user_by_non_admin(self): - # When - res = self.client.post('/v1.4/user', data=json.dumps(self.user_dict['user'])) - # Then - self.assertEqual('Invalid payload', res.json['messages']) - self.assertEqual(400, res.status_code) - - - @ordered - def test_create_user_by_admin(self): - # When - res = self.client.post('/v1.4/user', - headers={ - 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + str(self.token) - }, - data=json.dumps(self.user_dict['user'])) - # Then - user = res.json - self.assertEqual(201, res.status_code) - self.assertEqual(type(user['user']), dict) - self.assertEqual(user['user']['email'], self.user_dict['user']['email']) - self.assertEqual(user['user']['role'], self.user_dict['user']['role']) - - @ordered - def test_create_user_with_existing_email(self): - # When - res = self.client.post('/v1.4/user', - headers={ - 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + str(self.token) - }, - data=json.dumps(self.user_dict['user'])) - # Then - self.assertEqual('user with testuser@gmail.com email already exists', res.json['message']) - self.assertEqual(400, res.status_code) - - @ordered - def test_create_user_with_weak_password(self): - # When - self.user_dict['user']['password'] = '1234' - self.user_dict['user']['email'] = 'new@gmail.com' - res = self.client.post('/v1.4/user', - headers={ - 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + str(self.token) - }, - data=json.dumps(self.user_dict['user'])) - # Then - self.assertEqual('Sorry an error occurred while creating user', res.json['err_msg']) - self.assertEqual(400, res.status_code) - - - @ordered - def test_login_user_with_wrong_credential(self): - # When - res = self.client.post('/v1.4/user/login', - headers={ - 'Content-Type': 'application/json' - }, - data=json.dumps({'email': 'wrong@gmail.com', 'password': 'wrong'})) - - # Then - message = res.json - self.assertEqual('user not found', message['message']) - self.assertEqual(400, res.status_code) - - @ordered - def test_login_user_with_correct_credential(self): - # When - self.user_dict['user']['password'] = 'TestUser@12345' - self.user_dict['user']['email'] = 'testuser@gmail.com' - login_data = { - "email": self.user_dict['user']['email'], - "password": self.user_dict['user']['password'] - } - res = self.client.post('/v1.4/user/login', headers={'Content-Type': 'application/json'}, - data=json.dumps(login_data)) - - # Then - user = res.json - self.assertEqual(user['user']['email'], self.user_dict['user']['email']) - self.assertEqual(user['user']['role'], self.user_dict['user']['role']) - self.assertIsNotNone(user['token']) - self.assertEqual(200, res.status_code) - - @classmethod - def tearDownClass(cls) -> None: - # Call tearDown from parent - super().tearDownClass() - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTest(unittest.TestLoader( - ).loadTestsFromTestCase(UserTest)) - - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/utils/__init__.py b/utils/__init__.py deleted file mode 100644 index 311bf12..0000000 --- a/utils/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .misc import validate_hp_model -from .hp_simulator import HeatPumpSimulator -from .misc import expand_energy_demand diff --git a/utils/hp_simulator.py b/utils/hp_simulator.py deleted file mode 100644 index 342c563..0000000 --- a/utils/hp_simulator.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -HeatPumpSimulator: Module for running simulations -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Project Author Peter Yefi peteryefi@gmail.com -""" -from pathlib import Path -from typing import Dict - -from exports.energy_systems_factory import EnergySystemsExportFactory -from imports.energy_systems_factory import EnergySystemsFactory - - -class HeatPumpSimulator: - - def __init__(self, city, user_input: Dict): - """ - :param user_input: the user parameters for running simulation - """ - - - self._user_input = user_input - self._hp_type = user_input['HeatPumpType'].replace(" ", "_").lower() - # file to have results after simulation is run - self._city = city - EnergySystemsFactory(user_input['HeatPumpType'].lower(), self._city).enrich() - - def run_hp_simulation(self) -> str: - """ - Runs heat pump simulation and dumps output - in self._output_path - :return: None - """ - hp_type = 'water' if 'water' in self._hp_type else 'air' - del self._user_input['HeatPumpType'] - del self._user_input['EnergyDemand'] - model = self._user_input.pop('HeatPumpModel') - energy_demand_path = Path(Path(__file__).parent.parent / "data/energy_demand.txt") - return EnergySystemsExportFactory(city=self._city, - user_input=self._user_input, - hp_model=model, - output_path=None, - sim_type=self._user_input['SimType'], - demand_path=energy_demand_path).export(hp_type) diff --git a/utils/misc.py b/utils/misc.py deleted file mode 100644 index 0f23955..0000000 --- a/utils/misc.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Miscellaneous -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Project Author Peter Yefi peteryefi@gmail.com -""" -from typing import List -from pathlib import Path -import numpy as np - - -hp_models = { - 'air_source': ['012', '015', '018', '023', '030', '033', '037', '044', '047', '057', '070', '087', '097', '102', - '120', '130', '140'], - 'water_to_water': ['ClimateMaster 156 kW', 'ClimateMaster 256 kW', 'ClimateMaster 335 kW'] -} - - -def validate_hp_model(hp_type: str, model: str) -> bool: - """ - Validates the HP model parameter provided by users - for running insel simulation - :param hp_type: the type of heat pump: air source or - water to water - :param model: the model of heat pump - :return: bool - """ - if 'air' in hp_type.lower(): - if model in hp_models['air_source']: - return True - elif 'water' in hp_type.lower(): - if model in hp_models['water_to_water']: - return True - return False - - -def expand_energy_demand(hourly_energy_demand: List[float]): - """ - Replicates each value in the list 11 times and persist the values to a file - :param hourly_energy_demand: a list of hourly energy demand data - """ - energy_demand = Path(Path(__file__).parent.parent / "data/energy_demand.txt") - with open(energy_demand, 'w') as demand_file: - repeated_demand_values = np.repeat(hourly_energy_demand, 12).tolist() - for demand in repeated_demand_values: - demand_file.write("%.6f\n" % demand) \ No newline at end of file