diff --git a/app/__pycache__/__init__.cpython-312.pyc b/app/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 82fbe022..00000000 Binary files a/app/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/app/__pycache__/main.cpython-312.pyc b/app/__pycache__/main.cpython-312.pyc deleted file mode 100644 index d1c2e28d..00000000 Binary files a/app/__pycache__/main.cpython-312.pyc and /dev/null differ diff --git a/app/core/__pycache__/config.cpython-312.pyc b/app/core/__pycache__/config.cpython-312.pyc deleted file mode 100644 index 121334dc..00000000 Binary files a/app/core/__pycache__/config.cpython-312.pyc and /dev/null differ diff --git a/app/core/__pycache__/database.cpython-312.pyc b/app/core/__pycache__/database.cpython-312.pyc deleted file mode 100644 index 6ca0fae9..00000000 Binary files a/app/core/__pycache__/database.cpython-312.pyc and /dev/null differ diff --git a/app/core/__pycache__/security.cpython-312.pyc b/app/core/__pycache__/security.cpython-312.pyc deleted file mode 100644 index 18f9c558..00000000 Binary files a/app/core/__pycache__/security.cpython-312.pyc and /dev/null differ diff --git a/app/core/config.py b/app/core/config.py deleted file mode 100644 index d6272904..00000000 --- a/app/core/config.py +++ /dev/null @@ -1,11 +0,0 @@ -from pydantic_settings import BaseSettings - -class Settings(BaseSettings): - DATABASE_URL: str - SECRET_KEY: str - ACCESS_TOKEN_EXPIRE_MINUTES: int = 10080 # 7 dage - - class Config: - env_file = ".env" - -settings = Settings() diff --git a/app/core/database.py b/app/core/database.py deleted file mode 100644 index 7eb83441..00000000 --- a/app/core/database.py +++ /dev/null @@ -1,21 +0,0 @@ -from sqlalchemy import create_engine -from sqlalchemy.orm import DeclarativeBase, sessionmaker -from app.core.config import settings - -engine = create_engine( - settings.DATABASE_URL, - pool_pre_ping=True, # genforbinder hvis connection er død - pool_recycle=3600, # genbruger ikke forbindelser ældre end 1 time -) - -SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) - -class Base(DeclarativeBase): - pass - -def get_db(): - db = SessionLocal() - try: - yield db - finally: - db.close() diff --git a/app/core/security.py b/app/core/security.py deleted file mode 100644 index 2f51eaea..00000000 --- a/app/core/security.py +++ /dev/null @@ -1,53 +0,0 @@ -from datetime import datetime, timedelta, timezone -from jose import JWTError, jwt -from passlib.context import CryptContext -from fastapi import Depends, HTTPException, status -from fastapi.security import OAuth2PasswordBearer -from sqlalchemy.orm import Session -from app.core.config import settings -from app.core.database import get_db - -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login") - -ALGORITHM = "HS256" - - -def hash_password(password: str) -> str: - return pwd_context.hash(password) - - -def verify_password(plain: str, hashed: str) -> bool: - return pwd_context.verify(plain, hashed) - - -def create_access_token(data: dict) -> str: - expire = datetime.now(timezone.utc) + timedelta( - minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES - ) - return jwt.encode({**data, "exp": expire}, settings.SECRET_KEY, algorithm=ALGORITHM) - - -def get_current_user( - token: str = Depends(oauth2_scheme), - db: Session = Depends(get_db), -): - from app.models.user import User - - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Kunne ikke validere token", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: - payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[ALGORITHM]) - user_id: str = payload.get("sub") - if user_id is None: - raise credentials_exception - except JWTError: - raise credentials_exception - - user = db.query(User).filter(User.id == user_id).first() - if user is None: - raise credentials_exception - return user diff --git a/app/models/__init__.py b/app/models/__init__.py deleted file mode 100644 index b2c654ec..00000000 --- a/app/models/__init__.py +++ /dev/null @@ -1,137 +0,0 @@ -import uuid -from datetime import datetime, timezone -from sqlalchemy import ( - Boolean, DateTime, ForeignKey, Integer, String, Text -) -from sqlalchemy.orm import Mapped, mapped_column, relationship -from app.core.database import Base - - -def new_uuid() -> str: - return str(uuid.uuid4()) - -def now_utc() -> datetime: - return datetime.now(timezone.utc) - - -# ── User ────────────────────────────────────────────────────────────────────── - -class User(Base): - __tablename__ = "users" - - id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) - username: Mapped[str] = mapped_column(String(64), unique=True, nullable=False) - email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False) - password_hash: Mapped[str] = mapped_column(String(255), nullable=False) - created_at: Mapped[datetime] = mapped_column(DateTime, default=now_utc) - - projects: Mapped[list["Project"]] = relationship("Project", back_populates="owner") - memberships: Mapped[list["ProjectMember"]] = relationship("ProjectMember", back_populates="user") - songs: Mapped[list["Song"]] = relationship("Song", back_populates="owner") - alternatives: Mapped[list["DanceAlternative"]] = relationship("DanceAlternative", foreign_keys="DanceAlternative.created_by", back_populates="creator") - alt_ratings: Mapped[list["DanceAlternativeRating"]] = relationship("DanceAlternativeRating", foreign_keys="DanceAlternativeRating.user_id", back_populates="user") - - -# ── Project ─────────────────────────────────────────────────────────────────── - -class Project(Base): - __tablename__ = "projects" - - id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) - owner_id: Mapped[str] = mapped_column(String(36), ForeignKey("users.id"), nullable=False) - name: Mapped[str] = mapped_column(String(128), nullable=False) - description: Mapped[str] = mapped_column(Text, default="") - is_public: Mapped[bool] = mapped_column(Boolean, default=False) - updated_at: Mapped[datetime] = mapped_column(DateTime, default=now_utc, onupdate=now_utc) - - owner: Mapped["User"] = relationship("User", back_populates="projects") - members: Mapped[list["ProjectMember"]] = relationship("ProjectMember", back_populates="project", cascade="all, delete-orphan") - project_songs: Mapped[list["ProjectSong"]] = relationship("ProjectSong", back_populates="project", order_by="ProjectSong.position", cascade="all, delete-orphan") - - -class ProjectMember(Base): - __tablename__ = "project_members" - - id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) - project_id: Mapped[str] = mapped_column(String(36), ForeignKey("projects.id"), nullable=False) - user_id: Mapped[str] = mapped_column(String(36), ForeignKey("users.id"), nullable=False) - role: Mapped[str] = mapped_column(String(16), default="viewer") # owner | editor | viewer - status: Mapped[str] = mapped_column(String(16), default="pending") # pending | accepted - invited_at: Mapped[datetime] = mapped_column(DateTime, default=now_utc) - - project: Mapped["Project"] = relationship("Project", back_populates="members") - user: Mapped["User"] = relationship("User", back_populates="memberships") - - -# ── Song ────────────────────────────────────────────────────────────────────── - -class Song(Base): - __tablename__ = "songs" - - id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) - owner_id: Mapped[str] = mapped_column(String(36), ForeignKey("users.id"), nullable=False) - title: Mapped[str] = mapped_column(String(255), nullable=False) - artist: Mapped[str] = mapped_column(String(255), default="") - local_path: Mapped[str] = mapped_column(String(512), default="") # kun relevant på PC - bpm: Mapped[int] = mapped_column(Integer, default=0) - duration_sec: Mapped[int] = mapped_column(Integer, default=0) - synced_at: Mapped[datetime] = mapped_column(DateTime, default=now_utc) - - owner: Mapped["User"] = relationship("User", back_populates="songs") - dances: Mapped[list["SongDance"]] = relationship("SongDance", back_populates="song", order_by="SongDance.dance_order", cascade="all, delete-orphan") - project_songs: Mapped[list["ProjectSong"]] = relationship("ProjectSong", back_populates="song") - - -class ProjectSong(Base): - __tablename__ = "project_songs" - - id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) - project_id: Mapped[str] = mapped_column(String(36), ForeignKey("projects.id"), nullable=False) - song_id: Mapped[str] = mapped_column(String(36), ForeignKey("songs.id"), nullable=False) - position: Mapped[int] = mapped_column(Integer, nullable=False) - status: Mapped[str] = mapped_column(String(16), default="pending") # pending | playing | played | skipped - - project: Mapped["Project"] = relationship("Project", back_populates="project_songs") - song: Mapped["Song"] = relationship("Song", back_populates="project_songs") - - -# ── Dance ───────────────────────────────────────────────────────────────────── - -class SongDance(Base): - __tablename__ = "song_dances" - - id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) - song_id: Mapped[str] = mapped_column(String(36), ForeignKey("songs.id"), nullable=False) - dance_name: Mapped[str] = mapped_column(String(128), nullable=False) - dance_order: Mapped[int] = mapped_column(Integer, default=1) - - song: Mapped["Song"] = relationship("Song", back_populates="dances") - alternatives: Mapped[list["DanceAlternative"]] = relationship("DanceAlternative", foreign_keys="DanceAlternative.song_dance_id", back_populates="song_dance", cascade="all, delete-orphan") - - -class DanceAlternative(Base): - __tablename__ = "dance_alternatives" - - id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) - song_dance_id: Mapped[str] = mapped_column(String(36), ForeignKey("song_dances.id"), nullable=False) - alt_song_dance_id: Mapped[str] = mapped_column(String(36), ForeignKey("song_dances.id"), nullable=False) - created_by: Mapped[str] = mapped_column(String(36), ForeignKey("users.id"), nullable=False) - note: Mapped[str] = mapped_column(Text, default="") - bayesian_score: Mapped[float] = mapped_column(default=0.0) # genberegnes ved hver rating - - song_dance: Mapped["SongDance"] = relationship("SongDance", foreign_keys=[song_dance_id], back_populates="alternatives") - alt_song_dance: Mapped["SongDance"] = relationship("SongDance", foreign_keys=[alt_song_dance_id]) - creator: Mapped["User"] = relationship("User", foreign_keys=[created_by]) - ratings: Mapped[list["DanceAlternativeRating"]] = relationship("DanceAlternativeRating", back_populates="alternative", cascade="all, delete-orphan") - - -class DanceAlternativeRating(Base): - __tablename__ = "dance_alternative_ratings" - - id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) - alternative_id: Mapped[str] = mapped_column(String(36), ForeignKey("dance_alternatives.id"), nullable=False) - user_id: Mapped[str] = mapped_column(String(36), ForeignKey("users.id"), nullable=False) - score: Mapped[int] = mapped_column(Integer, nullable=False) # 1-5 - - alternative: Mapped["DanceAlternative"] = relationship("DanceAlternative", back_populates="ratings") - user: Mapped["User"] = relationship("User", foreign_keys=[user_id]) diff --git a/app/models/__pycache__/__init__.cpython-312.pyc b/app/models/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 8fabe48e..00000000 Binary files a/app/models/__pycache__/__init__.cpython-312.pyc and /dev/null differ