forked from retoor/devplacepy
Add attachment management CRUD to the /uploads API
Complete the read and update faces of the signed-in user's attachment
management over the existing attachments table:
- GET /uploads: paginated list of the user's own attachments, newest
first, with an optional linked/orphaned filter
- GET /uploads/{uid}: fetch one attachment (owner or admin)
- PATCH /uploads/{uid}: rename the display filename, always preserving
the original extension (owner or admin, audited as attachment.rename)
Adds get_user_attachments/get_user_attachment data helpers, the
rename_attachment operation, AttachmentRenameForm, the UploadItemOut and
UploadsListOut schemas, the Devii tools list_attachments/get_attachment/
rename_attachment, expanded API reference documentation for the full
lifecycle including delete, and api-tier tests.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from ..spec import Action
|
||||
from ._shared import body, confirm, path, upload
|
||||
from ._shared import body, confirm, path, query, upload
|
||||
|
||||
|
||||
UPLOAD_ACTIONS: tuple[Action, ...] = (
|
||||
@@ -14,6 +14,44 @@ UPLOAD_ACTIONS: tuple[Action, ...] = (
|
||||
summary="Upload a local file and obtain its attachment uid",
|
||||
params=(upload("file", "Local filesystem path of the file to upload."),),
|
||||
),
|
||||
Action(
|
||||
name="list_attachments",
|
||||
method="GET",
|
||||
path="/uploads",
|
||||
summary="List your own uploaded attachments, newest first",
|
||||
description=(
|
||||
"Returns the signed-in user's attachments as {attachments, pagination, total}. Each item "
|
||||
"carries its uid, original_filename, mime_type, url, size, target_type/target_uid/target_url "
|
||||
"(where it is used, if any), and a 'linked' flag. Pass linked=true to list only attachments "
|
||||
"already attached to a post/comment/project/gist/issue, or linked=false for orphaned uploads."
|
||||
),
|
||||
params=(
|
||||
query("page", "1-based page number, 24 per page."),
|
||||
query("linked", "Filter: true = attached only, false = orphaned only."),
|
||||
),
|
||||
),
|
||||
Action(
|
||||
name="get_attachment",
|
||||
method="GET",
|
||||
path="/uploads/{attachment_uid}",
|
||||
summary="Get the metadata of one of your attachments by uid",
|
||||
params=(path("attachment_uid", "Uid of the attachment."),),
|
||||
),
|
||||
Action(
|
||||
name="rename_attachment",
|
||||
method="PATCH",
|
||||
path="/uploads/{attachment_uid}",
|
||||
summary="Rename an attachment you own (its display filename); the file extension is preserved",
|
||||
description=(
|
||||
"Updates only the display filename of the attachment; the stored file and its extension are "
|
||||
"unchanged (the original extension is always kept, so the file type cannot be altered). "
|
||||
"Administrators may rename any user's attachment."
|
||||
),
|
||||
params=(
|
||||
path("attachment_uid", "Uid of the attachment."),
|
||||
body("filename", "New display filename.", required=True),
|
||||
),
|
||||
),
|
||||
Action(
|
||||
name="attach_url",
|
||||
method="POST",
|
||||
@@ -39,7 +77,16 @@ UPLOAD_ACTIONS: tuple[Action, ...] = (
|
||||
name="delete_attachment",
|
||||
method="DELETE",
|
||||
path="/uploads/delete/{attachment_uid}",
|
||||
summary="Delete an uploaded attachment (your own, or anyone's when you are an administrator). Soft delete, confirmation required",
|
||||
summary="Delete an uploaded attachment (your own, or anyone's when you are an administrator). Confirmation required",
|
||||
description=(
|
||||
"Removes one attachment by uid. Use list_attachments (or get_attachment) to find the uid of the "
|
||||
"file the user wants gone, then delete it. The attachment leaves the owner's attachment list and "
|
||||
"disappears from every post, comment, project, gist, message, or issue it was attached to, and its "
|
||||
"file stops being served. Only the owner may delete their own; an administrator may delete anyone's "
|
||||
"(otherwise 403); an unknown or already-removed uid returns 404. This is confirmation-gated: the "
|
||||
"first call is refused so you can show the user the exact attachment (filename + where it is used) "
|
||||
"first, and only a repeat call with confirm=true performs it."
|
||||
),
|
||||
params=(path("attachment_uid", "Uid of the attachment."), confirm()),
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user