forked from s_ranjbar/city_retrofit
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
|
from pathlib import Path
|
||||||
|
|
||||||
dotenv_path = (Path(__file__).parent / '.env').resolve()
|
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.
|
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
|
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._roof_type = None
|
||||||
self._internal_zones = None
|
self._internal_zones = None
|
||||||
self._shell = None
|
self._shell = None
|
||||||
self._human_readable_name = None
|
self._alias = None
|
||||||
self._type = 'building'
|
self._type = 'building'
|
||||||
self._heating = dict()
|
self._heating = dict()
|
||||||
self._cooling = dict()
|
self._cooling = dict()
|
||||||
|
@ -404,16 +404,16 @@ class Building(CityObject):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@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: str
|
||||||
"""
|
"""
|
||||||
return self._human_readable_name
|
return self._alias
|
||||||
|
|
||||||
@human_readable_name.setter
|
@alias.setter
|
||||||
def human_readable_name(self, value):
|
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):
|
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
|
@staticmethod
|
||||||
def hash_password(password: str) -> str:
|
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 Application
|
||||||
from hub.persistence.models import UserApplications
|
from hub.persistence.models import UserApplications
|
||||||
from hub.persistence.repositories import UserRepo
|
from hub.persistence.repositories import UserRepo
|
||||||
|
from hub.persistence.repositories import ApplicationRepo
|
||||||
from hub.hub_logger import logger
|
from hub.hub_logger import logger
|
||||||
|
|
||||||
|
|
||||||
class DBSetup:
|
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 db_name:
|
||||||
:param app_env:
|
:param app_env:
|
||||||
:param dotenv_path:
|
:param dotenv_path:
|
||||||
|
@ -26,17 +27,30 @@ class DBSetup:
|
||||||
UserApplications.__table__.create(bind=repo.engine, checkfirst=True)
|
UserApplications.__table__.create(bind=repo.engine, checkfirst=True)
|
||||||
HeatPumpSimulation.__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._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
|
@staticmethod
|
||||||
def _create_admin_user(user_repo):
|
def _create_admin_app(application_repo, application_uuid):
|
||||||
email = 'admin@hub.com'
|
name = 'AdminTool'
|
||||||
password = 'HubAdmin#!98'
|
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...')
|
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:
|
if type(user) is dict:
|
||||||
logger.info(user)
|
logger.info(user)
|
||||||
else:
|
else:
|
||||||
print(f'Created Admin user with email: {email}, password: {password} and role: {UserRoles.Admin.value}')
|
print(f'Created Admin user')
|
||||||
logger.info(f'Created Admin user with email: {email}, password: {password} and role: {UserRoles.Admin.value}')
|
logger.info(f'Created Admin user')
|
||||||
print('Remember to change the admin default password and email address with the UserFactory')
|
|
|
@ -5,3 +5,4 @@ from .heat_pump_simulation import HeatPumpTypes
|
||||||
from .user import User, UserRoles
|
from .user import User, UserRoles
|
||||||
from .user_applications import UserApplications
|
from .user_applications import UserApplications
|
||||||
from .application import Application
|
from .application import Application
|
||||||
|
from .city_object import CityObject
|
||||||
|
|
|
@ -7,6 +7,7 @@ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy import Column, Integer, String, Sequence
|
from sqlalchemy import Column, Integer, String, Sequence
|
||||||
from sqlalchemy import DateTime
|
from sqlalchemy import DateTime
|
||||||
|
|
||||||
|
@ -21,9 +22,11 @@ class Application(Base):
|
||||||
id = Column(Integer, Sequence('application_id_seq'), primary_key=True)
|
id = Column(Integer, Sequence('application_id_seq'), primary_key=True)
|
||||||
name = Column(String, nullable=False)
|
name = Column(String, nullable=False)
|
||||||
description = 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)
|
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
updated = 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.name = name
|
||||||
self.description = description
|
self.description = description
|
||||||
|
self.application_uuid = application_uuid
|
||||||
|
|
|
@ -5,13 +5,12 @@ Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Peter Yefi peteryefi@gmail.com
|
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 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):
|
class City(Base):
|
||||||
|
@ -21,28 +20,19 @@ class City(Base):
|
||||||
id = Column(Integer, Sequence('city_id_seq'), primary_key=True)
|
id = Column(Integer, Sequence('city_id_seq'), primary_key=True)
|
||||||
city = Column(PickleType, nullable=False)
|
city = Column(PickleType, nullable=False)
|
||||||
name = Column(String, nullable=False)
|
name = Column(String, nullable=False)
|
||||||
srs_name = Column(String, nullable=False)
|
level_of_detail = Column(Integer, nullable=False)
|
||||||
climate_reference_city = Column(String, nullable=True)
|
climate_file = Column(String, nullable=False)
|
||||||
time_zone = Column(String, nullable=True)
|
application_id = Column(Integer, ForeignKey('application.id'), nullable=False)
|
||||||
country_code = Column(String, nullable=False)
|
user_id = Column(Integer, ForeignKey('user.id'), nullable=True)
|
||||||
latitude = Column(Float)
|
|
||||||
longitude = Column(Float)
|
|
||||||
lower_corner = Column(JSONB, nullable=False)
|
|
||||||
upper_corner = Column(JSONB, nullable=False)
|
|
||||||
hub_release = Column(String, nullable=False)
|
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)
|
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
updated = 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.city = city
|
||||||
self.user_id = user_id
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.srs_name = srs_name
|
self.level_of_detail = level_of_detail
|
||||||
self.country_code = country_code
|
self.climate_file = climate_file
|
||||||
l_corner = l_corner.tolist() if type(l_corner) == np.ndarray else l_corner
|
self.application_id = application_id
|
||||||
u_corner = u_corner.tolist() if type(u_corner) == np.ndarray else u_corner
|
self.user_id = user_id
|
||||||
self.lower_corner = l_corner
|
self.hub_release = hub_release
|
||||||
self.upper_corner = u_corner
|
|
||||||
|
|
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"
|
__tablename__ = "user"
|
||||||
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
|
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
|
||||||
name = Column(String, nullable=False)
|
name = Column(String, nullable=False)
|
||||||
email = Column(String, nullable=False, unique=True)
|
|
||||||
password = Column(String, nullable=False)
|
password = Column(String, nullable=False)
|
||||||
role = Column(Enum(UserRoles), nullable=False, default=UserRoles.Hub_Reader)
|
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)
|
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
|
|
||||||
@validates("email")
|
def __init__(self, name, password, role, application_id):
|
||||||
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):
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.email = email
|
|
||||||
self.password = password
|
self.password = password
|
||||||
self.role = role
|
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 .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
|
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 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):
|
class CityRepo(BaseRepo):
|
||||||
|
@ -32,44 +33,25 @@ class CityRepo(BaseRepo):
|
||||||
cls._instance = super(CityRepo, cls).__new__(cls)
|
cls._instance = super(CityRepo, cls).__new__(cls)
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
def insert(self, city: City, user_id: int) -> Union[City, Dict]:
|
def insert(self, city: City, application_id, 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)
|
Insert a city
|
||||||
db_city.climate_reference_city = city.climate_reference_city
|
:param city: The complete city instance
|
||||||
db_city.longitude = city.longitude
|
:param application_id: Application id owning the instance
|
||||||
db_city.latitude = city.latitude
|
:param user_id: User id owning the instance
|
||||||
db_city.time_zone = city.time_zone
|
:return: City and Dictionary
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
# Retrieve hub project latest release
|
release = __version__
|
||||||
response = requests.get("https://rs-loy-gitlab.concordia.ca/api/v4/projects/2/repository/branches/master",
|
db_city = DBCity(pickle.dumps(city), city.name, city.level_of_detail, city.climate_file, application_id, user_id,
|
||||||
headers={"PRIVATE-TOKEN": self.config.hub_token})
|
release)
|
||||||
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)
|
|
||||||
|
|
||||||
# Do not persist the same city for the same version of Hub
|
self.session.add(db_city)
|
||||||
if exiting_city is None:
|
self.session.flush()
|
||||||
db_city.hub_release = recent_commit
|
self.session.commit()
|
||||||
cities = self.get_by_name(city.name)
|
return db_city
|
||||||
# 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'}
|
|
||||||
except SQLAlchemyError as err:
|
except SQLAlchemyError as err:
|
||||||
logger.error(f'Error while adding city: {err}')
|
logger.error(f'An error occurred while creating city: {err}')
|
||||||
except HTTPError as err:
|
|
||||||
logger.error(f'Error retrieving Hub latest release: {err}')
|
|
||||||
|
|
||||||
def get_by_id(self, city_id: int) -> DBCity:
|
def get_by_id(self, city_id: int) -> DBCity:
|
||||||
"""
|
"""
|
||||||
|
@ -82,16 +64,16 @@ class CityRepo(BaseRepo):
|
||||||
except SQLAlchemyError as err:
|
except SQLAlchemyError as err:
|
||||||
logger.error(f'Error while fetching city: {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
|
Fetch a City based on the name and hub project
|
||||||
:param hub_commit: the latest hub commit
|
:param hub_release: the hub release
|
||||||
:param city_name: the name of the city
|
:param city_name: the name of the city
|
||||||
:return: a city
|
:return: a city
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self.session.execute(select(DBCity)
|
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:
|
except SQLAlchemyError as err:
|
||||||
logger.error(f'Error while fetching city: {err}')
|
logger.error(f'Error while fetching city: {err}')
|
||||||
|
|
||||||
|
|
|
@ -30,16 +30,15 @@ class UserRepo(BaseRepo):
|
||||||
cls._instance = super(UserRepo, cls).__new__(cls)
|
cls._instance = super(UserRepo, cls).__new__(cls)
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
def insert(self, name: str, email: str, password: str, role: UserRoles) -> Union[User, Dict]:
|
def insert(self, name: str, password: str, role: UserRoles, application_id: int) -> Union[User, Dict]:
|
||||||
user = self.get_by_email(email)
|
user = self.get_by_name_and_application(name, application_id)
|
||||||
if user is None:
|
if user is None:
|
||||||
try:
|
try:
|
||||||
if Auth.validate_password(password):
|
user = User(name=name, password=Auth.hash_password(password), role=role, application_id=application_id)
|
||||||
user = User(name=name, email=email, password=Auth.hash_password(password), role=role)
|
self.session.add(user)
|
||||||
self.session.add(user)
|
self.session.flush()
|
||||||
self.session.flush()
|
self.session.commit()
|
||||||
self.session.commit()
|
return user
|
||||||
return user
|
|
||||||
except SQLAlchemyError as err:
|
except SQLAlchemyError as err:
|
||||||
logger.error(f'An error occurred while creating user: {err}')
|
logger.error(f'An error occurred while creating user: {err}')
|
||||||
else:
|
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"]
|
requires = ["setuptools>=61.0.0", "wheel"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[options.packages.find_namespace]
|
||||||
name = "cerc_hub"
|
where = "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"
|
|
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 os.path
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
|
main_ns = {}
|
||||||
|
version = convert_path('hub/version.py')
|
||||||
|
with open(version) as f:
|
||||||
|
exec(f.read(), main_ns)
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='hub',
|
name='cerc-hub',
|
||||||
version="0.1",
|
version=main_ns['__version__'],
|
||||||
packages=find_packages(exclude="unittests"),
|
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=[
|
data_files=[
|
||||||
('config', [os.path.join('hub/config', 'configuration.ini')]),
|
('hub/config', glob.glob('hub/config/*.ini')),
|
||||||
('greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')),
|
('hub/catalog_factories/greenery/ecore_greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')),
|
||||||
('data', glob.glob('hub/data/construction/*.xml')),
|
('hub/data/construction.', glob.glob('hub/data/construction/*.xml')),
|
||||||
('data', glob.glob('hub/data/customized_imports/*.xml')),
|
('hub/data/customized_imports/', glob.glob('hub/data/customized_imports/*.xml')),
|
||||||
('data', glob.glob('hub/data/energy_systems/*.xml')),
|
('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.xml')),
|
||||||
('data', glob.glob('hub/data/energy_systems/*.insel')),
|
('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.insel')),
|
||||||
('data', glob.glob('hub/data/energy_systems/*.xlsx')),
|
('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.xlsx')),
|
||||||
('data', glob.glob('hub/data/energy_systems/*.txt')),
|
('hub/data/energy_systems/*', glob.glob('hub/data/energy_systems/*.txt')),
|
||||||
('data', glob.glob('hub/data/energy_systems/*.yaml')),
|
('hub/data/energy_systems/*', glob.glob('hub/data/energy_systems/*.yaml')),
|
||||||
('data', glob.glob('hub/data/greenery/*.xml')),
|
('hub/data/greenery/', glob.glob('hub/data/greenery/*.xml')),
|
||||||
('data', glob.glob('hub/data/life_cycle_assessment/*.xml')),
|
('hub/data/life_cycle_assessment/', glob.glob('hub/data/life_cycle_assessment/*.xml')),
|
||||||
('data', glob.glob('hub/data/schedules/*.xml')),
|
('hub/data/schedules/', glob.glob('hub/data/schedules/*.xml')),
|
||||||
('data', glob.glob('hub/data/schedules/*.xlsx')),
|
('hub/data/schedules/', glob.glob('hub/data/schedules/*.xlsx')),
|
||||||
('data', glob.glob('hub/data/schedules/idf_files/*.idf')),
|
('hub/data/schedules/idf_files/', glob.glob('hub/data/schedules/idf_files/*.idf')),
|
||||||
('data', glob.glob('hub/data/sensors/*.json')),
|
('hub/data/sensors/', glob.glob('hub/data/sensors/*.json')),
|
||||||
('data', glob.glob('hub/data/usage/*.xml')),
|
('hub/data/usage/', glob.glob('hub/data/usage/*.xml')),
|
||||||
('data', glob.glob('hub/data/usage/*.xlsx')),
|
('hub/data/usage/', glob.glob('hub/data/usage/*.xlsx')),
|
||||||
('data', glob.glob('hub/data/weather/*.dat')),
|
('hub/data/weather/', glob.glob('hub/data/weather/*.dat')),
|
||||||
('data', glob.glob('hub/data/weather/epw/*.epw')),
|
('hub/data/weather/epw/', glob.glob('hub/data/weather/epw/*.epw')),
|
||||||
('data', glob.glob('hub/data/weather/*.dat'))
|
('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']
|
setup_requires=['setuptools']
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user