feat: update approval on 5 main module

This commit is contained in:
hanif salafi 2026-01-20 08:08:14 +07:00
parent 4976e47a9d
commit 6da67768df
38 changed files with 18911 additions and 15327 deletions

View File

@ -11,6 +11,7 @@ type Banners struct {
ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"`
Position *string `json:"position" gorm:"type:varchar"`
Status *string `json:"status" gorm:"type:varchar"`
StatusId *int `json:"status_id" gorm:"type:int4;default:1"`
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()"`

View File

@ -9,6 +9,7 @@ type Galleries struct {
Title string `json:"title" gorm:"type:varchar"`
Description *string `json:"description" gorm:"type:text"`
ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"`
StatusId *int `json:"status_id" gorm:"type:int4;default:1"`
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()"`

View File

@ -12,6 +12,7 @@ type Products struct {
ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"`
Colors *string `json:"colors" gorm:"type:text"` // JSON array stored as text
Status *string `json:"status" gorm:"type:varchar"`
StatusId *int `json:"status_id" gorm:"type:int4;default:1"`
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()"`

View File

@ -9,6 +9,7 @@ type Promotions struct {
Title string `json:"title" gorm:"type:varchar"`
Description *string `json:"description" gorm:"type:text"`
ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"`
StatusId *int `json:"status_id" gorm:"type:int4;default:1"`
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()"`

View File

@ -11,6 +11,7 @@ type SalesAgents struct {
Phone *string `json:"phone" gorm:"type:varchar"`
AgentType *string `json:"agent_type" gorm:"type:text"` // JSON array stored as text
ProfilePicturePath *string `json:"profile_picture_path" gorm:"type:varchar"`
StatusId *int `json:"status_id" gorm:"type:int4;default:1"`
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()"`

View File

@ -50,6 +50,7 @@ func (_i *BannersRouter) RegisterBannersRoutes() {
router.Get("/:id", bannersController.Show)
router.Post("/", bannersController.Save)
router.Put("/:id", bannersController.Update)
router.Put("/:id/approve", bannersController.Approve)
router.Delete("/:id", bannersController.Delete)
})
}

View File

@ -1,6 +1,7 @@
package controller
import (
"jaecoo-be/app/database/entity/users"
"jaecoo-be/app/module/banners/request"
"jaecoo-be/app/module/banners/service"
"jaecoo-be/utils/paginator"
@ -21,6 +22,7 @@ type BannersController interface {
Save(c *fiber.Ctx) error
Update(c *fiber.Ctx) error
Delete(c *fiber.Ctx) error
Approve(c *fiber.Ctx) error
Viewer(c *fiber.Ctx) error
}
@ -271,6 +273,51 @@ func (_i *bannersController) Delete(c *fiber.Ctx) error {
})
}
// Approve Banner
// @Summary Approve Banner
// @Description API for approving Banner (only for admin with roleId = 1)
// @Tags Banners
// @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param id path int true "Banner ID"
// @Success 200 {object} response.Response
// @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError
// @Failure 500 {object} response.InternalServerError
// @Router /banners/{id}/approve [put]
func (_i *bannersController) Approve(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
if err != nil {
return err
}
// Get user from context
user := c.Locals("user")
if user == nil {
return utilRes.Resp(c, utilRes.Response{
Success: false,
Messages: utilRes.Messages{"Unauthorized: user not found"},
})
}
// Type assert to get user role ID
userRoleId := uint(0)
if userData, ok := user.(*users.Users); ok {
userRoleId = userData.UserRoleId
}
bannerData, err := _i.bannersService.Approve(uint(id), userRoleId)
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"Banner successfully approved"},
Data: bannerData,
})
}
// Viewer Banner
// @Summary Viewer Banner
// @Description API for viewing Banner file

View File

@ -18,6 +18,7 @@ func BannersResponseMapper(banner *entity.Banners, host string) *res.BannersResp
ThumbnailPath: banner.ThumbnailPath,
Position: banner.Position,
Status: banner.Status,
StatusId: banner.StatusId,
IsActive: banner.IsActive,
CreatedAt: banner.CreatedAt,
UpdatedAt: banner.UpdatedAt,

View File

