Persistence refactory

This commit is contained in:
Guille Gutierrez 2023-02-01 06:05:12 -05:00
parent 5978757348
commit 672b9874f2
17 changed files with 143 additions and 247 deletions

View File

@ -1,6 +1,5 @@
from .base_repo import BaseRepo from .repository import Repository
from .repositories.city_repo import CityRepo from .repositories.city import City
from .repositories.heat_pump_simulation_repo import HeatPumpSimulationRepo
from .db_setup import DBSetup from .db_setup import DBSetup
from .repositories.user_repo import UserRepo from .repositories.user import User
from .models.user import UserRoles from .models.user import UserRoles

View File

@ -13,9 +13,9 @@ from hub.hub_logger import logger
Base = declarative_base() Base = declarative_base()
class BaseConfiguration(object): class Configuration:
""" """
Base configuration class to hold common persistence configuration Configuration class to hold common persistence configuration
""" """
def __init__(self, db_name: str, dotenv_path: str, app_env='TEST'): def __init__(self, db_name: str, dotenv_path: str, app_env='TEST'):

View File

@ -1,13 +1,19 @@
"""
Database setup
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com
"""
from hub.persistence import BaseRepo from hub.persistence import Repository
from hub.persistence.models import Application
from hub.persistence.models import City from hub.persistence.models import City
from hub.persistence.models import HeatPumpSimulation from hub.persistence.models import CityObject
from hub.persistence.models import User from hub.persistence.models import User
from hub.persistence.models import UserRoles from hub.persistence.models import UserRoles
from hub.persistence.models import Application from hub.persistence.models import SimulationResults
from hub.persistence.models import UserApplications from hub.persistence.repositories import User as UserRepository
from hub.persistence.repositories import UserRepo from hub.persistence.repositories import Application as ApplicationRepository
from hub.persistence.repositories import ApplicationRepo
from hub.hub_logger import logger from hub.hub_logger import logger
@ -20,14 +26,17 @@ class DBSetup:
:param app_env: :param app_env:
:param dotenv_path: :param dotenv_path:
""" """
repo = BaseRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) repository = Repository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
User.__table__.create(bind=repo.engine, checkfirst=True)
City.__table__.create(bind=repo.engine, checkfirst=True) # Create the tables using the models
Application.__table__.create(bind=repo.engine, checkfirst=True) Application.__table__.create(bind=repository.engine, checkfirst=True)
UserApplications.__table__.create(bind=repo.engine, checkfirst=True) City.__table__.create(bind=repository.engine, checkfirst=True)
HeatPumpSimulation.__table__.create(bind=repo.engine, checkfirst=True) CityObject.__table__.create(bind=repository.engine, checkfirst=True)
self._user_repo = UserRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) SimulationResults.__table__.create(bind=repository.engine, checkfirst=True)
self._application_repo = ApplicationRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) User.__table__.create(bind=repository.engine, checkfirst=True)
self._user_repo = UserRepository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
self._application_repo = ApplicationRepository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
self._create_admin_user(self._user_repo, admin_password) self._create_admin_user(self._user_repo, admin_password)
self._create_admin_app(self._application_repo, application_uuid) self._create_admin_app(self._application_repo, application_uuid)

View File

@ -1,8 +1,5 @@
from .city import City
from .heat_pump_simulation import HeatPumpSimulation
from .heat_pump_simulation import SimulationTypes
from .heat_pump_simulation import HeatPumpTypes
from .user import User, UserRoles
from .user_applications import UserApplications
from .application import Application from .application import Application
from .city import City
from .city_object import CityObject from .city_object import CityObject
from .simulation_results import SimulationResults
from .user import User, UserRoles

View File

@ -11,14 +11,12 @@ 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
from hub.persistence.db_config import Base
class Application:
class Application(Base):
""" """
A model representation of an application A model representation of an application
""" """
__tablename__ = "application" __table__ = "application"
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)

View File

@ -10,13 +10,11 @@ import datetime
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey from sqlalchemy import Column, Integer, String, Sequence, ForeignKey
from sqlalchemy import DateTime, PickleType from sqlalchemy import DateTime, PickleType
from hub.persistence.db_config import Base
class City:
class City(Base):
"""A model representation of a city """A model representation of a city
""" """
__tablename__ = "city" __table__ = "city"
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)

View File

