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 0000000..838c097 Binary files /dev/null and b/test.db differ