import typing import sqlalchemy import sqlalchemy.engine.base from .app_route import app_route_database from .product import product from .product_loader import product_loader from .exception import bad_request_exception from .exception import not_found_exception from .exception import access_denied_exception from .exception import database_exception from .exception import incorrect_target_exception from .users_collection import users_collection from .reservation import reservation from .reservation import reservation_factory from .reservation_loader import reservation_loader from .deep_request import deep_request from .reservations_collection import reservations_collection from .reservations_response import reservations_response class reservation_deep_request(deep_request): @property def has_product(self) -> bool: return self.target_barcode is not None or self.target_name is not None @property def has_email(self) -> bool: return self.email is not None @property def has_phone_number(self) -> bool: return self.phone_number is not None @property def has_apikey(self) -> bool: return self.apikey is not None class reservation_app(app_route_database): def __init__( self, connection: sqlalchemy.engine.base.Engine, users: users_collection ) -> None: super().__init__(connection) self.__users_collection = users def get_by_user(self, params: dict) -> dict: request = reservation_deep_request(params) try: with self.__reservation_loader as loader: collection = self.__load_by_user(request, loader) self.__reservation_user_filter(collection, request) reservations_list = reservations_response() \ .collection(collection.results()) return self._success(reservations = reservations_list) except Exception as error: return self.__catch(error) def get_by_product(self, params: dict) -> dict: request = reservation_deep_request(params) try: self.__login(request) item = self.__load_product(request) with self.__reservation_loader as loader: collection = loader.get_by_target(item) self.__reservation_user_filter(collection, request) reservations_list = reservations_response() \ .collection(collection.results()) return self._success(reservations = reservations_list) except Exception as error: return self.__catch(error) def rent_product(self, params: dict) -> dict: request = reservation_deep_request(params) try: self.__login(request) item = self.__load_product(request) rent = self.__create_factory(request).target(item).result() with self.__reservation_loader as loader: if not self.__product_avairable(item): raise bad_request_exception("Item already not avairable") if not loader.store(rent): raise database_exception() return self._success() except Exception as error: return self.__catch(error) def give_back_product(self, params: dict) -> dict: request = reservation_deep_request(params) try: self.__login(request) target = self.__get_reservation(request) with self.__reservation_loader as loader: if loader.drop(target): return self._success() raise database_exception() except Exception as error: return self.__catch(error) def __reservation_user_filter( self, collection: reservations_collection, request: deep_request ) -> bool: if not request.has_email and not request.has_phone_number: return False if request.has_email: collection.by_email(request.email) if request.has_phone_number: collection.by_phone_number(request.phone_number) return True def __reservation_product_filter( self, collection: reservations_collection, request: deep_request ) -> bool: if not request.has_product: return False item = self.__load_product(request) collection.by_target(item) return True def __get_reservation(self, request: deep_request) -> reservation: with self.__reservation_loader as loader: item = self.__load_product(request) collection = loader.get_by_target(item) if not self.__reservation_user_filter(collection, request): raise bad_request_exception("Not contaim email or phone") result = collection.results() if len(result) == 0: raise not_found_exception() if len(result) > 1: raise incorrect_target_exception("Found too much targets.") return result[0] def __load_by_user( self, request: deep_request, loader: reservation_loader ) -> reservations_collection: if request.has_email: return loader.get_by_email(request.email) if request.has_phone_number: return loader.get_by_phone_number(request.phone_number) raise bad_request_exception("Has no email or phone number") def __create_factory(self, request: deep_request) -> reservation_factory: if not request.has_email and not request.has_phone_number: raise bad_request_exception("Not contain email or/and phone") factory = reservation_factory() if request.has_email: factory.email(request.email) if request.has_phone_number: factory.phone_number(request.phone_number) return factory def __login(self, request: deep_request) -> None: if not request.has_apikey: raise access_denied_exception() if self.__users_collection.get(request.apikey): return raise access_denied_exception() def __load_product(self, request: deep_request) -> product: if request.target_barcode is not None: return self.__product_by_barcode(request) if request.target_name is not None: return self.__product_by_name(request) raise bad_request_exception("Not contain barcode or name") def __product_by_barcode(self, request: deep_request) -> product: with self.__product_loader as loader: product = loader.get_by_barcode(request.target_barcode) if product is not None: return product raise not_found_exception() def __product_avairable(self, target: product) -> bool: with self.__product_loader as loader: return loader.get_by_barcode(target.barcode).on_stock > 0 def __product_by_name(self, request: deep_request) -> product: with self.__product_loader as loader: product = loader.get_by_name(request.target_name) if product is not None: product.on_stock return product raise not_found_exception() def __catch(self, error: Exception) -> dict: return self._fail(str(error)) @property def __reservation_loader(self): return reservation_loader(self._connection) @property def __product_loader(self): return product_loader(self._connection)