From 08820dbee55c57026d0f3acb38c9bd6441683316 Mon Sep 17 00:00:00 2001 From: hanif salafi Date: Fri, 24 Oct 2025 08:47:07 +0700 Subject: [PATCH] feat: add publish/unpublish article, show by slug article, update response article --- app/module/articles/articles.module.go | 5 + .../controller/articles.controller.go | 115 +++++++++++ app/module/articles/mapper/articles.mapper.go | 21 ++ .../repository/articles.repository.go | 15 +- .../articles/response/articles.response.go | 4 + .../articles/service/articles.service.go | 143 +++++++++++++ docs/swagger/docs.go | 194 ++++++++++++++++++ docs/swagger/swagger.json | 194 ++++++++++++++++++ docs/swagger/swagger.yaml | 126 ++++++++++++ 9 files changed, 816 insertions(+), 1 deletion(-) diff --git a/app/module/articles/articles.module.go b/app/module/articles/articles.module.go index 79e0ae4..7a3f1ed 100644 --- a/app/module/articles/articles.module.go +++ b/app/module/articles/articles.module.go @@ -58,8 +58,13 @@ func (_i *ArticlesRouter) RegisterArticlesRoutes() { router.Get("/pending-approval", articlesController.GetPendingApprovals) router.Get("/waiting-for-approval", articlesController.GetArticlesWaitingForApproval) + // Publish/Unpublish routes + router.Put("/:id/publish", articlesController.Publish) + router.Put("/:id/unpublish", articlesController.Unpublish) + router.Get("/", articlesController.All) router.Get("/old-id/:id", articlesController.ShowByOldId) + router.Get("/slug/:slug", articlesController.ShowBySlug) router.Get("/:id", articlesController.Show) router.Post("/", articlesController.Save) router.Put("/:id", articlesController.Update) diff --git a/app/module/articles/controller/articles.controller.go b/app/module/articles/controller/articles.controller.go index 851744e..04c37cc 100644 --- a/app/module/articles/controller/articles.controller.go +++ b/app/module/articles/controller/articles.controller.go @@ -23,6 +23,7 @@ type ArticlesController interface { All(c *fiber.Ctx) error Show(c *fiber.Ctx) error ShowByOldId(c *fiber.Ctx) error + ShowBySlug(c *fiber.Ctx) error Save(c *fiber.Ctx) error SaveThumbnail(c *fiber.Ctx) error Update(c *fiber.Ctx) error @@ -39,6 +40,10 @@ type ArticlesController interface { GetApprovalStatus(c *fiber.Ctx) error GetPendingApprovals(c *fiber.Ctx) error GetArticlesWaitingForApproval(c *fiber.Ctx) error + + // Publish/Unpublish methods + Publish(c *fiber.Ctx) error + Unpublish(c *fiber.Ctx) error } func NewArticlesController(articlesService service.ArticlesService, log zerolog.Logger) ArticlesController { @@ -174,6 +179,42 @@ func (_i *articlesController) ShowByOldId(c *fiber.Ctx) error { }) } +// ShowBySlug Articles +// @Summary Get one Articles by Slug +// @Description API for getting one Articles by slug +// @Tags Articles +// @Security Bearer +// @Param X-Client-Key header string true "Insert the X-Client-Key" +// @Param slug path string true "Articles Slug" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /articles/slug/{slug} [get] +func (_i *articlesController) ShowBySlug(c *fiber.Ctx) error { + slug := c.Params("slug") + if slug == "" { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": true, + "msg": "Slug parameter is required", + }) + } + + // Get ClientId from context + clientId := middleware.GetClientID(c) + + articlesData, err := _i.articlesService.ShowBySlug(clientId, slug) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Articles successfully retrieved"}, + Data: articlesData, + }) +} + // Save Articles // @Summary Create Articles // @Description API for create Articles @@ -680,3 +721,77 @@ func (_i *articlesController) GetArticlesWaitingForApproval(c *fiber.Ctx) error Meta: paging, }) } + +// Publish Articles +// @Summary Publish Article +// @Description API for publishing an article +// @Tags Articles +// @Security Bearer +// @Param X-Client-Key header string true "Insert the X-Client-Key" +// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token" +// @Param Authorization header string false "Insert your access token" default(Bearer ) +// @Param id path int true "article id" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /articles/{id}/publish [put] +func (_i *articlesController) Publish(c *fiber.Ctx) error { + id, err := strconv.ParseUint(c.Params("id"), 10, 0) + if err != nil { + return err + } + + // Get ClientId from context + clientId := middleware.GetClientID(c) + + // Get Authorization token from header + authToken := c.Get("Authorization") + + err = _i.articlesService.Publish(clientId, uint(id), authToken) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Article successfully published"}, + }) +} + +// Unpublish Articles +// @Summary Unpublish Article +// @Description API for unpublishing an article +// @Tags Articles +// @Security Bearer +// @Param X-Client-Key header string true "Insert the X-Client-Key" +// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token" +// @Param Authorization header string false "Insert your access token" default(Bearer ) +// @Param id path int true "article id" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /articles/{id}/unpublish [put] +func (_i *articlesController) Unpublish(c *fiber.Ctx) error { + id, err := strconv.ParseUint(c.Params("id"), 10, 0) + if err != nil { + return err + } + + // Get ClientId from context + clientId := middleware.GetClientID(c) + + // Get Authorization token from header + authToken := c.Get("Authorization") + + err = _i.articlesService.Unpublish(clientId, uint(id), authToken) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Article successfully unpublished"}, + }) +} diff --git a/app/module/articles/mapper/articles.mapper.go b/app/module/articles/mapper/articles.mapper.go index ca440f4..f5af3f2 100644 --- a/app/module/articles/mapper/articles.mapper.go +++ b/app/module/articles/mapper/articles.mapper.go @@ -53,6 +53,23 @@ func ArticlesResponseMapper( } } + // Calculate PublishStatus based on conditions + publishStatus := "Cancel" // Default status + + if articlesReq.IsPublish != nil && *articlesReq.IsPublish { + // Published: isPublish = true + publishStatus = "Published" + } else if articlesReq.PublishSchedule != nil && *articlesReq.PublishSchedule != "" { + // On Schedule: has publishSchedule and isPublish = false + if articlesReq.IsPublish == nil || !*articlesReq.IsPublish { + publishStatus = "On Schedule" + } + } else if articlesReq.IsPublish != nil && !*articlesReq.IsPublish && + articlesReq.IsDraft != nil && !*articlesReq.IsDraft { + // Cancel: isPublish = false and isDraft = false + publishStatus = "Cancel" + } + if articlesReq != nil { articlesRes = &res.ArticlesResponse{ ID: articlesReq.ID, @@ -73,9 +90,13 @@ func ArticlesResponseMapper( CommentCount: articlesReq.CommentCount, OldId: articlesReq.OldId, StatusId: articlesReq.StatusId, + IsDraft: articlesReq.IsDraft, + DraftedAt: articlesReq.DraftedAt, IsBanner: articlesReq.IsBanner, IsPublish: articlesReq.IsPublish, + PublishSchedule: articlesReq.PublishSchedule, PublishedAt: articlesReq.PublishedAt, + PublishStatus: publishStatus, IsActive: articlesReq.IsActive, Source: articlesReq.Source, CustomCreatorName: articlesReq.CustomCreatorName, diff --git a/app/module/articles/repository/articles.repository.go b/app/module/articles/repository/articles.repository.go index 0c6cfd6..63beaed 100644 --- a/app/module/articles/repository/articles.repository.go +++ b/app/module/articles/repository/articles.repository.go @@ -27,6 +27,7 @@ type ArticlesRepository interface { FindOne(clientId *uuid.UUID, id uint) (articles *entity.Articles, err error) FindByFilename(clientId *uuid.UUID, thumbnailName string) (articleReturn *entity.Articles, err error) FindByOldId(clientId *uuid.UUID, oldId uint) (articles *entity.Articles, err error) + FindBySlug(clientId *uuid.UUID, slug string) (articles *entity.Articles, err error) Create(clientId *uuid.UUID, articles *entity.Articles) (articleReturn *entity.Articles, err error) Update(clientId *uuid.UUID, id uint, articles *entity.Articles) (err error) UpdateSkipNull(clientId *uuid.UUID, id uint, articles *entity.Articles) (err error) @@ -104,7 +105,7 @@ func (_i *articlesRepository) GetAll(clientId *uuid.UUID, userLevelId *uint, req Where("acd.category_id = ?", req.CategoryId) } query = query.Where("articles.is_active = ?", true) - + // Add client filter if clientId != nil { query = query.Where("articles.client_id = ?", clientId) @@ -246,6 +247,18 @@ func (_i *articlesRepository) FindByOldId(clientId *uuid.UUID, oldId uint) (arti return articles, nil } +func (_i *articlesRepository) FindBySlug(clientId *uuid.UUID, slug string) (articles *entity.Articles, err error) { + query := _i.DB.DB.Where("slug = ?", slug) + if clientId != nil { + query = query.Where("client_id = ?", clientId) + } + if err := query.First(&articles).Error; err != nil { + return nil, err + } + + return articles, nil +} + func (_i *articlesRepository) Create(clientId *uuid.UUID, articles *entity.Articles) (articleReturn *entity.Articles, err error) { // Set client ID if clientId != nil { diff --git a/app/module/articles/response/articles.response.go b/app/module/articles/response/articles.response.go index d972d7e..d5a7a5a 100644 --- a/app/module/articles/response/articles.response.go +++ b/app/module/articles/response/articles.response.go @@ -26,9 +26,13 @@ type ArticlesResponse struct { AiArticleId *int `json:"aiArticleId"` OldId *uint `json:"oldId"` StatusId *int `json:"statusId"` + IsDraft *bool `json:"isDraft"` + DraftedAt *time.Time `json:"draftedAt"` IsBanner *bool `json:"isBanner"` IsPublish *bool `json:"isPublish"` PublishedAt *time.Time `json:"publishedAt"` + PublishSchedule *string `json:"publishSchedule"` + PublishStatus string `json:"publishStatus"` // "On Schedule", "Published", "Cancel" IsActive *bool `json:"isActive"` Source *string `json:"source"` CustomCreatorName *string `json:"customCreatorName"` diff --git a/app/module/articles/service/articles.service.go b/app/module/articles/service/articles.service.go index 4c051b0..947d7b9 100644 --- a/app/module/articles/service/articles.service.go +++ b/app/module/articles/service/articles.service.go @@ -58,6 +58,7 @@ type ArticlesService interface { All(clientId *uuid.UUID, authToken string, req request.ArticlesQueryRequest) (articles []*response.ArticlesResponse, paging paginator.Pagination, err error) Show(clientId *uuid.UUID, id uint) (articles *response.ArticlesResponse, err error) ShowByOldId(clientId *uuid.UUID, oldId uint) (articles *response.ArticlesResponse, err error) + ShowBySlug(clientId *uuid.UUID, slug string) (articles *response.ArticlesResponse, err error) Save(clientId *uuid.UUID, req request.ArticlesCreateRequest, authToken string) (articles *entity.Articles, err error) SaveThumbnail(clientId *uuid.UUID, c *fiber.Ctx) (err error) Update(clientId *uuid.UUID, id uint, req request.ArticlesUpdateRequest) (err error) @@ -83,6 +84,10 @@ type ArticlesService interface { AutoApproveArticle(clientId *uuid.UUID, articleId uint, reason string) error GetClientApprovalSettings(clientId *uuid.UUID) (*response.ClientApprovalSettingsResponse, error) SetArticleApprovalExempt(clientId *uuid.UUID, articleId uint, exempt bool, reason string) error + + // Publish/Unpublish methods + Publish(clientId *uuid.UUID, articleId uint, authToken string) error + Unpublish(clientId *uuid.UUID, articleId uint, authToken string) error } // NewArticlesService init ArticlesService @@ -176,6 +181,17 @@ func (_i *articlesService) ShowByOldId(clientId *uuid.UUID, oldId uint) (article return mapper.ArticlesResponseMapper(_i.Log, host, clientId, result, _i.ArticleCategoriesRepo, _i.ArticleCategoryDetailsRepo, _i.ArticleFilesRepo, _i.UsersRepo), nil } +func (_i *articlesService) ShowBySlug(clientId *uuid.UUID, slug string) (articles *response.ArticlesResponse, err error) { + result, err := _i.Repo.FindBySlug(clientId, slug) + if err != nil { + return nil, err + } + + host := _i.Cfg.App.Domain + + return mapper.ArticlesResponseMapper(_i.Log, host, clientId, result, _i.ArticleCategoriesRepo, _i.ArticleCategoryDetailsRepo, _i.ArticleFilesRepo, _i.UsersRepo), nil +} + func (_i *articlesService) Save(clientId *uuid.UUID, req request.ArticlesCreateRequest, authToken string) (articles *entity.Articles, err error) { _i.Log.Info().Interface("data", req).Msg("") newReq := req.ToEntity() @@ -1205,6 +1221,133 @@ func (_i *articlesService) SetArticleApprovalExempt(clientId *uuid.UUID, article return nil } +// Publish publishes an article +func (_i *articlesService) Publish(clientId *uuid.UUID, articleId uint, authToken string) error { + // Extract user info from auth token + user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) + if user == nil { + return errors.New("user not found from auth token") + } + + // Check if article exists + article, err := _i.Repo.FindOne(clientId, articleId) + if err != nil { + return err + } + + // Check if article is already published + if article.IsPublish != nil && *article.IsPublish { + return errors.New("article is already published") + } + + // Check if user has permission to publish + // For now, we'll allow any authenticated user to publish + // You can add more sophisticated permission checks here + + // Update article to published status + isPublish := true + publishedAt := time.Now() + isDraftFalse := false + statusIdTwo := 2 // Published status + + article.IsPublish = &isPublish + article.PublishedAt = &publishedAt + article.IsDraft = &isDraftFalse + article.DraftedAt = nil + article.StatusId = &statusIdTwo + article.PublishSchedule = nil // Clear any scheduled publish time + + err = _i.Repo.Update(clientId, articleId, article) + if err != nil { + return err + } + + // Create approval record for audit trail + articleApproval := &entity.ArticleApprovals{ + ArticleId: articleId, + ApprovalBy: user.ID, + StatusId: statusIdTwo, + Message: "Article published", + ApprovalAtLevel: nil, + } + _, err = _i.ArticleApprovalsRepo.Create(articleApproval) + if err != nil { + _i.Log.Error().Err(err).Msg("Failed to create approval record for published article") + // Don't return error as article was already updated + } + + _i.Log.Info(). + Str("article_id", fmt.Sprintf("%d", articleId)). + Str("client_id", clientId.String()). + Str("user_id", fmt.Sprintf("%d", user.ID)). + Msg("Article published successfully") + + return nil +} + +// Unpublish unpublishes an article +func (_i *articlesService) Unpublish(clientId *uuid.UUID, articleId uint, authToken string) error { + // Extract user info from auth token + user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) + if user == nil { + return errors.New("user not found from auth token") + } + + // Check if article exists + article, err := _i.Repo.FindOne(clientId, articleId) + if err != nil { + return err + } + + // Check if article is already unpublished + if article.IsPublish == nil || !*article.IsPublish { + return errors.New("article is already unpublished") + } + + // Check if user has permission to unpublish + // For now, we'll allow any authenticated user to unpublish + // You can add more sophisticated permission checks here + + // Update article to unpublished status + isPublishFalse := false + isDraftTrue := true + draftedAt := time.Now() + statusIdOne := 1 // Draft status + + article.IsPublish = &isPublishFalse + article.PublishedAt = nil + article.IsDraft = &isDraftTrue + article.DraftedAt = &draftedAt + article.StatusId = &statusIdOne + + err = _i.Repo.Update(clientId, articleId, article) + if err != nil { + return err + } + + // Create approval record for audit trail + articleApproval := &entity.ArticleApprovals{ + ArticleId: articleId, + ApprovalBy: user.ID, + StatusId: statusIdOne, + Message: "Article unpublished", + ApprovalAtLevel: nil, + } + _, err = _i.ArticleApprovalsRepo.Create(articleApproval) + if err != nil { + _i.Log.Error().Err(err).Msg("Failed to create approval record for unpublished article") + // Don't return error as article was already updated + } + + _i.Log.Info(). + Str("article_id", fmt.Sprintf("%d", articleId)). + Str("client_id", clientId.String()). + Str("user_id", fmt.Sprintf("%d", user.ID)). + Msg("Article unpublished successfully") + + return nil +} + // findNextApprovalLevel finds the next higher level for approval func (_i *articlesService) findNextApprovalLevel(clientId *uuid.UUID, currentLevelNumber int) int { // For now, we'll use a simple logic based on level numbers diff --git a/docs/swagger/docs.go b/docs/swagger/docs.go index 102db9d..28a0801 100644 --- a/docs/swagger/docs.go +++ b/docs/swagger/docs.go @@ -7307,6 +7307,62 @@ const docTemplate = `{ } } }, + "/articles/slug/{slug}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one Articles by slug", + "tags": [ + "Articles" + ], + "summary": "Get one Articles by Slug", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Articles Slug", + "name": "slug", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/articles/statistic/monthly": { "get": { "security": [ @@ -7913,6 +7969,75 @@ const docTemplate = `{ } } }, + "/articles/{id}/publish": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for publishing an article", + "tags": [ + "Articles" + ], + "summary": "Publish Article", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header" + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "type": "integer", + "description": "article id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/articles/{id}/submit-approval": { "post": { "security": [ @@ -7990,6 +8115,75 @@ const docTemplate = `{ } } }, + "/articles/{id}/unpublish": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for unpublishing an article", + "tags": [ + "Articles" + ], + "summary": "Unpublish Article", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header" + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "type": "integer", + "description": "article id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/bookmarks": { "get": { "security": [ diff --git a/docs/swagger/swagger.json b/docs/swagger/swagger.json index 81ddcd5..1dd8971 100644 --- a/docs/swagger/swagger.json +++ b/docs/swagger/swagger.json @@ -7296,6 +7296,62 @@ } } }, + "/articles/slug/{slug}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one Articles by slug", + "tags": [ + "Articles" + ], + "summary": "Get one Articles by Slug", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Articles Slug", + "name": "slug", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/articles/statistic/monthly": { "get": { "security": [ @@ -7902,6 +7958,75 @@ } } }, + "/articles/{id}/publish": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for publishing an article", + "tags": [ + "Articles" + ], + "summary": "Publish Article", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header" + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "type": "integer", + "description": "article id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/articles/{id}/submit-approval": { "post": { "security": [ @@ -7979,6 +8104,75 @@ } } }, + "/articles/{id}/unpublish": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for unpublishing an article", + "tags": [ + "Articles" + ], + "summary": "Unpublish Article", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header" + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "type": "integer", + "description": "article id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/bookmarks": { "get": { "security": [ diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 949fcf0..a083b3b 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -6106,6 +6106,51 @@ paths: summary: Get Article Approval Status tags: - Articles + /articles/{id}/publish: + put: + description: API for publishing an article + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + required: true + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + type: string + - default: Bearer + description: Insert your access token + in: header + name: Authorization + type: string + - description: article id + in: path + name: id + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Publish Article + tags: + - Articles /articles/{id}/submit-approval: post: description: API for submitting article for approval workflow @@ -6156,6 +6201,51 @@ paths: summary: Submit Article for Approval tags: - Articles + /articles/{id}/unpublish: + put: + description: API for unpublishing an article + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + required: true + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + type: string + - default: Bearer + description: Insert your access token + in: header + name: Authorization + type: string + - description: article id + in: path + name: id + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Unpublish Article + tags: + - Articles /articles/banner/{id}: put: description: API for Update Banner Articles @@ -6332,6 +6422,42 @@ paths: summary: PublishScheduling Articles tags: - Articles + /articles/slug/{slug}: + get: + description: API for getting one Articles by slug + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + required: true + type: string + - description: Articles Slug + in: path + name: slug + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get one Articles by Slug + tags: + - Articles /articles/statistic/monthly: get: description: API for ArticleMonthlyStats of Article