|
|
@@ -0,0 +1,235 @@
|
|
|
+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 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_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:
|
|
|
+ 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)
|
|
|
+
|