Files
RenewCMS/features/upload_article_image.feature
T

95 lines
5.0 KiB
Gherkin

Feature: Uploading an image to an article
As an authenticated RenewCMS user managing the CMS
I want to attach an image file to an existing article and get back the
image's public location
So that an unknown article answers 404 the same way every other article
write does, without ever creating an orphaned image, and a disallowed
content type is rejected with 400 before it becomes part of the
article, without a maintainer needing to trust the client to send a
sane file
Background:
Given internal/infrastructure/useCases.CreateImageUseCase.CreateImage
already checks the uploaded content type against the allowed list
(image/png, image/jpeg, image/webp, image/svg+xml) and the size
against the 10485760-byte maximum before calling image.Repository.Create,
returning image.ErrImageTypeNotAllowed or image.ErrImageTooLarge and
calling the repository not at all when either check fails
And internal/infrastructure/persistence's ArticleRepository.AddImage
already returns article.ErrArticleNotFound when the article id doesn't
match any row, and image.ErrImageNotFound when the article exists but
the image id doesn't, both asserted with errors.Is
And before this slice, api/handlers/image.Handler.PostImage existed and
was wired to CreateImageUseCase and UpdateArticleUseCase.AddImage, but
no route called it, and every error it got back from either use case
fell through to a blanket 500
And this slice mounts POST /v1/article/{id}/image in api/router.go, in
the same jwtauth Verifier + Authenticator group as the other article
write routes, and changes the upload flow so that the article's
existence is confirmed before the image is created, so that an
unknown article id never leaves an orphaned image behind
And this slice changes PostImage's error handling so that errors.Is(err,
image.ErrImageTypeNotAllowed) or errors.Is(err, image.ErrImageTooLarge)
answers 400 with the sentinel's own message, errors.Is(err,
article.ErrArticleNotFound) answers 404 with body
apperr.ArticleNotFoundErrorMessage, and any other error still falls
back to a generic 500
And PostImage reads the uploaded file from the multipart form field
"file"
And on success PostImage answers 201 with a JSON body {"location": ...}
holding the created image's public path, e.g.
"/static/uploadedImages/<stored-filename>"
Scenario: Uploading an allowed image type to an existing article succeeds
Given a valid jwt cookie for a user with id 1
And the article repository contains an article with id 1 titled
"Backyard Renovation Update"
When the client sends POST /v1/article/1/image with that cookie and a
multipart form field "file" holding a file named "before.png" with
content type "image/png"
Then the response status is 201
And the response body is JSON with a "location" field whose value is
"/static/uploadedImages/before.png"
And the image repository contains a new image whose Path is
"/static/uploadedImages/before.png"
And the article repository's article with id 1 has that new image's id
in its Images slice
Scenario: Uploading to an unknown article answers 404 and creates no image
Given a valid jwt cookie for a user with id 1
And the article repository has no article with id 9999
When the client sends POST /v1/article/9999/image with that cookie and a
multipart form field "file" holding a file named "before.png" with
content type "image/png"
Then the response status is 404
And the response body is the text "Article not found"
And the image repository's Create is never called
And no image exists in the image repository
Scenario: Uploading a disallowed content type answers 400 before the article is touched
Given a valid jwt cookie for a user with id 1
And the article repository contains an article with id 1 titled
"Backyard Renovation Update"
When the client sends POST /v1/article/1/image with that cookie and a
multipart form field "file" holding a file named "notes.pdf" with
content type "application/pdf"
Then the response status is 400
And the response body is the text
"the file must be a PNG, JPEG, WEBP, or SVG image"
And the image repository's Create is never called
And the article repository's article with id 1 still has an empty
Images slice
Scenario: Uploading an image still requires authentication
Given no jwt cookie is sent
And the article repository contains an article with id 1 titled
"Backyard Renovation Update"
When the client sends POST /v1/article/1/image without a cookie and a
multipart form field "file" holding a file named "before.png" with
content type "image/png"
Then the response status is 401
And the image repository's Create is never called
And the article repository's article with id 1 still has an empty
Images slice