diff --git a/api/main.py b/api/main.py index cad5c63..b2f5ca3 100644 --- a/api/main.py +++ b/api/main.py @@ -4,6 +4,7 @@ from fastapi import FastAPI from sys import argv from routers.prefixes import prefix_router +from routers.tickets import ticket_router if argv[1] == "run": app = FastAPI(title="TAM3 API Server", docs_url=None, redoc_url=None) @@ -11,3 +12,4 @@ else: app = FastAPI(title="TAM3 API Server") app.include_router(prefix_router) +app.include_router(ticket_router) \ No newline at end of file diff --git a/api/repos/tickets.py b/api/repos/tickets.py new file mode 100644 index 0000000..6ae9825 --- /dev/null +++ b/api/repos/tickets.py @@ -0,0 +1,40 @@ +from dataclasses import dataclass +from .template import Repo + +@dataclass +class Ticket: + prefix: str + t_id: int + first_name: str = "" + last_name: str = "" + phone_number: str = "" + preference: str = "CALL" + changed: bool = False + +class TicketRepo(Repo): + def get_prefix_one(self, prefix: str, t_id: int): + self.cur.execute("SELECT * FROM tickets WHERE prefix = %s AND t_id = %s", (prefix, t_id)) + result = self.cur.fetchone() + if not result: + return Ticket(prefix=prefix, t_id=t_id) + return Ticket(*result) + def get_prefix_range(self, prefix: str, t_from: int, t_to: int): + r_dict = {i: Ticket(prefix=prefix, t_id=i) for i in range(t_from, t_to+1)} + self.cur.execute("SELECT * FROM tickets WHERE prefix = %s AND t_id BETWEEN %s AND %s", (prefix, t_from, t_to)) + results = self.cur.fetchall() + for r in results: + r_dict[r[1]] = Ticket(*r) + return list(r_dict.values()) + def get_prefix_all(self, prefix: str): + self.cur.execute("SELECT * FROM tickets WHERE prefix = %s", (prefix,)) + results = self.cur.fetchall() + return [Ticket(*r) for r in results] + def get_all(self): + self.cur.execute("SELECT * FROM tickets") + results = self.cur.fetchall() + return [Ticket(*r) for r in results] + def post_list(self, tickets: list[Ticket]): + for t in tickets: + self.cur.execute("REPLACE INTO tickets VALUES (%s, %s, %s, %s, %s, %s)", (t.prefix, t.t_id, t.first_name, t.last_name, t.phone_number, t.preference)) + self.conn.commit() + return {"detail": "Tickets posted successfully."} \ No newline at end of file diff --git a/api/routers/prefixes.py b/api/routers/prefixes.py index 0d8367c..0a25dea 100644 --- a/api/routers/prefixes.py +++ b/api/routers/prefixes.py @@ -1,26 +1,36 @@ from fastapi import APIRouter +from repos.api_keys import ApiKeyRepo from repos.prefixes import Prefix, PrefixRepo +from exceptions import bad_key prefix_router = APIRouter(prefix="/api/prefixes") @prefix_router.get("/") -def get_all_prefixes(): +def get_all_prefixes(api_key: str): + if not ApiKeyRepo().check_api(api_key): + raise bad_key return PrefixRepo().get_all() @prefix_router.get("/{prefix_name}/") -def get_one_prefix(prefix_name: str): +def get_one_prefix(api_key: str, prefix_name: str): + if not ApiKeyRepo().check_api(api_key): + raise bad_key return PrefixRepo().get_one(prefix_name) @prefix_router.post("/") -def post_one_prefix(p: Prefix): +def post_one_prefix(api_key: str, p: Prefix): + if not ApiKeyRepo().check_api(api_key): + raise bad_key rep_detail = PrefixRepo().add_one(p) return {"detail": rep_detail} @prefix_router.delete("/") -def del_one_prefix(prefix_name: str): +def del_one_prefix(api_key: str, prefix_name: str): + if not ApiKeyRepo().check_api(api_key): + raise bad_key rep_detail = PrefixRepo().del_one(prefix_name) return {"detail": rep_detail} diff --git a/api/routers/tickets.py b/api/routers/tickets.py new file mode 100644 index 0000000..6739efa --- /dev/null +++ b/api/routers/tickets.py @@ -0,0 +1,36 @@ +from fastapi import APIRouter +from repos.tickets import TicketRepo, Ticket +from repos.api_keys import ApiKeyRepo +from exceptions import bad_key + +ticket_router = APIRouter(prefix="/api/tickets") + +@ticket_router.get("/") +def get_all_tickets(api_key: str) -> list[Ticket]: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return TicketRepo().get_all() + +@ticket_router.get("/{prefix}/") +def get_prefix_tickets(api_key: str, prefix: str) -> list[Ticket]: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return TicketRepo().get_prefix_all(prefix) + +@ticket_router.get("/{prefix}/{t_id}/") +def get_prefix_ticket_one(api_key: str, prefix: str, t_id: int) -> Ticket: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return TicketRepo().get_prefix_one(prefix, t_id) + +@ticket_router.get("/{prefix}/{t_from}/{t_to}") +def get_prefix_ticket_range(api_key: str, prefix: str, t_from: int, t_to: int) -> list[Ticket]: + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return TicketRepo().get_prefix_range(prefix, t_from, t_to) + +@ticket_router.post("/") +def post_tickets(api_key: str, tickets: list[Ticket]): + if not ApiKeyRepo().check_api(api_key): + raise bad_key + return TicketRepo().post_list(tickets) \ No newline at end of file diff --git a/webapp/src/routes/api/tickets/+server.js b/webapp/src/routes/api/tickets/+server.js new file mode 100644 index 0000000..065b443 --- /dev/null +++ b/webapp/src/routes/api/tickets/+server.js @@ -0,0 +1,20 @@ +import { db } from "$lib/server/db"; +import { tickets } from "$lib/server/db/schema"; +import { env } from "$env/dynamic/private"; + +export async function GET({ params }) { + if (env.TAM3_REMOTE) { + const res = await fetch(`${env.TAM3_REMOTE}/api/tickets/?api_key=${env.TAM3_REMOTE_KEY}`); + if (!res.ok) { + return new Response(JSON.stringify({details: "Couldn't fetch tickets."}), { + status: res.status, + statusText: res.statusText + }); + }; + const data = await res.json(); + return new Response(JSON.stringify(data), {status: 200, statusText: "Tickets fetched successfully."}) + } else { + const data = await db.select().from(tickets); + return new Response(JSON.stringify(data), {status: 200, statusText: "Tickets loaded successfully."}) + }; +} \ No newline at end of file diff --git a/webapp/src/routes/api/tickets/[prefix]/[t_from]/[t_to]/+server.js b/webapp/src/routes/api/tickets/[prefix]/[t_from]/[t_to]/+server.js new file mode 100644 index 0000000..1a4b5af --- /dev/null +++ b/webapp/src/routes/api/tickets/[prefix]/[t_from]/[t_to]/+server.js @@ -0,0 +1,35 @@ +import { db } from "$lib/server/db"; +import { tickets } from "$lib/server/db/schema"; +import { env } from "$env/dynamic/private"; +import { eq, and } from "drizzle-orm"; + +export async function GET({ params }) { + let n_t_from = parseInt(params.t_from), n_t_to = parseInt(params.t_to); + if (env.TAM3_REMOTE) { + const res = await fetch(`${env.TAM3_REMOTE}/api/tickets/${params.prefix}/${n_t_from}/${n_t_to}/?api_key=${env.TAM3_REMOTE_KEY}`); + if (!res.ok) { + return new Response(JSON.stringify({details: "Unable to fetch tickets."}), {status: res.status, statusText: res.statusText}) + }; + const data = await res.json(); + return new Response(JSON.stringify(data), { + headers: {'Content-Type': 'application/json'}, + status: 200, + statusText: "Tickets fetched successfully." + }) + } else { + let r_dict = {}; + for (let i=n_t_from; i <= n_t_to; i++) { + let data = await db.select().from(tickets).where(and(eq(tickets.prefix, params.prefix), eq(tickets.t_id, i))); + if (data[0]) { + r_dict[i] = {...data[0]}; + } else { + r_dict[i] = {prefix: params.prefix, t_id: i, first_name: "", last_name: "", phone_number: "", preference: "CALL", changed: false}; + } + }; + return new Response(JSON.stringify(Object.values(r_dict)), { + headers: {'Content-Type': 'application/json'}, + status: 200, + statusText: "Tickets loaded successfully." + }) + } +} \ No newline at end of file