fix: A30 + A37 + A39 + A40 + A41 — fin du P2/P3 XS/S (v7.4.0)
- A30 — `require_scope()` câblé : 69 sites stricts de api_v2.py passent par la factory (Bearer + scope en 1 appel, contrôle manuel supprimé) ; sémantique alignée sur celle des handlers (pas de default "read" → 0 changement de comportement) ; 12 top-level morts supprimés (0 ref app ET tests) : unsync_block, find_referring, _b64url, strip_markdown, format_number, get_auto_property_value, get_next_unique_id, local_date_in_tz, verify_device_token, _get_dynamic_groups, _require_user_gitea, validate_upload_request - A37 — CORS sans `*` : origines = app_base_url + allow_origin_regex (localhost/dev, origines d'extension pour le Web Clipper), méthodes et entêtes minutées, allow_credentials explicite + test test_cors_no_star - A39 — htmx : décision « rien » documentée (32 attributs hx-* réels sur 6 templates, conversion = refonte du view-switching sans test E2E) - A40 — version d'assets à source unique : ENV.globals["asset_version"] lu au boot depuis le fichier VERSION ; littéraux `?v=` de base.html éliminés ; test test_asset_version_single_source - A41 — app.css : 91 règles mortes purgées (-10 274 octets, 121 618 → 111 344), scan templates/JS/CSS/Python à 0 référence suite **1031/1031** · `ruff check app tests` OK · OpenAPI 511 chemins / 7.4.0 docs (ROADMAP/CHANGELOG/WORKLOAD/VERSION) à jour
This commit is contained in:
+71
-208
@@ -16,7 +16,7 @@ from fastapi import APIRouter, Header, HTTPException, Request
|
||||
from fastapi.responses import JSONResponse, Response
|
||||
|
||||
from app.db import get_conn
|
||||
from app.services.api_v2_helpers import (
|
||||
from app.services.api_v2_helpers import ( # noqa: F401 — require_scope est utilisé par les handlers
|
||||
audit_log,
|
||||
check_idempotency,
|
||||
check_v2_rate_limit,
|
||||
@@ -24,6 +24,7 @@ from app.services.api_v2_helpers import (
|
||||
has_scope,
|
||||
paginate_headers,
|
||||
parse_pagination,
|
||||
require_scope,
|
||||
row_to_dict,
|
||||
store_idempotency,
|
||||
to_iso8601,
|
||||
@@ -47,10 +48,8 @@ def _v2_rate_check(request: Request, user: dict) -> None:
|
||||
|
||||
@router.post("/tokens")
|
||||
async def create_token(request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -110,10 +109,8 @@ async def list_tokens(request: Request, authorization: str | None = Header(defau
|
||||
|
||||
@router.delete("/tokens/{token_id}")
|
||||
async def revoke_token(token_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT id, user_id FROM api_tokens WHERE id=?", (token_id,)).fetchone()
|
||||
if not row:
|
||||
@@ -127,10 +124,8 @@ async def revoke_token(token_id: int, request: Request, authorization: str | Non
|
||||
|
||||
@router.post("/tokens/{token_id}/rotate")
|
||||
async def rotate_token(token_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT id, user_id, name, scopes FROM api_tokens WHERE id=?", (token_id,)).fetchone()
|
||||
if not row:
|
||||
@@ -171,10 +166,8 @@ async def get_me(request: Request, authorization: str | None = Header(default=No
|
||||
|
||||
@router.patch("/users/me")
|
||||
async def patch_me(request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -239,10 +232,8 @@ async def list_workspaces(request: Request, authorization: str | None = Header(d
|
||||
|
||||
@router.post("/workspaces")
|
||||
async def create_workspace(request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
idem = check_idempotency(request, user["id"])
|
||||
if idem:
|
||||
return JSONResponse(content=idem["data"], status_code=idem["status"])
|
||||
@@ -291,10 +282,8 @@ async def get_workspace(workspace_id: int, request: Request, authorization: str
|
||||
|
||||
@router.patch("/workspaces/{workspace_id}")
|
||||
async def patch_workspace(workspace_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -321,10 +310,8 @@ async def patch_workspace(workspace_id: int, request: Request, authorization: st
|
||||
|
||||
@router.delete("/workspaces/{workspace_id}")
|
||||
async def delete_workspace(workspace_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT * FROM workspaces WHERE id=?", (workspace_id,)).fetchone()
|
||||
if not row:
|
||||
@@ -349,10 +336,8 @@ async def list_workspace_members(workspace_id: int, request: Request, authorizat
|
||||
|
||||
@router.post("/workspaces/{workspace_id}/members")
|
||||
async def invite_member(workspace_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -389,10 +374,8 @@ async def invite_member(workspace_id: int, request: Request, authorization: str
|
||||
|
||||
@router.patch("/workspaces/{workspace_id}/members/{uid}")
|
||||
async def update_member_role(workspace_id: int, uid: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -417,10 +400,8 @@ async def update_member_role(workspace_id: int, uid: int, request: Request, auth
|
||||
|
||||
@router.delete("/workspaces/{workspace_id}/members/{uid}")
|
||||
async def remove_member(workspace_id: int, uid: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
ws = conn.execute("SELECT owner_id FROM workspaces WHERE id=?", (workspace_id,)).fetchone()
|
||||
if not ws:
|
||||
@@ -470,10 +451,8 @@ async def list_collections_v2(request: Request, authorization: str | None = Head
|
||||
|
||||
@router.post("/collections")
|
||||
async def create_collection_v2(request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
idem = check_idempotency(request, user["id"])
|
||||
if idem:
|
||||
return JSONResponse(content=idem["data"], status_code=idem["status"])
|
||||
@@ -528,10 +507,8 @@ async def get_collection_v2(collection_id: int, request: Request, authorization:
|
||||
|
||||
@router.patch("/collections/{collection_id}")
|
||||
async def patch_collection_v2(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -555,10 +532,8 @@ async def patch_collection_v2(collection_id: int, request: Request, authorizatio
|
||||
|
||||
@router.delete("/collections/{collection_id}")
|
||||
async def delete_collection_v2(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT * FROM collections WHERE id=?", (collection_id,)).fetchone()
|
||||
if not row:
|
||||
@@ -570,10 +545,8 @@ async def delete_collection_v2(collection_id: int, request: Request, authorizati
|
||||
|
||||
@router.post("/collections/{collection_id}/linked")
|
||||
async def create_linked_db(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -609,10 +582,8 @@ async def create_linked_db(collection_id: int, request: Request, authorization:
|
||||
|
||||
@router.post("/collections/{collection_id}/task")
|
||||
async def toggle_task(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT is_task FROM collections WHERE id=?", (collection_id,)).fetchone()
|
||||
if not row:
|
||||
@@ -636,10 +607,8 @@ async def list_sources(collection_id: int, request: Request, authorization: str
|
||||
|
||||
@router.post("/collections/{collection_id}/sources")
|
||||
async def add_source(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -662,10 +631,8 @@ async def add_source(collection_id: int, request: Request, authorization: str |
|
||||
|
||||
@router.delete("/collections/{collection_id}/sources/{source_id}")
|
||||
async def remove_source(collection_id: int, source_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM collection_data_sources WHERE collection_id=? AND (id=? OR source_collection_id=?)", (collection_id, source_id, source_id))
|
||||
conn.commit()
|
||||
@@ -734,10 +701,8 @@ async def list_collection_pages_v2(collection_id: int, request: Request, authori
|
||||
|
||||
@router.post("/collections/{collection_id}/pages")
|
||||
async def create_collection_page_v2(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
idem = check_idempotency(request, user["id"])
|
||||
if idem:
|
||||
return JSONResponse(content=idem["data"], status_code=idem["status"])
|
||||
@@ -816,10 +781,8 @@ async def get_page_v2(page_id: int, request: Request, authorization: str | None
|
||||
|
||||
@router.patch("/pages/{page_id}")
|
||||
async def patch_page_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -865,10 +828,8 @@ async def patch_page_v2(page_id: int, request: Request, authorization: str | Non
|
||||
|
||||
@router.delete("/pages/{page_id}")
|
||||
async def delete_page_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT * FROM collection_pages WHERE id=?", (page_id,)).fetchone()
|
||||
if not row:
|
||||
@@ -884,10 +845,8 @@ async def delete_page_v2(page_id: int, request: Request, authorization: str | No
|
||||
|
||||
@router.post("/pages/{page_id}/restore")
|
||||
async def restore_page_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
# For soft-deleted pages (deleted_at) - but collection_pages has no deleted_at; handle pages table
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT deleted_at FROM pages WHERE id=?", (page_id,)).fetchone()
|
||||
@@ -903,10 +862,8 @@ async def restore_page_v2(page_id: int, request: Request, authorization: str | N
|
||||
|
||||
@router.post("/pages/{page_id}/move")
|
||||
async def move_page_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -934,10 +891,8 @@ async def list_sub_items_v2(page_id: int, request: Request, authorization: str |
|
||||
|
||||
@router.post("/pages/{page_id}/sub-items")
|
||||
async def create_sub_item_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -965,10 +920,8 @@ async def list_dependencies_v2(page_id: int, request: Request, authorization: st
|
||||
|
||||
@router.post("/pages/{page_id}/dependencies")
|
||||
async def add_dependency_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -992,10 +945,8 @@ async def add_dependency_v2(page_id: int, request: Request, authorization: str |
|
||||
|
||||
@router.delete("/pages/{page_id}/dependencies/{dep_id}")
|
||||
async def remove_dependency_v2(page_id: int, dep_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM page_dependencies WHERE page_id=? AND dependency_id=?", (page_id, dep_id))
|
||||
conn.commit()
|
||||
@@ -1016,10 +967,8 @@ async def list_properties_v2(collection_id: int, request: Request, authorization
|
||||
|
||||
@router.post("/collections/{collection_id}/properties")
|
||||
async def create_property_v2(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1043,10 +992,8 @@ async def create_property_v2(collection_id: int, request: Request, authorization
|
||||
|
||||
@router.patch("/properties/{prop_id}")
|
||||
async def patch_property_v2(prop_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1069,10 +1016,8 @@ async def patch_property_v2(prop_id: int, request: Request, authorization: str |
|
||||
|
||||
@router.delete("/properties/{prop_id}")
|
||||
async def delete_property_v2(prop_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
if not conn.execute("SELECT id FROM collection_properties WHERE id=?", (prop_id,)).fetchone():
|
||||
raise HTTPException(404, "Property not found")
|
||||
@@ -1083,10 +1028,8 @@ async def delete_property_v2(prop_id: int, request: Request, authorization: str
|
||||
|
||||
@router.post("/properties/{prop_id}/relation")
|
||||
async def create_relation_v2(prop_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1158,10 +1101,8 @@ async def list_views_v2(collection_id: int, request: Request, authorization: str
|
||||
|
||||
@router.post("/collections/{collection_id}/views")
|
||||
async def create_view_v2(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1185,10 +1126,8 @@ async def create_view_v2(collection_id: int, request: Request, authorization: st
|
||||
|
||||
@router.patch("/views/{view_id}")
|
||||
async def patch_view_v2(view_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1218,10 +1157,8 @@ async def patch_view_v2(view_id: int, request: Request, authorization: str | Non
|
||||
|
||||
@router.delete("/views/{view_id}")
|
||||
async def delete_view_v2(view_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
if not conn.execute("SELECT id FROM collection_views WHERE id=?", (view_id,)).fetchone():
|
||||
raise HTTPException(404, "View not found")
|
||||
@@ -1232,10 +1169,8 @@ async def delete_view_v2(view_id: int, request: Request, authorization: str | No
|
||||
|
||||
@router.post("/views/{view_id}/save-as")
|
||||
async def save_as_view_v2(view_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1261,10 +1196,8 @@ async def list_dashboards_v2(collection_id: int, request: Request, authorization
|
||||
|
||||
@router.post("/collections/{collection_id}/dashboards")
|
||||
async def create_dashboard_v2(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1279,10 +1212,8 @@ async def create_dashboard_v2(collection_id: int, request: Request, authorizatio
|
||||
|
||||
@router.patch("/dashboards/{dashboard_id}")
|
||||
async def patch_dashboard_v2(dashboard_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1303,10 +1234,8 @@ async def patch_dashboard_v2(dashboard_id: int, request: Request, authorization:
|
||||
|
||||
@router.delete("/dashboards/{dashboard_id}")
|
||||
async def delete_dashboard_v2(dashboard_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM collection_dashboards WHERE id=?", (dashboard_id,))
|
||||
conn.commit()
|
||||
@@ -1326,10 +1255,8 @@ async def list_comments_v2(page_id: int, request: Request, authorization: str |
|
||||
|
||||
@router.post("/pages/{page_id}/comments")
|
||||
async def create_comment_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1351,10 +1278,8 @@ async def create_comment_v2(page_id: int, request: Request, authorization: str |
|
||||
|
||||
@router.patch("/comments/{comment_id}")
|
||||
async def patch_comment_v2(comment_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1379,10 +1304,8 @@ async def patch_comment_v2(comment_id: int, request: Request, authorization: str
|
||||
|
||||
@router.delete("/comments/{comment_id}")
|
||||
async def delete_comment_v2(comment_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT * FROM comments WHERE id=?", (comment_id,)).fetchone()
|
||||
if not row:
|
||||
@@ -1395,10 +1318,8 @@ async def delete_comment_v2(comment_id: int, request: Request, authorization: st
|
||||
|
||||
@router.post("/pages/{page_id}/mentions")
|
||||
async def create_mention_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1498,10 +1419,8 @@ async def list_favorites_v2(request: Request, authorization: str | None = Header
|
||||
|
||||
@router.post("/favorites")
|
||||
async def add_favorite_v2(request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1523,10 +1442,8 @@ async def add_favorite_v2(request: Request, authorization: str | None = Header(d
|
||||
|
||||
@router.delete("/favorites/{page_id}")
|
||||
async def remove_favorite_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM favorites WHERE user_id=? AND page_id=?", (user["id"], page_id))
|
||||
conn.commit()
|
||||
@@ -1550,10 +1467,8 @@ async def list_tags_v2(request: Request, authorization: str | None = Header(defa
|
||||
|
||||
@router.post("/tags")
|
||||
async def create_tag_v2(request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1573,10 +1488,8 @@ async def create_tag_v2(request: Request, authorization: str | None = Header(def
|
||||
|
||||
@router.patch("/tags/{tag_id}")
|
||||
async def patch_tag_v2(tag_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1593,10 +1506,8 @@ async def patch_tag_v2(tag_id: int, request: Request, authorization: str | None
|
||||
|
||||
@router.delete("/tags/{tag_id}")
|
||||
async def delete_tag_v2(tag_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM tags WHERE id=? AND user_id=?", (tag_id, user["id"]))
|
||||
conn.commit()
|
||||
@@ -1604,10 +1515,8 @@ async def delete_tag_v2(tag_id: int, request: Request, authorization: str | None
|
||||
|
||||
@router.post("/pages/{page_id}/tags")
|
||||
async def attach_tag_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1625,10 +1534,8 @@ async def attach_tag_v2(page_id: int, request: Request, authorization: str | Non
|
||||
|
||||
@router.delete("/pages/{page_id}/tags/{tag_id}")
|
||||
async def detach_tag_v2(page_id: int, tag_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM page_tags WHERE page_id=? AND tag_id=?", (page_id, tag_id))
|
||||
conn.commit()
|
||||
@@ -1659,10 +1566,8 @@ async def list_shares_v2(page_id: int, request: Request, authorization: str | No
|
||||
|
||||
@router.post("/pages/{page_id}/shares")
|
||||
async def create_share_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1688,10 +1593,8 @@ async def create_share_v2(page_id: int, request: Request, authorization: str | N
|
||||
|
||||
@router.patch("/shares/{share_id}")
|
||||
async def patch_share_v2(share_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1708,10 +1611,8 @@ async def patch_share_v2(share_id: int, request: Request, authorization: str | N
|
||||
|
||||
@router.delete("/shares/{share_id}")
|
||||
async def delete_share_v2(share_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT page_id FROM page_shares WHERE id=?", (share_id,)).fetchone()
|
||||
if not row:
|
||||
@@ -1726,10 +1627,8 @@ async def delete_share_v2(share_id: int, request: Request, authorization: str |
|
||||
|
||||
@router.post("/pages/{page_id}/publish")
|
||||
async def publish_page_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1749,10 +1648,8 @@ async def publish_page_v2(page_id: int, request: Request, authorization: str | N
|
||||
|
||||
@router.delete("/pages/{page_id}/publish")
|
||||
async def unpublish_page_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("UPDATE pages SET is_published=0 WHERE id=?", (page_id,))
|
||||
conn.commit()
|
||||
@@ -1776,10 +1673,8 @@ async def list_history_v2(page_id: int, request: Request, authorization: str | N
|
||||
|
||||
@router.post("/pages/{page_id}/history/restore")
|
||||
async def restore_history_v2(page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1820,10 +1715,8 @@ async def list_sprints_v2(collection_id: int, request: Request, authorization: s
|
||||
|
||||
@router.post("/collections/{collection_id}/sprints")
|
||||
async def create_sprint_v2(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1845,10 +1738,8 @@ async def create_sprint_v2(collection_id: int, request: Request, authorization:
|
||||
|
||||
@router.patch("/sprints/{sprint_id}")
|
||||
async def patch_sprint_v2(sprint_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1872,10 +1763,8 @@ async def patch_sprint_v2(sprint_id: int, request: Request, authorization: str |
|
||||
|
||||
@router.delete("/sprints/{sprint_id}")
|
||||
async def delete_sprint_v2(sprint_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM sprints WHERE id=?", (sprint_id,))
|
||||
conn.commit()
|
||||
@@ -1883,10 +1772,8 @@ async def delete_sprint_v2(sprint_id: int, request: Request, authorization: str
|
||||
|
||||
@router.post("/sprints/{sprint_id}/assign")
|
||||
async def assign_sprint_v2(sprint_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1904,10 +1791,8 @@ async def assign_sprint_v2(sprint_id: int, request: Request, authorization: str
|
||||
|
||||
@router.delete("/sprints/{sprint_id}/assign/{page_id}")
|
||||
async def unassign_sprint_v2(sprint_id: int, page_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM sprint_pages WHERE sprint_id=? AND page_id=?", (sprint_id, page_id))
|
||||
conn.commit()
|
||||
@@ -1951,10 +1836,8 @@ async def list_templates_v2(collection_id: int, request: Request, authorization:
|
||||
|
||||
@router.post("/collections/{collection_id}/templates")
|
||||
async def create_template_v2(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1970,10 +1853,8 @@ async def create_template_v2(collection_id: int, request: Request, authorization
|
||||
|
||||
@router.patch("/templates/{template_id}")
|
||||
async def patch_template_v2(template_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -1991,10 +1872,8 @@ async def patch_template_v2(template_id: int, request: Request, authorization: s
|
||||
|
||||
@router.delete("/templates/{template_id}")
|
||||
async def delete_template_v2(template_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM page_templates WHERE id=?", (template_id,))
|
||||
conn.commit()
|
||||
@@ -2002,10 +1881,8 @@ async def delete_template_v2(template_id: int, request: Request, authorization:
|
||||
|
||||
@router.post("/templates/{template_id}/apply")
|
||||
async def apply_template_v2(template_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
tpl = conn.execute("SELECT * FROM page_templates WHERE id=?", (template_id,)).fetchone()
|
||||
if not tpl:
|
||||
@@ -2027,10 +1904,8 @@ async def list_db_templates_v2(request: Request, authorization: str | None = Hea
|
||||
|
||||
@router.post("/templates/database/{template_id}/apply")
|
||||
async def apply_db_template_v2(template_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -2104,10 +1979,8 @@ async def export_csv_v2(collection_id: int, request: Request, authorization: str
|
||||
|
||||
@router.post("/collections/{collection_id}/import/csv")
|
||||
async def import_csv_v2(collection_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
form = await request.form()
|
||||
file = form.get("file")
|
||||
@@ -2283,10 +2156,8 @@ async def list_webhooks_v2(request: Request, authorization: str | None = Header(
|
||||
|
||||
@router.post("/webhooks")
|
||||
async def create_webhook_v2(request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -2313,10 +2184,8 @@ async def create_webhook_v2(request: Request, authorization: str | None = Header
|
||||
|
||||
@router.patch("/webhooks/{webhook_id}")
|
||||
async def patch_webhook_v2(webhook_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -2336,10 +2205,8 @@ async def patch_webhook_v2(webhook_id: int, request: Request, authorization: str
|
||||
|
||||
@router.delete("/webhooks/{webhook_id}")
|
||||
async def delete_webhook_v2(webhook_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM webhook_subscriptions WHERE id=?", (webhook_id,))
|
||||
conn.commit()
|
||||
@@ -2348,10 +2215,8 @@ async def delete_webhook_v2(webhook_id: int, request: Request, authorization: st
|
||||
|
||||
@router.post("/webhooks/{webhook_id}/test")
|
||||
async def test_webhook_v2(webhook_id: int, request: Request, authorization: str | None = Header(default=None)):
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
with get_conn() as conn:
|
||||
row = conn.execute("SELECT * FROM webhook_subscriptions WHERE id=?", (webhook_id,)).fetchone()
|
||||
if not row:
|
||||
@@ -2399,10 +2264,8 @@ async def list_deliveries_v2(webhook_id: int, request: Request,
|
||||
async def retry_webhook_deliveries(webhook_id: int, request: Request,
|
||||
authorization: str | None = Header(default=None)):
|
||||
"""Manually retry failed deliveries for a webhook."""
|
||||
user = get_bearer_user(request, authorization)
|
||||
user = require_scope("write")(request, authorization)
|
||||
_v2_rate_check(request, user)
|
||||
if not has_scope(user.get("_token_scopes"), "write"):
|
||||
raise HTTPException(403, "Insufficient scope. Required: write")
|
||||
|
||||
from app.services.webhook_outbound import retry_due_deliveries
|
||||
|
||||
|
||||
Reference in New Issue
Block a user