import typing import sqlalchemy import sqlalchemy.engine.base from .app_route import app_route_database from .product import product from .product import product_factory from .product_loader import product_loader from .product_response import product_response from .product_builder import product_builder from .exception import bad_request_exception from .exception import not_found_exception from .exception import access_denied_exception from .users_collection import users_collection from .image import image from .directory_image import directory_image class product_app(app_route_database): def __init__( self, connection: sqlalchemy.engine.base.Engine, users: users_collection, images: directory_image ) -> None: super().__init__(connection) self.__users_collection = users self.__response = product_response(images) self.__images_manager = images def all(self) -> dict: try: with self.__products_database as loader: return self.__collection(loader.load_all()) except Exception as error: return self._fail(str(error)) def get_barcode(self, target: str) -> dict: try: with self.__products_database as loader: return self.__single(loader.get_by_barcode(target)) except Exception as error: return self._fail(str(error)) def get_name(self, target: str) -> dict: try: with self.__products_database as loader: return self.__single(loader.get_by_name(target)) except Exception as error: return self._fail(str(error)) def search_name(self, target: str) -> dict: try: with self.__products_database as loader: return self.__collection(loader.search_by_name(target)) except Exception as error: return self._fail(str(error)) def search_author(self, target: str) -> dict: try: with self.__products_database as loader: return self.__collection(loader.search_by_author(target)) except Exception as error: return self._fail(str(error)) def check_barcode(self, target: str) -> dict: try: with self.__products_database as loader: return self.__exists(loader.barcode_in_use(target)) except Exception as error: return self._fail(str(error)) def check_name(self, target: str) -> dict: try: with self.__products_database as loader: return self.__exists(loader.name_in_use(target)) except Exception as error: return self._fail(str(error)) def __image(self, send: dict) -> image | None: if not "image" in send: return None return image(send["image"]) def create(self, send: dict) -> dict: try: if not self.__logged_in(send): raise access_denied_exception() target = product_builder().modify(send).result image = self.__image(send) if image is None: raise bad_request_exception("not contain image") with self.__products_database as loader: result = loader.store(target) if not result: return self.__modify(result, "Can not create product.") try: self.__images_manager.save(image, target) except Exception as error: loader.drop(target) raise error return self._success() except Exception as error: return self._fail(str(error)) def __logged_in(self, send: dict) -> bool: if not "apikey" in send: return False return self.__users.get(send["apikey"]) is not None def __select_by_sended( self, send: dict, loader: product_loader ) -> product | None: barcode = None name = None if "target_barcode" in send: barcode = send["target_barcode"] if "target_name" in send: name = send["target_name"] if barcode is not None and name is not None: content = "Give only one, target_name or target_barcode" raise bad_request_exception(content) if barcode is None and name is None: content = "Give target_barcode or target_name" raise bad_request_exception(content) result = None if barcode is not None: result = loader.get_by_barcode(barcode) if name is not None: result = loader.get_by_name(name) if result is None: raise not_found_exception() return result def update(self, send: dict) -> dict: try: if not self.__logged_in(send): raise access_denied_exception() with self.__products_database as loader: target = self.__select_by_sended(send, loader) old = target.save_copy() updated = product_builder(target).modify(send).result if not loader.store(updated): return self._fail("Can not update product.") try: self.__images_manager.update(old, updated) except Exception as error: updated.restore_copy(old) if not loader.store(updated): error = "Image caould be moved. Can not restore " error = error + "previous product. Fatal error." return self._fail(error) raise error return self._success() except Exception as error: return self._fail(str(error)) def update_image(self, send: dict) -> dict: try: if not self.__logged_in(send): raise access_denied_exception() image = self.__image(send) if image is None: raise bad_request_exception("Not found image in request.") with self.__products_database as loader: target = self.__select_by_sended(send, loader) self.__images_manager.drop(target) self.__images_manager.save(image, target) return self._success() except Exception as error: return self._fail(str(error)) def delete(self, send: dict) -> dict: try: if not self.__logged_in(send): raise access_denied_exception() with self.__products_database as loader: target = self.__select_by_sended(send, loader) copy = target.save_copy() if not loader.drop(target): return self._fail("Can not delete product.") self.__images_manager.drop(copy) return self._success() except Exception as error: return self._fail(str(error)) def __modify(self, result: bool, cause: str) -> dict: if result: return self._success() else: return self._fail(cause) def __exists(self, result: bool) -> dict: return self._success(exists = result) def __single(self, target: product) -> dict: if target is None: return self._fail("Can not found product in database.") return self._success(product = self.__response.single(target)) def __collection(self, target: typing.Iterable[product]) -> dict: return self._success(collection = self.__response.collection(target)) @property def __users(self) -> users_collection: return self.__users_collection @property def __products_database(self) -> product_loader: return product_loader(self._connection)