From e90bc1cc727b7c31fec1b6ce30d0677042a29793 Mon Sep 17 00:00:00 2001 From: Jack Case Date: Sun, 19 Oct 2025 15:33:34 +0000 Subject: [PATCH] started actual fastapi server with DB --- slopserver/db.py | 12 ++++++++++++ slopserver/models.py | 29 +++++++++++++++++++++++++++++ slopserver/server.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 slopserver/db.py create mode 100644 slopserver/server.py diff --git a/slopserver/db.py b/slopserver/db.py new file mode 100644 index 0000000..58d3f27 --- /dev/null +++ b/slopserver/db.py @@ -0,0 +1,12 @@ +from collections.abc import Iterable +from urllib.parse import ParseResult +from sqlalchemy import select +from sqlalchemy.engine import Engine +from sqlalchemy.orm import Session +from slopserver.models import Domain, Path, User + +def select_slop(urls: list[ParseResult], engine: Engine) -> Iterable[Domain]: + query = select(Domain).where(Domain.domain_name.in_(url[1] for url in urls)) + with Session(engine) as session: + rows = session.scalars(query).all() + return rows \ No newline at end of file diff --git a/slopserver/models.py b/slopserver/models.py index 89403aa..af9691e 100644 --- a/slopserver/models.py +++ b/slopserver/models.py @@ -1,4 +1,8 @@ +from typing import Annotated from sqlmodel import Field, SQLModel, create_engine, Relationship +from pydantic import AfterValidator, BaseModel + +from urllib.parse import urlparse, ParseResult NAMING_CONVENTION = { "ix": "ix_%(column_0_label)s", @@ -11,6 +15,10 @@ NAMING_CONVENTION = { metadata = SQLModel.metadata metadata.naming_convention = NAMING_CONVENTION +################################################ +# Database Models +################################################ + class Domain(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) domain_name: str = Field(index=True, unique=True) @@ -31,3 +39,24 @@ class User(SQLModel, table=True): salt: str email_verified: bool = Field(default=False) + +################################################ +# API Models +################################################ + +def url_validator(urls: list[str]) -> list[ParseResult]: + parsed_urls = list() + for url in urls: + try: + parsed = urlparse(url) + if not parsed.netloc: + raise ValueError(f"couldn't parse domain from '{url}'") + parsed_urls.append(parsed) + except ValueError as e: + raise ValueError(f"couldn't parse '{url}' as a URL") + return parsed_urls + + +class SlopReport(BaseModel): + """Accept reports of one or more slop page URLs""" + slop_urls: Annotated[list[str], AfterValidator(url_validator)] \ No newline at end of file diff --git a/slopserver/server.py b/slopserver/server.py new file mode 100644 index 0000000..edde8a3 --- /dev/null +++ b/slopserver/server.py @@ -0,0 +1,28 @@ +"""API Operations + +- signup +- verify email +- Get auth token +- get top x reported domains +- get reports for given domains/pages +- post report +""" + +from fastapi import FastAPI +from sqlalchemy import create_engine +from slopserver.models import Domain, Path, User +from slopserver.models import SlopReport +from slopserver.db import select_slop + +app = FastAPI() + +temp_engine = create_engine("postgresql+psycopg://slop-farmer@192.168.1.163/slop-farmer") + +@app.post("/report/") +async def report_slop(report: SlopReport): + pass + +@app.post("/check/") +async def check_slop(check: SlopReport): + slop_results = select_slop(check.slop_urls, temp_engine) + return slop_results \ No newline at end of file