This commit is contained in:
parent
51706d2d11
commit
853e99ca5f
21 changed files with 1402 additions and 77 deletions
74
app.py
74
app.py
|
|
@ -18,10 +18,14 @@ from auth import (
|
|||
create_login_session,
|
||||
create_oauth_state,
|
||||
current_session_user,
|
||||
resolve_forgejo_token,
|
||||
resolve_forgejo_auth,
|
||||
)
|
||||
from forgejo_client import ForgejoClient, ForgejoClientError
|
||||
from live_prototype import discussion_card_from_issue
|
||||
from live_prototype import (
|
||||
DISCUSSION_LABEL_NAME,
|
||||
discussion_card_from_issue,
|
||||
issue_has_discussion_label,
|
||||
)
|
||||
from prototype_cache import PrototypePayloadCache
|
||||
from settings import Settings, get_settings
|
||||
from update_events import UpdateBroker, stream_sse_events
|
||||
|
|
@ -31,15 +35,22 @@ DIST_DIR = BASE_DIR / "frontend" / "dist"
|
|||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
app = FastAPI(title="Robot U Community Prototype")
|
||||
settings = get_settings()
|
||||
app = FastAPI(title="Robot U Community Site")
|
||||
prototype_cache = PrototypePayloadCache()
|
||||
update_broker = UpdateBroker()
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
allow_origins=list(settings.cors_allow_origins),
|
||||
allow_methods=["GET", "POST", "DELETE", "OPTIONS"],
|
||||
allow_headers=[
|
||||
"Authorization",
|
||||
"Content-Type",
|
||||
"X-Forgejo-Signature",
|
||||
"X-Gitea-Signature",
|
||||
"X-Hub-Signature-256",
|
||||
],
|
||||
)
|
||||
|
||||
@app.get("/health")
|
||||
|
|
@ -50,12 +61,13 @@ def create_app() -> FastAPI:
|
|||
async def prototype(request: Request) -> JSONResponse:
|
||||
settings = get_settings()
|
||||
session_user = current_session_user(request, settings)
|
||||
forgejo_token, auth_source = resolve_forgejo_token(request, settings)
|
||||
forgejo_token, auth_source, auth_scheme = resolve_forgejo_auth(request, settings)
|
||||
payload = await prototype_cache.get(settings)
|
||||
payload["auth"] = await _auth_payload_for_request(
|
||||
settings,
|
||||
forgejo_token=forgejo_token,
|
||||
auth_source=auth_source,
|
||||
auth_scheme=auth_scheme,
|
||||
session_user=session_user,
|
||||
)
|
||||
return JSONResponse(payload)
|
||||
|
|
@ -67,11 +79,13 @@ def create_app() -> FastAPI:
|
|||
if session_user:
|
||||
return JSONResponse(_auth_payload(session_user, "session"))
|
||||
|
||||
forgejo_token, auth_source = resolve_forgejo_token(request, settings)
|
||||
forgejo_token, auth_source, auth_scheme = resolve_forgejo_auth(request, settings)
|
||||
if not forgejo_token or auth_source == "server":
|
||||
return JSONResponse(_auth_payload(None, "none"))
|
||||
|
||||
async with ForgejoClient(settings, forgejo_token=forgejo_token) as client:
|
||||
async with ForgejoClient(
|
||||
settings, forgejo_token=forgejo_token, auth_scheme=auth_scheme
|
||||
) as client:
|
||||
try:
|
||||
user = await client.fetch_current_user()
|
||||
except ForgejoClientError as error:
|
||||
|
|
@ -183,6 +197,11 @@ def create_app() -> FastAPI:
|
|||
detail="This site only reads public Forgejo repositories.",
|
||||
)
|
||||
issue = await client.fetch_issue(owner, repo, issue_number)
|
||||
if not issue_has_discussion_label(issue):
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="This issue is not labeled as a discussion.",
|
||||
)
|
||||
comments = [
|
||||
_discussion_reply(comment)
|
||||
for comment in await client.list_issue_comments(owner, repo, issue_number)
|
||||
|
|
@ -203,14 +222,16 @@ def create_app() -> FastAPI:
|
|||
body = _required_string(payload, "body")
|
||||
issue_number = _required_positive_int(payload, "number")
|
||||
settings = get_settings()
|
||||
forgejo_token, auth_source = resolve_forgejo_token(request, settings)
|
||||
forgejo_token, auth_source, auth_scheme = resolve_forgejo_auth(request, settings)
|
||||
if not forgejo_token or auth_source == "server":
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Sign in or send an Authorization token before replying.",
|
||||
)
|
||||
|
||||
async with ForgejoClient(settings, forgejo_token=forgejo_token) as client:
|
||||
async with ForgejoClient(
|
||||
settings, forgejo_token=forgejo_token, auth_scheme=auth_scheme
|
||||
) as client:
|
||||
try:
|
||||
repo_payload = await client.fetch_repository(owner, repo)
|
||||
if repo_payload.get("private"):
|
||||
|
|
@ -248,14 +269,16 @@ def create_app() -> FastAPI:
|
|||
)
|
||||
|
||||
settings = get_settings()
|
||||
forgejo_token, auth_source = resolve_forgejo_token(request, settings)
|
||||
forgejo_token, auth_source, auth_scheme = resolve_forgejo_auth(request, settings)
|
||||
if not forgejo_token or auth_source == "server":
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Sign in or send an Authorization token before starting a discussion.",
|
||||
)
|
||||
|
||||
async with ForgejoClient(settings, forgejo_token=forgejo_token) as client:
|
||||
async with ForgejoClient(
|
||||
settings, forgejo_token=forgejo_token, auth_scheme=auth_scheme
|
||||
) as client:
|
||||
try:
|
||||
repo_payload = await client.fetch_repository(owner, repo)
|
||||
if repo_payload.get("private"):
|
||||
|
|
@ -263,11 +286,29 @@ def create_app() -> FastAPI:
|
|||
status_code=403,
|
||||
detail="This site only writes to public Forgejo repositories.",
|
||||
)
|
||||
issue = await client.create_issue(owner, repo, title, issue_body)
|
||||
discussion_label_id = await client.ensure_repo_label(
|
||||
owner,
|
||||
repo,
|
||||
DISCUSSION_LABEL_NAME,
|
||||
color="#0f6f8f",
|
||||
description="Shown on Robot U as a community discussion.",
|
||||
)
|
||||
issue = await client.create_issue(
|
||||
owner,
|
||||
repo,
|
||||
title,
|
||||
issue_body,
|
||||
label_ids=[discussion_label_id],
|
||||
)
|
||||
except ForgejoClientError as error:
|
||||
raise HTTPException(status_code=502, detail=str(error)) from error
|
||||
|
||||
issue["repository"] = _issue_repository_payload(repo_payload, owner, repo)
|
||||
if not issue_has_discussion_label(issue):
|
||||
issue["labels"] = [
|
||||
*[label for label in issue.get("labels", []) if isinstance(label, dict)],
|
||||
{"id": discussion_label_id, "name": DISCUSSION_LABEL_NAME},
|
||||
]
|
||||
prototype_cache.invalidate()
|
||||
await update_broker.publish(
|
||||
"content-updated",
|
||||
|
|
@ -429,6 +470,7 @@ async def _auth_payload_for_request(
|
|||
*,
|
||||
forgejo_token: str | None,
|
||||
auth_source: str,
|
||||
auth_scheme: str,
|
||||
session_user: dict[str, Any] | None,
|
||||
) -> dict[str, object]:
|
||||
if session_user:
|
||||
|
|
@ -437,7 +479,9 @@ async def _auth_payload_for_request(
|
|||
if not forgejo_token or auth_source == "server":
|
||||
return _auth_payload(None, "none")
|
||||
|
||||
async with ForgejoClient(settings, forgejo_token=forgejo_token) as client:
|
||||
async with ForgejoClient(
|
||||
settings, forgejo_token=forgejo_token, auth_scheme=auth_scheme
|
||||
) as client:
|
||||
try:
|
||||
user = await client.fetch_current_user()
|
||||
except ForgejoClientError as error:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue