Partial correction of persistence
This commit is contained in:
parent
10623cc466
commit
5978757348
@ -74,7 +74,7 @@ from hub.persistence import DBSetup
|
||||
from pathlib import Path
|
||||
|
||||
dotenv_path = (Path(__file__).parent / '.env').resolve()
|
||||
DBSetup(db_name='hub_db', app_env='PROD', dotenv_path=dotenv_path)
|
||||
DBSetup(db_name='hub_db', app_env='PROD', dotenv_path=dotenv_path, admin_password="your password here", application_uuid="your admin application uuid")
|
||||
```
|
||||
The *DBSetUp* class also creates a default admin user with default credentials that can be changed.
|
||||
with the import UserFactory class. The admin user (name, email, password and role) is logged into the console after it is created by the
|
||||
|
@ -34,7 +34,7 @@ class Building(CityObject):
|
||||
self._roof_type = None
|
||||
self._internal_zones = None
|
||||
self._shell = None
|
||||
self._human_readable_name = None
|
||||
self._alias = None
|
||||
self._type = 'building'
|
||||
self._heating = dict()
|
||||
self._cooling = dict()
|
||||
@ -404,16 +404,16 @@ class Building(CityObject):
|
||||
return False
|
||||
|
||||
@property
|
||||
def human_readable_name(self):
|
||||
def alias(self):
|
||||
"""
|
||||
Get the human-readable name for the building
|
||||
Get the alias name for the building
|
||||
:return: str
|
||||
"""
|
||||
return self._human_readable_name
|
||||
return self._alias
|
||||
|
||||
@human_readable_name.setter
|
||||
def human_readable_name(self, value):
|
||||
@alias.setter
|
||||
def alias(self, value):
|
||||
"""
|
||||
Set the human-readable name for the building
|
||||
Set the alias name for the building
|
||||
"""
|
||||
self._human_readable_name = value
|
||||
self._alias = value
|
||||
|
@ -11,20 +11,6 @@ import re
|
||||
|
||||
class Auth(object):
|
||||
|
||||
@staticmethod
|
||||
def validate_password(password: str) -> bool:
|
||||
"""
|
||||
Validates a password
|
||||
:param password: the password to validate
|
||||
:return:
|
||||
"""
|
||||
pattern = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!#%*?&]{6,20}$"
|
||||
pattern = re.compile(pattern)
|
||||
if not re.search(pattern, password):
|
||||
raise ValueError("Password must be between 6 to 20 characters and must have at least a number, an uppercase "
|
||||
"letter, a lowercase letter, and a special character")
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def hash_password(password: str) -> str:
|
||||
"""
|
||||
|
@ -7,14 +7,15 @@ from hub.persistence.models import UserRoles
|
||||
from hub.persistence.models import Application
|
||||
from hub.persistence.models import UserApplications
|
||||
from hub.persistence.repositories import UserRepo
|
||||
from hub.persistence.repositories import ApplicationRepo
|
||||
from hub.hub_logger import logger
|
||||
|
||||
|
||||
class DBSetup:
|
||||
|
||||
def __init__(self, db_name, app_env, dotenv_path):
|
||||
def __init__(self, db_name, app_env, dotenv_path, admin_password, application_uuid):
|
||||
"""
|
||||
Creates database tables and a default admin user
|
||||
Creates database tables a default admin user and a default admin app with the given password and uuid
|
||||
:param db_name:
|
||||
:param app_env:
|
||||
:param dotenv_path:
|
||||
@ -26,17 +27,30 @@ class DBSetup:
|
||||
UserApplications.__table__.create(bind=repo.engine, checkfirst=True)
|
||||
HeatPumpSimulation.__table__.create(bind=repo.engine, checkfirst=True)
|
||||
self._user_repo = UserRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
|
||||
self._create_admin_user(self._user_repo)
|
||||
self._application_repo = ApplicationRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
|
||||
self._create_admin_user(self._user_repo, admin_password)
|
||||
self._create_admin_app(self._application_repo, application_uuid)
|
||||
|
||||
@staticmethod
|
||||
def _create_admin_user(user_repo):
|
||||
email = 'admin@hub.com'
|
||||
password = 'HubAdmin#!98'
|
||||
def _create_admin_app(application_repo, application_uuid):
|
||||
name = 'AdminTool'
|
||||
description = 'Admin tool to control city persistence and to test the API v1.4'
|
||||
print('Creating default admin tool application...')
|
||||
application = application_repo.insert(name, description, application_uuid)
|
||||
if type(application) is dict:
|
||||
logger.info(application)
|
||||
else:
|
||||
msg = f'Created Admin tool with application_uuid: {application_uuid}'
|
||||
print(msg)
|
||||
logger.info(msg)
|
||||
|
||||
@staticmethod
|
||||
def _create_admin_user(user_repo, admin_password, application_id):
|
||||
password = admin_password
|
||||
print('Creating default admin user...')
|
||||
user = user_repo.insert('Administrator', email, password, UserRoles.Admin)
|
||||
user = user_repo.insert('Administrator', password, UserRoles.Admin, application_id)
|
||||
if type(user) is dict:
|
||||
logger.info(user)
|
||||
else:
|
||||
print(f'Created Admin user with email: {email}, password: {password} and role: {UserRoles.Admin.value}')
|
||||
logger.info(f'Created Admin user with email: {email}, password: {password} and role: {UserRoles.Admin.value}')
|
||||
print('Remember to change the admin default password and email address with the UserFactory')
|
||||
print(f'Created Admin user')
|
||||
logger.info(f'Created Admin user')
|
@ -5,3 +5,4 @@ from .heat_pump_simulation import HeatPumpTypes
|
||||
from .user import User, UserRoles
|
||||
from .user_applications import UserApplications
|
||||
from .application import Application
|
||||
from .city_object import CityObject
|
||||
|
@ -7,6 +7,7 @@ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
||||
|
||||
import datetime
|
||||
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy import Column, Integer, String, Sequence
|
||||
from sqlalchemy import DateTime
|
||||
|
||||
@ -21,9 +22,11 @@ class Application(Base):
|
||||
id = Column(Integer, Sequence('application_id_seq'), primary_key=True)
|
||||
name = Column(String, nullable=False)
|
||||
description = Column(String, nullable=False)
|
||||
application_uuid = Column(UUID(as_uuid=True), nullable=False)
|
||||
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
|
||||
def __init__(self, name, description):
|
||||
def __init__(self, name, description, application_uuid):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.application_uuid = application_uuid
|
||||
|
@ -5,13 +5,12 @@ Copyright © 2022 Concordia CERC group
|
||||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey
|
||||
from sqlalchemy import DateTime, PickleType, Float
|
||||
from hub.persistence.db_config import Base
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
import datetime
|
||||
import numpy as np
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey
|
||||
from sqlalchemy import DateTime, PickleType
|
||||
|
||||
from hub.persistence.db_config import Base
|
||||
|
||||
|
||||
class City(Base):
|
||||
@ -21,28 +20,19 @@ class City(Base):
|
||||
id = Column(Integer, Sequence('city_id_seq'), primary_key=True)
|
||||
city = Column(PickleType, nullable=False)
|
||||
name = Column(String, nullable=False)
|
||||
srs_name = Column(String, nullable=False)
|
||||
climate_reference_city = Column(String, nullable=True)
|
||||
time_zone = Column(String, nullable=True)
|
||||
country_code = Column(String, nullable=False)
|
||||
latitude = Column(Float)
|
||||
longitude = Column(Float)
|
||||
lower_corner = Column(JSONB, nullable=False)
|
||||
upper_corner = Column(JSONB, nullable=False)
|
||||
level_of_detail = Column(Integer, nullable=False)
|
||||
climate_file = Column(String, nullable=False)
|
||||
application_id = Column(Integer, ForeignKey('application.id'), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey('user.id'), nullable=True)
|
||||
hub_release = Column(String, nullable=False)
|
||||
city_version = Column(Integer, nullable=False)
|
||||
user_id = Column(Integer, ForeignKey('user.id'))
|
||||
user = relationship("User", back_populates="cities")
|
||||
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
|
||||
def __init__(self, city, name, srs_name, country_code, l_corner, u_corner, user_id):
|
||||
def __init__(self, city, name, level_of_detail, climate_file, application_id, user_id, hub_release):
|
||||
self.city = city
|
||||
self.user_id = user_id
|
||||
self.name = name
|
||||
self.srs_name = srs_name
|
||||
self.country_code = country_code
|
||||
l_corner = l_corner.tolist() if type(l_corner) == np.ndarray else l_corner
|
||||
u_corner = u_corner.tolist() if type(u_corner) == np.ndarray else u_corner
|
||||
self.lower_corner = l_corner
|
||||
self.upper_corner = u_corner
|
||||
self.level_of_detail = level_of_detail
|
||||
self.climate_file = climate_file
|
||||
self.application_id = application_id
|
||||
self.user_id = user_id
|
||||
self.hub_release = hub_release
|
||||
|
44
hub/persistence/models/city_object.py
Normal file
44
hub/persistence/models/city_object.py
Normal file
@ -0,0 +1,44 @@
|
||||
"""
|
||||
Model representation of a city object
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float
|
||||
from sqlalchemy import DateTime
|
||||
|
||||
from hub.persistence.db_config import Base
|
||||
|
||||
|
||||
class CityObject(Base):
|
||||
"""
|
||||
A model representation of an application
|
||||
"""
|
||||
__tablename__ = "city_object"
|
||||
id = Column(Integer, Sequence('application_id_seq'), primary_key=True)
|
||||
city_id = Column(Integer, ForeignKey('city.id'), nullable=False)
|
||||
name = Column(String, nullable=False)
|
||||
alias = Column(String, nullable=True)
|
||||
type = Column(String, nullable=False)
|
||||
year_of_construction = Column(Integer, nullable=True)
|
||||
function = Column(String, nullable=True)
|
||||
usage = Column(String, nullable=True)
|
||||
volume = Column(Float, nullable=False)
|
||||
area = Column(Float, nullable=False)
|
||||
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
|
||||
def __init__(self, city_id, name, alias, object_type, year_of_construction, function, usage, volume, area):
|
||||
self.city_id = city_id
|
||||
self.name = name
|
||||
self.alias = alias
|
||||
self.type = object_type
|
||||
self.year_of_construction = year_of_construction
|
||||
self.function = function
|
||||
self.usage = usage
|
||||
self.volume = volume
|
||||
self.area = area
|
||||
|
@ -1,83 +0,0 @@
|
||||
"""
|
||||
Model representation of the results of heat pump simulation
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Sequence
|
||||
from sqlalchemy import Enum, ForeignKey, Float, DateTime
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from hub.persistence.db_config import Base
|
||||
import enum
|
||||
import datetime
|
||||
|
||||
|
||||
class SimulationTypes(enum.Enum):
|
||||
Parallel = 'PARALLEL'
|
||||
Series = 'SERIES'
|
||||
|
||||
|
||||
class HeatPumpTypes(enum.Enum):
|
||||
Air = 'Air Source'
|
||||
Water = 'Water to Water'
|
||||
|
||||
|
||||
class HeatPumpSimulation(Base):
|
||||
"""A model representation of a building
|
||||
|
||||
Attributes:
|
||||
city_id, A reference to the city which was used to run this simulation.
|
||||
hourly_electricity_demand, A JSON object that has hours and their electricity demand
|
||||
daily_electricity_demand, A JSON object that has days and their electricity demand
|
||||
monthly_electricity_demand, A JSON object that has months and their electricity demand
|
||||
daily_fossil_fuel_consumption, A JSON object that has days and fossil fuel consumption
|
||||
monthly_fossil_fuel_consumption, A JSON object that has months and fossil fuel consumption
|
||||
heat_pump_type, Water or air heat pump
|
||||
simulation_type, The type of heat pump simulation (parallel or series)
|
||||
heat_pump_model, The model of the heat pump (either water to water or air source)
|
||||
start year, HP simulation start year
|
||||
end year, HP simulation end year
|
||||
max_hp_energy_input, Maximum heat pump energy input
|
||||
max_demand_storage_hour, Hours of storage at maximum demand
|
||||
building_supply_temp, building supply temperature
|
||||
temp_difference, Difference in HP and building supply temperatures
|
||||
fuel_lhv, The lower heating value of fuel
|
||||
fuel_price, The price of fuel
|
||||
fuel_efficiency, the efficiency of fuel
|
||||
fuel_density, the density of fuel
|
||||
hp_supply_temp, supply temperature of heat pump
|
||||
|
||||
|
||||
"""
|
||||
__tablename__ = "heat_pump_simulation"
|
||||
id = Column(Integer, Sequence('hp_simulation_id_seq'), primary_key=True)
|
||||
city_id = Column(Integer, ForeignKey('city.id'), nullable=False)
|
||||
daily_electricity_demand = Column(JSONB, nullable=False)
|
||||
hourly_electricity_demand = Column(JSONB, nullable=False)
|
||||
daily_fossil_fuel_consumption = Column(JSONB, nullable=False)
|
||||
monthly_fossil_fuel_consumption = Column(JSONB, nullable=False)
|
||||
monthly_electricity_demand = Column(JSONB, nullable=False)
|
||||
heat_pump_type = Column(Enum(HeatPumpTypes), nullable=False)
|
||||
simulation_type = Column(Enum(SimulationTypes), nullable=False)
|
||||
heat_pump_model = Column(String, nullable=False)
|
||||
start_year = Column(Integer, nullable=False)
|
||||
end_year = Column(Integer, nullable=False)
|
||||
max_hp_energy_input = Column(Float, nullable=False)
|
||||
max_demand_storage_hour = Column(Float, nullable=False)
|
||||
building_supply_temp = Column(Float, nullable=False)
|
||||
temp_difference = Column(Float, nullable=False)
|
||||
fuel_lhv = Column(Float, nullable=False)
|
||||
fuel_price = Column(Float, nullable=False)
|
||||
fuel_efficiency = Column(Float, nullable=False)
|
||||
fuel_density = Column(Float, nullable=False)
|
||||
hp_supply_temp = Column(Float, nullable=False)
|
||||
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
|
||||
def __init__(self, city_id, hourly_elec_demand, daily_elec_demand, monthly_elec_demand, daily_fossil, monthly_fossil):
|
||||
self.city_id = city_id
|
||||
self.hourly_electricity_demand = hourly_elec_demand
|
||||
self.daily_electricity_demand = daily_elec_demand
|
||||
self.monthly_electricity_demand = monthly_elec_demand
|
||||
self.daily_fossil_fuel_consumption = daily_fossil
|
||||
self.monthly_fossil_fuel_consumption = monthly_fossil
|
34
hub/persistence/models/simulation_results.py
Normal file
34
hub/persistence/models/simulation_results.py
Normal file
@ -0,0 +1,34 @@
|
||||
"""
|
||||
Model representation of simulation results
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float
|
||||
from sqlalchemy import DateTime
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
|
||||
from hub.persistence.db_config import Base
|
||||
|
||||
|
||||
class CityObject(Base):
|
||||
"""
|
||||
A model representation of an application
|
||||
"""
|
||||
__tablename__ = "simulation_results"
|
||||
id = Column(Integer, Sequence('application_id_seq'), primary_key=True)
|
||||
city_id = Column(Integer, ForeignKey('city.id'), nullable=True)
|
||||
city_object_id = Column(Integer, ForeignKey('city_object.id'), nullable=True)
|
||||
name = Column(String, nullable=False)
|
||||
values = Column(JSONB, nullable=False)
|
||||
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
|
||||
def __init__(self, name, values, city_id=None, city_object_id=None):
|
||||
self.name = name
|
||||
self.values = values
|
||||
self.city_id = city_id
|
||||
self.city_object_id = city_object_id
|
@ -26,22 +26,14 @@ class User(Base):
|
||||
__tablename__ = "user"
|
||||
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
|
||||
name = Column(String, nullable=False)
|
||||
email = Column(String, nullable=False, unique=True)
|
||||
password = Column(String, nullable=False)
|
||||
role = Column(Enum(UserRoles), nullable=False, default=UserRoles.Hub_Reader)
|
||||
cities = relationship("City", back_populates="user")
|
||||
application_id = Column(Integer, nullable=False)
|
||||
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
|
||||
@validates("email")
|
||||
def validate_email(self, key, address):
|
||||
pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
|
||||
if not re.match(pattern, address):
|
||||
raise ValueError("failed simple email validation")
|
||||
return address
|
||||
|
||||
def __init__(self, name, email, password, role):
|
||||
def __init__(self, name, password, role, application_id):
|
||||
self.name = name
|
||||
self.email = email
|
||||
self.password = password
|
||||
self.role = role
|
||||
self.application_id = application_id
|
||||
|
@ -1,30 +0,0 @@
|
||||
"""
|
||||
Model representation of the user applications
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
from sqlalchemy import Column, Integer, ForeignKey, PrimaryKeyConstraint
|
||||
from sqlalchemy import DateTime
|
||||
|
||||
from hub.persistence.db_config import Base
|
||||
|
||||
|
||||
class UserApplications(Base):
|
||||
"""
|
||||
A model representation of the user applications
|
||||
"""
|
||||
__tablename__ = "user_applications"
|
||||
user_id = Column(Integer, ForeignKey('user.id'))
|
||||
application_id = Column(Integer, ForeignKey('application.id'))
|
||||
|
||||
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
__table_args__ = (PrimaryKeyConstraint(user_id, application_id),)
|
||||
|
||||
def __init__(self, user_id, application_id):
|
||||
self.user_id = user_id
|
||||
self.application_id = application_id
|
@ -1 +1,2 @@
|
||||
from .user_repo import UserRepo
|
||||
from .application_repo import ApplicationRepo
|
||||
|
84
hub/persistence/repositories/application_repo.py
Normal file
84
hub/persistence/repositories/application_repo.py
Normal file
@ -0,0 +1,84 @@
|
||||
"""
|
||||
Application repository with database CRUD operations
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
||||
"""
|
||||
|
||||
import datetime
|
||||
from typing import Union, Dict
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from hub.hub_logger import logger
|
||||
from hub.persistence import BaseRepo
|
||||
from hub.persistence.models import Application
|
||||
|
||||
|
||||
class ApplicationRepo(BaseRepo):
|
||||
_instance = None
|
||||
|
||||
def __init__(self, db_name: str, dotenv_path: str, app_env: str):
|
||||
super().__init__(db_name, dotenv_path, app_env)
|
||||
|
||||
def __new__(cls, db_name, dotenv_path, app_env):
|
||||
"""
|
||||
Implemented for a singleton pattern
|
||||
"""
|
||||
if cls._instance is None:
|
||||
cls._instance = super(ApplicationRepo, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def insert(self, name: str, description: str, application_uuid: str) -> Union[Application, Dict]:
|
||||
application = self.get_by_uuid(application_uuid)
|
||||
if application is None:
|
||||
try:
|
||||
application = Application(name=name, description=description, application_uuid=application_uuid)
|
||||
self.session.add(application)
|
||||
self.session.flush()
|
||||
self.session.commit()
|
||||
return application
|
||||
except SQLAlchemyError as err:
|
||||
logger.error(f'An error occurred while creating application: {err}')
|
||||
else:
|
||||
return {'message': f'An application with {application_uuid} application uuid, already exists'}
|
||||
|
||||
def update(self, application_uuid: str, name: str, description: str) -> Union[Dict, None]:
|
||||
"""
|
||||
Updates an application
|
||||
:param application_uuid: the application uuid of the application to be updated
|
||||
:param name: the application name
|
||||
:param description: the application description
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
self.session.query(Application).filter(Application.application_uuid == application_uuid) \
|
||||
.update({'name': name, 'description': description, 'updated': datetime.datetime.utcnow()})
|
||||
self.session.commit()
|
||||
except SQLAlchemyError as err:
|
||||
logger.error(f'Error while updating application: {err}')
|
||||
return {'err_msg': 'Error occurred while updating application'}
|
||||
|
||||
def get_by_uuid(self, application_uuid: str) -> [Application]:
|
||||
"""
|
||||
Fetch Application based on the application uuid
|
||||
:param application_uuid: the application uuid
|
||||
:return: [Application] with the provided application_uuid
|
||||
"""
|
||||
try:
|
||||
return self.session.execute(select(Application).where(Application.application_uuid == application_uuid)).first()
|
||||
except SQLAlchemyError as err:
|
||||
logger.error(f'Error while fetching application by application_uuid: {err}')
|
||||
|
||||
def delete_application(self, application_uuid: str):
|
||||
"""
|
||||
Deletes an application with the application_uuid
|
||||
:param application_uuid: The application uuid
|
||||
:return: None
|
||||
"""
|
||||
try:
|
||||
self.session.query(Application).filter(Application.application_uuid == application_uuid).delete()
|
||||
self.session.commit()
|
||||
except SQLAlchemyError as err:
|
||||
logger.error(f'Error while deleting application: {err}')
|
@ -5,17 +5,18 @@ Copyright © 2022 Concordia CERC group
|
||||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from hub.city_model_structure.city import City
|
||||
from hub.persistence import BaseRepo
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy import select
|
||||
from hub.persistence.models import City as DBCity
|
||||
import pickle
|
||||
import requests
|
||||
from urllib3.exceptions import HTTPError
|
||||
from typing import Union, Dict
|
||||
from hub.hub_logger import logger
|
||||
import datetime
|
||||
import pickle
|
||||
from typing import Union, Dict
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from hub.city_model_structure.city import City
|
||||
from hub.hub_logger import logger
|
||||
from hub.persistence import BaseRepo
|
||||
from hub.persistence.models import City as DBCity
|
||||
from hub.version import __version__
|
||||
|
||||
|
||||
class CityRepo(BaseRepo):
|
||||
@ -32,44 +33,25 @@ class CityRepo(BaseRepo):
|
||||
cls._instance = super(CityRepo, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def insert(self, city: City, user_id: int) -> Union[City, Dict]:
|
||||
db_city = DBCity(pickle.dumps(city), city.name, city.srs_name, city.country_code, city.lower_corner,
|
||||
city.upper_corner, user_id)
|
||||
db_city.climate_reference_city = city.climate_reference_city
|
||||
db_city.longitude = city.longitude
|
||||
db_city.latitude = city.latitude
|
||||
db_city.time_zone = city.time_zone
|
||||
|
||||
def insert(self, city: City, application_id, user_id: int) -> Union[City, Dict]:
|
||||
"""
|
||||
Insert a city
|
||||
:param city: The complete city instance
|
||||
:param application_id: Application id owning the instance
|
||||
:param user_id: User id owning the instance
|
||||
:return: City and Dictionary
|
||||
"""
|
||||
try:
|
||||
# Retrieve hub project latest release
|
||||
response = requests.get("https://rs-loy-gitlab.concordia.ca/api/v4/projects/2/repository/branches/master",
|
||||
headers={"PRIVATE-TOKEN": self.config.hub_token})
|
||||
recent_commit = response.json()["commit"]["id"]
|
||||
logger.info(f'Current commit of hub is {recent_commit}')
|
||||
exiting_city = self._get_by_hub_version(recent_commit, city.name)
|
||||
release = __version__
|
||||
db_city = DBCity(pickle.dumps(city), city.name, city.level_of_detail, city.climate_file, application_id, user_id,
|
||||
release)
|
||||
|
||||
# Do not persist the same city for the same version of Hub
|
||||
if exiting_city is None:
|
||||
db_city.hub_release = recent_commit
|
||||
cities = self.get_by_name(city.name)
|
||||
# update version for the same city but different hub versions
|
||||
|
||||
if len(cities) == 0:
|
||||
db_city.city_version = 0
|
||||
else:
|
||||
db_city.city_version = cities[-1].city_version + 1
|
||||
|
||||
# Persist city
|
||||
self.session.add(db_city)
|
||||
self.session.flush()
|
||||
self.session.commit()
|
||||
return db_city
|
||||
else:
|
||||
return {'message': f'Same version of {city.name} exist'}
|
||||
self.session.add(db_city)
|
||||
self.session.flush()
|
||||
self.session.commit()
|
||||
return db_city
|
||||
except SQLAlchemyError as err:
|
||||
logger.error(f'Error while adding city: {err}')
|
||||
except HTTPError as err:
|
||||
logger.error(f'Error retrieving Hub latest release: {err}')
|
||||
logger.error(f'An error occurred while creating city: {err}')
|
||||
|
||||
def get_by_id(self, city_id: int) -> DBCity:
|
||||
"""
|
||||
@ -82,16 +64,16 @@ class CityRepo(BaseRepo):
|
||||
except SQLAlchemyError as err:
|
||||
logger.error(f'Error while fetching city: {err}')
|
||||
|
||||
def _get_by_hub_version(self, hub_commit: str, city_name: str) -> City:
|
||||
def _get_by_hub_version(self, hub_release: str, city_name: str) -> City:
|
||||
"""
|
||||
Fetch a City based on the name and hub project recent commit
|
||||
:param hub_commit: the latest hub commit
|
||||
Fetch a City based on the name and hub project
|
||||
:param hub_release: the hub release
|
||||
:param city_name: the name of the city
|
||||
:return: a city
|
||||
"""
|
||||
try:
|
||||
return self.session.execute(select(DBCity)
|
||||
.where(DBCity.hub_release == hub_commit, DBCity.name == city_name)).first()
|
||||
.where(DBCity.hub_release == hub_release, DBCity.name == city_name)).first()
|
||||
except SQLAlchemyError as err:
|
||||
logger.error(f'Error while fetching city: {err}')
|
||||
|
||||
|
@ -30,16 +30,15 @@ class UserRepo(BaseRepo):
|
||||
cls._instance = super(UserRepo, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def insert(self, name: str, email: str, password: str, role: UserRoles) -> Union[User, Dict]:
|
||||
user = self.get_by_email(email)
|
||||
def insert(self, name: str, password: str, role: UserRoles, application_id: int) -> Union[User, Dict]:
|
||||
user = self.get_by_name_and_application(name, application_id)
|
||||
if user is None:
|
||||
try:
|
||||
if Auth.validate_password(password):
|
||||
user = User(name=name, email=email, password=Auth.hash_password(password), role=role)
|
||||
self.session.add(user)
|
||||
self.session.flush()
|
||||
self.session.commit()
|
||||
return user
|
||||
user = User(name=name, password=Auth.hash_password(password), role=role, application_id=application_id)
|
||||
self.session.add(user)
|
||||
self.session.flush()
|
||||
self.session.commit()
|
||||
return user
|
||||
except SQLAlchemyError as err:
|
||||
logger.error(f'An error occurred while creating user: {err}')
|
||||
else:
|
||||
|
1
hub/version.py
Normal file
1
hub/version.py
Normal file
@ -0,0 +1 @@
|
||||
__version__ = '0.1.7.3'
|
@ -4,49 +4,5 @@
|
||||
requires = ["setuptools>=61.0.0", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "cerc_hub"
|
||||
version = "0.1.7.3"
|
||||
description = "CERC Hub consist in a set of classes (Central data model), importers and exporters to help researchers to create better and sustainable cities"
|
||||
readme = "README.md"
|
||||
authors = [{ name = "Guillermo Gutierrez", email = "Guillermo.GutierrezMorote@concordia.ca" }]
|
||||
license = { file = "LICENSE.md" }
|
||||
classifiers = [
|
||||
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
]
|
||||
keywords = ["city", "hub", "cerc"]
|
||||
dependencies = [
|
||||
"xmltodict",
|
||||
"numpy",
|
||||
"trimesh",
|
||||
"pyproj",
|
||||
"pandas",
|
||||
"requests",
|
||||
"esoreader",
|
||||
"geomeppy",
|
||||
"PyWavefront",
|
||||
"xlrd",
|
||||
"openpyxl",
|
||||
"networkx",
|
||||
"parseidf==1.0.0",
|
||||
"ply",
|
||||
"rhino3dm==7.7.0",
|
||||
"scipy",
|
||||
"PyYAML",
|
||||
"pyecore==0.12.2",
|
||||
"python-dotenv",
|
||||
"SQLAlchemy",
|
||||
"bcrypt==4.0.1",
|
||||
"shapely",
|
||||
"geopandas",
|
||||
"triangle"
|
||||
]
|
||||
requires-python = ">=3.9"
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = ["pip-tools", "pytest"]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://rs-loy-gitlab.concordia.ca/Guille/hub"
|
||||
[options.packages.find_namespace]
|
||||
where = "hub"
|
106
setup.py
106
setup.py
@ -1,32 +1,90 @@
|
||||
from setuptools import setup, find_packages
|
||||
from setuptools import setup, find_packages, convert_path
|
||||
import os.path
|
||||
import glob
|
||||
|
||||
main_ns = {}
|
||||
version = convert_path('hub/version.py')
|
||||
with open(version) as f:
|
||||
exec(f.read(), main_ns)
|
||||
|
||||
setup(
|
||||
name='hub',
|
||||
version="0.1",
|
||||
packages=find_packages(exclude="unittests"),
|
||||
name='cerc-hub',
|
||||
version=main_ns['__version__'],
|
||||
description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help researchers "
|
||||
"to create better and sustainable cities",
|
||||
long_description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help "
|
||||
"researchers to create better and sustainable cities",
|
||||
classifiers=[
|
||||
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
],
|
||||
include_package_data=True,
|
||||
packages=['hub',
|
||||
'hub.catalog_factories',
|
||||
'hub.catalog_factories.construction',
|
||||
'hub.catalog_factories.data_models',
|
||||
'hub.catalog_factories.data_models.construction',
|
||||
'hub.catalog_factories.data_models.greenery',
|
||||
'hub.catalog_factories.data_models.usages',
|
||||
'hub.catalog_factories.greenery',
|
||||
'hub.catalog_factories.greenery.ecore_greenery',
|
||||
'hub.catalog_factories.usage',
|
||||
'hub.city_model_structure',
|
||||
'hub.city_model_structure.attributes',
|
||||
'hub.city_model_structure.building_demand',
|
||||
'hub.city_model_structure.energy_systems',
|
||||
'hub.city_model_structure.greenery',
|
||||
'hub.city_model_structure.iot',
|
||||
'hub.city_model_structure.transport',
|
||||
'hub.config',
|
||||
'hub.data',
|
||||
'hub.exports',
|
||||
'hub.exports.building_energy',
|
||||
'hub.exports.building_energy.idf_files',
|
||||
'hub.exports.building_energy.insel',
|
||||
'hub.exports.energy_systems',
|
||||
'hub.exports.formats',
|
||||
'hub.helpers',
|
||||
'hub.hub_logger',
|
||||
'hub.imports',
|
||||
'hub.imports.construction',
|
||||
'hub.imports.construction.helpers',
|
||||
'hub.imports.construction.data_classes',
|
||||
'hub.imports.energy_systems',
|
||||
'hub.imports.geometry',
|
||||
'hub.imports.geometry.citygml_classes',
|
||||
'hub.imports.geometry.helpers',
|
||||
'hub.imports.usage',
|
||||
'hub.imports.weather',
|
||||
'hub.imports.weather.helpers',
|
||||
'hub.persistence',
|
||||
'hub.persistence.models',
|
||||
'hub.persistence.repositories',
|
||||
'hub.imports'
|
||||
],
|
||||
data_files=[
|
||||
('config', [os.path.join('hub/config', 'configuration.ini')]),
|
||||
('greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')),
|
||||
('data', glob.glob('hub/data/construction/*.xml')),
|
||||
('data', glob.glob('hub/data/customized_imports/*.xml')),
|
||||
('data', glob.glob('hub/data/energy_systems/*.xml')),
|
||||
('data', glob.glob('hub/data/energy_systems/*.insel')),
|
||||
('data', glob.glob('hub/data/energy_systems/*.xlsx')),
|
||||
('data', glob.glob('hub/data/energy_systems/*.txt')),
|
||||
('data', glob.glob('hub/data/energy_systems/*.yaml')),
|
||||
('data', glob.glob('hub/data/greenery/*.xml')),
|
||||
('data', glob.glob('hub/data/life_cycle_assessment/*.xml')),
|
||||
('data', glob.glob('hub/data/schedules/*.xml')),
|
||||
('data', glob.glob('hub/data/schedules/*.xlsx')),
|
||||
('data', glob.glob('hub/data/schedules/idf_files/*.idf')),
|
||||
('data', glob.glob('hub/data/sensors/*.json')),
|
||||
('data', glob.glob('hub/data/usage/*.xml')),
|
||||
('data', glob.glob('hub/data/usage/*.xlsx')),
|
||||
('data', glob.glob('hub/data/weather/*.dat')),
|
||||
('data', glob.glob('hub/data/weather/epw/*.epw')),
|
||||
('data', glob.glob('hub/data/weather/*.dat'))
|
||||
('hub/config', glob.glob('hub/config/*.ini')),
|
||||
('hub/catalog_factories/greenery/ecore_greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')),
|
||||
('hub/data/construction.', glob.glob('hub/data/construction/*.xml')),
|
||||
('hub/data/customized_imports/', glob.glob('hub/data/customized_imports/*.xml')),
|
||||
('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.xml')),
|
||||
('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.insel')),
|
||||
('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.xlsx')),
|
||||
('hub/data/energy_systems/*', glob.glob('hub/data/energy_systems/*.txt')),
|
||||
('hub/data/energy_systems/*', glob.glob('hub/data/energy_systems/*.yaml')),
|
||||
('hub/data/greenery/', glob.glob('hub/data/greenery/*.xml')),
|
||||
('hub/data/life_cycle_assessment/', glob.glob('hub/data/life_cycle_assessment/*.xml')),
|
||||
('hub/data/schedules/', glob.glob('hub/data/schedules/*.xml')),
|
||||
('hub/data/schedules/', glob.glob('hub/data/schedules/*.xlsx')),
|
||||
('hub/data/schedules/idf_files/', glob.glob('hub/data/schedules/idf_files/*.idf')),
|
||||
('hub/data/sensors/', glob.glob('hub/data/sensors/*.json')),
|
||||
('hub/data/usage/', glob.glob('hub/data/usage/*.xml')),
|
||||
('hub/data/usage/', glob.glob('hub/data/usage/*.xlsx')),
|
||||
('hub/data/weather/', glob.glob('hub/data/weather/*.dat')),
|
||||
('hub/data/weather/epw/', glob.glob('hub/data/weather/epw/*.epw')),
|
||||
('hub/data/weather/', glob.glob('hub/data/weather/*.dat')),
|
||||
('hub/exports/building_energy/idf_files', glob.glob('hub/exports/building_energy/idf_files/*.idf'))
|
||||
],
|
||||
setup_requires=['setuptools']
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user