@ -22,6 +22,7 @@ type BannersRepository interface {
Update(id uint, banner *entity.Banners) (err error)
Delete(id uint) (err error)
FindByThumbnailPath(thumbnailPath string) (banner *entity.Banners, err error)
Approve(id uint) (err error)
}
func NewBannersRepository(db *database.Database, log zerolog.Logger) BannersRepository {
@ -97,3 +98,9 @@ func (_i *bannersRepository) FindByThumbnailPath(thumbnailPath string) (banner *
err = _i.DB.DB.Where("thumbnail_path LIKE ? AND is_active = ?", "%"+thumbnailPath, true).First(banner).Error
return
}
func (_i *bannersRepository) Approve(id uint) (err error) {
statusId := 2 // Approved status
err = _i.DB.DB.Model(&entity.Banners{}).Where("id = ?", id).Update("status_id", statusId).Error
return
}

View File

@ -12,6 +12,7 @@ type BannersResponse struct {
ThumbnailUrl *string `json:"thumbnail_url"`
Position *string `json:"position"`
Status *string `json:"status"`
StatusId *int `json:"status_id"`
IsActive *bool `json:"is_active"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`

View File

@ -37,6 +37,7 @@ type BannersService interface {
Create(c *fiber.Ctx, req request.BannersCreateRequest) (banner *response.BannersResponse, err error)
Update(c *fiber.Ctx, id uint, req request.BannersUpdateRequest) (banner *response.BannersResponse, err error)
Delete(id uint) (err error)
Approve(id uint, userRoleId uint) (banner *response.BannersResponse, err error)
UploadFileToMinio(c *fiber.Ctx, fileKey string) (filePath *string, err error)
Viewer(c *fiber.Ctx) (err error)
}
@ -197,6 +198,35 @@ func (_i *bannersService) Delete(id uint) (err error) {
return
}
func (_i *bannersService) Approve(id uint, userRoleId uint) (banner *response.BannersResponse, err error) {
// Check if user has admin role (roleId = 1)
if userRoleId != 1 {
err = errors.New("unauthorized: only admin can approve")
return
}
// Approve banner (update status_id to 2)
err = _i.Repo.Approve(id)
if err != nil {
return
}
// Get updated banner data
bannerEntity, err := _i.Repo.FindOne(id)
if err != nil {
return
}
if bannerEntity == nil {
err = errors.New("banner not found")
return
}
host := _i.Cfg.App.Domain
banner = mapper.BannersResponseMapper(bannerEntity, host)
return
}
func (_i *bannersService) Viewer(c *fiber.Ctx) (err error) {
filename := c.Params("filename")

View File

@ -1,6 +1,7 @@
package controller
import (
"jaecoo-be/app/database/entity/users"
"jaecoo-be/app/module/galleries/request"
"jaecoo-be/app/module/galleries/service"
"jaecoo-be/utils/paginator"
@ -22,6 +23,7 @@ type GalleriesController interface {
Save(c *fiber.Ctx) error
Update(c *fiber.Ctx) error
Delete(c *fiber.Ctx) error
Approve(c *fiber.Ctx) error
}
func NewGalleriesController(galleriesService service.GalleriesService) GalleriesController {
@ -192,3 +194,48 @@ func (_i *galleriesController) Delete(c *fiber.Ctx) error {
Messages: utilRes.Messages{"Gallery successfully deleted"},
})
}
// Approve Gallery
// @Summary Approve Gallery
// @Description API for approving Gallery (only for admin with roleId = 1)
// @Tags Galleries
// @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param id path int true "Gallery ID"
// @Success 200 {object} response.Response
// @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError
// @Failure 500 {object} response.InternalServerError
// @Router /galleries/{id}/approve [put]
func (_i *galleriesController) Approve(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
if err != nil {
return err
}
// Get user from context
user := c.Locals("user")
if user == nil {
return utilRes.Resp(c, utilRes.Response{
Success: false,
Messages: utilRes.Messages{"Unauthorized: user not found"},
})
}
// Type assert to get user role ID
userRoleId := uint(0)
if userData, ok := user.(*users.Users); ok {
userRoleId = userData.UserRoleId
}
galleryData, err := _i.galleriesService.Approve(uint(id), userRoleId)
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"Gallery successfully approved"},
Data: galleryData,
})
}

View File

@ -49,6 +49,7 @@ func (_i *GalleriesRouter) RegisterGalleriesRoutes() {
router.Get("/:id", galleriesController.Show)
router.Post("/", galleriesController.Save)
router.Put("/:id", galleriesController.Update)
router.Put("/:id/approve", galleriesController.Approve)
router.Delete("/:id", galleriesController.Delete)
})
}

View File