@ -10,14 +10,11 @@ import datetime
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float
from sqlalchemy import DateTime from sqlalchemy import DateTime
from hub.persistence.db_config import Base class CityObject:
class CityObject(Base):
""" """
A model representation of an application A model representation of an application
""" """
__tablename__ = "city_object" __table__ = "city_object"
id = Column(Integer, Sequence('application_id_seq'), primary_key=True) id = Column(Integer, Sequence('application_id_seq'), primary_key=True)
city_id = Column(Integer, ForeignKey('city.id'), nullable=False) city_id = Column(Integer, ForeignKey('city.id'), nullable=False)
name = Column(String, nullable=False) name = Column(String, nullable=False)
@ -41,4 +38,3 @@ class CityObject(Base):
self.usage = usage self.usage = usage
self.volume = volume self.volume = volume
self.area = area self.area = area

View File

@ -7,18 +7,15 @@ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
import datetime import datetime
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float from sqlalchemy import Column, Integer, String, Sequence, ForeignKey
from sqlalchemy import DateTime from sqlalchemy import DateTime
from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.dialects.postgresql import JSONB
from hub.persistence.db_config import Base class SimulationResults:
class CityObject(Base):
""" """
A model representation of an application A model representation of an application
""" """
__tablename__ = "simulation_results" __table__ = "simulation_results"
id = Column(Integer, Sequence('application_id_seq'), primary_key=True) id = Column(Integer, Sequence('application_id_seq'), primary_key=True)
city_id = Column(Integer, ForeignKey('city.id'), nullable=True) city_id = Column(Integer, ForeignKey('city.id'), nullable=True)
city_object_id = Column(Integer, ForeignKey('city_object.id'), nullable=True) city_object_id = Column(Integer, ForeignKey('city_object.id'), nullable=True)

View File

@ -5,14 +5,11 @@ Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com Project Coder Peter Yefi peteryefi@gmail.com
""" """
import datetime
import enum
from sqlalchemy import Column, Integer, String, Sequence from sqlalchemy import Column, Integer, String, Sequence
from sqlalchemy import DateTime, Enum from sqlalchemy import DateTime, Enum
from hub.persistence.db_config import Base
import datetime
from sqlalchemy.orm import validates
import re
import enum
from sqlalchemy.orm import relationship
class UserRoles(enum.Enum): class UserRoles(enum.Enum):
@ -20,10 +17,11 @@ class UserRoles(enum.Enum):
Hub_Reader = 'Hub_Reader' Hub_Reader = 'Hub_Reader'
class User(Base): class User:
"""A model representation of a city
""" """
__tablename__ = "user" A model representation of a city
"""
__table__ = "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)
password = Column(String, nullable=False) password = Column(String, nullable=False)

View File

@ -1,2 +1,2 @@
from .user_repo import UserRepo from .user import User
from .application_repo import ApplicationRepo from .application import Application

View File

@ -12,11 +12,11 @@ from sqlalchemy import select
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from hub.hub_logger import logger from hub.hub_logger import logger
from hub.persistence import BaseRepo from hub.persistence import Repository
from hub.persistence.models import Application from hub.persistence.models import Application as Model
class ApplicationRepo(BaseRepo): class Application(Repository):
_instance = None _instance = None
def __init__(self, db_name: str, dotenv_path: str, app_env: str): def __init__(self, db_name: str, dotenv_path: str, app_env: str):
@ -27,14 +27,14 @@ class ApplicationRepo(BaseRepo):
Implemented for a singleton pattern Implemented for a singleton pattern
""" """
if cls._instance is None: if cls._instance is None:
cls._instance = super(ApplicationRepo, cls).__new__(cls) cls._instance = super(Application, cls).__new__(cls)
return cls._instance return cls._instance
def insert(self, name: str, description: str, application_uuid: str) -> Union[Application, Dict]: def insert(self, name: str, description: str, application_uuid: str) -> Union[Model, Dict]:
application = self.get_by_uuid(application_uuid) application = self.get_by_uuid(application_uuid)
if application is None: if application is None:
try: try:
application = Application(name=name, description=description, application_uuid=application_uuid) application = Model(name=name, description=description, application_uuid=application_uuid)
self.session.add(application) self.session.add(application)
self.session.flush() self.session.flush()
self.session.commit() self.session.commit()
@ -53,21 +53,24 @@ class ApplicationRepo(BaseRepo):
:return: :return:
""" """
try: try:
self.session.query(Application).filter(Application.application_uuid == application_uuid) \ self.session.query(Model).filter(
.update({'name': name, 'description': description, 'updated': datetime.datetime.utcnow()}) Model.application_uuid == application_uuid
).update({'name': name, 'description': description, 'updated': datetime.datetime.utcnow()})
self.session.commit() self.session.commit()
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while updating application: {err}') logger.error(f'Error while updating application: {err}')
return {'err_msg': 'Error occurred while updating application'} return {'err_msg': 'Error occurred while updating application'}
def get_by_uuid(self, application_uuid: str) -> [Application]: def get_by_uuid(self, application_uuid: str) -> [Model]:
""" """
Fetch Application based on the application uuid Fetch Application based on the application uuid
:param application_uuid: the application uuid :param application_uuid: the application uuid
:return: [Application] with the provided application_uuid :return: [Application] with the provided application_uuid
""" """
try: try:
return self.session.execute(select(Application).where(Application.application_uuid == application_uuid)).first() return self.session.execute(select(Model).where(
Model.application_uuid == application_uuid)
).first()
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching application by application_uuid: {err}') logger.error(f'Error while fetching application by application_uuid: {err}')
@ -78,7 +81,7 @@ class ApplicationRepo(BaseRepo):
:return: None :return: None
""" """
try: try:
self.session.query(Application).filter(Application.application_uuid == application_uuid).delete() self.session.query(Model).filter(Model.application_uuid == application_uuid).delete()
self.session.commit() self.session.commit()
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while deleting application: {err}') logger.error(f'Error while deleting application: {err}')

