110 lines
5.6 KiB
Gherkin
110 lines
5.6 KiB
Gherkin
Feature: An authenticated user can publish and unpublish an article
|
|
|
|
As an authenticated RenewCMS user managing the CMS
|
|
I want to flip an article's is_online flag from an HTTP endpoint
|
|
So that a draft can be published to the public site and a published article can be
|
|
pulled back offline, without deleting it
|
|
|
|
Background:
|
|
Given internal/domain/article.Repository already exposes
|
|
UpdateIsOnline(id uint32, isOnline bool) (Article, error), and
|
|
UpdateArticleUseCase.UpdateIsOnline delegates to it unchanged
|
|
And UpdateArticleUseCase is already built in api/dependecyInjection.go as
|
|
container.UpdateArticleUseCase, but before this slice no handler or route calls it
|
|
And this slice adds Handler.PublishArticle and Handler.UnpublishArticle, backed by
|
|
UpdateArticleUseCase.UpdateIsOnline(id, true) and UpdateIsOnline(id, false)
|
|
And this slice mounts PATCH /v1/article/{id}/publish and
|
|
PATCH /v1/article/{id}/unpublish inside the same jwtauth Verifier + Authenticator
|
|
group as GET /v1/article/{id}, POST /v1/article/ and DELETE /v1/article/{id} in
|
|
api/router.go, so both require a valid jwt cookie
|
|
And a successful publish or unpublish answers 200 with the JSON body of the updated
|
|
article.Article, the same shape GetArticle and PostArticle already return
|
|
And an id that does not parse as a uint32 answers 400 with body
|
|
apperr.IdUint32ErrorMessage, the same as GetArticle and DeleteArticle
|
|
And an id absent from the article repository answers 404 with body
|
|
apperr.ArticleNotFoundErrorMessage, backed by errors.Is(err, article.ErrArticleNotFound),
|
|
the same as DeleteArticle already does per features/write_not_found_errors.feature
|
|
And GET /v1/article/ with no jwt cookie only returns online articles, per
|
|
features/public_article_listing.feature; this slice does not change that behavior,
|
|
only feeds it
|
|
|
|
Scenario: Publishing an offline article makes it online
|
|
Given a valid jwt cookie for a user with id 1
|
|
And the article repository contains an offline article titled "Draft: Kitchen Remodel" with id 2
|
|
When the client sends PATCH /v1/article/2/publish with that cookie
|
|
Then the response status is 200
|
|
And the response body is the article with id 2 and "is_online": true
|
|
|
|
Scenario: Unpublishing an online article makes it offline
|
|
Given a valid jwt cookie for a user with id 1
|
|
And the article repository contains an online article titled "Backyard Renovation Update" with id 1
|
|
When the client sends PATCH /v1/article/1/unpublish with that cookie
|
|
Then the response status is 200
|
|
And the response body is the article with id 1 and "is_online": false
|
|
|
|
Scenario: Publishing an already-online article is idempotent
|
|
Given a valid jwt cookie for a user with id 1
|
|
And the article repository contains an online article with id 1
|
|
When the client sends PATCH /v1/article/1/publish with that cookie
|
|
Then the response status is 200
|
|
And the response body is the article with id 1 and "is_online": true
|
|
And no error is returned
|
|
|
|
Scenario: Unpublishing an already-offline article is idempotent
|
|
Given a valid jwt cookie for a user with id 1
|
|
And the article repository contains an offline article with id 2
|
|
When the client sends PATCH /v1/article/2/unpublish with that cookie
|
|
Then the response status is 200
|
|
And the response body is the article with id 2 and "is_online": false
|
|
And no error is returned
|
|
|
|
Scenario Outline: Publishing or unpublishing an unknown article answers 404
|
|
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 PATCH /v1/article/9999/<action> with that cookie
|
|
Then the response status is 404
|
|
And the response body is the text "Article not found"
|
|
|
|
Examples:
|
|
| action |
|
|
| publish |
|
|
| unpublish |
|
|
|
|
Scenario Outline: A malformed id answers 400 before any repository call
|
|
Given a valid jwt cookie for a user with id 1
|
|
When the client sends PATCH /v1/article/not-a-number/<action> with that cookie
|
|
Then the response status is 400
|
|
And the response body is the text apperr.IdUint32ErrorMessage
|
|
|
|
Examples:
|
|
| action |
|
|
| publish |
|
|
| unpublish |
|
|
|
|
Scenario Outline: Publish and unpublish require authentication
|
|
Given no jwt cookie is sent
|
|
And the article repository contains an article with id 1
|
|
When the client sends PATCH /v1/article/1/<action> without a cookie
|
|
Then the response status is 401
|
|
|
|
Examples:
|
|
| action |
|
|
| publish |
|
|
| unpublish |
|
|
|
|
Scenario: Publishing an article makes it appear in the public online-only list
|
|
Given a valid jwt cookie for a user with id 1
|
|
And the article repository contains an offline article titled "Draft: Kitchen Remodel" with id 2
|
|
When the client sends PATCH /v1/article/2/publish with that cookie
|
|
And the client then sends GET /v1/article/ with no jwt cookie
|
|
Then the response status of the second request is 200
|
|
And the response body of the second request is a JSON array containing the article with id 2
|
|
|
|
Scenario: Unpublishing an article removes it from the public online-only list
|
|
Given a valid jwt cookie for a user with id 1
|
|
And the article repository contains an online article titled "Backyard Renovation Update" with id 1
|
|
When the client sends PATCH /v1/article/1/unpublish with that cookie
|
|
And the client then sends GET /v1/article/ with no jwt cookie
|
|
Then the response status of the second request is 200
|
|
And the article with id 1 is absent from the response body of the second request
|