feat: add bookmarks
This commit is contained in:
parent
a4c83f8f0c
commit
faecc65a46
|
|
@ -0,0 +1,21 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Bookmarks struct {
|
||||||
|
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||||
|
UserId uint `json:"user_id" gorm:"type:int4;not null"`
|
||||||
|
ArticleId uint `json:"article_id" gorm:"type:int4;not null"`
|
||||||
|
ClientId *uuid.UUID `json:"client_id" gorm:"type:UUID"`
|
||||||
|
IsActive *bool `json:"is_active" gorm:"type:bool;default:true"`
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||||
|
|
||||||
|
// Relations
|
||||||
|
User Users `json:"user" gorm:"foreignKey:UserId;references:ID"`
|
||||||
|
Article Articles `json:"article" gorm:"foreignKey:ArticleId;references:ID"`
|
||||||
|
}
|
||||||
|
|
@ -98,6 +98,7 @@ func Models() []interface{} {
|
||||||
entity.ArticleComments{},
|
entity.ArticleComments{},
|
||||||
entity.ArticleNulisAI{},
|
entity.ArticleNulisAI{},
|
||||||
entity.AuditTrails{},
|
entity.AuditTrails{},
|
||||||
|
entity.Bookmarks{},
|
||||||
entity.Cities{},
|
entity.Cities{},
|
||||||
entity.Clients{},
|
entity.Clients{},
|
||||||
entity.ClientApprovalSettings{},
|
entity.ClientApprovalSettings{},
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
package activity_logs
|
package activity_logs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"go.uber.org/fx"
|
|
||||||
"web-medols-be/app/module/activity_logs/controller"
|
"web-medols-be/app/module/activity_logs/controller"
|
||||||
"web-medols-be/app/module/activity_logs/repository"
|
"web-medols-be/app/module/activity_logs/repository"
|
||||||
"web-medols-be/app/module/activity_logs/service"
|
"web-medols-be/app/module/activity_logs/service"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"go.uber.org/fx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// struct of ActivityLogsRouter
|
// struct of ActivityLogsRouter
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package bookmarks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"web-medols-be/app/middleware"
|
||||||
|
"web-medols-be/app/module/bookmarks/controller"
|
||||||
|
"web-medols-be/app/module/bookmarks/repository"
|
||||||
|
"web-medols-be/app/module/bookmarks/service"
|
||||||
|
usersRepo "web-medols-be/app/module/users/repository"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"go.uber.org/fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BookmarksRouter struct of BookmarksRouter
|
||||||
|
type BookmarksRouter struct {
|
||||||
|
App fiber.Router
|
||||||
|
Controller controller.BookmarksController
|
||||||
|
UsersRepo usersRepo.UsersRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBookmarksModule register bulky of Bookmarks module
|
||||||
|
var NewBookmarksModule = fx.Options(
|
||||||
|
// register repository of Bookmarks module
|
||||||
|
fx.Provide(repository.NewBookmarksRepository),
|
||||||
|
|
||||||
|
// register service of Bookmarks module
|
||||||
|
fx.Provide(service.NewBookmarksService),
|
||||||
|
|
||||||
|
// register controller of Bookmarks module
|
||||||
|
fx.Provide(controller.NewBookmarksController),
|
||||||
|
|
||||||
|
// register router of Bookmarks module
|
||||||
|
fx.Provide(NewBookmarksRouter),
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewBookmarksRouter init BookmarksRouter
|
||||||
|
func NewBookmarksRouter(fiber *fiber.App, controller controller.BookmarksController, usersRepo usersRepo.UsersRepository) *BookmarksRouter {
|
||||||
|
return &BookmarksRouter{
|
||||||
|
App: fiber,
|
||||||
|
Controller: controller,
|
||||||
|
UsersRepo: usersRepo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterBookmarksRoutes register routes of Bookmarks module
|
||||||
|
func (_i *BookmarksRouter) RegisterBookmarksRoutes() {
|
||||||
|
// define controllers
|
||||||
|
bookmarksController := _i.Controller
|
||||||
|
|
||||||
|
// define routes
|
||||||
|
_i.App.Route("/bookmarks", func(router fiber.Router) {
|
||||||
|
// Add user middleware to extract user level from JWT token
|
||||||
|
router.Use(middleware.UserMiddleware(_i.UsersRepo))
|
||||||
|
|
||||||
|
// Public routes (require authentication)
|
||||||
|
router.Get("/", bookmarksController.All)
|
||||||
|
router.Get("/:id", bookmarksController.Show)
|
||||||
|
router.Post("/", bookmarksController.Save)
|
||||||
|
router.Delete("/:id", bookmarksController.Delete)
|
||||||
|
|
||||||
|
// User-specific routes
|
||||||
|
router.Get("/user", bookmarksController.GetByUserId)
|
||||||
|
router.Post("/toggle/:articleId", bookmarksController.ToggleBookmark)
|
||||||
|
router.Get("/summary", bookmarksController.GetBookmarkSummary)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,342 @@
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"web-medols-be/app/middleware"
|
||||||
|
"web-medols-be/app/module/bookmarks/request"
|
||||||
|
"web-medols-be/app/module/bookmarks/service"
|
||||||
|
"web-medols-be/utils/paginator"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
|
||||||
|
utilRes "web-medols-be/utils/response"
|
||||||
|
utilVal "web-medols-be/utils/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bookmarksController struct {
|
||||||
|
bookmarksService service.BookmarksService
|
||||||
|
Log zerolog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type BookmarksController interface {
|
||||||
|
All(c *fiber.Ctx) error
|
||||||
|
Show(c *fiber.Ctx) error
|
||||||
|
Save(c *fiber.Ctx) error
|
||||||
|
Delete(c *fiber.Ctx) error
|
||||||
|
GetByUserId(c *fiber.Ctx) error
|
||||||
|
ToggleBookmark(c *fiber.Ctx) error
|
||||||
|
GetBookmarkSummary(c *fiber.Ctx) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBookmarksController(bookmarksService service.BookmarksService, log zerolog.Logger) BookmarksController {
|
||||||
|
return &bookmarksController{
|
||||||
|
bookmarksService: bookmarksService,
|
||||||
|
Log: log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All Bookmarks
|
||||||
|
// @Summary Get all Bookmarks
|
||||||
|
// @Description API for getting all Bookmarks
|
||||||
|
// @Tags Bookmarks
|
||||||
|
// @Security Bearer
|
||||||
|
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
||||||
|
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||||
|
// @Param req query request.BookmarksQueryRequest false "query parameters"
|
||||||
|
// @Param req query paginator.Pagination false "pagination parameters"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.BadRequestError
|
||||||
|
// @Failure 401 {object} response.UnauthorizedError
|
||||||
|
// @Failure 500 {object} response.InternalServerError
|
||||||
|
// @Router /bookmarks [get]
|
||||||
|
func (_i *bookmarksController) All(c *fiber.Ctx) error {
|
||||||
|
paginate, err := paginator.Paginate(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
reqContext := request.BookmarksQueryRequestContext{
|
||||||
|
ArticleId: c.Query("articleId"),
|
||||||
|
}
|
||||||
|
req := reqContext.ToParamRequest()
|
||||||
|
req.Pagination = paginate
|
||||||
|
|
||||||
|
// Get ClientId from context
|
||||||
|
clientId := middleware.GetClientID(c)
|
||||||
|
|
||||||
|
_i.Log.Info().Interface("clientId", clientId).Msg("")
|
||||||
|
|
||||||
|
// Get Authorization token from header
|
||||||
|
authToken := c.Get("Authorization")
|
||||||
|
|
||||||
|
bookmarksData, paging, err := _i.bookmarksService.All(clientId, authToken, req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: true,
|
||||||
|
Messages: utilRes.Messages{"Successfully retrieved bookmarks"},
|
||||||
|
Data: bookmarksData,
|
||||||
|
Meta: &paging,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show Bookmark
|
||||||
|
// @Summary Get Bookmark by ID
|
||||||
|
// @Description API for getting Bookmark by ID
|
||||||
|
// @Tags Bookmarks
|
||||||
|
// @Security Bearer
|
||||||
|
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
||||||
|
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||||
|
// @Param id path int true "Bookmark ID"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.BadRequestError
|
||||||
|
// @Failure 401 {object} response.UnauthorizedError
|
||||||
|
// @Failure 500 {object} response.InternalServerError
|
||||||
|
// @Router /bookmarks/{id} [get]
|
||||||
|
func (_i *bookmarksController) Show(c *fiber.Ctx) error {
|
||||||
|
id, err := strconv.Atoi(c.Params("id"))
|
||||||
|
if err != nil {
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: false,
|
||||||
|
Messages: utilRes.Messages{"Invalid bookmark ID"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get ClientId from context
|
||||||
|
clientId := middleware.GetClientID(c)
|
||||||
|
|
||||||
|
_i.Log.Info().Interface("clientId", clientId).Msg("")
|
||||||
|
|
||||||
|
bookmarkData, err := _i.bookmarksService.Show(clientId, uint(id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: true,
|
||||||
|
Messages: utilRes.Messages{"Successfully retrieved bookmark"},
|
||||||
|
Data: bookmarkData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save Bookmark
|
||||||
|
// @Summary Create new Bookmark
|
||||||
|
// @Description API for creating new Bookmark
|
||||||
|
// @Tags Bookmarks
|
||||||
|
// @Security Bearer
|
||||||
|
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
||||||
|
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||||
|
// @Param req body request.BookmarksCreateRequest true "Bookmark data"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.BadRequestError
|
||||||
|
// @Failure 401 {object} response.UnauthorizedError
|
||||||
|
// @Failure 500 {object} response.InternalServerError
|
||||||
|
// @Router /bookmarks [post]
|
||||||
|
func (_i *bookmarksController) Save(c *fiber.Ctx) error {
|
||||||
|
var req request.BookmarksCreateRequest
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: false,
|
||||||
|
Messages: utilRes.Messages{"Invalid request body"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate request
|
||||||
|
if err := utilVal.ValidateStruct(req); err != nil {
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: false,
|
||||||
|
Messages: utilRes.Messages{"Validation error"},
|
||||||
|
Data: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get ClientId from context
|
||||||
|
clientId := middleware.GetClientID(c)
|
||||||
|
|
||||||
|
// Get Authorization token from header
|
||||||
|
authToken := c.Get("Authorization")
|
||||||
|
_i.Log.Info().Interface("clientId", clientId).Msg("")
|
||||||
|
_i.Log.Info().Str("authToken", authToken).Msg("")
|
||||||
|
|
||||||
|
bookmarkData, err := _i.bookmarksService.Save(clientId, req, authToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: true,
|
||||||
|
Messages: utilRes.Messages{"Successfully created bookmark"},
|
||||||
|
Data: bookmarkData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete Bookmark
|
||||||
|
// @Summary Delete Bookmark
|
||||||
|
// @Description API for deleting Bookmark
|
||||||
|
// @Tags Bookmarks
|
||||||
|
// @Security Bearer
|
||||||
|
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
||||||
|
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||||
|
// @Param id path int true "Bookmark ID"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.BadRequestError
|
||||||
|
// @Failure 401 {object} response.UnauthorizedError
|
||||||
|
// @Failure 500 {object} response.InternalServerError
|
||||||
|
// @Router /bookmarks/{id} [delete]
|
||||||
|
func (_i *bookmarksController) Delete(c *fiber.Ctx) error {
|
||||||
|
id, err := strconv.Atoi(c.Params("id"))
|
||||||
|
if err != nil {
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: false,
|
||||||
|
Messages: utilRes.Messages{"Invalid bookmark ID"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get ClientId from context
|
||||||
|
clientId := middleware.GetClientID(c)
|
||||||
|
|
||||||
|
_i.Log.Info().Interface("clientId", clientId).Msg("")
|
||||||
|
|
||||||
|
err = _i.bookmarksService.Delete(clientId, uint(id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: true,
|
||||||
|
Messages: utilRes.Messages{"Successfully deleted bookmark"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Bookmarks by User ID
|
||||||
|
// @Summary Get Bookmarks by User ID
|
||||||
|
// @Description API for getting Bookmarks by User ID
|
||||||
|
// @Tags Bookmarks
|
||||||
|
// @Security Bearer
|
||||||
|
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
||||||
|
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||||
|
// @Param req query request.BookmarksQueryRequest false "query parameters"
|
||||||
|
// @Param req query paginator.Pagination false "pagination parameters"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.BadRequestError
|
||||||
|
// @Failure 401 {object} response.UnauthorizedError
|
||||||
|
// @Failure 500 {object} response.InternalServerError
|
||||||
|
// @Router /bookmarks/user [get]
|
||||||
|
func (_i *bookmarksController) GetByUserId(c *fiber.Ctx) error {
|
||||||
|
paginate, err := paginator.Paginate(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
reqContext := request.BookmarksQueryRequestContext{
|
||||||
|
ArticleId: c.Query("articleId"),
|
||||||
|
}
|
||||||
|
req := reqContext.ToParamRequest()
|
||||||
|
req.Pagination = paginate
|
||||||
|
|
||||||
|
// Get ClientId from context
|
||||||
|
clientId := middleware.GetClientID(c)
|
||||||
|
|
||||||
|
// Get Authorization token from header
|
||||||
|
authToken := c.Get("Authorization")
|
||||||
|
_i.Log.Info().Interface("clientId", clientId).Msg("")
|
||||||
|
_i.Log.Info().Str("authToken", authToken).Msg("")
|
||||||
|
|
||||||
|
bookmarksData, paging, err := _i.bookmarksService.GetByUserId(clientId, authToken, req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: true,
|
||||||
|
Messages: utilRes.Messages{"Successfully retrieved user bookmarks"},
|
||||||
|
Data: bookmarksData,
|
||||||
|
Meta: &paging,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle Bookmark
|
||||||
|
// @Summary Toggle Bookmark (Add/Remove)
|
||||||
|
// @Description API for toggling bookmark status for an article
|
||||||
|
// @Tags Bookmarks
|
||||||
|
// @Security Bearer
|
||||||
|
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
||||||
|
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||||
|
// @Param articleId 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 /bookmarks/toggle/{articleId} [post]
|
||||||
|
func (_i *bookmarksController) ToggleBookmark(c *fiber.Ctx) error {
|
||||||
|
articleId, err := strconv.Atoi(c.Params("articleId"))
|
||||||
|
if err != nil {
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: false,
|
||||||
|
Messages: utilRes.Messages{"Invalid article ID"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get ClientId from context
|
||||||
|
clientId := middleware.GetClientID(c)
|
||||||
|
|
||||||
|
// Get Authorization token from header
|
||||||
|
authToken := c.Get("Authorization")
|
||||||
|
_i.Log.Info().Interface("clientId", clientId).Msg("")
|
||||||
|
_i.Log.Info().Str("authToken", authToken).Msg("")
|
||||||
|
|
||||||
|
isBookmarked, err := _i.bookmarksService.ToggleBookmark(clientId, authToken, uint(articleId))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
message := "Bookmark removed"
|
||||||
|
if isBookmarked {
|
||||||
|
message = "Bookmark added"
|
||||||
|
}
|
||||||
|
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: true,
|
||||||
|
Messages: utilRes.Messages{message},
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"isBookmarked": isBookmarked,
|
||||||
|
"articleId": articleId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Bookmark Summary
|
||||||
|
// @Summary Get Bookmark Summary for User
|
||||||
|
// @Description API for getting bookmark summary including total count and recent bookmarks
|
||||||
|
// @Tags Bookmarks
|
||||||
|
// @Security Bearer
|
||||||
|
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
||||||
|
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.BadRequestError
|
||||||
|
// @Failure 401 {object} response.UnauthorizedError
|
||||||
|
// @Failure 500 {object} response.InternalServerError
|
||||||
|
// @Router /bookmarks/summary [get]
|
||||||
|
func (_i *bookmarksController) GetBookmarkSummary(c *fiber.Ctx) error {
|
||||||
|
// Get ClientId from context
|
||||||
|
clientId := middleware.GetClientID(c)
|
||||||
|
|
||||||
|
// Get Authorization token from header
|
||||||
|
authToken := c.Get("Authorization")
|
||||||
|
_i.Log.Info().Interface("clientId", clientId).Msg("")
|
||||||
|
_i.Log.Info().Str("authToken", authToken).Msg("")
|
||||||
|
|
||||||
|
summaryData, err := _i.bookmarksService.GetBookmarkSummary(clientId, authToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return utilRes.Resp(c, utilRes.Response{
|
||||||
|
Success: true,
|
||||||
|
Messages: utilRes.Messages{"Successfully retrieved bookmark summary"},
|
||||||
|
Data: summaryData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package mapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"web-medols-be/app/database/entity"
|
||||||
|
"web-medols-be/app/module/bookmarks/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToBookmarksResponse(bookmark *entity.Bookmarks) *response.BookmarksResponse {
|
||||||
|
return &response.BookmarksResponse{
|
||||||
|
ID: bookmark.ID,
|
||||||
|
UserId: bookmark.UserId,
|
||||||
|
ArticleId: bookmark.ArticleId,
|
||||||
|
IsActive: bookmark.IsActive,
|
||||||
|
CreatedAt: bookmark.CreatedAt,
|
||||||
|
UpdatedAt: bookmark.UpdatedAt,
|
||||||
|
Article: response.ArticleDetails{
|
||||||
|
ID: bookmark.Article.ID,
|
||||||
|
Title: bookmark.Article.Title,
|
||||||
|
Slug: bookmark.Article.Slug,
|
||||||
|
Description: bookmark.Article.Description,
|
||||||
|
HtmlDescription: bookmark.Article.HtmlDescription,
|
||||||
|
CategoryId: bookmark.Article.CategoryId,
|
||||||
|
TypeId: bookmark.Article.TypeId,
|
||||||
|
Tags: bookmark.Article.Tags,
|
||||||
|
ThumbnailUrl: getThumbnailUrl(bookmark.Article.ThumbnailPath),
|
||||||
|
PageUrl: bookmark.Article.PageUrl,
|
||||||
|
CreatedById: bookmark.Article.CreatedById,
|
||||||
|
ShareCount: bookmark.Article.ShareCount,
|
||||||
|
ViewCount: bookmark.Article.ViewCount,
|
||||||
|
CommentCount: bookmark.Article.CommentCount,
|
||||||
|
StatusId: bookmark.Article.StatusId,
|
||||||
|
IsBanner: bookmark.Article.IsBanner,
|
||||||
|
IsPublish: bookmark.Article.IsPublish,
|
||||||
|
PublishedAt: bookmark.Article.PublishedAt,
|
||||||
|
IsActive: bookmark.Article.IsActive,
|
||||||
|
CreatedAt: bookmark.Article.CreatedAt,
|
||||||
|
UpdatedAt: bookmark.Article.UpdatedAt,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToBookmarksResponseList(bookmarks []entity.Bookmarks) []*response.BookmarksResponse {
|
||||||
|
var responses []*response.BookmarksResponse
|
||||||
|
for _, bookmark := range bookmarks {
|
||||||
|
responses = append(responses, ToBookmarksResponse(&bookmark))
|
||||||
|
}
|
||||||
|
return responses
|
||||||
|
}
|
||||||
|
|
||||||
|
func getThumbnailUrl(thumbnailPath *string) string {
|
||||||
|
if thumbnailPath != nil && *thumbnailPath != "" {
|
||||||
|
return *thumbnailPath
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,217 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"web-medols-be/app/database"
|
||||||
|
"web-medols-be/app/database/entity"
|
||||||
|
"web-medols-be/app/module/bookmarks/request"
|
||||||
|
"web-medols-be/utils/paginator"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bookmarksRepository struct {
|
||||||
|
DB *database.Database
|
||||||
|
Log zerolog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// BookmarksRepository define interface of IBookmarksRepository
|
||||||
|
type BookmarksRepository interface {
|
||||||
|
GetAll(clientId *uuid.UUID, req request.BookmarksQueryRequest) (bookmarks []*entity.Bookmarks, paging paginator.Pagination, err error)
|
||||||
|
FindOne(clientId *uuid.UUID, id uint) (bookmark *entity.Bookmarks, err error)
|
||||||
|
FindByUserAndArticle(clientId *uuid.UUID, userId uint, articleId uint) (bookmark *entity.Bookmarks, err error)
|
||||||
|
Create(clientId *uuid.UUID, bookmark *entity.Bookmarks) (bookmarkReturn *entity.Bookmarks, err error)
|
||||||
|
Update(clientId *uuid.UUID, id uint, bookmark *entity.Bookmarks) (err error)
|
||||||
|
Delete(clientId *uuid.UUID, id uint) (err error)
|
||||||
|
GetByUserId(clientId *uuid.UUID, userId uint, req request.BookmarksQueryRequest) (bookmarks []*entity.Bookmarks, paging paginator.Pagination, err error)
|
||||||
|
CountByUserId(clientId *uuid.UUID, userId uint) (count int64, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBookmarksRepository(db *database.Database, log zerolog.Logger) BookmarksRepository {
|
||||||
|
return &bookmarksRepository{
|
||||||
|
DB: db,
|
||||||
|
Log: log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// implement interface of IBookmarksRepository
|
||||||
|
func (_i *bookmarksRepository) GetAll(clientId *uuid.UUID, req request.BookmarksQueryRequest) (bookmarks []*entity.Bookmarks, paging paginator.Pagination, err error) {
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
query := _i.DB.DB.Model(&entity.Bookmarks{}).Preload("User").Preload("Article")
|
||||||
|
|
||||||
|
// Apply client filter
|
||||||
|
if clientId != nil {
|
||||||
|
query = query.Where("client_id = ?", clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply filters
|
||||||
|
if req.UserId != nil {
|
||||||
|
query = query.Where("user_id = ?", *req.UserId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.ArticleId != nil {
|
||||||
|
query = query.Where("article_id = ?", *req.ArticleId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count total records
|
||||||
|
if err = query.Count(&count).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to count bookmarks")
|
||||||
|
return nil, paging, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply pagination
|
||||||
|
if req.Pagination != nil {
|
||||||
|
offset := (req.Pagination.Page - 1) * req.Pagination.Limit
|
||||||
|
query = query.Offset(offset).Limit(req.Pagination.Limit)
|
||||||
|
paging = *req.Pagination
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute query
|
||||||
|
if err = query.Find(&bookmarks).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to get bookmarks")
|
||||||
|
return nil, paging, err
|
||||||
|
}
|
||||||
|
|
||||||
|
paging.Count = count
|
||||||
|
paging = *paginator.Paging(&paging)
|
||||||
|
|
||||||
|
return bookmarks, paging, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksRepository) FindOne(clientId *uuid.UUID, id uint) (bookmark *entity.Bookmarks, err error) {
|
||||||
|
query := _i.DB.DB.Model(&entity.Bookmarks{}).Preload("User").Preload("Article")
|
||||||
|
|
||||||
|
// Apply client filter
|
||||||
|
if clientId != nil {
|
||||||
|
query = query.Where("client_id = ?", clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = query.Where("id = ?", id).First(&bookmark).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to find bookmark")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bookmark, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksRepository) FindByUserAndArticle(clientId *uuid.UUID, userId uint, articleId uint) (bookmark *entity.Bookmarks, err error) {
|
||||||
|
query := _i.DB.DB.Model(&entity.Bookmarks{})
|
||||||
|
|
||||||
|
// Apply client filter
|
||||||
|
if clientId != nil {
|
||||||
|
query = query.Where("client_id = ?", clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = query.Where("user_id = ? AND article_id = ?", userId, articleId).First(&bookmark).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to find bookmark by user and article")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bookmark, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksRepository) Create(clientId *uuid.UUID, bookmark *entity.Bookmarks) (bookmarkReturn *entity.Bookmarks, err error) {
|
||||||
|
bookmark.ClientId = clientId
|
||||||
|
|
||||||
|
if err = _i.DB.DB.Create(bookmark).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to create bookmark")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bookmark, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksRepository) Update(clientId *uuid.UUID, id uint, bookmark *entity.Bookmarks) (err error) {
|
||||||
|
query := _i.DB.DB.Model(&entity.Bookmarks{})
|
||||||
|
|
||||||
|
// Apply client filter
|
||||||
|
if clientId != nil {
|
||||||
|
query = query.Where("client_id = ?", clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = query.Where("id = ?", id).Updates(bookmark).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to update bookmark")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksRepository) Delete(clientId *uuid.UUID, id uint) (err error) {
|
||||||
|
query := _i.DB.DB.Model(&entity.Bookmarks{})
|
||||||
|
|
||||||
|
// Apply client filter
|
||||||
|
if clientId != nil {
|
||||||
|
query = query.Where("client_id = ?", clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = query.Where("id = ?", id).Delete(&entity.Bookmarks{}).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to delete bookmark")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksRepository) GetByUserId(clientId *uuid.UUID, userId uint, req request.BookmarksQueryRequest) (bookmarks []*entity.Bookmarks, paging paginator.Pagination, err error) {
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
query := _i.DB.DB.Model(&entity.Bookmarks{}).Preload("User").Preload("Article")
|
||||||
|
|
||||||
|
// Apply client filter
|
||||||
|
if clientId != nil {
|
||||||
|
query = query.Where("client_id = ?", clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply user filter
|
||||||
|
query = query.Where("user_id = ?", userId)
|
||||||
|
|
||||||
|
// Apply additional filters
|
||||||
|
if req.ArticleId != nil {
|
||||||
|
query = query.Where("article_id = ?", *req.ArticleId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count total records
|
||||||
|
if err = query.Count(&count).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to count user bookmarks")
|
||||||
|
return nil, paging, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply pagination
|
||||||
|
if req.Pagination != nil {
|
||||||
|
offset := (req.Pagination.Page - 1) * req.Pagination.Limit
|
||||||
|
query = query.Offset(offset).Limit(req.Pagination.Limit)
|
||||||
|
paging = *req.Pagination
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute query
|
||||||
|
if err = query.Find(&bookmarks).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to get user bookmarks")
|
||||||
|
return nil, paging, err
|
||||||
|
}
|
||||||
|
|
||||||
|
paging.Count = count
|
||||||
|
paging = *paginator.Paging(&paging)
|
||||||
|
|
||||||
|
return bookmarks, paging, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksRepository) CountByUserId(clientId *uuid.UUID, userId uint) (count int64, err error) {
|
||||||
|
query := _i.DB.DB.Model(&entity.Bookmarks{})
|
||||||
|
|
||||||
|
// Apply client filter
|
||||||
|
if clientId != nil {
|
||||||
|
query = query.Where("client_id = ?", clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply user filter
|
||||||
|
query = query.Where("user_id = ?", userId)
|
||||||
|
|
||||||
|
if err = query.Count(&count).Error; err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to count user bookmarks")
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
"web-medols-be/app/database/entity"
|
||||||
|
"web-medols-be/utils/paginator"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BookmarksGeneric interface {
|
||||||
|
ToEntity()
|
||||||
|
}
|
||||||
|
|
||||||
|
type BookmarksQueryRequest struct {
|
||||||
|
UserId *uint `json:"userId"`
|
||||||
|
ArticleId *uint `json:"articleId"`
|
||||||
|
Pagination *paginator.Pagination `json:"pagination"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BookmarksCreateRequest struct {
|
||||||
|
ArticleId uint `json:"articleId" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req BookmarksCreateRequest) ToEntity(userId uint) *entity.Bookmarks {
|
||||||
|
return &entity.Bookmarks{
|
||||||
|
UserId: userId,
|
||||||
|
ArticleId: req.ArticleId,
|
||||||
|
IsActive: boolPtr(true),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
UpdatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type BookmarksQueryRequestContext struct {
|
||||||
|
UserId string `json:"userId"`
|
||||||
|
ArticleId string `json:"articleId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req BookmarksQueryRequestContext) ToParamRequest() BookmarksQueryRequest {
|
||||||
|
var request BookmarksQueryRequest
|
||||||
|
|
||||||
|
if userIdStr := req.UserId; userIdStr != "" {
|
||||||
|
userId, err := strconv.Atoi(userIdStr)
|
||||||
|
if err == nil {
|
||||||
|
userIdUint := uint(userId)
|
||||||
|
request.UserId = &userIdUint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if articleIdStr := req.ArticleId; articleIdStr != "" {
|
||||||
|
articleId, err := strconv.Atoi(articleIdStr)
|
||||||
|
if err == nil {
|
||||||
|
articleIdUint := uint(articleId)
|
||||||
|
request.ArticleId = &articleIdUint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to create bool pointer
|
||||||
|
func boolPtr(b bool) *bool {
|
||||||
|
return &b
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BookmarksResponse struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
UserId uint `json:"userId"`
|
||||||
|
ArticleId uint `json:"articleId"`
|
||||||
|
IsActive *bool `json:"isActive"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
|
|
||||||
|
// Article details
|
||||||
|
Article ArticleDetails `json:"article"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArticleDetails struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
HtmlDescription string `json:"htmlDescription"`
|
||||||
|
CategoryId int `json:"categoryId"`
|
||||||
|
TypeId int `json:"typeId"`
|
||||||
|
Tags string `json:"tags"`
|
||||||
|
ThumbnailUrl string `json:"thumbnailUrl"`
|
||||||
|
PageUrl *string `json:"pageUrl"`
|
||||||
|
CreatedById *uint `json:"createdById"`
|
||||||
|
ShareCount *int `json:"shareCount"`
|
||||||
|
ViewCount *int `json:"viewCount"`
|
||||||
|
CommentCount *int `json:"commentCount"`
|
||||||
|
StatusId *int `json:"statusId"`
|
||||||
|
IsBanner *bool `json:"isBanner"`
|
||||||
|
IsPublish *bool `json:"isPublish"`
|
||||||
|
PublishedAt *time.Time `json:"publishedAt"`
|
||||||
|
IsActive *bool `json:"isActive"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BookmarksSummaryResponse struct {
|
||||||
|
TotalBookmarks int `json:"totalBookmarks"`
|
||||||
|
RecentBookmarks []*BookmarksResponse `json:"recentBookmarks"`
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,244 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"web-medols-be/app/database/entity"
|
||||||
|
articlesRepository "web-medols-be/app/module/articles/repository"
|
||||||
|
"web-medols-be/app/module/bookmarks/mapper"
|
||||||
|
"web-medols-be/app/module/bookmarks/repository"
|
||||||
|
"web-medols-be/app/module/bookmarks/request"
|
||||||
|
"web-medols-be/app/module/bookmarks/response"
|
||||||
|
usersRepository "web-medols-be/app/module/users/repository"
|
||||||
|
"web-medols-be/utils/paginator"
|
||||||
|
utilSvc "web-medols-be/utils/service"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BookmarksService
|
||||||
|
type bookmarksService struct {
|
||||||
|
Repo repository.BookmarksRepository
|
||||||
|
ArticlesRepo articlesRepository.ArticlesRepository
|
||||||
|
UsersRepo usersRepository.UsersRepository
|
||||||
|
Log zerolog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// BookmarksService define interface of IBookmarksService
|
||||||
|
type BookmarksService interface {
|
||||||
|
All(clientId *uuid.UUID, authToken string, req request.BookmarksQueryRequest) (bookmarks []*response.BookmarksResponse, paging paginator.Pagination, err error)
|
||||||
|
Show(clientId *uuid.UUID, id uint) (bookmark *response.BookmarksResponse, err error)
|
||||||
|
Save(clientId *uuid.UUID, req request.BookmarksCreateRequest, authToken string) (bookmark *entity.Bookmarks, err error)
|
||||||
|
Delete(clientId *uuid.UUID, id uint) error
|
||||||
|
GetByUserId(clientId *uuid.UUID, authToken string, req request.BookmarksQueryRequest) (bookmarks []*response.BookmarksResponse, paging paginator.Pagination, err error)
|
||||||
|
ToggleBookmark(clientId *uuid.UUID, authToken string, articleId uint) (isBookmarked bool, err error)
|
||||||
|
GetBookmarkSummary(clientId *uuid.UUID, authToken string) (summary *response.BookmarksSummaryResponse, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBookmarksService init BookmarksService
|
||||||
|
func NewBookmarksService(
|
||||||
|
repo repository.BookmarksRepository,
|
||||||
|
articlesRepo articlesRepository.ArticlesRepository,
|
||||||
|
usersRepo usersRepository.UsersRepository,
|
||||||
|
log zerolog.Logger,
|
||||||
|
) BookmarksService {
|
||||||
|
return &bookmarksService{
|
||||||
|
Repo: repo,
|
||||||
|
ArticlesRepo: articlesRepo,
|
||||||
|
UsersRepo: usersRepo,
|
||||||
|
Log: log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// implement interface of IBookmarksService
|
||||||
|
func (_i *bookmarksService) All(clientId *uuid.UUID, authToken string, req request.BookmarksQueryRequest) (bookmarks []*response.BookmarksResponse, paging paginator.Pagination, err error) {
|
||||||
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||||
|
if user == nil {
|
||||||
|
_i.Log.Error().Msg("User not found from auth token")
|
||||||
|
return nil, paging, errors.New("user not found")
|
||||||
|
}
|
||||||
|
req.UserId = &user.ID
|
||||||
|
|
||||||
|
bookmarksEntity, paging, err := _i.Repo.GetAll(clientId, req)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to get all bookmarks")
|
||||||
|
return nil, paging, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert []*entity.Bookmarks to []entity.Bookmarks
|
||||||
|
var bookmarksSlice []entity.Bookmarks
|
||||||
|
for _, b := range bookmarksEntity {
|
||||||
|
bookmarksSlice = append(bookmarksSlice, *b)
|
||||||
|
}
|
||||||
|
bookmarks = mapper.ToBookmarksResponseList(bookmarksSlice)
|
||||||
|
return bookmarks, paging, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksService) Show(clientId *uuid.UUID, id uint) (bookmark *response.BookmarksResponse, err error) {
|
||||||
|
bookmarkEntity, err := _i.Repo.FindOne(clientId, id)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to show bookmark")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmark = mapper.ToBookmarksResponse(bookmarkEntity)
|
||||||
|
return bookmark, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksService) Save(clientId *uuid.UUID, req request.BookmarksCreateRequest, authToken string) (bookmark *entity.Bookmarks, err error) {
|
||||||
|
// Extract user info from auth token
|
||||||
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||||
|
if user == nil {
|
||||||
|
_i.Log.Error().Msg("User not found from auth token")
|
||||||
|
return nil, errors.New("user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if article exists
|
||||||
|
_, err = _i.ArticlesRepo.FindOne(clientId, req.ArticleId)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Article not found")
|
||||||
|
return nil, errors.New("article not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if bookmark already exists
|
||||||
|
existingBookmark, err := _i.Repo.FindByUserAndArticle(clientId, user.ID, req.ArticleId)
|
||||||
|
if err == nil && existingBookmark != nil {
|
||||||
|
_i.Log.Error().Msg("Bookmark already exists")
|
||||||
|
return nil, errors.New("article already bookmarked")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new bookmark
|
||||||
|
bookmarkEntity := req.ToEntity(user.ID)
|
||||||
|
bookmark, err = _i.Repo.Create(clientId, bookmarkEntity)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to create bookmark")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bookmark, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksService) Delete(clientId *uuid.UUID, id uint) error {
|
||||||
|
err := _i.Repo.Delete(clientId, id)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to delete bookmark")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksService) GetByUserId(clientId *uuid.UUID, authToken string, req request.BookmarksQueryRequest) (bookmarks []*response.BookmarksResponse, paging paginator.Pagination, err error) {
|
||||||
|
// Extract user info from auth token
|
||||||
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||||
|
if user == nil {
|
||||||
|
_i.Log.Error().Msg("User not found from auth token")
|
||||||
|
return nil, paging, errors.New("user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmarksEntity, paging, err := _i.Repo.GetByUserId(clientId, user.ID, req)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to get bookmarks by user ID")
|
||||||
|
return nil, paging, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert []*entity.Bookmarks to []entity.Bookmarks
|
||||||
|
var bookmarksSlice []entity.Bookmarks
|
||||||
|
for _, b := range bookmarksEntity {
|
||||||
|
bookmarksSlice = append(bookmarksSlice, *b)
|
||||||
|
}
|
||||||
|
bookmarks = mapper.ToBookmarksResponseList(bookmarksSlice)
|
||||||
|
return bookmarks, paging, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksService) ToggleBookmark(clientId *uuid.UUID, authToken string, articleId uint) (isBookmarked bool, err error) {
|
||||||
|
// Extract user info from auth token
|
||||||
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||||
|
if user == nil {
|
||||||
|
_i.Log.Error().Msg("User not found from auth token")
|
||||||
|
return false, errors.New("user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if article exists
|
||||||
|
_, err = _i.ArticlesRepo.FindOne(clientId, articleId)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Article not found")
|
||||||
|
return false, errors.New("article not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if bookmark already exists
|
||||||
|
existingBookmark, err := _i.Repo.FindByUserAndArticle(clientId, user.ID, articleId)
|
||||||
|
if err == nil && existingBookmark != nil {
|
||||||
|
// Bookmark exists, delete it
|
||||||
|
err = _i.Repo.Delete(clientId, existingBookmark.ID)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to delete existing bookmark")
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil // Bookmark removed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bookmark doesn't exist, create it
|
||||||
|
bookmarkEntity := &entity.Bookmarks{
|
||||||
|
UserId: user.ID,
|
||||||
|
ArticleId: articleId,
|
||||||
|
IsActive: boolPtr(true),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = _i.Repo.Create(clientId, bookmarkEntity)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to create bookmark")
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil // Bookmark added
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_i *bookmarksService) GetBookmarkSummary(clientId *uuid.UUID, authToken string) (summary *response.BookmarksSummaryResponse, err error) {
|
||||||
|
// Extract user info from auth token
|
||||||
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||||
|
if user == nil {
|
||||||
|
_i.Log.Error().Msg("User not found from auth token")
|
||||||
|
return nil, errors.New("user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get total count
|
||||||
|
totalCount, err := _i.Repo.CountByUserId(clientId, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to count user bookmarks")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get recent bookmarks (last 5)
|
||||||
|
req := request.BookmarksQueryRequest{
|
||||||
|
Pagination: &paginator.Pagination{
|
||||||
|
Page: 1,
|
||||||
|
Limit: 5,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
recentBookmarksEntity, _, err := _i.Repo.GetByUserId(clientId, user.ID, req)
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Err(err).Msg("Failed to get recent bookmarks")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert []*entity.Bookmarks to []entity.Bookmarks
|
||||||
|
var bookmarksSlice []entity.Bookmarks
|
||||||
|
for _, b := range recentBookmarksEntity {
|
||||||
|
bookmarksSlice = append(bookmarksSlice, *b)
|
||||||
|
}
|
||||||
|
recentBookmarks := mapper.ToBookmarksResponseList(bookmarksSlice)
|
||||||
|
|
||||||
|
summary = &response.BookmarksSummaryResponse{
|
||||||
|
TotalBookmarks: int(totalCount),
|
||||||
|
RecentBookmarks: recentBookmarks,
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to create bool pointer
|
||||||
|
func boolPtr(b bool) *bool {
|
||||||
|
return &b
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"web-medols-be/app/module/article_files"
|
"web-medols-be/app/module/article_files"
|
||||||
"web-medols-be/app/module/article_nulis_ai"
|
"web-medols-be/app/module/article_nulis_ai"
|
||||||
"web-medols-be/app/module/articles"
|
"web-medols-be/app/module/articles"
|
||||||
|
"web-medols-be/app/module/bookmarks"
|
||||||
"web-medols-be/app/module/cities"
|
"web-medols-be/app/module/cities"
|
||||||
"web-medols-be/app/module/client_approval_settings"
|
"web-medols-be/app/module/client_approval_settings"
|
||||||
"web-medols-be/app/module/clients"
|
"web-medols-be/app/module/clients"
|
||||||
|
|
@ -54,6 +55,7 @@ type Router struct {
|
||||||
ArticleApprovalsRouter *article_approvals.ArticleApprovalsRouter
|
ArticleApprovalsRouter *article_approvals.ArticleApprovalsRouter
|
||||||
ArticlesRouter *articles.ArticlesRouter
|
ArticlesRouter *articles.ArticlesRouter
|
||||||
ArticleNulisAIRouter *article_nulis_ai.ArticleNulisAIRouter
|
ArticleNulisAIRouter *article_nulis_ai.ArticleNulisAIRouter
|
||||||
|
BookmarksRouter *bookmarks.BookmarksRouter
|
||||||
CitiesRouter *cities.CitiesRouter
|
CitiesRouter *cities.CitiesRouter
|
||||||
ClientApprovalSettingsRouter *client_approval_settings.ClientApprovalSettingsRouter
|
ClientApprovalSettingsRouter *client_approval_settings.ClientApprovalSettingsRouter
|
||||||
ClientsRouter *clients.ClientsRouter
|
ClientsRouter *clients.ClientsRouter
|
||||||
|
|
@ -89,6 +91,7 @@ func NewRouter(
|
||||||
articleApprovalsRouter *article_approvals.ArticleApprovalsRouter,
|
articleApprovalsRouter *article_approvals.ArticleApprovalsRouter,
|
||||||
articlesRouter *articles.ArticlesRouter,
|
articlesRouter *articles.ArticlesRouter,
|
||||||
articleNulisRouter *article_nulis_ai.ArticleNulisAIRouter,
|
articleNulisRouter *article_nulis_ai.ArticleNulisAIRouter,
|
||||||
|
bookmarksRouter *bookmarks.BookmarksRouter,
|
||||||
citiesRouter *cities.CitiesRouter,
|
citiesRouter *cities.CitiesRouter,
|
||||||
clientApprovalSettingsRouter *client_approval_settings.ClientApprovalSettingsRouter,
|
clientApprovalSettingsRouter *client_approval_settings.ClientApprovalSettingsRouter,
|
||||||
clientsRouter *clients.ClientsRouter,
|
clientsRouter *clients.ClientsRouter,
|
||||||
|
|
@ -122,6 +125,7 @@ func NewRouter(
|
||||||
ArticleApprovalsRouter: articleApprovalsRouter,
|
ArticleApprovalsRouter: articleApprovalsRouter,
|
||||||
ArticlesRouter: articlesRouter,
|
ArticlesRouter: articlesRouter,
|
||||||
ArticleNulisAIRouter: articleNulisRouter,
|
ArticleNulisAIRouter: articleNulisRouter,
|
||||||
|
BookmarksRouter: bookmarksRouter,
|
||||||
CitiesRouter: citiesRouter,
|
CitiesRouter: citiesRouter,
|
||||||
ClientApprovalSettingsRouter: clientApprovalSettingsRouter,
|
ClientApprovalSettingsRouter: clientApprovalSettingsRouter,
|
||||||
ClientsRouter: clientsRouter,
|
ClientsRouter: clientsRouter,
|
||||||
|
|
@ -165,6 +169,7 @@ func (r *Router) Register() {
|
||||||
r.ArticlesRouter.RegisterArticlesRoutes()
|
r.ArticlesRouter.RegisterArticlesRoutes()
|
||||||
r.ArticleCommentsRouter.RegisterArticleCommentsRoutes()
|
r.ArticleCommentsRouter.RegisterArticleCommentsRoutes()
|
||||||
r.ArticleNulisAIRouter.RegisterArticleNulisAIRoutes()
|
r.ArticleNulisAIRouter.RegisterArticleNulisAIRoutes()
|
||||||
|
r.BookmarksRouter.RegisterBookmarksRoutes()
|
||||||
r.CitiesRouter.RegisterCitiesRoutes()
|
r.CitiesRouter.RegisterCitiesRoutes()
|
||||||
r.ClientApprovalSettingsRouter.RegisterClientApprovalSettingsRoutes()
|
r.ClientApprovalSettingsRouter.RegisterClientApprovalSettingsRoutes()
|
||||||
r.ClientsRouter.RegisterClientsRoutes()
|
r.ClientsRouter.RegisterClientsRoutes()
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ body-limit = 1048576000 # "100 * 1024 * 1024"
|
||||||
[db.postgres]
|
[db.postgres]
|
||||||
dsn = "postgresql://medols_user:MedolsDB@2025@38.47.180.165:5432/medols_db" # <driver>://<username>:<password>@<host>:<port>/<database>
|
dsn = "postgresql://medols_user:MedolsDB@2025@38.47.180.165:5432/medols_db" # <driver>://<username>:<password>@<host>:<port>/<database>
|
||||||
log-mode = "ERROR"
|
log-mode = "ERROR"
|
||||||
migrate = false
|
migrate = true
|
||||||
seed = false
|
seed = false
|
||||||
|
|
||||||
[logger]
|
[logger]
|
||||||
|
|
|
||||||
|
|
@ -7943,6 +7943,524 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/bookmarks": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for getting all Bookmarks",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Get all Bookmarks",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "articleId",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "userId",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "nextPage",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "previousPage",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "sort",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "sortBy",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "totalPage",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for creating new Bookmark",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Create new Bookmark",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Bookmark data",
|
||||||
|
"name": "req",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.BookmarksCreateRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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/summary": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for getting bookmark summary including total count and recent bookmarks",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Get Bookmark Summary for User",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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/toggle/{articleId}": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for toggling bookmark status for an article",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Toggle Bookmark (Add/Remove)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Article ID",
|
||||||
|
"name": "articleId",
|
||||||
|
"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/user": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for getting Bookmarks by User ID",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Get Bookmarks by User ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "articleId",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "userId",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "nextPage",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "previousPage",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "sort",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "sortBy",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "totalPage",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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/{id}": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for getting Bookmark by ID",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Get Bookmark by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Bookmark 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for deleting Bookmark",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Delete Bookmark",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Bookmark 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/cities": {
|
"/cities": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -15738,6 +16256,17 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"request.BookmarksCreateRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"articleId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"articleId": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"request.BulkCreateApprovalWorkflowStepsRequest": {
|
"request.BulkCreateApprovalWorkflowStepsRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -7932,6 +7932,524 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/bookmarks": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for getting all Bookmarks",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Get all Bookmarks",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "articleId",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "userId",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "nextPage",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "previousPage",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "sort",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "sortBy",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "totalPage",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for creating new Bookmark",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Create new Bookmark",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Bookmark data",
|
||||||
|
"name": "req",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.BookmarksCreateRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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/summary": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for getting bookmark summary including total count and recent bookmarks",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Get Bookmark Summary for User",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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/toggle/{articleId}": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for toggling bookmark status for an article",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Toggle Bookmark (Add/Remove)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Article ID",
|
||||||
|
"name": "articleId",
|
||||||
|
"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/user": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for getting Bookmarks by User ID",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Get Bookmarks by User ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "articleId",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "userId",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "nextPage",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "previousPage",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "sort",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "sortBy",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "totalPage",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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/{id}": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for getting Bookmark by ID",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Get Bookmark by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Bookmark 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for deleting Bookmark",
|
||||||
|
"tags": [
|
||||||
|
"Bookmarks"
|
||||||
|
],
|
||||||
|
"summary": "Delete Bookmark",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer \u003cAdd access token here\u003e",
|
||||||
|
"description": "Insert your access token",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Bookmark 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/cities": {
|
"/cities": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -15727,6 +16245,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"request.BookmarksCreateRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"articleId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"articleId": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"request.BulkCreateApprovalWorkflowStepsRequest": {
|
"request.BulkCreateApprovalWorkflowStepsRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -529,6 +529,13 @@ definitions:
|
||||||
- title
|
- title
|
||||||
- typeId
|
- typeId
|
||||||
type: object
|
type: object
|
||||||
|
request.BookmarksCreateRequest:
|
||||||
|
properties:
|
||||||
|
articleId:
|
||||||
|
type: integer
|
||||||
|
required:
|
||||||
|
- articleId
|
||||||
|
type: object
|
||||||
request.BulkCreateApprovalWorkflowStepsRequest:
|
request.BulkCreateApprovalWorkflowStepsRequest:
|
||||||
properties:
|
properties:
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -6452,6 +6459,338 @@ paths:
|
||||||
summary: Get articles waiting for approval by current user level
|
summary: Get articles waiting for approval by current user level
|
||||||
tags:
|
tags:
|
||||||
- Articles
|
- Articles
|
||||||
|
/bookmarks:
|
||||||
|
get:
|
||||||
|
description: API for getting all Bookmarks
|
||||||
|
parameters:
|
||||||
|
- description: Insert the X-Client-Key
|
||||||
|
in: header
|
||||||
|
name: X-Client-Key
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- default: Bearer <Add access token here>
|
||||||
|
description: Insert your access token
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: articleId
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: userId
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: count
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: limit
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: nextPage
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: page
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: previousPage
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: sort
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: sortBy
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: totalPage
|
||||||
|
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: Get all Bookmarks
|
||||||
|
tags:
|
||||||
|
- Bookmarks
|
||||||
|
post:
|
||||||
|
description: API for creating new Bookmark
|
||||||
|
parameters:
|
||||||
|
- description: Insert the X-Client-Key
|
||||||
|
in: header
|
||||||
|
name: X-Client-Key
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- default: Bearer <Add access token here>
|
||||||
|
description: Insert your access token
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
type: string
|
||||||
|
- description: Bookmark data
|
||||||
|
in: body
|
||||||
|
name: req
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/request.BookmarksCreateRequest'
|
||||||
|
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: Create new Bookmark
|
||||||
|
tags:
|
||||||
|
- Bookmarks
|
||||||
|
/bookmarks/{id}:
|
||||||
|
delete:
|
||||||
|
description: API for deleting Bookmark
|
||||||
|
parameters:
|
||||||
|
- description: Insert the X-Client-Key
|
||||||
|
in: header
|
||||||
|
name: X-Client-Key
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- default: Bearer <Add access token here>
|
||||||
|
description: Insert your access token
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
type: string
|
||||||
|
- description: Bookmark 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: Delete Bookmark
|
||||||
|
tags:
|
||||||
|
- Bookmarks
|
||||||
|
get:
|
||||||
|
description: API for getting Bookmark by ID
|
||||||
|
parameters:
|
||||||
|
- description: Insert the X-Client-Key
|
||||||
|
in: header
|
||||||
|
name: X-Client-Key
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- default: Bearer <Add access token here>
|
||||||
|
description: Insert your access token
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
type: string
|
||||||
|
- description: Bookmark 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: Get Bookmark by ID
|
||||||
|
tags:
|
||||||
|
- Bookmarks
|
||||||
|
/bookmarks/summary:
|
||||||
|
get:
|
||||||
|
description: API for getting bookmark summary including total count and recent
|
||||||
|
bookmarks
|
||||||
|
parameters:
|
||||||
|
- description: Insert the X-Client-Key
|
||||||
|
in: header
|
||||||
|
name: X-Client-Key
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- default: Bearer <Add access token here>
|
||||||
|
description: Insert your access token
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
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 Bookmark Summary for User
|
||||||
|
tags:
|
||||||
|
- Bookmarks
|
||||||
|
/bookmarks/toggle/{articleId}:
|
||||||
|
post:
|
||||||
|
description: API for toggling bookmark status for an article
|
||||||
|
parameters:
|
||||||
|
- description: Insert the X-Client-Key
|
||||||
|
in: header
|
||||||
|
name: X-Client-Key
|
||||||
|
required: true
|
||||||
|
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: articleId
|
||||||
|
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: Toggle Bookmark (Add/Remove)
|
||||||
|
tags:
|
||||||
|
- Bookmarks
|
||||||
|
/bookmarks/user:
|
||||||
|
get:
|
||||||
|
description: API for getting Bookmarks by User ID
|
||||||
|
parameters:
|
||||||
|
- description: Insert the X-Client-Key
|
||||||
|
in: header
|
||||||
|
name: X-Client-Key
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- default: Bearer <Add access token here>
|
||||||
|
description: Insert your access token
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: articleId
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: userId
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: count
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: limit
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: nextPage
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: page
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: previousPage
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: sort
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: sortBy
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: totalPage
|
||||||
|
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: Get Bookmarks by User ID
|
||||||
|
tags:
|
||||||
|
- Bookmarks
|
||||||
/cities:
|
/cities:
|
||||||
get:
|
get:
|
||||||
description: API for getting all Cities
|
description: API for getting all Cities
|
||||||
|
|
|
||||||
2
main.go
2
main.go
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"web-medols-be/app/module/article_files"
|
"web-medols-be/app/module/article_files"
|
||||||
"web-medols-be/app/module/article_nulis_ai"
|
"web-medols-be/app/module/article_nulis_ai"
|
||||||
"web-medols-be/app/module/articles"
|
"web-medols-be/app/module/articles"
|
||||||
|
"web-medols-be/app/module/bookmarks"
|
||||||
"web-medols-be/app/module/cities"
|
"web-medols-be/app/module/cities"
|
||||||
"web-medols-be/app/module/client_approval_settings"
|
"web-medols-be/app/module/client_approval_settings"
|
||||||
"web-medols-be/app/module/clients"
|
"web-medols-be/app/module/clients"
|
||||||
|
|
@ -80,6 +81,7 @@ func main() {
|
||||||
articles.NewArticlesModule,
|
articles.NewArticlesModule,
|
||||||
article_comments.NewArticleCommentsModule,
|
article_comments.NewArticleCommentsModule,
|
||||||
article_nulis_ai.NewArticleNulisAIModule,
|
article_nulis_ai.NewArticleNulisAIModule,
|
||||||
|
bookmarks.NewBookmarksModule,
|
||||||
cities.NewCitiesModule,
|
cities.NewCitiesModule,
|
||||||
client_approval_settings.NewClientApprovalSettingsModule,
|
client_approval_settings.NewClientApprovalSettingsModule,
|
||||||
clients.NewClientsModule,
|
clients.NewClientsModule,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue