2025-05-10 14:14:35 +03:00
2025-05-04 18:00:30 +03:00
2025-05-10 14:14:35 +03:00
2025-05-04 21:29:04 +03:00
2025-05-10 14:13:07 +03:00
2025-05-04 18:00:30 +03:00
2025-05-10 14:14:35 +03:00
2025-05-04 21:29:04 +03:00
2025-05-04 18:00:30 +03:00
2025-05-10 14:14:35 +03:00
2025-05-05 16:17:47 +03:00
2025-05-10 14:13:07 +03:00

Eurovision 25 Homereview Backend

Description

This project provides the backend API for the "Eurovision 25 Homereview" application. It allows a small, known group of users, organized into households/groups, to collaboratively review and score Eurovision Song Contest entries during the live show. Users submit numerical scores (1-100) for stage show, wardrobe, and song quality, along with optional text comments. Users can update their scores until the contest is marked as finished by an admin. Afterward, users can view aggregated results within their group or across all participants, including basic statistics.

This backend is built with FastAPI, SQLModel, and SQLite, focusing on core functionality for a fun, trusted-group experience.

Key Features

  • User Authentication & Management: Secure login (JWT), Admin management of users (add, view, update/deactivate).
  • Group Management: Associates users with specific households/groups.
  • Contest Control: Admin can toggle contest status (active for reviews vs. inactive for results).
  • Song Data: Serves information about the participating songs.
  • Review Submission & Updates: Allows users to submit and update numerical scores (1-100 per category) and optional text reviews per song while the contest is active.
  • Results Viewing: Displays aggregated results (group or all) and basic statistics after the contest concludes.

Technology Stack

  • Framework: FastAPI
  • Database: SQLite
  • ORM / Data Validation: SQLModel
  • Python Version: Python 3.12+
  • Package Manager: uv
  • ASGI Server: Uvicorn
  • Authentication: JWT (python-jose or similar library recommended)
  • Password Hashing: passlib (using bcrypt or similar) recommended

Project Structure

.
├── assets/           # Development assets (e.g., notes, mockups) - Not used by the running app
├── docs/             # Documentation (e.g., database_schema.md)
│   └── database_schema.md
├── src/              # ALL application source code and runtime data
│   ├── data/         # Data storage (e.g., SQLite database file)
│   ├── routes/       # API endpoint definitions (routers)
│   │   ├── auth.py
│   │   ├── admin.py
│   │   ├── users.py
│   │   ├── songs.py
│   │   ├── reviews.py
│   │   └── results.py
│   ├── models/       # SQLModel definitions
│   ├── schemas/      # Pydantic schemas (if distinct from models)
│   ├── static/       # Static files served directly by the web server/FastAPI
│   │   └── avatars/  # User avatar images (e.g., 0.png, 1.png)
│   └── app.py        # FastAPI application instance and setup
├── .env.example      # Example environment variables (if used)
├── .gitignore
├── pyproject.toml    # Project metadata and dependencies for uv
├── LICENSE
└── README.md

(Note: Router filenames and static directory structure are suggestions)

Prerequisites

  • Python 3.12 or higher
  • uv package manager (pip install uv)
  • Git

Setup and Installation

  1. Clone the repository:

    git clone <your-repository-url>
    cd eurovision-25-homereview-backend
    
  2. Install dependencies using uv: (Dependencies are defined in pyproject.toml)

    # Create and activate a virtual environment (recommended)
    # python -m venv .venv
    # source .venv/bin/activate  # On Linux/macOS
    # .\.venv\Scripts\activate  # On Windows
    
    # Install dependencies into the active virtual environment
    uv sync
    
  3. Configuration:

    • If using environment variables (e.g., for SECRET_KEY for JWT), copy .env.example to .env (in the project root) and fill in the required values.

Running the Application Locally

  1. Static Files Setup (Development):

    • Ensure the static files directory exists (e.g., src/static/avatars/) and contains the necessary avatar images (0.jpg, 1.jpg, etc.).
    • In src/app.py, you likely need to mount the static directory using FastAPI's StaticFiles. Example:
      # Inside src/app.py
      from fastapi.staticfiles import StaticFiles
      
      # ... other FastAPI setup ...
      
      app.mount("/static", StaticFiles(directory="src/static"), name="static")
      
      (Adjust the path /static and directory "src/static" as needed)
  2. Start the development server: Ensure you are in the project's root directory.

    # Assuming your FastAPI app instance is named 'app' in 'src/app.py'
    uvicorn src.app:app --reload
    

    (The command src.app:app correctly points to the app object inside src/app.py)

  3. Access the API: The API will typically be available at http://127.0.0.1:8000. Static files will be available under the path you mounted (e.g., http://127.0.0.1:8000/static/avatars/1.jpg).

API Documentation & Endpoints

FastAPI provides automatic interactive API documentation where you can explore and test the endpoints below:

Authentication (/auth)

  • POST /token
    • Action: User login. Accepts username and password.
    • Auth: None required.
    • Response: Access Token (JWT).

Users (/users)

  • GET /users/me
    • Action: Get details of the currently authenticated user.
    • Auth: Required (User).
    • Response: Current user's details (ID, username, group info, avatar_id).
    • Note: Clients should construct the avatar image URL using the avatar_id and the static path (e.g., /static/avatars/{avatar_id}.jpg).

Contest/Songs (/songs, /contest)

  • GET /songs/
    • Action: Get the list of participating songs for the contest.
    • Auth: Required (User).
    • Response: List of song objects.
  • GET /contest/status
    • Action: Check if the contest is active (reviews allowed) or inactive (results available).
    • Auth: Required (User).
    • Response: { "is_active": true/false }.

Reviews (/reviews)

  • POST /reviews/
    • Action: Submit or Update a review for a song by the current user. Requires song_id, score_song, score_show, score_wardrobe, optional text_review.
    • Auth: Required (User).
    • Notes: Only allowed when the contest is active. Updates existing review if one exists for the user/song pair.
  • GET /reviews/me
    • Action: Get all reviews submitted by the current user.
    • Auth: Required (User).
    • Response: List of the user's review objects.

Results (/results)

  • GET /results/
    • Action: Get aggregated song results. Use query param ?scope=group (default) or ?scope=all.
    • Auth: Required (User).
    • Notes: Only available when the contest is inactive.
    • Response: List of songs with aggregated scores based on scope.
  • GET /results/stats
    • Action: Get overall statistics (best song, wardrobe, etc.). Use query param ?scope=group (default) or ?scope=all.
    • Auth: Required (User).
    • Notes: Only available when the contest is inactive.
    • Response: Statistics object based on scope.

Admin (/admin)

  • PATCH /admin/contest/status
    • Action: Set the contest status (active/inactive). Requires {"is_active": boolean}.
    • Auth: Required (Admin).
  • POST /admin/users
    • Action: Add a new user. Requires username, password, group_id.
    • Auth: Required (Admin).
  • GET /admin/users
    • Action: List users (optional query filters: group_id, is_active).
    • Auth: Required (Admin).
  • GET /admin/users/{user_id}
    • Action: Get details for a specific user.
    • Auth: Required (Admin).
  • PATCH /admin/users/{user_id}
    • Action: Update a user (optional: group_id, password, is_active). Use is_active: false to deactivate.
    • Auth: Required (Admin).

Database

  • This application uses SQLite for data storage.
  • The database file (e.g., database.sqlite) is configured to be stored within the src/data/ directory.
  • The application should create this file automatically on first run if it doesn't exist (depending on your SQLModel/database connection setup). You might need to ensure the src/data/ directory exists or is created by the application.
  • Database Migrations: Currently, database migrations (like Alembic) are not implemented. Schema changes require manual database adjustments or deletion/recreation of the file in src/data/.
  • Schema Documentation: A high-level overview of the database schema can be found in docs/database_schema.md.

Security Considerations

  • Authentication: Uses JWT Bearer tokens obtained via the /token endpoint. Most endpoints require a valid token.
  • Authorization: Admin endpoints require specific user privileges (implementation details depend on your user model/logic).
  • Passwords: User passwords should be securely hashed using passlib before storage.
  • Scope: This application is designed for a small group of known and trusted users. Features like self-registration are omitted. Do not expose this backend directly to the public internet without further security hardening.

Static Assets (Avatars)

  • User avatars (e.g., 0.jpg, 1.jpg) are served as static files rather than through a dedicated API endpoint.
  • These files should be placed in a directory accessible to the web server (e.g., src/static/avatars/).
  • The web server (Nginx, Apache, or FastAPI's StaticFiles for development) must be configured to serve files from this directory under a specific URL path (e.g., /static/avatars/).
  • Clients are responsible for constructing the full URL to an avatar image using the avatar_id returned by the API and the configured static path.

Testing

Automated tests are not implemented at this time. Manual testing via the API documentation UI and beta testing by the user group are the primary methods of verification.

Deployment

  • Containerization: The intended deployment method is containerization using Podman on a private home server. A Containerfile/Dockerfile should be placed in the project root.
  • Static Files: The production deployment must include configuring the web server (like Nginx running as a reverse proxy or alongside) to efficiently serve the static files (avatars) from their directory (e.g., /var/www/html/static/avatars or similar) under the expected URL path (e.g., /static/avatars/). This is more performant than serving via Python in production.
  • Source Code: The container build process needs to ensure the src directory contents are correctly copied into the container image.

TODOs

  • Replace password hashing with passlib

Contributing

This is primarily a personal project. Contributions are generally not expected. If you find a bug, feel free to open an issue in the repository.

License

This project is licensed under the MIT License. See the LICENSE file for details.

S
Description
No description provided
Readme
653 KiB
Languages
Python 98.6%
Dockerfile 1.4%