# 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="topics-hub",
                method="GET",
                path="/topics",
                title="Browse topics",
                summary="The topics hub - every post topic with its live post count, linking to its own crawlable listing page.",
                auth="public",
                interactive=True,
            ),
            endpoint(
                id="topics-list",
                method="GET",
                path="/topics/{topic}",
                title="Browse one topic",
                summary=(
                    "A single topic's post listing, on its own permanent, crawlable URL (unlike /feed?topic=, "
                    "whose canonical collapses back to /feed). Same author-interleaved pagination as the feed."
                ),
                auth="public",
                interactive=True,
                params=[
                    field(
                        "topic", "path", "enum", True, "devlog", "Topic key.", TOPICS
                    ),
                    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).",
                    ),
                    field(
                        "war_faction_a",
                        "form",
                        "string",
                        False,
                        "",
                        "Optional Opinion War faction A name (max 30 chars). Both faction names start the week-long battle.",
                    ),
                    field(
                        "war_faction_b",
                        "form",
                        "string",
                        False,
                        "",
                        "Optional Opinion War faction B name (max 30 chars). Must differ from faction A.",
                    ),
                ],
                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.",
                    )
                ],
            ),
        ],
}
