100 lines
5.4 KiB
Gherkin
100 lines
5.4 KiB
Gherkin
Feature: Removing an image from an article
|
|
|
|
As an authenticated RenewCMS user managing the CMS
|
|
I want to delete an already-uploaded image by its id
|
|
So that a removed image's file and row are actually gone, and a delete on
|
|
an unknown article or an unknown image answers 404 the same way every
|
|
other article write does
|
|
|
|
Background:
|
|
Given internal/infrastructure/useCases.DeleteImageUseCase.DeleteImage(imageId)
|
|
already exists and calls image.Repository.Delete(imageId), which returns
|
|
image.ErrImageNotFound for an unknown id and, on the real ImageRepository,
|
|
also removes the uploaded file from UPLOAD_DIR, per
|
|
features/delete_article_cascades_images.feature
|
|
And this slice changes POST /v1/article/{id}/image's success response
|
|
(api/handlers/image.Handler.PostImage, features/upload_article_image.feature)
|
|
to also return the created image's numeric id, so the 201 body becomes
|
|
{"id": ..., "location": ...}; this lets a client address the image later
|
|
through this slice's DELETE route
|
|
And this slice mounts DELETE /v1/article/{articleId}/image/{imageId} in
|
|
api/router.go, in the same jwtauth Verifier + Authenticator group as
|
|
POST .../image
|
|
And this slice adds a DeleteImage method to api/handlers/image.Handler,
|
|
grows NewHandler's signature to also take DeleteImageUseCase, and wires
|
|
it in api/router.go
|
|
And DeleteImage parses articleId and imageId from the URL, answering 400
|
|
with apperr.IdUint32ErrorMessage if either isn't a valid uint32
|
|
And DeleteImage first calls GetArticleUseCase.GetArticle(articleId);
|
|
errors.Is(err, article.ErrArticleNotFound) answers 404 with
|
|
apperr.ArticleNotFoundErrorMessage; this only confirms the article id
|
|
in the URL names a real article, and does not verify that the image id
|
|
belongs to that article's Images slice (a shallow existence check on
|
|
both ids, not an ownership check)
|
|
And DeleteImage then calls DeleteImageUseCase.DeleteImage(imageId);
|
|
errors.Is(err, image.ErrImageNotFound) answers 404 with the new
|
|
apperr.ImageNotFoundErrorMessage = "Image not found"; any other error
|
|
falls back to the existing generic 500
|
|
And on success DeleteImage answers 204 with an empty body, the same shape
|
|
as DELETE /v1/article/{id}
|
|
|
|
Scenario: Removing an image from an article it belongs to 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" whose Images slice holds image id 10
|
|
And the image repository contains an image with id 10
|
|
When the client sends DELETE /v1/article/1/image/10 with that cookie
|
|
Then the response status is 204
|
|
And the response body is empty
|
|
And the image repository no longer contains an image with id 10
|
|
|
|
Scenario: Removing an image from an unknown article answers 404 and never touches the image repository
|
|
Given a valid jwt cookie for a user with id 1
|
|
And the article repository has no article with id 9999
|
|
And the image repository contains an image with id 10
|
|
When the client sends DELETE /v1/article/9999/image/10 with that cookie
|
|
Then the response status is 404
|
|
And the response body is the text "Article not found"
|
|
And the image repository's Delete is never called
|
|
And the image repository still contains the image with id 10
|
|
|
|
Scenario: Removing an unknown image from an existing article answers 404
|
|
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"
|
|
And the image repository has no image with id 9999
|
|
When the client sends DELETE /v1/article/1/image/9999 with that cookie
|
|
Then the response status is 404
|
|
And the response body is the text "Image not found"
|
|
|
|
Scenario: Removing an image id that belongs to a different article still succeeds, because the check is shallow
|
|
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" whose Images slice is empty
|
|
And the article repository contains a second article with id 2 whose
|
|
Images slice holds image id 10
|
|
And the image repository contains an image with id 10
|
|
When the client sends DELETE /v1/article/1/image/10 with that cookie
|
|
Then the response status is 204
|
|
And the image repository no longer contains an image with id 10
|
|
|
|
Scenario: Removing 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" whose Images slice holds image id 10
|
|
And the image repository contains an image with id 10
|
|
When the client sends DELETE /v1/article/1/image/10 without a cookie
|
|
Then the response status is 401
|
|
And the image repository still contains the image with id 10
|
|
|
|
Scenario Outline: A malformed id in the URL answers 400 before either repository is touched
|
|
Given a valid jwt cookie for a user with id 1
|
|
When the client sends DELETE /v1/article/<article_id>/image/<image_id> with that cookie
|
|
Then the response status is 400
|
|
And the response body is the text "The server expects the ID to be in the format of an unsigned 32-bit integer (uint32)."
|
|
|
|
Examples:
|
|
| article_id | image_id |
|
|
| abc | 10 |
|
|
| 1 | abc |
|