View File

@ -12,14 +12,14 @@ from typing import Union, Dict
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from hub.city_model_structure.city import City from hub.city_model_structure.city import City as CityHub
from hub.hub_logger import logger from hub.hub_logger import logger
from hub.persistence import BaseRepo from hub.persistence import Repository
from hub.persistence.models import City as DBCity from hub.persistence.models import City as Model
from hub.version import __version__ from hub.version import __version__
class CityRepo(BaseRepo): class City(Repository):
_instance = None _instance = None
def __init__(self, db_name: str, dotenv_path: str, app_env: str): def __init__(self, db_name: str, dotenv_path: str, app_env: str):
@ -30,10 +30,10 @@ class CityRepo(BaseRepo):
Implemented for a singleton pattern Implemented for a singleton pattern
""" """
if cls._instance is None: if cls._instance is None:
cls._instance = super(CityRepo, cls).__new__(cls) cls._instance = super(City, cls).__new__(cls)
return cls._instance return cls._instance
def insert(self, city: City, application_id, user_id: int) -> Union[City, Dict]: def insert(self, city: CityHub, application_id, user_id: int) -> Union[Model, Dict]:
""" """
Insert a city Insert a city
:param city: The complete city instance :param city: The complete city instance
@ -42,9 +42,14 @@ class CityRepo(BaseRepo):
:return: City and Dictionary :return: City and Dictionary
""" """
try: try:
release = __version__ db_city = Model(
db_city = DBCity(pickle.dumps(city), city.name, city.level_of_detail, city.climate_file, application_id, user_id, pickle.dumps(city),
release) city.name,
city.level_of_detail,
city.climate_file,
application_id,
user_id,
__version__)
self.session.add(db_city) self.session.add(db_city)
self.session.flush() self.session.flush()
@ -53,18 +58,18 @@ class CityRepo(BaseRepo):
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'An error occurred while creating city: {err}') logger.error(f'An error occurred while creating city: {err}')
def get_by_id(self, city_id: int) -> DBCity: def get_by_id(self, city_id: int) -> Model:
""" """
Fetch a City based on the id Fetch a City based on the id
:param city_id: the city id :param city_id: the city id
:return: a city :return: a city
""" """
try: try:
return self.session.execute(select(DBCity).where(DBCity.id == city_id)).first()[0] return self.session.execute(select(Model).where(Model.id == city_id)).first()[0]
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_release: str, city_name: str) -> City: def _get_by_hub_version_and_name(self, hub_release: str, city_name: str) -> Model:
""" """
Fetch a City based on the name and hub project Fetch a City based on the name and hub project
:param hub_release: the hub release :param hub_release: the hub release
@ -72,55 +77,50 @@ class CityRepo(BaseRepo):
:return: a city :return: a city
""" """
try: try:
return self.session.execute(select(DBCity) return self.session.execute(select(Model)
.where(DBCity.hub_release == hub_release, DBCity.name == city_name)).first() .where(Model.hub_release == hub_release, Model.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}')
def update(self, city_id: int, city: City): def get_by_name(self, city_name: str) -> [Model]:
"""
Updates a city
:param city_id: the id of the city to be updated
:param city: the city object
:return:
"""
try:
self.session.query(DBCity).filter(DBCity.id == city_id) \
.update({
'name': city.name, 'srs_name': city.srs_name, 'country_code': city.country_code, 'longitude': city.longitude,
'latitude': city.latitude, 'time_zone': city.time_zone, 'lower_corner': city.lower_corner.tolist(),
'upper_corner': city.upper_corner.tolist(), 'climate_reference_city': city.climate_reference_city,
'updated': datetime.datetime.utcnow()
})
self.session.commit()
except SQLAlchemyError as err:
logger.error(f'Error while updating city: {err}')
def get_by_name(self, city_name: str) -> [DBCity]:
""" """
Fetch city based on the name Fetch city based on the name
:param city_name: the name of the building :param city_name: the name of the building
:return: [ModelCity] with the provided name :return: [ModelCity] with the provided name
""" """
try: try:
result_set = self.session.execute(select(DBCity).where(DBCity.name == city_name)) result_set = self.session.execute(select(Model).where(Model.name == city_name))
return [building[0] for building in result_set] return [building[0] for building in result_set]
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching city by name: {err}') logger.error(f'Error while fetching city by name: {err}')
def get_by_user(self, user_id: int) -> [DBCity]: def get_by_user(self, user_id: int) -> [Model]:
""" """
Fetch city based on the user who created it Fetch city based on the user who created it
:param user_id: the id of the user :param user_id: the id of the user
:return: [ModelCity] with the provided name :return: [ModelCity] with the provided name
""" """
try: try:
result_set = self.session.execute(select(DBCity).where(DBCity.user_id == user_id)) result_set = self.session.execute(select(Model).where(Model.user_id == user_id))
return [building[0] for building in result_set] return [building[0] for building in result_set]
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching city by name: {err}') logger.error(f'Error while fetching city by name: {err}')
def update(self, city_id: int, city: CityHub):
"""
Updates a city name (other updates makes no sense)
:param city_id: the id of the city to be updated
:param city: the city object
:return:
"""
try:
now = datetime.datetime.utcnow()
self.session.query(Model).filter(Model.id == city_id).update({'name': city.name,'updated': now})
self.session.commit()
except SQLAlchemyError as err:
logger.error(f'Error while updating city: {err}')
def delete_city(self, city_id: int): def delete_city(self, city_id: int):
""" """
Deletes a City with the id Deletes a City with the id
@ -128,7 +128,7 @@ class CityRepo(BaseRepo):
:return: a city :return: a city
""" """
try: try:
self.session.query(DBCity).filter(DBCity.id == city_id).delete() self.session.query(Model).filter(Model.id == city_id).delete()
self.session.commit() self.session.commit()
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching city: {err}') logger.error(f'Error while fetching city: {err}')

View File

@ -1,108 +0,0 @@
"""
Heat pump simulation repository with database CRUD operations
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com
"""
from hub.persistence import BaseRepo, CityRepo
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import select
from hub.persistence.models import HeatPumpSimulation
from typing import Union, Dict
from hub.hub_logger import logger
class HeatPumpSimulationRepo(BaseRepo):
_instance = None
def __init__(self, db_name, dotenv_path, app_env):
super().__init__(db_name, dotenv_path, app_env)
self._city_repo = CityRepo(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(HeatPumpSimulationRepo, cls).__new__(cls)
return cls._instance
def insert(self, hp_sim_data: Dict, city_id: int) -> Union[HeatPumpSimulation, Dict]:
"""
Inserts the results of heat pump simulation
:param hp_sim_data: dictionary with heatpump the simulation inputs and output
:param city_id: the city that was used in running the simulation
:return: HeatPumpSimulation
"""
city = self._city_repo.get_by_id(city_id)
if city is None:
return {'message': 'city not found in database'}
try:
hp_simulation = HeatPumpSimulation(city_id, hp_sim_data["HourlyElectricityDemand"],
hp_sim_data["DailyElectricityDemand"], hp_sim_data["MonthlyElectricityDemand"],
hp_sim_data["DailyFossilFuelConsumption"],
hp_sim_data["MonthlyFossilFuelConsumption"])
hp_simulation.city_id = city_id
hp_simulation.end_year = hp_sim_data["EndYear"]
hp_simulation.start_year = hp_sim_data["StartYear"]
hp_simulation.max_demand_storage_hour = hp_sim_data["HoursOfStorageAtMaxDemand"]
hp_simulation.max_hp_energy_input = hp_sim_data["MaximumHPEnergyInput"]
hp_simulation.building_supply_temp = hp_sim_data["BuildingSuppTemp"]
hp_simulation.temp_difference = hp_sim_data["TemperatureDifference"]
hp_simulation.fuel_lhv = hp_sim_data["FuelLHV"]
hp_simulation.fuel_price = hp_sim_data["FuelPrice"]
hp_simulation.fuel_efficiency = hp_sim_data["FuelEF"]
hp_simulation.fuel_density = hp_sim_data["FuelDensity"]
hp_simulation.hp_supply_temp = hp_sim_data["HPSupTemp"]
hp_simulation.simulation_type = hp_sim_data["SimulationType"]
hp_simulation.heat_pump_model = hp_sim_data["HeatPumpModel"]
hp_simulation.heat_pump_type = hp_sim_data["HeatPumpType"]
# Persist heat pump simulation data
self.session.add(hp_simulation)
self.session.flush()
self.session.commit()
return hp_simulation
except SQLAlchemyError as err:
logger.error(f'Error while saving heat pump simulation data: {err}')
except KeyError as err:
logger.error(f'A required field is missing in your heat pump simulation dictionary: {err}')
def get_by_id(self, hp_simulation_id: int) -> HeatPumpSimulation:
"""
Fetches heat pump simulation data
:param hp_simulation_id: the city id
:return: a HeatPumpSimulation
"""
try:
return self.session.execute(select(HeatPumpSimulation).where(HeatPumpSimulation.id == hp_simulation_id)).first()[
0]
except SQLAlchemyError as err:
logger.error(f'Error while fetching city: {err}')
def get_by_city(self, city_id: int) -> [HeatPumpSimulation]:
"""
Fetch heat pump simulation results by city
:param city_id: the name of the building
:return: [HeatPumpSimulation] with the provided name
"""
try:
result_set = self.session.execute(select(HeatPumpSimulation).where(HeatPumpSimulation.city_id == city_id))
return [sim_data[0] for sim_data in result_set]
except SQLAlchemyError as err:
logger.error(f'Error while fetching city by name: {err}')
def delete_hp_simulation(self, hp_simulation_id: int):
"""
Deletes a heat pump simulation results
:param hp_simulation_id: the heat pump simulation results id
:return:
"""
try:
self.session.query(HeatPumpSimulation).filter(HeatPumpSimulation.id == hp_simulation_id).delete()
self.session.commit()
except SQLAlchemyError as err:
logger.error(f'Error while fetching city: {err}')

View File

@ -5,10 +5,10 @@ Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com Project Coder Peter Yefi peteryefi@gmail.com
""" """
from hub.persistence import BaseRepo from hub.persistence import Repository
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import select from sqlalchemy import select
from hub.persistence.models import User from hub.persistence.models import User as Model
from hub.persistence.models import UserRoles from hub.persistence.models import UserRoles
from hub.helpers.auth import Auth from hub.helpers.auth import Auth
from typing import Union, Dict from typing import Union, Dict
@ -16,7 +16,7 @@ from hub.hub_logger import logger
import datetime import datetime
class UserRepo(BaseRepo): class User(Repository):
_instance = None _instance = None
def __init__(self, db_name: str, dotenv_path: str, app_env: str): def __init__(self, db_name: str, dotenv_path: str, app_env: str):
@ -27,14 +27,14 @@ class UserRepo(BaseRepo):
Implemented for a singleton pattern Implemented for a singleton pattern
""" """
if cls._instance is None: if cls._instance is None:
cls._instance = super(UserRepo, cls).__new__(cls) cls._instance = super(User, cls).__new__(cls)
return cls._instance return cls._instance
def insert(self, name: str, password: str, role: UserRoles, application_id: int) -> Union[User, Dict]: def insert(self, name: str, password: str, role: UserRoles, application_id: int) -> Union[Model, Dict]:
user = self.get_by_name_and_application(name, application_id) user = self.get_by_name_and_application(name, application_id)
if user is None: if user is None:
try: try:
user = User(name=name, password=Auth.hash_password(password), role=role, application_id=application_id) user = Model(name=name, password=Auth.hash_password(password), role=role, application_id=application_id)
self.session.add(user) self.session.add(user)
self.session.flush() self.session.flush()
self.session.commit() self.session.commit()
@ -42,38 +42,42 @@ class UserRepo(BaseRepo):
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:
return {'message': f'user with {email} email already exists'} return {'message': f'user {name} already exists for that application'}
def update(self, user_id: int, name: str, email: str, password: str, role: UserRoles) -> Union[Dict, None]: def update(self, user_id: int, name: str, password: str, role: UserRoles) -> Union[Dict, None]:
""" """
Updates a user Updates a user
:param user_id: the id of the user to be updated :param user_id: the id of the user to be updated
:param name: the name of the user :param name: the name of the user
:param email: the email of the user
:param password: the password of the user :param password: the password of the user
:param role: the role of the user :param role: the role of the user
:return: :return:
""" """
try: try:
if Auth.validate_password(password): self.session.query(Model).filter(Model.id == user_id).update({
self.session.query(User).filter(User.id == user_id) \ 'name': name,
.update({'name': name, 'email': email, 'password': Auth.hash_password(password), 'role': role, 'password': Auth.hash_password(password),
'updated': datetime.datetime.utcnow()}) 'role': role,
'updated': datetime.datetime.utcnow()
})
self.session.commit() self.session.commit()
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while updating user: {err}') logger.error(f'Error while updating user: {err}')
return {'err_msg': 'Error occurred while updated user'} return {'err_msg': 'Error occurred while updated user'}
def get_by_email(self, email: str) -> [User]: def get_by_name_and_application(self, name: str, application_id: int) -> [Model]:
""" """
Fetch user based on the email address Fetch user based on the email address
:param email: the email of the user :param name: User name
:return: [User] with the provided email :param application_id: User application name
:return: [User] matching the search criteria
""" """
try: try:
return self.session.execute(select(User).where(User.email == email)).first() return self.session.execute(
select(Model).where(Model.name == name and Model.application_id == application_id)
).first()
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching user by email: {err}') logger.error(f'Error while fetching user by name and application: {err}')
def delete_user(self, user_id: int): def delete_user(self, user_id: int):
""" """
@ -82,25 +86,27 @@ class UserRepo(BaseRepo):
:return: None :return: None
""" """
try: try:
self.session.query(User).filter(User.id == user_id).delete() self.session.query(Model).filter(Model.id == user_id).delete()
self.session.commit() self.session.commit()
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching user: {err}') logger.error(f'Error while fetching user: {err}')
def get_user_by_email_and_password(self, email: str, password: str) -> [User]: def get_user_by_name_application_and_password(self, name: str, password: str, application_id: int) -> [Model]:
""" """
Fetch user based on the email and password Fetch user based on the email and password
:param email: the email of the user :param name: User name
:param password: the password of the user :param password: User password
:param application_id: User password
:return: [User] with the provided email and password :return: [User] with the provided email and password
""" """
try: try:
user = self.session.execute(select(User).where(User.email == email)).first() user = self.session.execute(
select(Model).where(Model.name == name and Model.application_id == application_id)
).first()
if user: if user:
if Auth.check_password(password, user[0].password): if Auth.check_password(password, user[0].password):
return user return user
else: return {'message': 'invalid login information'}
return {'message': 'Wrong email/password combination'}
return {'message': 'user not found'}
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching user by email: {err}') logger.error(f'Error while fetching user by email: {err}')

View File

@ -5,17 +5,17 @@ Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com Project Coder Peter Yefi peteryefi@gmail.com
""" """
from hub.persistence.db_config import BaseConfiguration from hub.persistence.configuration import Configuration
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
class BaseRepo: class Repository:
def __init__(self, db_name, dotenv_path: str, app_env='TEST'): def __init__(self, db_name, dotenv_path: str, app_env='TEST'):
try: try:
self.config = BaseConfiguration(db_name, dotenv_path, app_env) self.configuration = Configuration(db_name, dotenv_path, app_env)
self.engine = create_engine(self.config.conn_string()) self.engine = create_engine(self.configuration.conn_string())
self.session = Session(self.engine) self.session = Session(self.engine)
except ValueError as err: except ValueError as err:
print(f'Missing value for credentials: {err}') print(f'Missing value for credentials: {err}')

View File

@ -13,7 +13,10 @@ setup(
description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help researchers " description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help researchers "
"to create better and sustainable cities", "to create better and sustainable cities",
long_description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help " 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", "researchers to create better and sustainable cities.\n\nDevelop at Concordia university in canada "
"as part of the research group from the next generation cities institute our aim among others it's "
"to provide a comprehensive set of tools to help researchers and urban developers to make decisions "
"to improve the livability and efficiency of our cities",
classifiers=[ classifiers=[
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Programming Language :: Python", "Programming Language :: Python",