From f55806972db4081489ad8cb9b26ab312cfea8b59 Mon Sep 17 00:00:00 2001 From: Dilan Gilluly Date: Fri, 26 Jun 2026 15:56:19 -0400 Subject: [PATCH] (add): Reports api endpoints, pycache correction --- api/.gitignore | 3 +- .../data/__pycache__/baskets.cpython-314.pyc | Bin 7417 -> 0 bytes .../data/__pycache__/drawing.cpython-314.pyc | Bin 7576 -> 0 bytes .../data/__pycache__/tickets.cpython-314.pyc | Bin 7575 -> 0 bytes api/app/data/reports.py | 50 ++++++++++++++++++ api/app/db.py | 8 +++ api/app/routers.py | 2 + client/src/lib/server/db/schema.js | 28 ++++++++++ .../api/reports/bybasket/[prefix]/+server.js | 24 +++++++++ .../api/reports/byname/[prefix]/+server.js | 24 +++++++++ 10 files changed, 138 insertions(+), 1 deletion(-) delete mode 100644 api/app/data/__pycache__/baskets.cpython-314.pyc delete mode 100644 api/app/data/__pycache__/drawing.cpython-314.pyc delete mode 100644 api/app/data/__pycache__/tickets.cpython-314.pyc create mode 100644 api/app/data/reports.py create mode 100644 client/src/routes/api/reports/bybasket/[prefix]/+server.js create mode 100644 client/src/routes/api/reports/byname/[prefix]/+server.js diff --git a/api/.gitignore b/api/.gitignore index 6ca7b68..a8149f9 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -1,2 +1,3 @@ /data -*/__pycache__ +__pycache__/ +*.pyc diff --git a/api/app/data/__pycache__/baskets.cpython-314.pyc b/api/app/data/__pycache__/baskets.cpython-314.pyc deleted file mode 100644 index 1568686f448fc3c2c9704ad4261c36b0e5bf66ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7417 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 RXPwy3kKI}xKsTPi{1@`k8nXZZ diff --git a/api/app/data/__pycache__/drawing.cpython-314.pyc b/api/app/data/__pycache__/drawing.cpython-314.pyc deleted file mode 100644 index 5d8137fa2a473972b954c81334909af58171a223..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7576 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%0D&9$*{Pe>pPxZ22X6JS7GowAd!Rp}$dLTM z2VG2FAm~=+&pzIlv16GH3PgB!hdo|!9e-!E=OU6VlE8#J`iHpHk;N&PKb} z35ZReaIST{{leQ$y|176g1}{CfOxy#>c7)Gm}~r$dRA#mfwsIpTBIF!eg5~jUv+&6 zbQr|3o$DOb;Hx~>RO&TRq~hJv!yj@VuwFyh>oE2jGWE*0_7>@}yJMk`j{IQ=l?`LJ zKI}GJ)orjyAHFL+k$>{3qBMscLlk?S#GWBq>e^bMt*=W(+IjcUbH7nOaALm!>~`RD J=w{?J{{_X}W=sG8 diff --git a/api/app/data/__pycache__/tickets.cpython-314.pyc b/api/app/data/__pycache__/tickets.cpython-314.pyc deleted file mode 100644 index 9e9e5910206ef8d403f47b1910a577d066ba6f79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7575 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 diff --git a/api/app/data/reports.py b/api/app/data/reports.py new file mode 100644 index 0000000..8c95fea --- /dev/null +++ b/api/app/data/reports.py @@ -0,0 +1,50 @@ +from dataclasses import dataclass +from db import RepoTemplate +from system.auth import AuthRepo +from fastapi import APIRouter, Header + +@dataclass +class ReportByNameLine: + last_name: str = "" + first_name: str = "" + phone_number: str = "" + pref: str = "" + prefix: str = "" + b_id: int = 0 + description: str = "" + donors: str = "" + winning_ticket: int = 0 + +@dataclass +class ReportByBasketLine: + prefix: str = "" + b_id: int = 0 + description: str = "" + donors: str = "" + winning_ticket: int = 0 + last_name: str = "" + first_name: str = "" + phone_number: str = "" + pref: str = "" + +class ReportsRepo(RepoTemplate): + def get_by_name_report(self, prefix: str): + self.cur.execute("SELECT * FROM report_by_name WHERE prefix = ?", (prefix,)) + results = self.cur.fetchall() + return [ReportByNameLine(*r) for r in results] + def get_by_basket_report(self, prefix: str): + self.cur.execute("SELECT * FROM report_by_basket WHERE prefix = ?", (prefix,)) + results = self.cur.fetchall() + return [ReportByBasketLine(*r) for r in results] + +reports_router = APIRouter(prefix="/api/reports") + +@reports_router.get("/byname/{prefix}") +def get_report_by_name(prefix: str, tam_key: str = Header("")): + AuthRepo().verify_key(tam_key) + return ReportsRepo().get_by_name_report(prefix) + +@reports_router.get("/bybasket/{prefix}") +def get_report_by_basket(prefix: str, tam_key: str = Header("")): + AuthRepo().verify_key(tam_key) + return ReportsRepo().get_by_basket_report(prefix) diff --git a/api/app/db.py b/api/app/db.py index cf31e1e..474bb7d 100644 --- a/api/app/db.py +++ b/api/app/db.py @@ -25,6 +25,14 @@ def init_db(): SELECT b.prefix, b.b_id, b.description, b.winning_ticket, t.last_name, t.first_name, t.phone_number FROM baskets b LEFT JOIN tickets t ON b.prefix = t.prefix AND b.winning_ticket = t.t_id ORDER BY b.prefix, b.b_id""") + cur.execute("""CREATE VIEW IF NOT EXISTS report_by_name AS + SELECT t.last_name, t.first_name, t.phone_number, t.pref, b.* + FROM baskets b LEFT JOIN tickets t ON b.prefix = t.prefix AND b.winning_ticket = t.t_id + ORDER BY t.last_name, t.first_name, t.phone_number, b.prefix, b.b_id""") + cur.execute("""CREATE VIEW IF NOT EXISTS report_by_basket AS + SELECT b.*, t.last_name, t.first_name, t.phone_number, t.pref + FROM baskets b LEFT JOIN tickets t ON b.prefix = t.prefix AND b.winning_ticket = t.t_id + ORDER BY b.prefix, b.b_id""") conn.commit() conn.close() diff --git a/api/app/routers.py b/api/app/routers.py index 320a1a6..25806fe 100644 --- a/api/app/routers.py +++ b/api/app/routers.py @@ -4,6 +4,7 @@ from system.prefixes import prefix_router from data.tickets import tickets_router from data.baskets import basket_router from data.drawing import drawing_router +from data.reports import reports_router def imp_routers(app: FastAPI): app.include_router(auth_router) @@ -11,3 +12,4 @@ def imp_routers(app: FastAPI): app.include_router(tickets_router) app.include_router(basket_router) app.include_router(drawing_router) + app.include_router(reports_router) diff --git a/client/src/lib/server/db/schema.js b/client/src/lib/server/db/schema.js index 819b900..129d6a8 100644 --- a/client/src/lib/server/db/schema.js +++ b/client/src/lib/server/db/schema.js @@ -43,3 +43,31 @@ export const drawing = sqliteView('drawing', { }).as(sql`SELECT b.prefix, b.b_id, b.description, b.winning_ticket, t.last_name, t.first_name, t.phone_number FROM baskets b LEFT JOIN tickets t ON b.prefix = t.prefix AND b.winning_ticket = t.t_id ORDER BY b.prefix, b.b_id`) + +export const reportByName = sqliteView('report_by_name', { + last_name: text('last_name'), + first_name: text('first_name'), + phone_number: text('phone_number'), + pref: text('pref'), + prefix: text('prefix'), + b_id: integer('b_id'), + description: text('description'), + donors: text('donors'), + winning_ticket: integer('winning_ticket') +}).as(sql`SELECT t.last_name, t.first_name, t.phone_number, t.pref, b.prefix, b.b_id, b.description, b.donors, b.winning_ticket + FROM baskets b LEFT JOIN tickets t ON b.prefix = t.prefix AND b.winning_ticket = t.t_id + ORDER BY t.last_name, t.first_name, t.phone_number, b.prefix, b.b_id`) + +export const reportByBasket = sqliteView('report_by_basket', { + prefix: text('prefix'), + b_id: integer('b_id'), + description: text('description'), + donors: text('donors'), + winning_ticket: integer('winning_ticket'), + last_name: text('last_name'), + first_name: text('first_name'), + phone_number: text('phone_number'), + pref: text('pref') +}).as(sql`SELECT b.prefix, b.b_id, b.description, b.donors, b.winning_ticket, t.last_name, t.first_name, t.phone_number, t.pref + FROM baskets b LEFT JOIN tickets t on b.prefix = t.prefix AND b.winning_ticket = t.t_id + ORDER BY b.prefix, b.b_id`) diff --git a/client/src/routes/api/reports/bybasket/[prefix]/+server.js b/client/src/routes/api/reports/bybasket/[prefix]/+server.js new file mode 100644 index 0000000..478e900 --- /dev/null +++ b/client/src/routes/api/reports/bybasket/[prefix]/+server.js @@ -0,0 +1,24 @@ +import { db } from '$lib/server/db/index.js'; +import { reportByBasket } from '$lib/server/db/schema.js'; +import { getPath, getSettings } from '$lib/server/settings'; +import { error, json } from '@sveltejs/kit'; +import { eq } from 'drizzle-orm'; + +export const GET = async ({ params }) => { + const { prefix } = params; + const s = getSettings(); + if (s.remote_server) { + const connStr = getPath(s); + try { + const res = await fetch(`${connStr}/api/reports/bybasket/${prefix}`, {headers: {'TAM-KEY': s.remote_key}}); + if (!res.ok) throw error(res.status); + const data = await res.json(); + return json(data); + } catch { + return json([]); + } + } else { + const data = await db.select().from(reportByBasket).where(eq(reportByBasket.prefix, prefix)); + return json(data); + } +} diff --git a/client/src/routes/api/reports/byname/[prefix]/+server.js b/client/src/routes/api/reports/byname/[prefix]/+server.js new file mode 100644 index 0000000..b59be8c --- /dev/null +++ b/client/src/routes/api/reports/byname/[prefix]/+server.js @@ -0,0 +1,24 @@ +import { db } from '$lib/server/db/index.js'; +import { reportByName } from '$lib/server/db/schema.js'; +import { getPath, getSettings } from '$lib/server/settings'; +import { error, json } from '@sveltejs/kit'; +import { eq } from 'drizzle-orm'; + +export const GET = async ({ params }) => { + const { prefix } = params; + const s = getSettings(); + if (s.remote_server) { + const connStr = getPath(s); + try { + const res = await fetch(`${connStr}/api/reports/byname/${prefix}`, {headers: {'TAM-KEY': s.remote_key}}); + if (!res.ok) throw error(res.status); + const data = await res.json(); + return json(data); + } catch { + return json([]); + } + } else { + const data = await db.select().from(reportByName).where(eq(reportByName.prefix, prefix)); + return json(data); + } +}