@ -15,6 +15,7 @@ func GalleriesResponseMapper(gallery *entity.Galleries, host string) *res.Galler
Title: gallery.Title,
Description: gallery.Description,
ThumbnailPath: gallery.ThumbnailPath,
StatusId: gallery.StatusId,
IsActive: gallery.IsActive,
CreatedAt: gallery.CreatedAt,
UpdatedAt: gallery.UpdatedAt,

View File

@ -21,6 +21,7 @@ type GalleriesRepository interface {
Create(gallery *entity.Galleries) (galleryReturn *entity.Galleries, err error)
Update(id uint, gallery *entity.Galleries) (err error)
Delete(id uint) (err error)
Approve(id uint) (err error)
}
func NewGalleriesRepository(db *database.Database, log zerolog.Logger) GalleriesRepository {
@ -82,3 +83,9 @@ func (_i *galleriesRepository) Delete(id uint) (err error) {
err = _i.DB.DB.Model(&entity.Galleries{}).Where("id = ?", id).Update("is_active", false).Error
return
}
func (_i *galleriesRepository) Approve(id uint) (err error) {
statusId := 2 // Approved status
err = _i.DB.DB.Model(&entity.Galleries{}).Where("id = ?", id).Update("status_id", statusId).Error
return
}

View File

@ -10,6 +10,7 @@ type GalleriesResponse struct {
Description *string `json:"description"`
ThumbnailPath *string `json:"thumbnail_path"`
ThumbnailUrl *string `json:"thumbnail_url"`
StatusId *int `json:"status_id"`
IsActive *bool `json:"is_active"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`

View File

@ -24,6 +24,7 @@ type GalleriesService interface {
Create(req request.GalleriesCreateRequest) (gallery *response.GalleriesResponse, err error)
Update(id uint, req request.GalleriesUpdateRequest) (gallery *response.GalleriesResponse, err error)
Delete(id uint) (err error)
Approve(id uint, userRoleId uint) (gallery *response.GalleriesResponse, err error)
}
func NewGalleriesService(repo repository.GalleriesRepository, log zerolog.Logger, cfg *config.Config) GalleriesService {
@ -105,3 +106,32 @@ func (_i *galleriesService) Delete(id uint) (err error) {
err = _i.Repo.Delete(id)
return
}
func (_i *galleriesService) Approve(id uint, userRoleId uint) (gallery *response.GalleriesResponse, err error) {
// Check if user has admin role (roleId = 1)
if userRoleId != 1 {
err = errors.New("unauthorized: only admin can approve")
return
}
// Approve gallery (update status_id to 2)
err = _i.Repo.Approve(id)
if err != nil {
return
}
// Get updated gallery data
galleryEntity, err := _i.Repo.FindOne(id)
if err != nil {
return
}
if galleryEntity == nil {
err = errors.New("gallery not found")
return
}
host := _i.Cfg.App.Domain
gallery = mapper.GalleriesResponseMapper(galleryEntity, host)
return
}

View File

@ -2,6 +2,7 @@ package controller
import (
"encoding/json"
"jaecoo-be/app/database/entity/users"
"jaecoo-be/app/module/products/request"
"jaecoo-be/app/module/products/service"
"jaecoo-be/utils/paginator"
@ -22,6 +23,7 @@ type ProductsController interface {
Save(c *fiber.Ctx) error
Update(c *fiber.Ctx) error
Delete(c *fiber.Ctx) error
Approve(c *fiber.Ctx) error
Viewer(c *fiber.Ctx) error
}
@ -279,6 +281,51 @@ func (_i *productsController) Delete(c *fiber.Ctx) error {
})
}
// Approve Product
// @Summary Approve Product
// @Description API for approving Product (only for admin with roleId = 1)
// @Tags Products
// @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param id path int true "Product ID"
// @Success 200 {object} response.Response
// @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError
// @Failure 500 {object} response.InternalServerError
// @Router /products/{id}/approve [put]
func (_i *productsController) Approve(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
if err != nil {
return err
}
// Get user from context
user := c.Locals("user")
if user == nil {
return utilRes.Resp(c, utilRes.Response{
Success: false,
Messages: utilRes.Messages{"Unauthorized: user not found"},
})
}
// Type assert to get user role ID
userRoleId := uint(0)
if userData, ok := user.(*users.Users); ok {
userRoleId = userData.UserRoleId
}
productData, err := _i.productsService.Approve(uint(id), userRoleId)
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"Product successfully approved"},
Data: productData,
})
}
// Viewer Product
// @Summary Viewer Product
// @Description API for viewing Product file

