233 lines
8.2 KiB
Python
233 lines
8.2 KiB
Python
import os
|
|
import httpx
|
|
|
|
API_URL = os.getenv("API_URL", "http://api:8000")
|
|
_TIMEOUT = 15.0
|
|
|
|
|
|
def _headers(token: str | None = None) -> dict:
|
|
h = {"Content-Type": "application/json"}
|
|
if token:
|
|
h["Authorization"] = f"Bearer {token}"
|
|
return h
|
|
|
|
|
|
# ─── Public ──────────────────────────────────────────────────────────────────
|
|
|
|
async def get_news(
|
|
offset: int = 0,
|
|
limit: int = 20,
|
|
category: str | None = None,
|
|
tag: str | None = None,
|
|
) -> dict | None:
|
|
params = {"offset": offset, "limit": limit}
|
|
if category:
|
|
params["category"] = category
|
|
if tag:
|
|
params["tag"] = tag
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.get(f"{API_URL}/news", params=params)
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return None
|
|
|
|
|
|
async def get_article(slug: str) -> dict | None:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.get(f"{API_URL}/news/{slug}")
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return None
|
|
|
|
|
|
async def get_categories() -> list:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.get(f"{API_URL}/news/categories")
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return []
|
|
|
|
|
|
# ─── Admin: Auth ─────────────────────────────────────────────────────────────
|
|
|
|
async def admin_login(username: str, password: str) -> str | None:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.post(
|
|
f"{API_URL}/admin/login",
|
|
json={"username": username, "password": password},
|
|
)
|
|
if r.status_code == 200:
|
|
return r.json().get("access_token")
|
|
return None
|
|
except httpx.RequestError:
|
|
return None
|
|
|
|
|
|
# ─── Admin: Articles ──────────────────────────────────────────────────────────
|
|
|
|
async def admin_list_articles(token: str, offset: int = 0, limit: int = 50, status: str | None = None) -> dict | None:
|
|
params = {"offset": offset, "limit": limit}
|
|
if status:
|
|
params["status"] = status
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.get(f"{API_URL}/admin/articles", params=params, headers=_headers(token))
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return None
|
|
|
|
|
|
async def admin_get_article(token: str, article_id: str) -> dict | None:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.get(f"{API_URL}/admin/articles/{article_id}", headers=_headers(token))
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return None
|
|
|
|
|
|
async def admin_create_article(token: str, data: dict) -> dict | None:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.post(f"{API_URL}/admin/articles", json=data, headers=_headers(token))
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return None
|
|
|
|
|
|
async def admin_update_article(token: str, article_id: str, data: dict) -> dict | None:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.put(f"{API_URL}/admin/articles/{article_id}", json=data, headers=_headers(token))
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return None
|
|
|
|
|
|
async def admin_delete_article(token: str, article_id: str) -> bool:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.delete(f"{API_URL}/admin/articles/{article_id}", headers=_headers(token))
|
|
return r.status_code == 200
|
|
except httpx.RequestError:
|
|
return False
|
|
|
|
|
|
async def admin_publish_article(token: str, article_id: str) -> bool:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.post(f"{API_URL}/admin/articles/{article_id}/publish", headers=_headers(token))
|
|
return r.status_code == 200
|
|
except httpx.RequestError:
|
|
return False
|
|
|
|
|
|
# ─── Admin: Categories ────────────────────────────────────────────────────────
|
|
|
|
async def admin_list_categories(token: str) -> list:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.get(f"{API_URL}/admin/categories", headers=_headers(token))
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return []
|
|
|
|
|
|
async def admin_create_category(token: str, name: str, slug: str = "") -> dict | None:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.post(
|
|
f"{API_URL}/admin/categories",
|
|
json={"name": name, "slug": slug or None},
|
|
headers=_headers(token),
|
|
)
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return None
|
|
|
|
|
|
async def admin_update_category(token: str, cat_id: str, name: str, slug: str = "") -> dict | None:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.put(
|
|
f"{API_URL}/admin/categories/{cat_id}",
|
|
json={"name": name, "slug": slug or None},
|
|
headers=_headers(token),
|
|
)
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return None
|
|
|
|
|
|
async def admin_delete_category(token: str, cat_id: str) -> bool:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.delete(f"{API_URL}/admin/categories/{cat_id}", headers=_headers(token))
|
|
return r.status_code == 200
|
|
except httpx.RequestError:
|
|
return False
|
|
|
|
|
|
# ─── Admin: Media ─────────────────────────────────────────────────────────────
|
|
|
|
async def admin_upload_media(token: str, file_bytes: bytes, filename: str, content_type: str) -> dict | None:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=60.0) as client:
|
|
r = await client.post(
|
|
f"{API_URL}/admin/media/upload",
|
|
files={"file": (filename, file_bytes, content_type)},
|
|
headers={"Authorization": f"Bearer {token}"},
|
|
)
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return None
|
|
|
|
|
|
async def admin_list_media(token: str, offset: int = 0, limit: int = 50, media_type: str | None = None) -> list:
|
|
params = {"offset": offset, "limit": limit}
|
|
if media_type:
|
|
params["media_type"] = media_type
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.get(f"{API_URL}/admin/media", params=params, headers=_headers(token))
|
|
if r.status_code == 200:
|
|
return r.json()
|
|
except httpx.RequestError:
|
|
pass
|
|
return []
|
|
|
|
|
|
async def admin_delete_media(token: str, media_id: str) -> bool:
|
|
try:
|
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
|
r = await client.delete(f"{API_URL}/admin/media/{media_id}", headers=_headers(token))
|
|
return r.status_code == 200
|
|
except httpx.RequestError:
|
|
return False
|