diff --git a/api/main.py b/api/main.py index b2f5ca3..646f243 100644 --- a/api/main.py +++ b/api/main.py @@ -5,6 +5,8 @@ from sys import argv from routers.prefixes import prefix_router from routers.tickets import ticket_router +from routers.baskets import basket_router +from routers.combined import combined_router if argv[1] == "run": app = FastAPI(title="TAM3 API Server", docs_url=None, redoc_url=None) @@ -12,4 +14,6 @@ else: app = FastAPI(title="TAM3 API Server") app.include_router(prefix_router) -app.include_router(ticket_router) \ No newline at end of file +app.include_router(ticket_router) +app.include_router(basket_router) +app.include_router(combined_router) \ No newline at end of file diff --git a/api/repos/baskets.py b/api/repos/baskets.py new file mode 100644 index 0000000..28f04dc --- /dev/null +++ b/api/repos/baskets.py @@ -0,0 +1,43 @@ +from dataclasses import dataclass +from .template import Repo + +@dataclass +class Basket: + prefix: str + b_id: int + description: str = "" + donors: str = "" + winning_ticket: int = 0 + changed: bool = False + +class BasketRepo(Repo): + def get_prefix_one(self, prefix: str, b_id: int): + self.cur.execute("SELECT * FROM baskets WHERE prefix = %s AND b_id = %s", (prefix, b_id)) + result = self.cur.fetchone() + if not result: + return Basket(prefix, b_id) + return Basket(*result) + def get_prefix_range(self, prefix: str, b_from: int, b_to: int): + r_dict = {i: Basket(prefix, i) for i in range(b_from, b_to+1)} + self.cur.execute("SELECT * FROM baskets WHERE prefix = %s AND b_id BETWEEN %s AND %s", (prefix, b_from, b_to)) + results = self.cur.fetchall() + for r in results: + r_dict[r[1]] = Basket(*r) + return list(r_dict.values()) + def get_prefix_all(self, prefix: str): + self.cur.execute("SELECT * FROM baskets WHERE prefix = %s", (prefix,)) + results = self.cur.fetchall() + if not results: + return [] + return [Basket(*r) for r in results] + def get_all(self): + self.cur.execute("SELECT * FROM baskets") + results = self.cur.fetchall() + if not results: + return [] + return [Basket(*r) for r in results] + def post_list(self, baskets: list[Basket]): + for b in baskets: + self.cur.execute("REPLACE INTO baskets VALUES (%s, %s, %s, %s, %s)", (b.prefix, b.b_id, b.description, b.donors, b.winning_ticket)) + self.conn.commit() + return {"detail": "Baskets posted successfully."} \ No newline at end of file diff --git a/api/repos/combined.py b/api/repos/combined.py new file mode 100644 index 0000000..a707290 --- /dev/null +++ b/api/repos/combined.py @@ -0,0 +1,43 @@ +from dataclasses import dataclass +from .template import Repo + +@dataclass +class Combined: + prefix: str + b_id: int + winning_ticket: int = 0 + winner: str = ", " + changed: bool = False + +class CombinedRepo(Repo): + def get_prefix_one(self, prefix: str, b_id: int) -> Combined: + self.cur.execute("SELECT * FROM combined WHERE prefix = %s AND b_id = %s", (prefix, b_id)) + result = self.cur.fetchone() + if not result: + return Combined(prefix, b_id) + return Combined(*result) + def get_prefix_range(self, prefix: str, b_from: int, b_to: int) -> list[Combined]: + r_dict = {i: Combined(prefix, i) for i in range(b_from, b_to+1)} + self.cur.execute("SELECT * FROM combined WHERE prefix = %s AND b_id BETWEEN %s AND %s", (prefix, b_from, b_to)) + results = self.cur.fetchall() + for b in results: + r_dict[b[1]] = Combined(*b) + return list(r_dict.values()) + def get_prefix_all(self, prefix:str) -> list[Combined]: + self.cur.execute("SELECT * FROM combined WHERE prefix = %s", (prefix,)) + results = self.cur.fetchall() + if not results: + return [] + return [Combined(*r) for r in results] + def get_all(self) -> list[Combined]: + self.cur.execute("SELECT * FROM combined") + results = self.cur.fetchall() + if not results: + return [] + return [Combined(*r) for r in results] + def post_list(self, c_entries: list[Combined]): + for combined in c_entries: + self.cur.execute("INSERT INTO baskets (prefix, b_id, winning_ticket) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE winning_ticket=%s", + (combined.prefix, combined.b_id, combined.winning_ticket, combined.winning_ticket)) + self.conn.commit() + return {"detail": "Winners posted successfully"} \ No newline at end of file diff --git a/api/routers/baskets.py b/api/routers/baskets.py new file mode 100644 index 0000000..1b8c4f1 --- /dev/null +++ b/api/routers/baskets.py @@ -0,0 +1,36 @@ +from fastapi import APIRouter +from exceptions import bad_key +from repos.api_keys import ApiKeyRepo +from repos.baskets import Basket, BasketRepo + +basket_router = APIRouter(prefix="/api/baskets") + +@basket_router.get("/") +def get_all_baskets(api_key: str) -> list[Basket]: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return BasketRepo().get_all() + +@basket_router.get("/{prefix}/") +def get_prefix_baskets(api_key: str, prefix: str) -> list[Basket]: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return BasketRepo().get_prefix_all(prefix) + +@basket_router.get("/{prefix}/{b_id}/") +def get_prefix_basket_one(api_key: str, prefix: str, b_id: int) -> Basket: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return BasketRepo().get_prefix_one(prefix, b_id) + +@basket_router.get("/{prefix}/{b_from}/{b_to}/") +def get_prefix_basket_range(api_key: str, prefix: str, b_from: int, b_to: int) -> list[Basket]: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return BasketRepo().get_prefix_range(prefix, b_from, b_to) + +@basket_router.post("/") +def post_basket_list(api_key: str, baskets: list[Basket]): + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return BasketRepo().post_list(baskets) \ No newline at end of file diff --git a/api/routers/combined.py b/api/routers/combined.py new file mode 100644 index 0000000..da5fba5 --- /dev/null +++ b/api/routers/combined.py @@ -0,0 +1,36 @@ +from fastapi import APIRouter +from repos.combined import Combined, CombinedRepo +from repos.api_keys import ApiKeyRepo +from exceptions import bad_key + +combined_router = APIRouter(prefix="/api/combined") + +@combined_router.get("/") +def get_all_combined(api_key: str) -> list[Combined]: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return CombinedRepo().get_all() + +@combined_router.get("/{prefix}/") +def get_prefix_combined(api_key: str, prefix: str) -> list[Combined]: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return CombinedRepo().get_prefix_all(prefix) + +@combined_router.get("/{prefix}/{b_id}/") +def get_prefix_combined_one(api_key: str, prefix: str, b_id: int) -> Combined: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return CombinedRepo().get_prefix_one(prefix, b_id) + +@combined_router.get("/{prefix}/{b_from}/{b_to}/") +def get_prefix_combined_range(api_key: str, prefix: str, b_from: int, b_to: int) -> list[Combined]: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return CombinedRepo().get_prefix_range(prefix, b_from, b_to) + +@combined_router.post("/") +def post_combined_range(api_key: str, winner_list: list[Combined]): + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return CombinedRepo().post_list(winner_list) \ No newline at end of file diff --git a/db/schema.sql b/db/schema.sql index 76325cb..79ba527 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS api_keys ( ); CREATE TABLE IF NOT EXISTS prefixes ( - `name` VARCHAR(255), + `name` VARCHAR(255) PRIMARY KEY, `color` VARCHAR(255), `weight` INT DEFAULT 0 ); @@ -24,7 +24,8 @@ CREATE TABLE IF NOT EXISTS baskets ( `b_id` INT, `description` VARCHAR(255), `donors` VARCHAR(255), - `winning_ticket` INT + `winning_ticket` INT, + PRIMARY KEY (`prefix`, `b_id`) ); CREATE VIEW IF NOT EXISTS combined AS diff --git a/webapp/src/lib/components/FormHeader.svelte b/webapp/src/lib/components/FormHeader.svelte index e3f94c3..edde6e7 100644 --- a/webapp/src/lib/components/FormHeader.svelte +++ b/webapp/src/lib/components/FormHeader.svelte @@ -1,9 +1,25 @@
| Basket ID | +Description | +Donors | +Changed | +
|---|---|---|---|
| {basket.b_id} | +basket.changed = true} bind:value={basket.description}> | +basket.changed = true} bind:value={basket.donors}> | ++ |