View File

@ -25,6 +25,7 @@ func ProductsResponseMapper(product *entity.Products, host string) *res.Products
ThumbnailPath: product.ThumbnailPath,
Colors: colors,
Status: product.Status,
StatusId: product.StatusId,
IsActive: product.IsActive,
CreatedAt: product.CreatedAt,
UpdatedAt: product.UpdatedAt,

View File

@ -50,6 +50,7 @@ func (_i *ProductsRouter) RegisterProductsRoutes() {
router.Get("/:id", productsController.Show)
router.Post("/", productsController.Save)
router.Put("/:id", productsController.Update)
router.Put("/:id/approve", productsController.Approve)
router.Delete("/:id", productsController.Delete)
})
}

View File

@ -22,6 +22,7 @@ type ProductsRepository interface {
Update(id uint, product *entity.Products) (err error)
Delete(id uint) (err error)
FindByThumbnailPath(thumbnailPath string) (product *entity.Products, err error)
Approve(id uint) (err error)
}
func NewProductsRepository(db *database.Database, log zerolog.Logger) ProductsRepository {
@ -98,3 +99,9 @@ func (_i *productsRepository) FindByThumbnailPath(thumbnailPath string) (product
return
}
func (_i *productsRepository) Approve(id uint) (err error) {
statusId := 2 // Approved status
err = _i.DB.DB.Model(&entity.Products{}).Where("id = ?", id).Update("status_id", statusId).Error
return
}

View File

@ -13,6 +13,7 @@ type ProductsResponse struct {
ThumbnailUrl *string `json:"thumbnail_url"`
Colors []string `json:"colors"`
Status *string `json:"status"`
StatusId *int `json:"status_id"`
IsActive *bool `json:"is_active"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`

View File

@ -37,6 +37,7 @@ type ProductsService interface {
Create(c *fiber.Ctx, req request.ProductsCreateRequest) (product *response.ProductsResponse, err error)
Update(c *fiber.Ctx, id uint, req request.ProductsUpdateRequest) (product *response.ProductsResponse, err error)
Delete(id uint) (err error)
Approve(id uint, userRoleId uint) (product *response.ProductsResponse, err error)
UploadFileToMinio(c *fiber.Ctx, fileKey string) (filePath *string, err error)
Viewer(c *fiber.Ctx) (err error)
}
@ -272,3 +273,32 @@ func getFileExtension(filename string) string {
// ambil ekstensi terakhir
return parts[len(parts)-1]
}
func (_i *productsService) Approve(id uint, userRoleId uint) (product *response.ProductsResponse, err error) {
// Check if user has admin role (roleId = 1)
if userRoleId != 1 {
err = errors.New("unauthorized: only admin can approve")
return
}
// Approve product (update status_id to 2)
err = _i.Repo.Approve(id)
if err != nil {
return
}
// Get updated product data
productEntity, err := _i.Repo.FindOne(id)
if err != nil {
return
}
if productEntity == nil {
err = errors.New("product not found")
return
}
host := _i.Cfg.App.Domain
product = mapper.ProductsResponseMapper(productEntity, host)
return
}

View File

@ -1,6 +1,7 @@
package controller
import (
"jaecoo-be/app/database/entity/users"
"jaecoo-be/app/module/promotions/request"
"jaecoo-be/app/module/promotions/service"
"jaecoo-be/utils/paginator"
@ -22,6 +23,7 @@ type PromotionsController interface {
Save(c *fiber.Ctx) error
Update(c *fiber.Ctx) error
Delete(c *fiber.Ctx) error
Approve(c *fiber.Ctx) error
Viewer(c *fiber.Ctx) error
}
@ -222,6 +224,51 @@ func (_i *promotionsController) Delete(c *fiber.Ctx) error {
})
}
// Approve Promotion
// @Summary Approve Promotion
// @Description API for approving Promotion (only for admin with roleId = 1)
// @Tags Promotions
// @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param id path int true "Promotion ID"
// @Success 200 {object} response.Response
// @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError
// @Failure 500 {object} response.InternalServerError
// @Router /promotions/{id}/approve [put]
func (_i *promotionsController) Approve(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
if err != nil {
return err
}
// Get user from context
user := c.Locals("user")
if user == nil {
return utilRes.Resp(c, utilRes.Response{
Success: false,
Messages: utilRes.Messages{"Unauthorized: user not found"},
})
}
// Type assert to get user role ID
userRoleId := uint(0)
if userData, ok := user.(*users.Users); ok {
userRoleId = userData.UserRoleId
}
promotionData, err := _i.promotionsService.Approve(uint(id), userRoleId)
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"Promotion successfully approved"},
Data: promotionData,
})
}
// Viewer Promotion
// @Summary Viewer Promotion
// @Description API for viewing Promotion file

