Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SQLAlchemy Helpers integration #23

Merged
merged 1 commit into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions config.toml.example
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -23,13 +24,6 @@ PREFERRED_URL_SCHEME = "http"
TEMPLATES_AUTO_RELOAD = ""
MAX_COOKIE_SIZE = ""

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add the SQLALCHEMY_DATABASE_URI variable with an example value of, say, sqlite:////tmp/w2fm.db, so that people have an example of how to configure the database.
I would put it close to the top because it's pretty important.

[flaskapp.database]
HOST = "localhost"
PORT = 5432
USERNAME = "root"
PASSWORD = "password"
NAME = "database"

[flaskapp.logsconf]
version = 1
disable_existing_loggers = false
Expand Down
2 changes: 1 addition & 1 deletion webhook_to_fedora_messaging/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
19 changes: 3 additions & 16 deletions webhook_to_fedora_messaging/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
2 changes: 0 additions & 2 deletions webhook_to_fedora_messaging/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later

import logging


class ConfigError(Exception):
def __init__(self, text):
Expand Down
14 changes: 5 additions & 9 deletions webhook_to_fedora_messaging/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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)}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It says "exiting" but it's neither exiting nor raising the exception. I think you should add a raise here so that the exception is propagated upwards the call stack.

raise

main.config.from_mapping(
confdata
)
main.config.from_mapping(confdata)
db.init_app(main)
dictConfig(confdata["logsconf"])

return main
11 changes: 7 additions & 4 deletions webhook_to_fedora_messaging/migrations/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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,
Expand Down Expand Up @@ -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,
)

Expand Down
13 changes: 0 additions & 13 deletions webhook_to_fedora_messaging/models/__init__.py
Original file line number Diff line number Diff line change
@@ -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)
2 changes: 1 addition & 1 deletion webhook_to_fedora_messaging/models/apikey.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion webhook_to_fedora_messaging/models/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
19 changes: 3 additions & 16 deletions webhook_to_fedora_messaging/models/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))
Loading