Feature/add or remove #7
+69
-2
@@ -4,6 +4,7 @@ from contextlib import asynccontextmanager
|
||||
|
||||
import uvicorn
|
||||
from fastapi import APIRouter, Depends, FastAPI, HTTPException, Request
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
@@ -63,6 +64,27 @@ api = FastAPI(
|
||||
async def feed_error_handler(request: Request, exc: FeedError):
|
||||
return JSONResponse(status_code=exc.status_code, content={"detail":str(exc)})
|
||||
|
||||
@api.exception_handler(RequestValidationError)
|
||||
async def validation_error_handler(request: Request, exc: RequestValidationError):
|
||||
errors = exc.errors()
|
||||
|
||||
# 1) If one of our own FeedErrors caused it, use its message as is
|
||||
for err in errors:
|
||||
original = (err.get("ctx") or {}).get("error")
|
||||
if isinstance(original, FeedError):
|
||||
return JSONResponse(
|
||||
status_code=original.status_code,
|
||||
content={"detail": str(original)},
|
||||
)
|
||||
|
||||
# 2) Anything else (missing field, bad enum value, bad header): flatten to one string
|
||||
messages = []
|
||||
for err in errors:
|
||||
field = ".".join(str(p) for p in err["loc"] if p != "body")
|
||||
msg = err["msg"].removeprefix("Value error, ")
|
||||
messages.append(f"{field}: {msg}" if field else msg)
|
||||
return JSONResponse(status_code=422, content={"detail": "; ".join(messages)})
|
||||
|
||||
@api.middleware("http")
|
||||
async def prometheus_middleware(request: Request, call_next):
|
||||
logger.debug(f"[FastAPI] Incoming request: {request.method} {request.url.path}")
|
||||
@@ -319,12 +341,57 @@ def add_feed(
|
||||
db.commit()
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.exception(f"[FastAPI] Failed to subscribe to user_id={user_id} to {url}")
|
||||
logger.exception(f"[FastAPI] Failed to subscribe user_id={user_id} to {url}")
|
||||
raise HTTPException(status_code=500) from e
|
||||
|
||||
logger.info(f"[FastAPI] user_id={user_id} subscribed to feed_id={feed_id}, url={url}")
|
||||
return {"status":"ok","detail":"Subscribed to feed","feed_id":feed_id}
|
||||
return {"status":"ok","detail":"Subscribed to feed","feed_url":url}
|
||||
|
||||
@user_router.post("/delete/feed")
|
||||
def delete_feed(
|
||||
user_id: UserId,
|
||||
feed_entry: FeedEntry,
|
||||
db = Depends(get_db),
|
||||
):
|
||||
url = feed_entry.rss_feed_url
|
||||
logger.info(f"[FastAPI] Unsubscribe request: RSS URL={url}, user_id={user_id}")
|
||||
|
||||
try:
|
||||
with db.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"SELECT id FROM rss_feeds WHERE rss_feed = %s",
|
||||
(url,),
|
||||
)
|
||||
known = cursor.fetchone()
|
||||
|
||||
if known is None:
|
||||
db.rollback()
|
||||
return {"status":"ok","detail":"Unsubscribed to feed","feed_url":url}
|
||||
|
||||
feed_id = known[0]
|
||||
cursor.execute(
|
||||
"UPDATE rss_feed_subscriptions SET active = 0 "
|
||||
"WHERE user_id = %s AND rss_feed_id = %s",
|
||||
(user_id, feed_id),
|
||||
)
|
||||
|
||||
cursor.execute(
|
||||
"SELECT 1 from rss_feed_subscriptions "
|
||||
"WHERE rss_feed_id = %s AND active = 1 LIMIT 1",
|
||||
(feed_id,),
|
||||
)
|
||||
if cursor.fetchone() is None:
|
||||
cursor.execute(
|
||||
"UPDATE rss_feeds SET active = 0 WHERE id = %s",
|
||||
(feed_id,),
|
||||
)
|
||||
|
||||
db.commit()
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.exception(f"[FastAPI] Failed to unsubscribe user_id={user_id} to {url}")
|
||||
raise HTTPException(status_code=500) from e
|
||||
return {"status":"ok","detail":"Unsubscribed to feed","feed_url":url}
|
||||
api.include_router(user_router)
|
||||
api.include_router(scheduler_router)
|
||||
|
||||
|
||||
Reference in new issue
Block a user