forked from retoor/devplacepy
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
This commit is contained in:
@@ -8,6 +8,8 @@ from devplacepy.content import load_detail, edit_content_item, delete_content_it
|
||||
from devplacepy.templating import templates
|
||||
from devplacepy.utils import get_current_user, require_user, not_found, XP_GIST
|
||||
from devplacepy.seo import base_seo_context, site_url, website_schema, software_source_code_schema, list_page_seo, next_page_url
|
||||
from devplacepy.responses import respond, action_result
|
||||
from devplacepy.schemas import GistsOut, GistDetailOut
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
@@ -55,7 +57,7 @@ async def gists_page(request: Request, language: str = None, user_uid: str = Non
|
||||
],
|
||||
next_url=next_page_url(request, next_cursor),
|
||||
)
|
||||
return templates.TemplateResponse(request, "gists.html", {
|
||||
return respond(request, "gists.html", {
|
||||
**seo_ctx,
|
||||
"request": request,
|
||||
"user": user,
|
||||
@@ -65,7 +67,7 @@ async def gists_page(request: Request, language: str = None, user_uid: str = Non
|
||||
"current_language": language,
|
||||
"languages": LANGUAGES,
|
||||
"gist_language_codes": get_gist_languages(),
|
||||
})
|
||||
}, model=GistsOut)
|
||||
|
||||
|
||||
@router.get("/{gist_slug}", response_class=HTMLResponse)
|
||||
@@ -93,9 +95,9 @@ async def gist_detail(request: Request, gist_slug: str):
|
||||
],
|
||||
schemas=[website_schema(base), software_source_code_schema(gist, base)],
|
||||
)
|
||||
return templates.TemplateResponse(request, "gist_detail.html", detail_context(request, user, detail, "gist", seo_ctx, {
|
||||
return respond(request, "gist_detail.html", detail_context(request, user, detail, "gist", seo_ctx, {
|
||||
"languages": LANGUAGES,
|
||||
}))
|
||||
}), model=GistDetailOut)
|
||||
|
||||
|
||||
@router.post("/create")
|
||||
@@ -116,7 +118,8 @@ async def create_gist(request: Request, data: Annotated[GistForm, Form()]):
|
||||
"source_code": source_code,
|
||||
"language": language,
|
||||
}, title, XP_GIST, "First Gist", description or "", data.attachment_uids)
|
||||
return RedirectResponse(url=f"/gists/{gist_slug}", status_code=302)
|
||||
url = f"/gists/{gist_slug}"
|
||||
return action_result(request, url, data={"uid": uid, "slug": gist_slug, "url": url})
|
||||
|
||||
|
||||
@router.post("/edit/{gist_slug}")
|
||||
@@ -125,7 +128,7 @@ async def edit_gist(request: Request, gist_slug: str, data: Annotated[GistEditFo
|
||||
language = data.language
|
||||
if language not in {l[0] for l in LANGUAGES}:
|
||||
language = "plaintext"
|
||||
return edit_content_item("gists", user, gist_slug, {
|
||||
return edit_content_item(request, "gists", user, gist_slug, {
|
||||
"title": data.title.strip(),
|
||||
"description": data.description.strip() or None,
|
||||
"source_code": data.source_code.strip(),
|
||||
@@ -136,4 +139,4 @@ async def edit_gist(request: Request, gist_slug: str, data: Annotated[GistEditFo
|
||||
@router.post("/delete/{gist_slug}")
|
||||
async def delete_gist(request: Request, gist_slug: str):
|
||||
user = require_user(request)
|
||||
return delete_content_item("gists", "gist", user, gist_slug, "/gists")
|
||||
return delete_content_item(request, "gists", "gist", user, gist_slug, "/gists")
|
||||
|
||||
Reference in New Issue
Block a user