diff --git a/src/app.py b/src/app.py index f090526..fdb392e 100644 --- a/src/app.py +++ b/src/app.py @@ -1,9 +1,15 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from routes import admin_router, score_router, user_router, card_router, movie_router -from sqlmodel import SQLModel, Session, create_engine from models import * +from lib.database import init_db + + +origins = [ + "http://localhost", + "http://localhost:3000", +] app = FastAPI( title="Paska joululeffa 2024", @@ -27,12 +33,6 @@ app.include_router(card_router) app.include_router(movie_router) -engine = create_engine("sqlite:///data.sqlite") - -SQLModel.metadata.create_all(engine) - - @app.on_event("startup") async def connect_db(): - with Session(engine) as session: - app.state.db = session + init_db() diff --git a/src/lib/database.py b/src/lib/database.py new file mode 100644 index 0000000..d300b2e --- /dev/null +++ b/src/lib/database.py @@ -0,0 +1,89 @@ +from contextlib import contextmanager +import duckdb +import bcrypt +from rich import print + + +from lib import settings +from models.user import UserIn, UserOut + + +@contextmanager +def get_db(): + try: + conn = duckdb.connect(database=settings.db_url) + yield conn + finally: + conn.close() + + +def db_run(sql): + with get_db() as conn: + conn.execute(sql) + + +def init_db(): + if settings.db_url.exists(): + # TODO: Development feature. Remove this in production + from os import unlink + + unlink(settings.db_url) + # return + sql = "" + with open("lib/database.sql") as f: + sql = f.read() + + db_run(sql) + + # Initialize default user + + hashed_password = bcrypt.hashpw("password".encode("utf-8"), bcrypt.gensalt()) + + sql = f"INSERT INTO users (username, password, is_admin) VALUES ('admin', '{hashed_password.decode('utf-8')}', true)" + db_run(sql) + + sql = f"INSERT INTO users (username, password, is_admin) VALUES ('test', '{hashed_password.decode('utf-8')}', false)" + db_run(sql) + + +def get_user_by_username(username) -> UserIn | None: + sql = f"SELECT * FROM users WHERE username = '{username}'" + with get_db() as conn: + result = conn.execute(sql).fetchone() + if result is not None: + return UserIn( + id=str(result[0]), + username=result[1], + password=result[2], + email=result[3], + avatar_url=result[4], + is_active=result[5], + is_admin=result[6], + last_login=result[7], + created_at=result[8], + updated_at=result[9], + ) + + return None + + +def get_all_users() -> list[UserOut]: + sql = "SELECT * FROM users" + with get_db() as conn: + result = conn.execute(sql).fetchall() + users = [] + for row in result: + user = UserOut( + id=str(row[0]), + username=row[1], + email=row[3], + avatar_url=row[4], + is_active=row[5], + is_admin=row[6], + last_login=row[7], + created_at=row[8], + updated_at=row[9], + ) + users.append(user) + + return users diff --git a/src/lib/database.sql b/src/lib/database.sql new file mode 100644 index 0000000..602a381 --- /dev/null +++ b/src/lib/database.sql @@ -0,0 +1,54 @@ +CREATE TABLE users ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + username TEXT UNIQUE NOT NULL, + password TEXT NOT NULL, + email TEXT UNIQUE DEFAULT NULL, + avatar_url TEXT DEFAULT 'https://api.dicebear.com/9.x/adventurer-neutral/svg?seed=Kingston' NULL, + is_active BOOLEAN DEFAULT TRUE, + is_admin BOOLEAN DEFAULT FALSE, + last_login TIMESTAMP DEFAULT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + modified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE movies ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + name TEXT NOT NULL, + imdb_id TEXT UNIQUE, + actors TEXT, + release_year INTEGER, + plot TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + modified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE cards ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + title TEXT NOT NULL, + description TEXT NOT NULL, + point_value INTEGER CHECK (point_value BETWEEN 1 AND 3), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + modified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE scores ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + movie_id UUID, + user_id UUID, + FOREIGN KEY (movie_id) REFERENCES movies(id), + FOREIGN KEY (user_id) REFERENCES users(id), + score INTEGER DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + modified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE log ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + message TEXT NOT NULL, + message_type TEXT NOT NULL, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Seed users table +--INSERT INTO users (username, password, is_admin) VALUES + -- ('asdasd', '$2b$12$$2b$12$luWF2SnKlRQjCcFTssaAtuBOBEmDDxZ9XMfDoc6fO/Nkiyu.sGrgW', true), -- password: asd \ No newline at end of file