View File

@ -16,6 +16,7 @@ func PromotionsResponseMapper(promotion *entity.Promotions, host string) *res.Pr
Title: promotion.Title,
Description: promotion.Description,
ThumbnailPath: promotion.ThumbnailPath,
StatusId: promotion.StatusId,
IsActive: promotion.IsActive,
CreatedAt: promotion.CreatedAt,
UpdatedAt: promotion.UpdatedAt,

View File

@ -50,6 +50,7 @@ func (_i *PromotionsRouter) RegisterPromotionsRoutes() {
router.Get("/:id", promotionsController.Show)
router.Post("/", promotionsController.Save)
router.Put("/:id", promotionsController.Update)
router.Put("/:id/approve", promotionsController.Approve)
router.Delete("/:id", promotionsController.Delete)
})
}

View File

@ -22,6 +22,7 @@ type PromotionsRepository interface {
Update(id uint, promotion *entity.Promotions) (err error)
Delete(id uint) (err error)
FindByThumbnailPath(thumbnailPath string) (promotion *entity.Promotions, err error)
Approve(id uint) (err error)
}
func NewPromotionsRepository(db *database.Database, log zerolog.Logger) PromotionsRepository {
@ -90,3 +91,8 @@ func (_i *promotionsRepository) FindByThumbnailPath(thumbnailPath string) (promo
return
}
func (_i *promotionsRepository) Approve(id uint) (err error) {
statusId := 2 // Approved status
err = _i.DB.DB.Model(&entity.Promotions{}).Where("id = ?", id).Update("status_id", statusId).Error
return
}

View File

@ -10,6 +10,7 @@ type PromotionsResponse struct {
Description *string `json:"description"`
ThumbnailPath *string `json:"thumbnail_path"`
ThumbnailUrl *string `json:"thumbnail_url"`
StatusId *int `json:"status_id"`
IsActive *bool `json:"is_active"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`

View File

@ -37,6 +37,7 @@ type PromotionsService interface {
Create(c *fiber.Ctx, req request.PromotionsCreateRequest) (promotion *response.PromotionsResponse, err error)
Update(id uint, req request.PromotionsUpdateRequest) (promotion *response.PromotionsResponse, err error)
Delete(id uint) (err error)
Approve(id uint, userRoleId uint) (promotion *response.PromotionsResponse, err error)
UploadFileToMinio(c *fiber.Ctx, fileKey string) (filePath *string, err error)
Viewer(c *fiber.Ctx) (err error)
}
@ -267,3 +268,32 @@ func getFileExtension(filename string) string {
// ambil ekstensi terakhir
return parts[len(parts)-1]
}
func (_i *promotionsService) Approve(id uint, userRoleId uint) (promotion *response.PromotionsResponse, err error) {
// Check if user has admin role (roleId = 1)
if userRoleId != 1 {
err = errors.New("unauthorized: only admin can approve")
return
}
// Approve promotion (update status_id to 2)
err = _i.Repo.Approve(id)
if err != nil {
return
}
// Get updated promotion data
promotionEntity, err := _i.Repo.FindOne(id)
if err != nil {
return
}
if promotionEntity == nil {
err = errors.New("promotion not found")
return
}
host := _i.Cfg.App.Domain
promotion = mapper.PromotionsResponseMapper(promotionEntity, host)
return
}

View File

@ -2,6 +2,7 @@ package controller
import (
"encoding/json"
"jaecoo-be/app/database/entity/users"
"jaecoo-be/app/module/sales_agents/request"
"jaecoo-be/app/module/sales_agents/service"
"jaecoo-be/utils/paginator"
@ -22,6 +23,7 @@ type SalesAgentsController interface {
Save(c *fiber.Ctx) error
Update(c *fiber.Ctx) error
Delete(c *fiber.Ctx) error
Approve(c *fiber.Ctx) error
Viewer(c *fiber.Ctx) error
}
@ -280,6 +282,51 @@ func (_i *salesAgentsController) Delete(c *fiber.Ctx) error {
})
}
// Approve SalesAgent
// @Summary Approve SalesAgent
// @Description API for approving SalesAgent (only for admin with roleId = 1)
// @Tags SalesAgents
// @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param id path int true "SalesAgent ID"
// @Success 200 {object} response.Response
// @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError
// @Failure 500 {object} response.InternalServerError
// @Router /sales-agents/{id}/approve [put]
func (_i *salesAgentsController) Approve(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
if err != nil {
return err
}
// Get user from context
user := c.Locals("user")
if user == nil {
return utilRes.Resp(c, utilRes.Response{
Success: false,
Messages: utilRes.Messages{"Unauthorized: user not found"},
})
}
// Type assert to get user role ID
userRoleId := uint(0)
if userData, ok := user.(*users.Users); ok {
userRoleId = userData.UserRoleId
}
agentData, err := _i.salesAgentsService.Approve(uint(id), userRoleId)
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"SalesAgent successfully approved"},
Data: agentData,
})
}
// Viewer SalesAgent
// @Summary Viewer SalesAgent
// @Description API for viewing SalesAgent profile picture file

