From 413f2347f9ed3e928f78faa3195879ed8f10a013 Mon Sep 17 00:00:00 2001 From: Akashdeep Dhar Date: Tue, 2 Jul 2024 09:55:15 +0530 Subject: [PATCH] Add SQLAlchemy Helpers integration Signed-off-by: Akashdeep Dhar --- config.toml.example | 8 +------- .../config/__init__.py | 2 +- webhook_to_fedora_messaging/database.py | 19 +++---------------- webhook_to_fedora_messaging/exceptions.py | 2 -- webhook_to_fedora_messaging/main.py | 14 +++++--------- webhook_to_fedora_messaging/migrations/env.py | 11 +++++++---- .../models/__init__.py | 13 ------------- webhook_to_fedora_messaging/models/apikey.py | 2 +- webhook_to_fedora_messaging/models/service.py | 2 +- webhook_to_fedora_messaging/models/util.py | 19 +++---------------- 10 files changed, 22 insertions(+), 70 deletions(-) diff --git a/config.toml.example b/config.toml.example index 8d26fb1..3d1bdbd 100644 --- a/config.toml.example +++ b/config.toml.example @@ -1,5 +1,6 @@ [flaskapp] DEBUG = true +SQLALCHEMY_DATABASE_URI = "sqlite:////tmp/w2fm.db" TESTING = true PROPAGATE_EXCEPTIONS = "" SECRET_KEY = "PLEASE-CHANGE-THIS-BEFORE-STARTING" @@ -23,13 +24,6 @@ PREFERRED_URL_SCHEME = "http" TEMPLATES_AUTO_RELOAD = "" MAX_COOKIE_SIZE = "" - [flaskapp.database] - HOST = "localhost" - PORT = 5432 - USERNAME = "root" - PASSWORD = "password" - NAME = "database" - [flaskapp.logsconf] version = 1 disable_existing_loggers = false diff --git a/webhook_to_fedora_messaging/config/__init__.py b/webhook_to_fedora_messaging/config/__init__.py index 2eaa335..7713cf3 100644 --- a/webhook_to_fedora_messaging/config/__init__.py +++ b/webhook_to_fedora_messaging/config/__init__.py @@ -9,7 +9,7 @@ from webhook_to_fedora_messaging.exceptions import ConfigError -def get_config(): +def get_config() -> dict: path = environ["W2FM_APPCONFIG"] try: with open(path, "rb") as file: diff --git a/webhook_to_fedora_messaging/database.py b/webhook_to_fedora_messaging/database.py index e827500..1351dac 100644 --- a/webhook_to_fedora_messaging/database.py +++ b/webhook_to_fedora_messaging/database.py @@ -8,20 +8,7 @@ Import the functions we will use in the main code and in migrations. """ -from sqlalchemy_helpers import ( # noqa: F401 - Base, - DatabaseManager, - exists_in_db, - get_or_create, - is_sqlite, -) +from sqlalchemy_helpers import Base, get_or_create, update_or_create, is_sqlite, exists_in_db # noqa: F401 +from sqlalchemy_helpers.flask_ext import DatabaseExtension, get_or_404, first_or_404 # noqa: F401 -from webhook_to_fedora_messaging.config import get_config - - -db_config = get_config().database.model_dump() -db = DatabaseManager( - str(db_config["sqlalchemy"]["url"]), - str(db_config["alembic"]["migrations_path"]), - engine_args=db_config["sqlalchemy"], -) +db = DatabaseExtension() diff --git a/webhook_to_fedora_messaging/exceptions.py b/webhook_to_fedora_messaging/exceptions.py index e1f393a..344bbfc 100644 --- a/webhook_to_fedora_messaging/exceptions.py +++ b/webhook_to_fedora_messaging/exceptions.py @@ -2,8 +2,6 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -import logging - class ConfigError(Exception): def __init__(self, text): diff --git a/webhook_to_fedora_messaging/main.py b/webhook_to_fedora_messaging/main.py index daa740f..babb0ec 100644 --- a/webhook_to_fedora_messaging/main.py +++ b/webhook_to_fedora_messaging/main.py @@ -7,17 +7,13 @@ custom configuration file will be inherently taken from the default values """ -import sys from flask import Flask - +from webhook_to_fedora_messaging.database import db from .config import get_config from .config.defaults import LOGGER_CONFIG - from logging.config import dictConfig - from webhook_to_fedora_messaging.exceptions import ConfigError - import logging @@ -35,13 +31,13 @@ def create_app(): # Then load the variables up from the custom configuration file try: - confdata = get_config() + confdata = get_config() except ConfigError as expt: logging.error(f"Exiting - Reason - {str(expt)}") + raise - main.config.from_mapping( - confdata - ) + main.config.from_mapping(confdata) + db.init_app(main) dictConfig(confdata["logsconf"]) return main diff --git a/webhook_to_fedora_messaging/migrations/env.py b/webhook_to_fedora_messaging/migrations/env.py index ab902a6..9ede731 100644 --- a/webhook_to_fedora_messaging/migrations/env.py +++ b/webhook_to_fedora_messaging/migrations/env.py @@ -7,8 +7,9 @@ from alembic import context from sqlalchemy import engine_from_config, pool -from webhook_to_fedora_messaging.config import get_config +from webhook_to_fedora_messaging.main import create_app from webhook_to_fedora_messaging.database import Base +from sqlalchemy_helpers.flask_ext import get_url_from_app # this is the Alembic Config object, which provides @@ -29,6 +30,9 @@ # my_important_option = alembic_config.get_main_option("my_important_option") # ... etc. +url = str(get_url_from_app(create_app)) +alembic_config.set_main_option("sqlalchemy.url", url) + def run_migrations_offline() -> None: """Run migrations in 'offline' mode. @@ -42,7 +46,6 @@ def run_migrations_offline() -> None: script output. """ - url = str(get_config().database.sqlalchemy.url) context.configure( url=url, target_metadata=target_metadata, @@ -73,8 +76,8 @@ def process_revision_directives(context, revision, directives): logger.info("No changes in schema detected.") connectable = engine_from_config( - get_config().database.sqlalchemy.model_dump(), - prefix="", + alembic_config.get_section(alembic_config.config_ini_section), + prefix="sqlalchemy.", poolclass=pool.NullPool, ) diff --git a/webhook_to_fedora_messaging/models/__init__.py b/webhook_to_fedora_messaging/models/__init__.py index 4d91f8a..637448d 100644 --- a/webhook_to_fedora_messaging/models/__init__.py +++ b/webhook_to_fedora_messaging/models/__init__.py @@ -1,16 +1,3 @@ # SPDX-FileCopyrightText: Contributors to the Fedora Project # # SPDX-License-Identifier: GPL-3.0-or-later - -from sqlalchemy import Column, Integer, Unicode - -from webhook_to_fedora_messaging.database import Base - - -class User(Base): - __tablename__ = "users" - - id = Column("id", Integer, primary_key=True) - name = Column(Unicode(254), index=True, unique=True, nullable=False) - full_name = Column(Unicode(254), nullable=False) - timezone = Column(Unicode(127), nullable=True) diff --git a/webhook_to_fedora_messaging/models/apikey.py b/webhook_to_fedora_messaging/models/apikey.py index a218e4a..6a86524 100644 --- a/webhook_to_fedora_messaging/models/apikey.py +++ b/webhook_to_fedora_messaging/models/apikey.py @@ -14,7 +14,7 @@ class APIKey(Base, UUIDCreatableMixin, CreatableMixin): __tablename__ = "apikeys" id = Column(Integer, primary_key=True, nullable=False) - user_id = Column(Integer, ForeignKey("user.id", ondelete="CASCADE"), unique=False, nullable=False) + user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), unique=False, nullable=False) name = Column(UnicodeText, nullable=False) token = Column(UnicodeText, unique=True, nullable=False, default=uuid4().hex) expiry_date = Column(DateTime, nullable=True) diff --git a/webhook_to_fedora_messaging/models/service.py b/webhook_to_fedora_messaging/models/service.py index 62ad780..6297e5b 100644 --- a/webhook_to_fedora_messaging/models/service.py +++ b/webhook_to_fedora_messaging/models/service.py @@ -12,7 +12,7 @@ class Service(Base, UUIDCreatableMixin, CreatableMixin): __tablename__ = "services" id = Column(Integer, primary_key=True, nullable=False) - user_id = Column(Integer, ForeignKey("user.id", ondelete="CASCADE"), unique=False, nullable=False) + user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), unique=False, nullable=False) name = Column(UnicodeText, nullable=False) type = Column(UnicodeText, nullable=False) desc = Column(UnicodeText, nullable=False) diff --git a/webhook_to_fedora_messaging/models/util.py b/webhook_to_fedora_messaging/models/util.py index 38e52a0..95066df 100644 --- a/webhook_to_fedora_messaging/models/util.py +++ b/webhook_to_fedora_messaging/models/util.py @@ -4,26 +4,13 @@ from sqlalchemy import Column, UnicodeText -from sqlalchemy.ext.compiler import compiles -from sqlalchemy.sql.expression import FunctionElement from sqlalchemy.types import DateTime as SQLDateTime +from datetime import datetime, UTC +from functools import partial from uuid import uuid4 -class utcnow(FunctionElement): - """ - Current timestamp in UTC for SQL expressions - """ - type = SQLDateTime - inherit_cache = True - - -@compiles(utcnow, "postgresql") -def _postgresql_utcnow(element, compiler, **kwargs): - return "(NOW() AT TIME ZONE 'utc')" - - class UUIDCreatableMixin: """ An SQLAlchemy mixin to automatically generate a custom 8-digit UUID string @@ -37,4 +24,4 @@ class CreatableMixin: An SQLAlchemy mixin to store the time when an entity was created """ - creation_date = Column("creation_date", SQLDateTime, nullable=False, server_default=utcnow()) + creation_date = Column("creation_date", SQLDateTime, nullable=False, default=partial(datetime.now, tz=UTC))