Add contest table and routes

This commit is contained in:
Esa Kataja
2025-05-15 17:58:52 +03:00
parent 9ecdc1b040
commit a0344903ec
4 changed files with 88 additions and 1 deletions
+2 -1
View File
@@ -3,7 +3,7 @@ from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
# Import routers # Import routers
from routes import auth, admin, users, songs, reviews, results from routes import auth, admin, users, songs, reviews, results, contest
from lib.logger import logger from lib.logger import logger
from lib.db import init_db from lib.db import init_db
@@ -60,3 +60,4 @@ app.include_router(users.router)
app.include_router(songs.router) app.include_router(songs.router)
app.include_router(reviews.router) app.include_router(reviews.router)
app.include_router(results.router) app.include_router(results.router)
app.include_router(contest.router)
+22
View File
@@ -9,6 +9,7 @@ DROP TABLE IF EXISTS Review;
DROP TABLE IF EXISTS Song; DROP TABLE IF EXISTS Song;
DROP TABLE IF EXISTS "User"; -- Quoted because USER is a reserved keyword DROP TABLE IF EXISTS "User"; -- Quoted because USER is a reserved keyword
DROP TABLE IF EXISTS Team; DROP TABLE IF EXISTS Team;
DROP TABLE IF EXISTS Contest;
DROP TABLE IF EXISTS CountryCodes; DROP TABLE IF EXISTS CountryCodes;
DROP VIEW IF EXISTS ReviewSummary; DROP VIEW IF EXISTS ReviewSummary;
DROP VIEW IF EXISTS ReviewSummaryByTeam; DROP VIEW IF EXISTS ReviewSummaryByTeam;
@@ -17,6 +18,7 @@ DROP SEQUENCE IF EXISTS group_id_seq;
DROP SEQUENCE IF EXISTS user_id_seq; DROP SEQUENCE IF EXISTS user_id_seq;
DROP SEQUENCE IF EXISTS song_id_seq; DROP SEQUENCE IF EXISTS song_id_seq;
DROP SEQUENCE IF EXISTS review_id_seq; DROP SEQUENCE IF EXISTS review_id_seq;
DROP SEQUENCE IF EXISTS contest_id_seq;
-- ============================================================================= -- =============================================================================
-- Sequences for Primary Keys -- Sequences for Primary Keys
@@ -25,6 +27,23 @@ CREATE SEQUENCE group_id_seq START 1;
CREATE SEQUENCE user_id_seq START 1; CREATE SEQUENCE user_id_seq START 1;
CREATE SEQUENCE song_id_seq START 1; CREATE SEQUENCE song_id_seq START 1;
CREATE SEQUENCE review_id_seq START 1; CREATE SEQUENCE review_id_seq START 1;
CREATE SEQUENCE contest_id_seq START 1;
-- =============================================================================
-- Table: Contest
-- Stores information about Eurovision contests by year.
-- =============================================================================
CREATE TABLE Contest (
id INTEGER PRIMARY KEY DEFAULT nextval('contest_id_seq'), -- Use sequence for auto-increment
year INTEGER DEFAULT EXTRACT(YEAR FROM CURRENT_DATE) NOT NULL, -- The year of the Eurovision contest
is_active BOOLEAN DEFAULT TRUE NOT NULL, -- Flag indicating if this is the active contest
finals_date DATE NOT NULL, -- Date of the finals
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the contest was created
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- Timestamp when the contest was last updated
);
-- Add index for faster lookups by year
CREATE INDEX idx_contest_year ON Contest (year);
-- ============================================================================= -- =============================================================================
-- Table: Group -- Table: Group
@@ -183,6 +202,9 @@ INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('CHE', 'Switz
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('UKR', 'Ukraine', 'Ukraina', 'Ukraina'); INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('UKR', 'Ukraine', 'Ukraina', 'Ukraina');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('GBR', 'United Kingdom', 'Englanti', 'Storbritannien'); INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('GBR', 'United Kingdom', 'Englanti', 'Storbritannien');
-- TODO: Clean this next year. Its now here just to get the show running
INSERT INTO Contest (year, finals_date) VALUES (2025, '2025-05-16');
-- ============================================================================= -- =============================================================================
-- Views (Optional - Not Created Here Based on Documentation Decision) -- Views (Optional - Not Created Here Based on Documentation Decision)
-- ============================================================================= -- =============================================================================
+25
View File
@@ -0,0 +1,25 @@
from pydantic import BaseModel, Field
from datetime import date, datetime
class Contest(BaseModel):
id: int
year: int = Field(
default_factory=lambda: datetime.now().year,
description="The year of the contest",
examples=[2025],
)
is_active: bool = Field(
default=True, description="Is this the active contest?", examples=[True, False]
)
finals_date: date = Field(
description="The date of the finals", examples=["2025-05-15"]
)
created_at: datetime = Field(
description="The date and time when the contest was created",
examples=["2025-05-15T17:40:42.000Z"],
)
updated_at: datetime = Field(
description="The date and time when the contest was last updated",
examples=["2025-05-15T17:40:42.000Z"],
)
+39
View File
@@ -0,0 +1,39 @@
from fastapi import APIRouter, HTTPException
from lib.db import get_connection
from lib.logger import logger
from models.contest import Contest
from models.msg import Message
router = APIRouter(prefix="/contest", tags=["contest"])
@router.get("/", response_model=list[Contest])
async def list_contests():
with get_connection() as conn:
logger.debug("Listing all contests")
df = conn.execute("SELECT * FROM Contest").fetchdf()
logger.debug(f"Contests: {df}")
contests = [Contest(**row) for row in df.to_dict(orient="records")]
return contests
@router.get("/{year}", response_model=Contest)
async def get_contest(year: int):
with get_connection() as conn:
df = conn.execute("SELECT * FROM Contest WHERE year = ?", (year,)).fetchdf()
if df.empty:
raise HTTPException(status_code=404, detail="Contest not found")
contest = Contest(**df.to_dict(orient="records")[0])
return contest
@router.put("/", response_model=Message)
async def update_contest(year: int, is_active: bool):
with get_connection() as conn:
logger.debug(f"Updating contest {year} to active: {is_active}")
conn.execute(
"UPDATE Contest SET is_active = ? WHERE year = ?",
(is_active, year),
)
return Message(message="Contest updated successfully")