diff --git a/MediaManager/src/auth/__init__.py b/MediaManager/src/auth/__init__.py index a363d09..36831fa 100644 --- a/MediaManager/src/auth/__init__.py +++ b/MediaManager/src/auth/__init__.py @@ -8,8 +8,8 @@ from jwt.exceptions import InvalidTokenError from pydantic import BaseModel import database -from database import UserInternal - +import database.user +from database.user import UserInternal class Token(BaseModel): access_token: str @@ -52,7 +52,7 @@ async def get_current_user(token: str = Depends(oauth2_scheme)) -> UserInternal: except InvalidTokenError: log.warning("received invalid token: " + token) raise credentials_exception - user = database.get_user(uid=token_data.uid) + user = database.user.get_user(uid=token_data.uid) if user is None: log.debug("user not found") raise credentials_exception diff --git a/MediaManager/src/auth/password.py b/MediaManager/src/auth/password.py index f1c1a74..76424bf 100644 --- a/MediaManager/src/auth/password.py +++ b/MediaManager/src/auth/password.py @@ -7,7 +7,8 @@ from fastapi.security import OAuth2PasswordRequestForm import database from auth import ACCESS_TOKEN_EXPIRE_MINUTES, create_access_token, Token, router -from database import UserInternal +from database import user +from database.user import User, UserInternal def verify_password(plain_password, hashed_password): @@ -31,7 +32,7 @@ def authenticate_user(email: str, password: str) -> bool | UserInternal: :param password: password of the user :return: if authentication succeeds, returns the user object with added name and lastname, otherwise or if the user doesn't exist returns False """ - user = database.get_user(email=email) + user = database.user.get_user(email=email) if not user: return False if not verify_password(password, user.hashed_password): diff --git a/MediaManager/src/database/__init__.py b/MediaManager/src/database/__init__.py new file mode 100644 index 0000000..c5995bb --- /dev/null +++ b/MediaManager/src/database/__init__.py @@ -0,0 +1,46 @@ +import logging +import os +from logging import getLogger + +import psycopg +from psycopg.rows import dict_row + +log = logging.getLogger(__name__) + +log.debug("servas") + +class PgDatabase(): + """PostgreSQL Database context manager using psycopg""" + + def __init__(self) -> None: + self.driver = psycopg + + def connect_to_database(self): + return self.driver.connect( + autocommit=True, + host=os.getenv("DB_HOST"), + port=os.getenv("DB_PORT"), + user=os.getenv("DB_USERNAME"), + password=os.getenv("DB_PASSWORD"), + dbname=os.getenv("DB_NAME"), + row_factory=dict_row + ) + def __enter__(self): + self.connection = self.connect_to_database() + return self + + def __exit__(self, exception_type, exc_val, traceback): + self.connection.close() + +def init_db(): + log.info("Initializing database") + from database import user + user.init_db() + log.info("Tables initialized successfully") + +init_db() +def drop_tables() -> None: + with PgDatabase() as db: + db.connection.execute("DROP TABLE IF EXISTS users CASCADE;") + log.info("User Table dropped") + diff --git a/MediaManager/src/database.py b/MediaManager/src/database/user.py similarity index 60% rename from MediaManager/src/database.py rename to MediaManager/src/database/user.py index 659211c..1b50878 100644 --- a/MediaManager/src/database.py +++ b/MediaManager/src/database/user.py @@ -1,13 +1,10 @@ -import os -from abc import ABC, abstractmethod -from logging import getLogger from uuid import uuid4 import psycopg -from psycopg.rows import dict_row from pydantic import BaseModel +from pydantic import UUID4 -log = getLogger(__name__) +from database import PgDatabase, log class User(BaseModel): @@ -27,65 +24,6 @@ class UserInternal(User): hashed_password: str -class Database(ABC): - """ - Database context manager - """ - - def __init__(self, driver) -> None: - self.driver = driver - - @abstractmethod - def connect_to_database(self): - raise NotImplementedError() - - def __enter__(self): - self.connection = self.connect_to_database() - return self - - def __exit__(self, exception_type, exc_val, traceback): - self.connection.close() - - -class PgDatabase(Database): - """PostgreSQL Database context manager using psycopg""" - - def __init__(self) -> None: - self.driver = psycopg - super().__init__(self.driver) - - def connect_to_database(self): - return self.driver.connect( - autocommit=True, - host=os.getenv("DB_HOST"), - port=os.getenv("DB_PORT"), - user=os.getenv("DB_USERNAME"), - password=os.getenv("DB_PASSWORD"), - dbname=os.getenv("DB_NAME"), - row_factory=dict_row - ) - - -def init_db(): - with PgDatabase() as db: - db.connection.execute(""" - CREATE TABLE IF NOT EXISTS users ( - id TEXT NOT NULL PRIMARY KEY, - lastname TEXT, - name TEXT NOT NULL, - email TEXT NOT NULL UNIQUE, - hashed_password TEXT NOT NULL - ); - """) - log.info("User Table initialized successfully") - - -def drop_tables() -> None: - with PgDatabase() as db: - db.connection.execute("DROP TABLE IF EXISTS users CASCADE;") - log.info("User Table dropped") - - def create_user(user: UserInternal) -> bool: """ @@ -106,7 +44,7 @@ def create_user(user: UserInternal) -> bool: return False log.info("User inserted successfully") - log.debug(f"Inserted following User: " + user.model_dump()) + log.debug(f"Inserted User: " + user.model_dump().__str__()) return True @@ -133,7 +71,20 @@ def get_user(email: str = None, uid: str = None) -> UserInternal | None: if result is None: return None - user = UserInternal(id=result["id"], name=result["name"], lastname=result["lastname"], email=result["email"], + user = UserInternal(id=result["id"].__str__(), name=result["name"], lastname=result["lastname"], email=result["email"], hashed_password=result["hashed_password"]) log.debug(f"Retrieved User succesfully: {user.model_dump()} ") return user + +def init_db(): + with PgDatabase() as db: + db.connection.execute(""" + CREATE TABLE IF NOT EXISTS users ( + id UUID NOT NULL PRIMARY KEY, + lastname TEXT, + name TEXT NOT NULL, + email TEXT NOT NULL UNIQUE, + hashed_password TEXT NOT NULL + ); + """) + log.info("User Table initialized successfully") \ No newline at end of file diff --git a/MediaManager/src/main.py b/MediaManager/src/main.py index 6eb143b..7f57cc3 100644 --- a/MediaManager/src/main.py +++ b/MediaManager/src/main.py @@ -4,6 +4,7 @@ import sys import uvicorn from fastapi import FastAPI +import database from auth import password from routers import users @@ -11,6 +12,8 @@ logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - module: %(name)s - %(funcName)s(): %(message)s", stream=sys.stdout) +database.init_db() + app = FastAPI(root_path="/api/v1") app.include_router(users.router, tags=["users"]) app.include_router(password.router, tags=["authentication"]) diff --git a/MediaManager/src/routers/users.py b/MediaManager/src/routers/users.py index 09eb0be..4c4e75a 100644 --- a/MediaManager/src/routers/users.py +++ b/MediaManager/src/routers/users.py @@ -6,7 +6,7 @@ from starlette.responses import JSONResponse import database from auth import get_current_user from auth.password import get_password_hash -from database import User, UserInternal +from database.user import UserInternal, User from routers import log router = APIRouter( @@ -34,7 +34,7 @@ async def create_user( ): internal_user = UserInternal(name=user.name, lastname=user.lastname, email=user.email, hashed_password=get_password_hash(user.password)) - if database.create_user(internal_user): + if database.user.create_user(internal_user): log.info("Created new user", internal_user.model_dump()) return internal_user else: diff --git a/MediaManager/test/MediaManager/test_main.http b/MediaManager/test/MediaManager/test_main.http deleted file mode 100644 index a2d81a9..0000000 --- a/MediaManager/test/MediaManager/test_main.http +++ /dev/null @@ -1,11 +0,0 @@ -# Test your FastAPI endpoints - -GET http://127.0.0.1:8000/ -Accept: application/json - -### - -GET http://127.0.0.1:8000/hello/User -Accept: application/json - -###