feat: update fixing sales agent
This commit is contained in:
parent
62c44904c7
commit
0dba3b27cf
|
|
@ -22,6 +22,7 @@ type SalesAgentsController interface {
|
||||||
Save(c *fiber.Ctx) error
|
Save(c *fiber.Ctx) error
|
||||||
Update(c *fiber.Ctx) error
|
Update(c *fiber.Ctx) error
|
||||||
Delete(c *fiber.Ctx) error
|
Delete(c *fiber.Ctx) error
|
||||||
|
Viewer(c *fiber.Ctx) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSalesAgentsController(salesAgentsService service.SalesAgentsService) SalesAgentsController {
|
func NewSalesAgentsController(salesAgentsService service.SalesAgentsService) SalesAgentsController {
|
||||||
|
|
@ -279,3 +280,19 @@ func (_i *salesAgentsController) Delete(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Viewer SalesAgent
|
||||||
|
// @Summary Viewer SalesAgent
|
||||||
|
// @Description API for viewing SalesAgent profile picture file
|
||||||
|
// @Tags SalesAgents
|
||||||
|
// @Security Bearer
|
||||||
|
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
||||||
|
// @Param filename path string true "SalesAgent File Name (e.g., user_277788.png)"
|
||||||
|
// @Success 200 {file} file
|
||||||
|
// @Failure 400 {object} response.BadRequestError
|
||||||
|
// @Failure 401 {object} response.UnauthorizedError
|
||||||
|
// @Failure 500 {object} response.InternalServerError
|
||||||
|
// @Router /sales-agents/viewer/{filename} [get]
|
||||||
|
func (_i *salesAgentsController) Viewer(c *fiber.Ctx) error {
|
||||||
|
return _i.salesAgentsService.Viewer(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"jaecoo-be/app/database/entity"
|
"jaecoo-be/app/database/entity"
|
||||||
res "jaecoo-be/app/module/sales_agents/response"
|
res "jaecoo-be/app/module/sales_agents/response"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SalesAgentsResponseMapper(agent *entity.SalesAgents, host string) *res.SalesAgentsResponse {
|
func SalesAgentsResponseMapper(agent *entity.SalesAgents, host string) *res.SalesAgentsResponse {
|
||||||
|
|
@ -17,22 +18,23 @@ func SalesAgentsResponseMapper(agent *entity.SalesAgents, host string) *res.Sale
|
||||||
}
|
}
|
||||||
|
|
||||||
response := &res.SalesAgentsResponse{
|
response := &res.SalesAgentsResponse{
|
||||||
ID: agent.ID,
|
ID: agent.ID,
|
||||||
Name: agent.Name,
|
Name: agent.Name,
|
||||||
JobTitle: agent.JobTitle,
|
JobTitle: agent.JobTitle,
|
||||||
Phone: agent.Phone,
|
Phone: agent.Phone,
|
||||||
AgentType: agentType,
|
AgentType: agentType,
|
||||||
ProfilePicturePath: agent.ProfilePicturePath,
|
ProfilePicturePath: agent.ProfilePicturePath,
|
||||||
IsActive: agent.IsActive,
|
IsActive: agent.IsActive,
|
||||||
CreatedAt: agent.CreatedAt,
|
CreatedAt: agent.CreatedAt,
|
||||||
UpdatedAt: agent.UpdatedAt,
|
UpdatedAt: agent.UpdatedAt,
|
||||||
}
|
}
|
||||||
|
|
||||||
if agent.ProfilePicturePath != nil && *agent.ProfilePicturePath != "" {
|
if agent.ProfilePicturePath != nil && *agent.ProfilePicturePath != "" {
|
||||||
profilePictureUrl := host + "/sales-agents/profile-picture/viewer/" + *agent.ProfilePicturePath
|
// Extract filename from path
|
||||||
|
filename := filepath.Base(*agent.ProfilePicturePath)
|
||||||
|
profilePictureUrl := host + "/sales-agents/viewer/" + filename
|
||||||
response.ProfilePictureUrl = &profilePictureUrl
|
response.ProfilePictureUrl = &profilePictureUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ type SalesAgentsRepository interface {
|
||||||
Create(agent *entity.SalesAgents) (agentReturn *entity.SalesAgents, err error)
|
Create(agent *entity.SalesAgents) (agentReturn *entity.SalesAgents, err error)
|
||||||
Update(id uint, agent *entity.SalesAgents) (err error)
|
Update(id uint, agent *entity.SalesAgents) (err error)
|
||||||
Delete(id uint) (err error)
|
Delete(id uint) (err error)
|
||||||
|
FindByProfilePicturePath(profilePicturePath string) (agent *entity.SalesAgents, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSalesAgentsRepository(db *database.Database, log zerolog.Logger) SalesAgentsRepository {
|
func NewSalesAgentsRepository(db *database.Database, log zerolog.Logger) SalesAgentsRepository {
|
||||||
|
|
@ -91,3 +92,9 @@ func (_i *salesAgentsRepository) Delete(id uint) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (_i *salesAgentsRepository) FindByProfilePicturePath(profilePicturePath string) (agent *entity.SalesAgents, err error) {
|
||||||
|
agent = &entity.SalesAgents{}
|
||||||
|
err = _i.DB.DB.Where("profile_picture_path LIKE ? AND is_active = ?", "%"+profilePicturePath, true).First(agent).Error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ func (_i *SalesAgentsRouter) RegisterSalesAgentsRoutes() {
|
||||||
// define routes
|
// define routes
|
||||||
_i.App.Route("/sales-agents", func(router fiber.Router) {
|
_i.App.Route("/sales-agents", func(router fiber.Router) {
|
||||||
router.Get("/", salesAgentsController.All)
|
router.Get("/", salesAgentsController.All)
|
||||||
|
router.Get("/viewer/:filename", salesAgentsController.Viewer)
|
||||||
router.Get("/:id", salesAgentsController.Show)
|
router.Get("/:id", salesAgentsController.Show)
|
||||||
router.Post("/", salesAgentsController.Save)
|
router.Post("/", salesAgentsController.Save)
|
||||||
router.Put("/:id", salesAgentsController.Update)
|
router.Put("/:id", salesAgentsController.Update)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"jaecoo-be/app/module/sales_agents/mapper"
|
"jaecoo-be/app/module/sales_agents/mapper"
|
||||||
"jaecoo-be/app/module/sales_agents/repository"
|
"jaecoo-be/app/module/sales_agents/repository"
|
||||||
"jaecoo-be/app/module/sales_agents/request"
|
"jaecoo-be/app/module/sales_agents/request"
|
||||||
|
|
@ -12,6 +13,7 @@ import (
|
||||||
minioStorage "jaecoo-be/config/config"
|
minioStorage "jaecoo-be/config/config"
|
||||||
"jaecoo-be/utils/paginator"
|
"jaecoo-be/utils/paginator"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"mime"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -36,6 +38,7 @@ type SalesAgentsService interface {
|
||||||
Update(c *fiber.Ctx, id uint, req request.SalesAgentsUpdateRequest) (agent *response.SalesAgentsResponse, err error)
|
Update(c *fiber.Ctx, id uint, req request.SalesAgentsUpdateRequest) (agent *response.SalesAgentsResponse, err error)
|
||||||
Delete(id uint) (err error)
|
Delete(id uint) (err error)
|
||||||
UploadFileToMinio(c *fiber.Ctx, fileKey string) (filePath *string, err error)
|
UploadFileToMinio(c *fiber.Ctx, fileKey string) (filePath *string, err error)
|
||||||
|
Viewer(c *fiber.Ctx) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSalesAgentsService(repo repository.SalesAgentsRepository, log zerolog.Logger, cfg *config.Config, minioStorage *minioStorage.MinioStorage) SalesAgentsService {
|
func NewSalesAgentsService(repo repository.SalesAgentsRepository, log zerolog.Logger, cfg *config.Config, minioStorage *minioStorage.MinioStorage) SalesAgentsService {
|
||||||
|
|
@ -193,3 +196,79 @@ func (_i *salesAgentsService) Delete(id uint) (err error) {
|
||||||
err = _i.Repo.Delete(id)
|
err = _i.Repo.Delete(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (_i *salesAgentsService) Viewer(c *fiber.Ctx) (err error) {
|
||||||
|
filename := c.Params("filename")
|
||||||
|
|
||||||
|
// Find sales agent by filename (repository will search using LIKE pattern)
|
||||||
|
result, err := _i.Repo.FindByProfilePicturePath(filename)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
||||||
|
"error": true,
|
||||||
|
"msg": "Sales agent file not found",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.ProfilePicturePath == nil || *result.ProfilePicturePath == "" {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
||||||
|
"error": true,
|
||||||
|
"msg": "Sales agent profile picture path not found",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName
|
||||||
|
objectName := *result.ProfilePicturePath
|
||||||
|
|
||||||
|
_i.Log.Info().Str("timestamp", time.Now().
|
||||||
|
Format(time.RFC3339)).Str("Service:Resource", "SalesAgents:Viewer").
|
||||||
|
Interface("data", objectName).Msg("")
|
||||||
|
|
||||||
|
// Create minio connection
|
||||||
|
minioClient, err := _i.MinioStorage.ConnectMinio()
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": true,
|
||||||
|
"msg": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fileContent, err := minioClient.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
_i.Log.Error().Str("timestamp", time.Now().
|
||||||
|
Format(time.RFC3339)).Str("Service:Resource", "SalesAgents:Viewer").
|
||||||
|
Interface("Error getting file", err).Msg("")
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": true,
|
||||||
|
"msg": "Failed to retrieve file",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
defer fileContent.Close()
|
||||||
|
|
||||||
|
// Determine Content-Type based on file extension
|
||||||
|
contentType := mime.TypeByExtension("." + getFileExtension(objectName))
|
||||||
|
if contentType == "" {
|
||||||
|
contentType = "application/octet-stream" // fallback if no MIME type matches
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Set("Content-Type", contentType)
|
||||||
|
|
||||||
|
if _, err := io.Copy(c.Response().BodyWriter(), fileContent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFileExtension(filename string) string {
|
||||||
|
// split file name
|
||||||
|
parts := strings.Split(filename, ".")
|
||||||
|
|
||||||
|
// jika tidak ada ekstensi, kembalikan string kosong
|
||||||
|
if len(parts) == 1 || (len(parts) == 2 && parts[0] == "") {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ambil ekstensi terakhir
|
||||||
|
return parts[len(parts)-1]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7324,6 +7324,62 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/sales-agents/viewer/{filename}": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for viewing SalesAgent profile picture file",
|
||||||
|
"tags": [
|
||||||
|
"SalesAgents"
|
||||||
|
],
|
||||||
|
"summary": "Viewer SalesAgent",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "SalesAgent File Name (e.g., user_277788.png)",
|
||||||
|
"name": "filename",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "file"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/sales-agents/{id}": {
|
"/sales-agents/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
|
||||||
|
|
@ -7313,6 +7313,62 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/sales-agents/viewer/{filename}": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API for viewing SalesAgent profile picture file",
|
||||||
|
"tags": [
|
||||||
|
"SalesAgents"
|
||||||
|
],
|
||||||
|
"summary": "Viewer SalesAgent",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Insert the X-Client-Key",
|
||||||
|
"name": "X-Client-Key",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "SalesAgent File Name (e.g., user_277788.png)",
|
||||||
|
"name": "filename",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "file"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/sales-agents/{id}": {
|
"/sales-agents/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
|
||||||
|
|
@ -5579,6 +5579,42 @@ paths:
|
||||||
summary: Update SalesAgent
|
summary: Update SalesAgent
|
||||||
tags:
|
tags:
|
||||||
- SalesAgents
|
- SalesAgents
|
||||||
|
/sales-agents/viewer/{filename}:
|
||||||
|
get:
|
||||||
|
description: API for viewing SalesAgent profile picture file
|
||||||
|
parameters:
|
||||||
|
- description: Insert the X-Client-Key
|
||||||
|
in: header
|
||||||
|
name: X-Client-Key
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: SalesAgent File Name (e.g., user_277788.png)
|
||||||
|
in: path
|
||||||
|
name: filename
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
type: file
|
||||||
|
"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: Viewer SalesAgent
|
||||||
|
tags:
|
||||||
|
- SalesAgents
|
||||||
/user-levels:
|
/user-levels:
|
||||||
get:
|
get:
|
||||||
description: API for getting all UserLevels
|
description: API for getting all UserLevels
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue