DevPlace CI / test (pull_request) Has been cancelled
The project detail page becomes a full project showcase built entirely
from existing platform mechanisms. One encompassing dark card wraps the
page; inner panels (tab bar, sidebar cards, devlog entries, comments)
sit one elevation lighter. The hero opens with a cover banner and an
optional logo tile, both plain attachment references
(cover_attachment_uid/logo_attachment_uid) uploaded through the
standard dp-upload attachment widget and linked via the existing
link_attachments choke point - the route validates each uid belongs to
the actor and is an image, and an empty value on edit keeps the current
one. The title block, type/platform chips and author row overlay the
banner behind a scrim with a dark text shadow, next to an owner-set
Visit Website CTA; website_url and repo_url are normalized in models
and render with rel noopener nofollow.
An anchor tab bar (Overview, Devlog, Screenshots when present,
Comments, Files) navigates the page. The main column keeps About, the
devlog timeline (with devlog_count and an owner Post update button
opening the shared composer preset to the devlog topic + project - the
form now lives once in _post_composer_form.html, included by feed.html
and project_detail.html), a Screenshots gallery built from image
attachments minus the cover/logo (thumbnails, lightbox, 12 rendered),
and the comment thread; the sidebar holds Links, Stats and the Author
card. Owners add gallery images from the More menu via
POST /projects/{slug}/screenshots (owner-only, audit
project.screenshots.add, Devii action project_add_screenshots, docs id
projects-screenshots). comment_count/devlog_count ride
ProjectDetailOut, the new fields ride ProjectOut, and the create/edit
faces (modals, Devii actions, API docs) carry them. The project
comment/files e2e tests scope their locators per the documented
dual-control idiom, and new unit/api/e2e tests cover URL normalization,
the counts, the hero attachment guard, the screenshots flow and the
preset composer.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1046 lines
38 KiB
Python
1046 lines
38 KiB
Python
# retoor <retoor@molodetz.nl>
|
|
|
|
from .._shared import COMMENT_TARGETS, GIST_LANGUAGES, PROJECT_TYPES, endpoint, field
|
|
from devplacepy.constants import TOPICS
|
|
|
|
GROUP = {
|
|
"slug": "content",
|
|
"title": "Posts, Comments, Projects, Gists & News",
|
|
"intro": """
|
|
# Posts, Comments, Projects, Gists & News
|
|
|
|
The core content types. Read endpoints render HTML pages; write endpoints accept form fields
|
|
and redirect to the new or updated resource. List fields such as `attachment_uids` are
|
|
repeated form keys - upload files first via [Uploads](/docs/uploads.html) and pass the returned
|
|
uids here. Engage with this content through [Votes, Reactions, Bookmarks & Polls](/docs/social-actions.html).
|
|
|
|
Every endpoint follows the shared [Conventions & Errors](/docs/conventions.html) (auth, content
|
|
negotiation, pagination, status codes); see [Authentication](/docs/authentication.html) for the
|
|
four ways to sign requests.
|
|
""",
|
|
"endpoints": [
|
|
endpoint(
|
|
id="home",
|
|
method="GET",
|
|
path="/",
|
|
title="Home",
|
|
summary=(
|
|
"The home page. Guests see the marketing splash; authenticated users see a "
|
|
"personalized home (welcome, feed shortcut, latest posts, news). It no longer "
|
|
"redirects to /feed. The latest-posts section interleaves authors so no two consecutive posts share an author."
|
|
),
|
|
auth="public",
|
|
interactive=True,
|
|
),
|
|
endpoint(
|
|
id="feed-list",
|
|
method="GET",
|
|
path="/feed",
|
|
title="Browse the feed",
|
|
summary="The main post feed. Returns an HTML page. Each page interleaves authors so no two consecutive posts share an author.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field(
|
|
"tab",
|
|
"query",
|
|
"enum",
|
|
False,
|
|
"all",
|
|
"Feed selector.",
|
|
["all", "trending", "following"],
|
|
),
|
|
field(
|
|
"topic", "query", "enum", False, "", "Filter by topic.", TOPICS
|
|
),
|
|
field(
|
|
"search",
|
|
"query",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Search post title, content, and author username.",
|
|
),
|
|
field("before", "query", "string", False, "", "Pagination cursor."),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="posts-create",
|
|
method="POST",
|
|
path="/posts/create",
|
|
title="Create a post",
|
|
summary="Publish a post, optionally with a poll. Redirects to the new post.",
|
|
auth="user",
|
|
encoding="form",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"content",
|
|
"form",
|
|
"textarea",
|
|
True,
|
|
"Posted from a script.",
|
|
"Body, 10-125000 characters.",
|
|
),
|
|
field(
|
|
"title",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"Hello",
|
|
"Optional title, up to 500 characters.",
|
|
),
|
|
field(
|
|
"topic", "form", "enum", False, "random", "Post topic.", TOPICS
|
|
),
|
|
field(
|
|
"project_uid",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Attach to a project.",
|
|
),
|
|
field(
|
|
"poll_question",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Optional poll question.",
|
|
),
|
|
field(
|
|
"poll_options",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Repeat the field for each poll option, or send a single newline- or comma-separated string (2-6 options).",
|
|
),
|
|
],
|
|
notes=["Returns a `302` redirect to `/posts/{slug}` on success."],
|
|
),
|
|
endpoint(
|
|
id="posts-detail",
|
|
method="GET",
|
|
path="/posts/{post_slug}",
|
|
title="View a post",
|
|
summary="Render a post with comments. Returns an HTML page.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field(
|
|
"post_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"POST_SLUG",
|
|
"Slug or UID of the post.",
|
|
)
|
|
],
|
|
),
|
|
endpoint(
|
|
id="posts-edit",
|
|
method="POST",
|
|
path="/posts/edit/{post_slug}",
|
|
title="Edit a post",
|
|
summary="Update a post you own, optionally adding a poll if it has none.",
|
|
auth="user",
|
|
encoding="form",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"post_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"POST_SLUG",
|
|
"Slug or UID of the post.",
|
|
),
|
|
field(
|
|
"content",
|
|
"form",
|
|
"textarea",
|
|
True,
|
|
"Updated body.",
|
|
"Body, 10-125000 characters.",
|
|
),
|
|
field(
|
|
"title",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"Updated title",
|
|
"Optional title.",
|
|
),
|
|
field(
|
|
"topic", "form", "enum", False, "random", "Post topic.", TOPICS
|
|
),
|
|
field(
|
|
"poll_question",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Optional poll question. Adds a poll only when the post has none.",
|
|
),
|
|
field(
|
|
"poll_options",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Repeat the field for each poll option, or send a single newline- or comma-separated string (2-6 options).",
|
|
),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="posts-delete",
|
|
method="POST",
|
|
path="/posts/delete/{post_slug}",
|
|
title="Delete a post",
|
|
summary="Delete a post you own; administrators may delete any user's post. Soft-deleted (hidden everywhere but restorable from admin trash) and cascades its comments and votes.",
|
|
auth="user",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"post_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"POST_SLUG",
|
|
"Slug or UID of the post.",
|
|
)
|
|
],
|
|
),
|
|
endpoint(
|
|
id="comments-create",
|
|
method="POST",
|
|
path="/comments/create",
|
|
title="Create a comment",
|
|
summary="Comment on any commentable target. Supports nested replies.",
|
|
auth="user",
|
|
encoding="form",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"content",
|
|
"form",
|
|
"textarea",
|
|
True,
|
|
"Nice work.",
|
|
"Body, 3-1000 characters.",
|
|
),
|
|
field(
|
|
"target_uid",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"POST_UID",
|
|
"UID of the target (or use post_uid).",
|
|
),
|
|
field(
|
|
"post_uid",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Convenience alias for a post target.",
|
|
),
|
|
field(
|
|
"target_type",
|
|
"form",
|
|
"enum",
|
|
False,
|
|
"post",
|
|
"Type of the target.",
|
|
COMMENT_TARGETS,
|
|
),
|
|
field(
|
|
"parent_uid",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Parent comment UID for a reply.",
|
|
),
|
|
],
|
|
notes=["Either `target_uid` or `post_uid` is required."],
|
|
),
|
|
endpoint(
|
|
id="comments-edit",
|
|
method="POST",
|
|
path="/comments/edit/{comment_uid}",
|
|
title="Edit a comment",
|
|
summary="Edit the body of a comment you own. Returns the updated comment.",
|
|
auth="user",
|
|
encoding="form",
|
|
params=[
|
|
field(
|
|
"comment_uid",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"COMMENT_UID",
|
|
"UID of the comment.",
|
|
),
|
|
field(
|
|
"content",
|
|
"form",
|
|
"textarea",
|
|
True,
|
|
"Edited body.",
|
|
"New body, 3-1000 characters.",
|
|
),
|
|
],
|
|
sample_response={
|
|
"uid": "COMMENT_UID",
|
|
"content": "Edited body.",
|
|
"url": "/posts/POST_SLUG#comment-COMMENT_UID",
|
|
"updated_at": "2026-06-15T12:00:00+00:00",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="comments-delete",
|
|
method="POST",
|
|
path="/comments/delete/{comment_uid}",
|
|
title="Delete a comment",
|
|
summary="Delete a comment you own; administrators may delete any user's comment. Soft-deleted (hidden everywhere but restorable from admin trash).",
|
|
auth="user",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"comment_uid",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"COMMENT_UID",
|
|
"UID of the comment.",
|
|
)
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-list",
|
|
method="GET",
|
|
path="/projects",
|
|
title="Browse projects",
|
|
summary="List projects. Returns an HTML page.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field(
|
|
"tab",
|
|
"query",
|
|
"enum",
|
|
False,
|
|
"recent",
|
|
"Sort selector.",
|
|
["recent", "popular", "released"],
|
|
),
|
|
field(
|
|
"search",
|
|
"query",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Search project title, description, and author username.",
|
|
),
|
|
field(
|
|
"project_type",
|
|
"query",
|
|
"enum",
|
|
False,
|
|
"",
|
|
"Filter by type.",
|
|
PROJECT_TYPES,
|
|
),
|
|
field("before", "query", "string", False, "", "Pagination cursor."),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-detail",
|
|
method="GET",
|
|
path="/projects/{project_slug}",
|
|
title="View a project",
|
|
summary="Render the project overview with its devlog, screenshots and comments. Returns an HTML page.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field(
|
|
"project_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"PROJECT_SLUG",
|
|
"Slug or UID of the project.",
|
|
),
|
|
field(
|
|
"before",
|
|
"query",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Devlog pagination cursor (devlog_next_cursor from the previous page).",
|
|
),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-screenshots",
|
|
method="POST",
|
|
path="/projects/{project_slug}/screenshots",
|
|
title="Add screenshots to a project",
|
|
summary="Link uploaded image attachments to an owned project's Screenshots gallery. Redirects to the gallery.",
|
|
auth="user",
|
|
encoding="form",
|
|
params=[
|
|
field(
|
|
"project_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"my-project-1a2b3c4d",
|
|
"Project slug or uid.",
|
|
),
|
|
field(
|
|
"attachment_uids",
|
|
"form",
|
|
"string",
|
|
True,
|
|
"ATTACHMENT_UID",
|
|
"Comma-separated attachment uids from POST /uploads/upload or /uploads/upload-url.",
|
|
),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-create",
|
|
method="POST",
|
|
path="/projects/create",
|
|
title="Create a project",
|
|
summary="Publish a project. Redirects to the new project.",
|
|
auth="user",
|
|
encoding="form",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"title",
|
|
"form",
|
|
"string",
|
|
True,
|
|
"My Project",
|
|
"Title, 1-200 characters.",
|
|
),
|
|
field(
|
|
"description",
|
|
"form",
|
|
"textarea",
|
|
True,
|
|
"What it does.",
|
|
"Description, 1-5000 characters.",
|
|
),
|
|
field(
|
|
"project_type",
|
|
"form",
|
|
"enum",
|
|
False,
|
|
"software",
|
|
"Project type.",
|
|
PROJECT_TYPES,
|
|
),
|
|
field(
|
|
"status",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"In Development",
|
|
"Free-form status label.",
|
|
),
|
|
field(
|
|
"platforms",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"Linux, Web",
|
|
"Comma-separated platforms.",
|
|
),
|
|
field(
|
|
"release_date",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"31/12/2026",
|
|
"Optional release date in DD/MM/YYYY format.",
|
|
),
|
|
field(
|
|
"demo_date",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"31/12/2026",
|
|
"Optional demo date in DD/MM/YYYY format.",
|
|
),
|
|
field(
|
|
"website_url",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"https://myproject.dev",
|
|
"Optional official website URL (http/https).",
|
|
),
|
|
field(
|
|
"repo_url",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"https://github.com/me/project",
|
|
"Optional source repository URL (http/https).",
|
|
),
|
|
field(
|
|
"cover_attachment_uid",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"ATTACHMENT_UID",
|
|
"Optional attachment uid of an uploaded cover image.",
|
|
),
|
|
field(
|
|
"logo_attachment_uid",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"ATTACHMENT_UID",
|
|
"Optional attachment uid of an uploaded project logo.",
|
|
),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-edit",
|
|
method="POST",
|
|
path="/projects/edit/{project_slug}",
|
|
title="Edit a project",
|
|
summary="Update an owned project. Redirects to the project.",
|
|
auth="user",
|
|
encoding="form",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"project_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"my-project-1a2b3c4d",
|
|
"Project slug or uid.",
|
|
),
|
|
field(
|
|
"title",
|
|
"form",
|
|
"string",
|
|
True,
|
|
"My Project",
|
|
"Title, 1-200 characters.",
|
|
),
|
|
field(
|
|
"description",
|
|
"form",
|
|
"textarea",
|
|
True,
|
|
"What it does.",
|
|
"Description, 1-5000 characters.",
|
|
),
|
|
field(
|
|
"project_type",
|
|
"form",
|
|
"enum",
|
|
False,
|
|
"software",
|
|
"Project type.",
|
|
PROJECT_TYPES,
|
|
),
|
|
field(
|
|
"status",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"In Development",
|
|
"Free-form status label.",
|
|
),
|
|
field(
|
|
"platforms",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"Linux, Web",
|
|
"Comma-separated platforms.",
|
|
),
|
|
field(
|
|
"release_date",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"31/12/2026",
|
|
"Optional release date in DD/MM/YYYY format.",
|
|
),
|
|
field(
|
|
"demo_date",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"31/12/2026",
|
|
"Optional demo date in DD/MM/YYYY format.",
|
|
),
|
|
field(
|
|
"website_url",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"https://myproject.dev",
|
|
"Optional official website URL (http/https).",
|
|
),
|
|
field(
|
|
"repo_url",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"https://github.com/me/project",
|
|
"Optional source repository URL (http/https).",
|
|
),
|
|
field(
|
|
"cover_attachment_uid",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"ATTACHMENT_UID",
|
|
"Optional attachment uid of an uploaded cover image.",
|
|
),
|
|
field(
|
|
"logo_attachment_uid",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"ATTACHMENT_UID",
|
|
"Optional attachment uid of an uploaded project logo.",
|
|
),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-delete",
|
|
method="POST",
|
|
path="/projects/delete/{project_slug}",
|
|
title="Delete a project",
|
|
summary="Delete a project you own; administrators may delete any user's project. Soft-deleted with all of its files (hidden everywhere but restorable from admin trash).",
|
|
auth="user",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"project_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"PROJECT_SLUG",
|
|
"Slug or UID of the project.",
|
|
)
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-private",
|
|
method="POST",
|
|
path="/projects/{project_slug}/private",
|
|
title="Set project visibility",
|
|
summary="Mark a project you own private or public. Send value=1 for private, value=0 for public. A project you hide as a member stays visible to administrators; a project you hide as an administrator is visible only to you, not to other administrators (this also hides its files and any attached containers).",
|
|
auth="user",
|
|
encoding="form",
|
|
params=[
|
|
field(
|
|
"project_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"PROJECT_SLUG",
|
|
"Slug or UID of the project.",
|
|
),
|
|
field(
|
|
"value",
|
|
"form",
|
|
"boolean",
|
|
True,
|
|
"1",
|
|
"1 to make the project private, 0 to make it public.",
|
|
),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-readonly",
|
|
method="POST",
|
|
path="/projects/{project_slug}/readonly",
|
|
title="Set project read-only",
|
|
summary="Mark a project you own read-only so all of its files become immutable (no writes, edits, moves, deletes, or uploads succeed), or writable again. Send value=1 for read-only, value=0 for writable.",
|
|
auth="user",
|
|
encoding="form",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"project_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"PROJECT_SLUG",
|
|
"Slug or UID of the project.",
|
|
),
|
|
field(
|
|
"value",
|
|
"form",
|
|
"boolean",
|
|
True,
|
|
"1",
|
|
"1 to make the project read-only, 0 to make it writable.",
|
|
),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-zip",
|
|
method="POST",
|
|
path="/projects/{project_slug}/zip",
|
|
title="Queue a project zip",
|
|
summary="Start a background job that archives the whole project. Returns the job uid and status URL to poll.",
|
|
auth="public",
|
|
params=[
|
|
field(
|
|
"project_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"PROJECT_SLUG",
|
|
"Slug or UID of the project.",
|
|
)
|
|
],
|
|
sample_response={
|
|
"uid": "ZIP_JOB_UID",
|
|
"status_url": "/zips/ZIP_JOB_UID",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="zips-status",
|
|
method="GET",
|
|
path="/zips/{uid}",
|
|
title="Zip job status",
|
|
summary="Poll a zip job. While pending or running download_url is null; once done it points at the archive.",
|
|
auth="public",
|
|
params=[
|
|
field(
|
|
"uid",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"ZIP_JOB_UID",
|
|
"Zip job uid returned when the job was queued.",
|
|
)
|
|
],
|
|
sample_response={
|
|
"uid": "ZIP_JOB_UID",
|
|
"kind": "zip",
|
|
"status": "done",
|
|
"preferred_name": "my-project",
|
|
"download_url": "/zips/ZIP_JOB_UID/download",
|
|
"error": None,
|
|
"bytes_in": 20480,
|
|
"bytes_out": 8192,
|
|
"item_count": 12,
|
|
"file_count": 10,
|
|
"dir_count": 2,
|
|
"created_at": "2026-06-09T10:00:00+00:00",
|
|
"completed_at": "2026-06-09T10:00:03+00:00",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="zips-download",
|
|
method="GET",
|
|
path="/zips/{uid}/download",
|
|
title="Download a zip archive",
|
|
summary="Stream the finished archive as application/zip. Each access extends the retention window.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field(
|
|
"uid",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"ZIP_JOB_UID",
|
|
"Zip job uid of a finished job.",
|
|
)
|
|
],
|
|
),
|
|
endpoint(
|
|
id="projects-fork",
|
|
method="POST",
|
|
path="/projects/{project_slug}/fork",
|
|
title="Queue a project fork",
|
|
summary="Start a background job that copies the whole project into a new project owned by you. Returns the job uid and status URL to poll.",
|
|
auth="user",
|
|
params=[
|
|
field(
|
|
"project_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"PROJECT_SLUG",
|
|
"Slug or UID of the project to fork.",
|
|
),
|
|
field(
|
|
"title",
|
|
"form",
|
|
"string",
|
|
True,
|
|
"My Fork",
|
|
"Title for the new forked project.",
|
|
),
|
|
],
|
|
sample_response={
|
|
"uid": "FORK_JOB_UID",
|
|
"status_url": "/forks/FORK_JOB_UID",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="forks-status",
|
|
method="GET",
|
|
path="/forks/{uid}",
|
|
title="Fork job status",
|
|
summary="Poll a fork job. While pending or running project_url is null; once done it points at the new project.",
|
|
auth="public",
|
|
params=[
|
|
field(
|
|
"uid",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"FORK_JOB_UID",
|
|
"Fork job uid returned when the job was queued.",
|
|
)
|
|
],
|
|
sample_response={
|
|
"uid": "FORK_JOB_UID",
|
|
"kind": "fork",
|
|
"status": "done",
|
|
"preferred_name": "My Fork",
|
|
"project_uid": "NEW_PROJECT_UID",
|
|
"project_url": "/projects/new-project-slug",
|
|
"source_project_uid": "SOURCE_PROJECT_UID",
|
|
"error": None,
|
|
"item_count": 12,
|
|
"created_at": "2026-06-09T10:00:00+00:00",
|
|
"completed_at": "2026-06-09T10:00:05+00:00",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="gists-list",
|
|
method="GET",
|
|
path="/gists",
|
|
title="Browse gists",
|
|
summary="List code gists. Returns an HTML page.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field(
|
|
"language",
|
|
"query",
|
|
"enum",
|
|
False,
|
|
"",
|
|
"Filter by language.",
|
|
GIST_LANGUAGES,
|
|
),
|
|
field(
|
|
"user_uid",
|
|
"query",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Filter by author UID.",
|
|
),
|
|
field(
|
|
"search",
|
|
"query",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Search gist title, description, and author username.",
|
|
),
|
|
field("before", "query", "string", False, "", "Pagination cursor."),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="gists-detail",
|
|
method="GET",
|
|
path="/gists/{gist_slug}",
|
|
title="View a gist",
|
|
summary="Render a gist with comments. Returns an HTML page.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field(
|
|
"gist_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"GIST_SLUG",
|
|
"Slug or UID of the gist.",
|
|
)
|
|
],
|
|
),
|
|
endpoint(
|
|
id="gists-create",
|
|
method="POST",
|
|
path="/gists/create",
|
|
title="Create a gist",
|
|
summary="Publish a code snippet. Redirects to the new gist.",
|
|
auth="user",
|
|
encoding="form",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"title",
|
|
"form",
|
|
"string",
|
|
True,
|
|
"Quick sort",
|
|
"Title, 1-200 characters.",
|
|
),
|
|
field(
|
|
"source_code",
|
|
"form",
|
|
"textarea",
|
|
True,
|
|
"print('hello')",
|
|
"Source, 1-400000 characters.",
|
|
),
|
|
field(
|
|
"language",
|
|
"form",
|
|
"enum",
|
|
False,
|
|
"python",
|
|
"Syntax language.",
|
|
GIST_LANGUAGES,
|
|
),
|
|
field(
|
|
"description",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Optional description.",
|
|
),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="gists-edit",
|
|
method="POST",
|
|
path="/gists/edit/{gist_slug}",
|
|
title="Edit a gist",
|
|
summary="Update a gist you own.",
|
|
auth="user",
|
|
encoding="form",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"gist_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"GIST_SLUG",
|
|
"Slug or UID of the gist.",
|
|
),
|
|
field(
|
|
"title",
|
|
"form",
|
|
"string",
|
|
True,
|
|
"Quick sort",
|
|
"Title, 1-200 characters.",
|
|
),
|
|
field(
|
|
"source_code",
|
|
"form",
|
|
"textarea",
|
|
True,
|
|
"print('hi')",
|
|
"Source, 1-400000 characters.",
|
|
),
|
|
field(
|
|
"language",
|
|
"form",
|
|
"enum",
|
|
False,
|
|
"python",
|
|
"Syntax language.",
|
|
GIST_LANGUAGES,
|
|
),
|
|
field(
|
|
"description",
|
|
"form",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Optional description.",
|
|
),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="gists-delete",
|
|
method="POST",
|
|
path="/gists/delete/{gist_slug}",
|
|
title="Delete a gist",
|
|
summary="Delete a gist you own; administrators may delete any user's gist. Soft-deleted (hidden everywhere but restorable from admin trash).",
|
|
auth="user",
|
|
destructive=True,
|
|
params=[
|
|
field(
|
|
"gist_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"GIST_SLUG",
|
|
"Slug or UID of the gist.",
|
|
)
|
|
],
|
|
),
|
|
endpoint(
|
|
id="news-list",
|
|
method="GET",
|
|
path="/news",
|
|
title="Browse news",
|
|
summary="Curated developer news. Returns an HTML page.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field(
|
|
"before",
|
|
"query",
|
|
"string",
|
|
False,
|
|
"",
|
|
"Pagination cursor (synced_at).",
|
|
)
|
|
],
|
|
),
|
|
endpoint(
|
|
id="news-detail",
|
|
method="GET",
|
|
path="/news/{news_slug}",
|
|
title="View a news article",
|
|
summary="Render a news article with comments. Returns an HTML page.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field(
|
|
"news_slug",
|
|
"path",
|
|
"string",
|
|
True,
|
|
"NEWS_SLUG",
|
|
"Slug or UID of the article.",
|
|
)
|
|
],
|
|
),
|
|
],
|
|
}
|