From c468f51672b4cf9b1f37a9907500a2c8f2608c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ur=C3=ADa?= Date: Sun, 15 Feb 2026 10:36:37 +0100 Subject: [PATCH] [UPD] Added api to create Library --- .python-version | 1 + app/api/actions/install.py | 7 ++++++- app/app.py | 7 ++++++- app/config/__init__.py | 26 +++++++++++++++++++++++--- app/config/defaults.py | 4 +++- app/controller/__init__.py | 7 +++++++ app/routes/__init__.py | 1 + app/routes/api/__init__.py | 6 ++++++ app/routes/api/blueprint.py | 3 +++ app/routes/api/install.py | 24 ++++++++++++++++++++++++ app/routes/api/library/__init__.py | 2 ++ app/routes/api/library/blueprint.py | 3 +++ app/routes/api/library/create.py | 28 ++++++++++++++++++++++++++++ app/schema/library/library.py | 11 +++++++++-- config.ini | 7 ++++++- main.py | 14 ++++++++++++++ test.db | Bin 0 -> 32768 bytes 17 files changed, 142 insertions(+), 9 deletions(-) create mode 100644 .python-version create mode 100644 app/routes/__init__.py create mode 100644 app/routes/api/__init__.py create mode 100644 app/routes/api/blueprint.py create mode 100644 app/routes/api/install.py create mode 100644 app/routes/api/library/__init__.py create mode 100644 app/routes/api/library/blueprint.py create mode 100644 app/routes/api/library/create.py create mode 100644 test.db diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..4c8b864 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12.3 \ No newline at end of file diff --git a/app/api/actions/install.py b/app/api/actions/install.py index 4d8653f..bd6feeb 100644 --- a/app/api/actions/install.py +++ b/app/api/actions/install.py @@ -1,12 +1,17 @@ from sqlalchemy import create_engine -from sqlalchemy.orm import Session from ...schema.library.base import Base from ...db.config.config import get_engine_configuration +import logging +logger = logging.getLogger(__name__) + def install(): + logger.info("Installing") engine_string, echo = get_engine_configuration() + logger.debug(f"engine_string: {engine_string}") engine = create_engine(engine_string, echo=echo=="true", future=True) # TODO metadata = Base.metadata metadata.create_all(engine) + logger.info("Installed") return engine \ No newline at end of file diff --git a/app/app.py b/app/app.py index 7232d4a..bdb7e01 100644 --- a/app/app.py +++ b/app/app.py @@ -1,3 +1,8 @@ +__version__ = "0.2.0.dev" + from flask import Flask -app = Flask(__name__) \ No newline at end of file +from .routes.api import api + +app = Flask(__name__) +app.register_blueprint(api) \ No newline at end of file diff --git a/app/config/__init__.py b/app/config/__init__.py index 46f6a97..d9a9117 100644 --- a/app/config/__init__.py +++ b/app/config/__init__.py @@ -1,6 +1,7 @@ import configparser from .defaults import default_db_query +from .defaults import default_app_port, default_app_debug import logging logger = logging.getLogger(__name__) @@ -8,9 +9,28 @@ logger = logging.getLogger(__name__) config = configparser.ConfigParser() config.read("config.ini") logger.debug(f"config: {config.sections()}") -if not "DataBase" in config: - config["DataBase"] = default_db_query + def save_config(): with open("config.ini", "w") as f: - f.write(config) \ No newline at end of file + config.write(f) + +def check_config(): + save = False + if not "DataBase" in config: + logger.debug("DataBase not found in Config") + config["DataBase"] = { + "query": default_db_query + } + save = True + if not "App" in config: + logger.debug("App not found in Config") + + config["App"] = { + "port": default_app_port, + "debug": default_app_debug + } + save = True + if save: save_config() + +check_config() \ No newline at end of file diff --git a/app/config/defaults.py b/app/config/defaults.py index e29f6c4..136f697 100644 --- a/app/config/defaults.py +++ b/app/config/defaults.py @@ -1 +1,3 @@ -default_db_query = "sqlite:///library.db" \ No newline at end of file +default_db_query = "sqlite:///library.db" +default_app_port = 15012 +default_app_debug = False \ No newline at end of file diff --git a/app/controller/__init__.py b/app/controller/__init__.py index 555f6bc..c9f272b 100644 --- a/app/controller/__init__.py +++ b/app/controller/__init__.py @@ -26,6 +26,13 @@ class LibraryController: def __del__(self): self.session.close() + def __enter__(self): + return self + + def __exit__(self, *exc): + del(self) + return False + @property def data(self): return self._library diff --git a/app/routes/__init__.py b/app/routes/__init__.py new file mode 100644 index 0000000..565e321 --- /dev/null +++ b/app/routes/__init__.py @@ -0,0 +1 @@ +from .api import api \ No newline at end of file diff --git a/app/routes/api/__init__.py b/app/routes/api/__init__.py new file mode 100644 index 0000000..898cfd7 --- /dev/null +++ b/app/routes/api/__init__.py @@ -0,0 +1,6 @@ +from .blueprint import api +from .install import post_install + +from .library import api_library + +api.register_blueprint(api_library) \ No newline at end of file diff --git a/app/routes/api/blueprint.py b/app/routes/api/blueprint.py new file mode 100644 index 0000000..467a4cf --- /dev/null +++ b/app/routes/api/blueprint.py @@ -0,0 +1,3 @@ +from flask import Blueprint + +api = Blueprint("api", __name__, url_prefix="/api") \ No newline at end of file diff --git a/app/routes/api/install.py b/app/routes/api/install.py new file mode 100644 index 0000000..fd71848 --- /dev/null +++ b/app/routes/api/install.py @@ -0,0 +1,24 @@ +from flask import request + +from ...config import config, save_config +from ...api.actions.install import install + +import logging +logger = logging.getLogger(__name__) + +from .blueprint import api + +@api.route("/install", methods=["POST"]) +def post_install(): + try: + body = request.json + except: + logger.debug("Installing with config.ini params") + else: + if body.get("query_string"): + config["DataBase"]["query"] = body.get("query_string") + save_config() + finally: + install() + return { "status": "ok" }, 200 + \ No newline at end of file diff --git a/app/routes/api/library/__init__.py b/app/routes/api/library/__init__.py new file mode 100644 index 0000000..b4a18a3 --- /dev/null +++ b/app/routes/api/library/__init__.py @@ -0,0 +1,2 @@ +from .blueprint import api_library +from .create import create_library \ No newline at end of file diff --git a/app/routes/api/library/blueprint.py b/app/routes/api/library/blueprint.py new file mode 100644 index 0000000..ff171f0 --- /dev/null +++ b/app/routes/api/library/blueprint.py @@ -0,0 +1,3 @@ +from flask import Blueprint + +api_library = Blueprint("api_library", __name__, url_prefix="/library") \ No newline at end of file diff --git a/app/routes/api/library/create.py b/app/routes/api/library/create.py new file mode 100644 index 0000000..8064bfb --- /dev/null +++ b/app/routes/api/library/create.py @@ -0,0 +1,28 @@ +from flask import request +from sqlalchemy.exc import IntegrityError + +from .blueprint import api_library + +from ....controller import LibraryController +from ....schema.library.library import Library + +import logging +logger = logging.getLogger(__name__) + +@api_library.route("/", methods=["POST"]) +def create_library(): + try: + data = request.json + except Exception as e: + logger.debug(f"{e}") + return { "status": "error", "error": "JSON Required" }, 415 + + with LibraryController() as controller: + try: + lib = Library(**data) + library = controller.create(lib) + except IntegrityError as e: + logger.debug(f"DB Error Creating {e}") + return { "status": "error", "error": f"{e.orig}" }, 400 + else: + return { "status": "ok", "result": library.data.to_dict() }, 200 \ No newline at end of file diff --git a/app/schema/library/library.py b/app/schema/library/library.py index c80e010..2231932 100644 --- a/app/schema/library/library.py +++ b/app/schema/library/library.py @@ -10,8 +10,8 @@ from .base import Base class Library(Base): __tablename__ = "library" id: Mapped[int] = mapped_column(primary_key=True) - name: Mapped[str] = mapped_column(String(255)) - notes: Mapped[str] = mapped_column(String(65656)) + name: Mapped[str] = mapped_column(String(255), unique=True) + notes: Mapped[Optional[str]] = mapped_column(String(65656)) envs: Mapped[List["Env"]] = relationship( back_populates="library", cascade="all, delete-orphan" @@ -29,5 +29,12 @@ class Library(Base): back_populates="library", cascade="all, delete-orphan" ) + def to_dict(self) -> dict: + return { + "id": self.id, + "name": self.name, + "notes": self.notes + } + def __repr__(self) -> str: return f"Library(id={self.id!r}, name={self.name!r}, notes={self.notes!r})" \ No newline at end of file diff --git a/config.ini b/config.ini index 5898dd6..8b56289 100644 --- a/config.ini +++ b/config.ini @@ -1,2 +1,7 @@ [DataBase] -query="sqlite:///library.db" +query = sqlite:///test.db + +[App] +port = 15012 +debug = False + diff --git a/main.py b/main.py index e69de29..990a848 100644 --- a/main.py +++ b/main.py @@ -0,0 +1,14 @@ +__version__ = "0.2.0.dev" + +from app import app +from app.config import config + +import logging +level = config["App"].get("debug", False) and logging.DEBUG or logging.INFO +logging.basicConfig(level=level) +logger = logging.getLogger(__name__) + +logger.info(f"Logging level set to {level}") + +if __name__ == "__main__": + app.run(port=config["App"]["port"], debug=config["App"]["debug"]) \ No newline at end of file diff --git a/test.db b/test.db new file mode 100644 index 0000000000000000000000000000000000000000..838c097b9a1e18175de1d2317aa439d6f491d499 GIT binary patch literal 32768 zcmeI&T~E_c7{Kus24z#62_d^6m=n0!;tNrOmxhW37w3R7Ot_jIE6`9jTstE1$`LR8 zJbntlh4E8(>FKd!*1edRXu|S8YqQgH+Os~t^DN|)?e3Jk&=rTx)~OSU$J%X8*R?ev zG)*()J|p*TnUn`)zCSrwp`x{y=J4YVP@U7%!(x{=ChI|`np9v zllJPOSgu%`mMzL#6;a+RmF|g5TAe$jFZ#$KUE6l?m1*ybm)5?>d-Xyz)W()=6*tRK zTRtAPAZ%;HvaRyEwX1Gx;K@HfCvmQ9Qm1ALoj21)Zhl_>xO`<14Q}*BJR-*6R5O{~)ftud#L`A5+S8F+~i@%+R-sK72xH%^NU`;9F&Z#1f;*R#|1hLW>o<{?) z5-PnL=|-36{!>2nE*}-gTFS`H&FP&Z6^G0rxlJXaP^+7(#7Q zg>ZRSh2S>M<(5i>AR9)c`qGJev2>MTeKDLne*5=?|NlWQ>qc&2LGLW8AY<3~Z6XnD z+&CiO(Q`KJ3pXg=_R7VbJxk=H5eu2Z{fX(Exu9!aqwc;7-uiM?Uv=7HQyo{k$?!0) zOv*nsYHdF&D|+^;CN~NK2q1s}0tg_000IagfB*srTvLHNdP*}jQ$ART9`Q9BuBgc; z1A&l-qTUX|jEqaqe$(VeK>z^+5I_I{1Q0*~0R#|00D)^OusCU^hp+#m|NqM${ZkM? z009ILKmY**5I_I{1Q0-Aj0IT#kMZOZ8UhF)fB*srAbL0p5I_I{1Q0*~0R#|0 L009IL7=M8uD}lU+ literal 0 HcmV?d00001