View File

@ -24,6 +24,7 @@ func SalesAgentsResponseMapper(agent *entity.SalesAgents, host string) *res.Sale
Phone: agent.Phone,
AgentType: agentType,
ProfilePicturePath: agent.ProfilePicturePath,
StatusId: agent.StatusId,
IsActive: agent.IsActive,
CreatedAt: agent.CreatedAt,
UpdatedAt: agent.UpdatedAt,

View File

@ -22,6 +22,7 @@ type SalesAgentsRepository interface {
Update(id uint, agent *entity.SalesAgents) (err error)
Delete(id uint) (err error)
FindByProfilePicturePath(profilePicturePath string) (agent *entity.SalesAgents, err error)
Approve(id uint) (err error)
}
func NewSalesAgentsRepository(db *database.Database, log zerolog.Logger) SalesAgentsRepository {
@ -98,3 +99,9 @@ func (_i *salesAgentsRepository) FindByProfilePicturePath(profilePicturePath str
return
}
func (_i *salesAgentsRepository) Approve(id uint) (err error) {
statusId := 2 // Approved status
err = _i.DB.DB.Model(&entity.SalesAgents{}).Where("id = ?", id).Update("status_id", statusId).Error
return
}

View File

@ -12,6 +12,7 @@ type SalesAgentsResponse struct {
AgentType []string `json:"agent_type"`
ProfilePicturePath *string `json:"profile_picture_path"`
ProfilePictureUrl *string `json:"profile_picture_url"`
StatusId *int `json:"status_id"`
IsActive *bool `json:"is_active"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`

View File

@ -50,6 +50,7 @@ func (_i *SalesAgentsRouter) RegisterSalesAgentsRoutes() {
router.Get("/:id", salesAgentsController.Show)
router.Post("/", salesAgentsController.Save)
router.Put("/:id", salesAgentsController.Update)
router.Put("/:id/approve", salesAgentsController.Approve)
router.Delete("/:id", salesAgentsController.Delete)
})
}

View File

@ -37,6 +37,7 @@ type SalesAgentsService interface {
Create(c *fiber.Ctx, req request.SalesAgentsCreateRequest) (agent *response.SalesAgentsResponse, err error)
Update(c *fiber.Ctx, id uint, req request.SalesAgentsUpdateRequest) (agent *response.SalesAgentsResponse, err error)
Delete(id uint) (err error)
Approve(id uint, userRoleId uint) (agent *response.SalesAgentsResponse, err error)
UploadFileToMinio(c *fiber.Ctx, fileKey string) (filePath *string, err error)
Viewer(c *fiber.Ctx) (err error)
}
@ -272,3 +273,32 @@ func getFileExtension(filename string) string {
// ambil ekstensi terakhir
return parts[len(parts)-1]
}
func (_i *salesAgentsService) Approve(id uint, userRoleId uint) (agent *response.SalesAgentsResponse, err error) {
// Check if user has admin role (roleId = 1)
if userRoleId != 1 {
err = errors.New("unauthorized: only admin can approve")
return
}
// Approve sales agent (update status_id to 2)
err = _i.Repo.Approve(id)
if err != nil {
return
}
// Get updated sales agent data
agentEntity, err := _i.Repo.FindOne(id)
if err != nil {
return
}
if agentEntity == nil {
err = errors.New("sales agent not found")
return
}
host := _i.Cfg.App.Domain
agent = mapper.SalesAgentsResponseMapper(agentEntity, host)
return
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff