feat: add publish/unpublish article, show by slug article, update response article
This commit is contained in:
parent
0d7b29dd7c
commit
08820dbee5
|
|
@ -58,8 +58,13 @@ func (_i *ArticlesRouter) RegisterArticlesRoutes() {
|
||||||
router.Get("/pending-approval", articlesController.GetPendingApprovals)
|
router.Get("/pending-approval", articlesController.GetPendingApprovals)
|
||||||
router.Get("/waiting-for-approval", articlesController.GetArticlesWaitingForApproval)
|
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("/", articlesController.All)
|
||||||
router.Get("/old-id/:id", articlesController.ShowByOldId)
|
router.Get("/old-id/:id", articlesController.ShowByOldId)
|
||||||
|
router.Get("/slug/:slug", articlesController.ShowBySlug)
|
||||||
router.Get("/:id", articlesController.Show)
|
router.Get("/:id", articlesController.Show)
|
||||||
router.Post("/", articlesController.Save)
|
router.Post("/", articlesController.Save)
|
||||||
router.Put("/:id", articlesController.Update)
|
router.Put("/:id", articlesController.Update)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ type ArticlesController interface {
|
||||||
All(c *fiber.Ctx) error
|
All(c *fiber.Ctx) error
|
||||||
Show(c *fiber.Ctx) error
|
Show(c *fiber.Ctx) error
|
||||||
ShowByOldId(c *fiber.Ctx) error
|
ShowByOldId(c *fiber.Ctx) error
|
||||||
|
ShowBySlug(c *fiber.Ctx) error
|
||||||
Save(c *fiber.Ctx) error
|
Save(c *fiber.Ctx) error
|
||||||
SaveThumbnail(c *fiber.Ctx) error
|
SaveThumbnail(c *fiber.Ctx) error
|
||||||
Update(c *fiber.Ctx) error
|
Update(c *fiber.Ctx) error
|
||||||
|
|
@ -39,6 +40,10 @@ type ArticlesController interface {
|
||||||
GetApprovalStatus(c *fiber.Ctx) error
|
GetApprovalStatus(c *fiber.Ctx) error
|
||||||
GetPendingApprovals(c *fiber.Ctx) error
|
GetPendingApprovals(c *fiber.Ctx) error
|
||||||
GetArticlesWaitingForApproval(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 {
|
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
|
// Save Articles
|
||||||
// @Summary Create Articles
|
// @Summary Create Articles
|
||||||
// @Description API for create Articles
|
// @Description API for create Articles
|
||||||
|
|
@ -680,3 +721,77 @@ func (_i *articlesController) GetArticlesWaitingForApproval(c *fiber.Ctx) error
|
||||||
Meta: paging,
|
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 <Add access token here>)
|
||||||
|
// @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 <Add access token here>)
|
||||||
|
// @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"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
if articlesReq != nil {
|
||||||
articlesRes = &res.ArticlesResponse{
|
articlesRes = &res.ArticlesResponse{
|
||||||
ID: articlesReq.ID,
|
ID: articlesReq.ID,
|
||||||
|
|
@ -73,9 +90,13 @@ func ArticlesResponseMapper(
|
||||||
CommentCount: articlesReq.CommentCount,
|
CommentCount: articlesReq.CommentCount,
|
||||||
OldId: articlesReq.OldId,
|
OldId: articlesReq.OldId,
|
||||||
StatusId: articlesReq.StatusId,
|
StatusId: articlesReq.StatusId,
|
||||||
|
IsDraft: articlesReq.IsDraft,
|
||||||
|
DraftedAt: articlesReq.DraftedAt,
|
||||||
IsBanner: articlesReq.IsBanner,
|
IsBanner: articlesReq.IsBanner,
|
||||||
IsPublish: articlesReq.IsPublish,
|
IsPublish: articlesReq.IsPublish,
|
||||||
|
PublishSchedule: articlesReq.PublishSchedule,
|
||||||
PublishedAt: articlesReq.PublishedAt,
|
PublishedAt: articlesReq.PublishedAt,
|
||||||
|
PublishStatus: publishStatus,
|
||||||
IsActive: articlesReq.IsActive,
|
IsActive: articlesReq.IsActive,
|
||||||
Source: articlesReq.Source,
|
Source: articlesReq.Source,
|
||||||
CustomCreatorName: articlesReq.CustomCreatorName,
|
CustomCreatorName: articlesReq.CustomCreatorName,
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ type ArticlesRepository interface {
|
||||||
FindOne(clientId *uuid.UUID, id uint) (articles *entity.Articles, err error)
|
FindOne(clientId *uuid.UUID, id uint) (articles *entity.Articles, err error)
|
||||||
FindByFilename(clientId *uuid.UUID, thumbnailName string) (articleReturn *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)
|
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)
|
Create(clientId *uuid.UUID, articles *entity.Articles) (articleReturn *entity.Articles, err error)
|
||||||
Update(clientId *uuid.UUID, id uint, articles *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)
|
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)
|
Where("acd.category_id = ?", req.CategoryId)
|
||||||
}
|
}
|
||||||
query = query.Where("articles.is_active = ?", true)
|
query = query.Where("articles.is_active = ?", true)
|
||||||
|
|
||||||
// Add client filter
|
// Add client filter
|
||||||
if clientId != nil {
|
if clientId != nil {
|
||||||
query = query.Where("articles.client_id = ?", clientId)
|
query = query.Where("articles.client_id = ?", clientId)
|
||||||
|
|
@ -246,6 +247,18 @@ func (_i *articlesRepository) FindByOldId(clientId *uuid.UUID, oldId uint) (arti
|
||||||
return articles, nil
|
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) {
|
func (_i *articlesRepository) Create(clientId *uuid.UUID, articles *entity.Articles) (articleReturn *entity.Articles, err error) {
|
||||||
// Set client ID
|
// Set client ID
|
||||||
if clientId != nil {
|
if clientId != nil {
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,13 @@ type ArticlesResponse struct {
|
||||||
AiArticleId *int `json:"aiArticleId"`
|
AiArticleId *int `json:"aiArticleId"`
|
||||||
OldId *uint `json:"oldId"`
|
OldId *uint `json:"oldId"`
|
||||||
StatusId *int `json:"statusId"`
|
StatusId *int `json:"statusId"`
|
||||||
|
IsDraft *bool `json:"isDraft"`
|
||||||
|
DraftedAt *time.Time `json:"draftedAt"`
|
||||||
IsBanner *bool `json:"isBanner"`
|
IsBanner *bool `json:"isBanner"`
|
||||||
IsPublish *bool `json:"isPublish"`
|
IsPublish *bool `json:"isPublish"`
|
||||||
PublishedAt *time.Time `json:"publishedAt"`
|
PublishedAt *time.Time `json:"publishedAt"`
|
||||||
|
PublishSchedule *string `json:"publishSchedule"`
|
||||||
|
PublishStatus string `json:"publishStatus"` // "On Schedule", "Published", "Cancel"
|
||||||
IsActive *bool `json:"isActive"`
|
IsActive *bool `json:"isActive"`
|
||||||
Source *string `json:"source"`
|
Source *string `json:"source"`
|
||||||
CustomCreatorName *string `json:"customCreatorName"`
|
CustomCreatorName *string `json:"customCreatorName"`
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ type ArticlesService interface {
|
||||||
All(clientId *uuid.UUID, authToken string, req request.ArticlesQueryRequest) (articles []*response.ArticlesResponse, paging paginator.Pagination, err error)
|
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)
|
Show(clientId *uuid.UUID, id uint) (articles *response.ArticlesResponse, err error)
|
||||||
ShowByOldId(clientId *uuid.UUID, oldId 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)
|
Save(clientId *uuid.UUID, req request.ArticlesCreateRequest, authToken string) (articles *entity.Articles, err error)
|
||||||
SaveThumbnail(clientId *uuid.UUID, c *fiber.Ctx) (err error)
|
SaveThumbnail(clientId *uuid.UUID, c *fiber.Ctx) (err error)
|
||||||
Update(clientId *uuid.UUID, id uint, req request.ArticlesUpdateRequest) (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
|
AutoApproveArticle(clientId *uuid.UUID, articleId uint, reason string) error
|
||||||
GetClientApprovalSettings(clientId *uuid.UUID) (*response.ClientApprovalSettingsResponse, error)
|
GetClientApprovalSettings(clientId *uuid.UUID) (*response.ClientApprovalSettingsResponse, error)
|
||||||
SetArticleApprovalExempt(clientId *uuid.UUID, articleId uint, exempt bool, reason string) 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
|
// 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
|
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) {
|
func (_i *articlesService) Save(clientId *uuid.UUID, req request.ArticlesCreateRequest, authToken string) (articles *entity.Articles, err error) {
|
||||||
_i.Log.Info().Interface("data", req).Msg("")
|
_i.Log.Info().Interface("data", req).Msg("")
|
||||||
newReq := req.ToEntity()
|
newReq := req.ToEntity()
|
||||||
|
|
@ -1205,6 +1221,133 @@ func (_i *articlesService) SetArticleApprovalExempt(clientId *uuid.UUID, article
|
||||||
return nil
|
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
|
// findNextApprovalLevel finds the next higher level for approval
|
||||||
func (_i *articlesService) findNextApprovalLevel(clientId *uuid.UUID, currentLevelNumber int) int {
|
func (_i *articlesService) findNextApprovalLevel(clientId *uuid.UUID, currentLevelNumber int) int {
|
||||||
// For now, we'll use a simple logic based on level numbers
|
// For now, we'll use a simple logic based on level numbers
|
||||||
|
|
|
||||||
|
|
@ -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": {
|
"/articles/statistic/monthly": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"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": {
|
"/articles/{id}/submit-approval": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"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": {
|
"/bookmarks": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
|
||||||
|
|
@ -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": {
|
"/articles/statistic/monthly": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"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": {
|
"/articles/{id}/submit-approval": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"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": {
|
"/bookmarks": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
|
||||||
|
|
@ -6106,6 +6106,51 @@ paths:
|
||||||
summary: Get Article Approval Status
|
summary: Get Article Approval Status
|
||||||
tags:
|
tags:
|
||||||
- Articles
|
- 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 <Add access token here>
|
||||||
|
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:
|
/articles/{id}/submit-approval:
|
||||||
post:
|
post:
|
||||||
description: API for submitting article for approval workflow
|
description: API for submitting article for approval workflow
|
||||||
|
|
@ -6156,6 +6201,51 @@ paths:
|
||||||
summary: Submit Article for Approval
|
summary: Submit Article for Approval
|
||||||
tags:
|
tags:
|
||||||
- Articles
|
- 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 <Add access token here>
|
||||||
|
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}:
|
/articles/banner/{id}:
|
||||||
put:
|
put:
|
||||||
description: API for Update Banner Articles
|
description: API for Update Banner Articles
|
||||||
|
|
@ -6332,6 +6422,42 @@ paths:
|
||||||
summary: PublishScheduling Articles
|
summary: PublishScheduling Articles
|
||||||
tags:
|
tags:
|
||||||
- Articles
|
- 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:
|
/articles/statistic/monthly:
|
||||||
get:
|
get:
|
||||||
description: API for ArticleMonthlyStats of Article
|
description: API for ArticleMonthlyStats of Article
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue