feat: Add client module with CRUD operations, DTOs, repository, and service layers
Deploy Application / deploy (push) Successful in 23s
Details
Deploy Application / deploy (push) Successful in 23s
Details
This commit is contained in:
parent
f9c5dc3f63
commit
2db31dc017
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/Caknoooo/go-gin-clean-starter/docs"
|
"github.com/Caknoooo/go-gin-clean-starter/docs"
|
||||||
"github.com/Caknoooo/go-gin-clean-starter/middlewares"
|
"github.com/Caknoooo/go-gin-clean-starter/middlewares"
|
||||||
"github.com/Caknoooo/go-gin-clean-starter/modules/auth"
|
"github.com/Caknoooo/go-gin-clean-starter/modules/auth"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/modules/client"
|
||||||
maintenancegroup "github.com/Caknoooo/go-gin-clean-starter/modules/maintenance_group"
|
maintenancegroup "github.com/Caknoooo/go-gin-clean-starter/modules/maintenance_group"
|
||||||
"github.com/Caknoooo/go-gin-clean-starter/modules/menu"
|
"github.com/Caknoooo/go-gin-clean-starter/modules/menu"
|
||||||
"github.com/Caknoooo/go-gin-clean-starter/modules/role"
|
"github.com/Caknoooo/go-gin-clean-starter/modules/role"
|
||||||
|
|
@ -124,6 +125,7 @@ func main() {
|
||||||
logs.RegisterRoutes(server, injector)
|
logs.RegisterRoutes(server, injector)
|
||||||
menu.RegisterRoutes(server, injector)
|
menu.RegisterRoutes(server, injector)
|
||||||
maintenancegroup.RegisterRoutes(server, injector)
|
maintenancegroup.RegisterRoutes(server, injector)
|
||||||
|
client.RegisterRoutes(server, injector)
|
||||||
|
|
||||||
// register swagger route
|
// register swagger route
|
||||||
server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ type M_Client struct {
|
||||||
Phone string `gorm:"type:varchar(20)" json:"phone"`
|
Phone string `gorm:"type:varchar(20)" json:"phone"`
|
||||||
Email string `gorm:"type:varchar(100)" json:"email"`
|
Email string `gorm:"type:varchar(100)" json:"email"`
|
||||||
Address string `gorm:"type:text" json:"address"`
|
Address string `gorm:"type:text" json:"address"`
|
||||||
LogoUrl string `gorm:"type:varchar(255)" json:"logo_url"`
|
Logo string `gorm:"type:text" json:"logo"` // simpan base64 string hasil konversi file gambar
|
||||||
|
|
||||||
Users []M_User `gorm:"foreignKey:ClientID;references:ID" json:"users"`
|
Users []M_User `gorm:"foreignKey:ClientID;references:ID" json:"users"`
|
||||||
MaintenanceGroups []M_MaintenanceGroup `gorm:"foreignKey:ClientID;references:ID" json:"maintenance_groups"`
|
MaintenanceGroups []M_MaintenanceGroup `gorm:"foreignKey:ClientID;references:ID" json:"maintenance_groups"`
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ func ListClientSeeder(db *gorm.DB) error {
|
||||||
Phone: data.Phone,
|
Phone: data.Phone,
|
||||||
Email: data.Email,
|
Email: data.Email,
|
||||||
Address: data.Address,
|
Address: data.Address,
|
||||||
LogoUrl: data.LogoUrl,
|
// Logo: data.LogoUrl,
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
fmt.Println("Error seeding client:", err)
|
fmt.Println("Error seeding client:", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/modules/client/dto"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/modules/client/query"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/modules/client/service"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/pkg/constants"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/pkg/utils"
|
||||||
|
"github.com/Caknoooo/go-pagination"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
ClientController interface {
|
||||||
|
Create(ctx *gin.Context)
|
||||||
|
Update(ctx *gin.Context)
|
||||||
|
Delete(ctx *gin.Context)
|
||||||
|
GetById(ctx *gin.Context)
|
||||||
|
GetAll(ctx *gin.Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientController struct {
|
||||||
|
clientService service.ClientService
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewClientController(i *do.Injector, clientService service.ClientService) ClientController {
|
||||||
|
db := do.MustInvokeNamed[*gorm.DB](i, constants.DB)
|
||||||
|
return &clientController{
|
||||||
|
clientService: clientService,
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *clientController) Create(ctx *gin.Context) {
|
||||||
|
var req dto.ClientCreateRequest
|
||||||
|
if err := ctx.ShouldBind(&req); err != nil {
|
||||||
|
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil)
|
||||||
|
ctx.JSON(http.StatusBadRequest, res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ambil file logo (opsional)
|
||||||
|
file, _, err := ctx.Request.FormFile("logo")
|
||||||
|
if err == nil && file != nil {
|
||||||
|
fileBytes, _ := io.ReadAll(file)
|
||||||
|
base64Str := base64.StdEncoding.EncodeToString(fileBytes)
|
||||||
|
req.Logo = base64Str
|
||||||
|
}
|
||||||
|
|
||||||
|
created, err := c.clientService.Create(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_CREATE_CLIENT, err.Error(), nil)
|
||||||
|
ctx.JSON(http.StatusInternalServerError, res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_CREATE_CLIENT, created)
|
||||||
|
ctx.JSON(http.StatusOK, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *clientController) Update(ctx *gin.Context) {
|
||||||
|
id := ctx.Param("id")
|
||||||
|
var req dto.ClientUpdateRequest
|
||||||
|
if err := ctx.ShouldBind(&req); err != nil {
|
||||||
|
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil)
|
||||||
|
ctx.JSON(http.StatusBadRequest, res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ambil file logo (opsional, untuk update)
|
||||||
|
file, _, err := ctx.Request.FormFile("logo")
|
||||||
|
if err == nil && file != nil {
|
||||||
|
fileBytes, _ := io.ReadAll(file)
|
||||||
|
base64Str := base64.StdEncoding.EncodeToString(fileBytes)
|
||||||
|
req.Logo = &base64Str
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := c.clientService.Update(ctx, req, id)
|
||||||
|
if err != nil {
|
||||||
|
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_UPDATE_CLIENT, err.Error(), nil)
|
||||||
|
ctx.JSON(http.StatusInternalServerError, res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_UPDATE_CLIENT, client)
|
||||||
|
ctx.JSON(http.StatusOK, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *clientController) Delete(ctx *gin.Context) {
|
||||||
|
id := ctx.Param("id")
|
||||||
|
if err := c.clientService.Delete(ctx, id); err != nil {
|
||||||
|
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_DELETE_CLIENT, err.Error(), nil)
|
||||||
|
ctx.JSON(http.StatusInternalServerError, res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_DELETE_CLIENT, nil)
|
||||||
|
ctx.JSON(http.StatusOK, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *clientController) GetById(ctx *gin.Context) {
|
||||||
|
id := ctx.Param("id")
|
||||||
|
client, err := c.clientService.GetById(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_CLIENT, err.Error(), nil)
|
||||||
|
ctx.JSON(http.StatusNotFound, res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_CLIENT, client)
|
||||||
|
ctx.JSON(http.StatusOK, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *clientController) GetAll(ctx *gin.Context) {
|
||||||
|
// clientId := ctx.MustGet("client_id").(string)
|
||||||
|
var filter = &query.ClientFilter{
|
||||||
|
Name: ctx.Query("name"),
|
||||||
|
PIC: ctx.Query("pic"),
|
||||||
|
Phone: ctx.Query("phone"),
|
||||||
|
Email: ctx.Query("email"),
|
||||||
|
Address: ctx.Query("address"),
|
||||||
|
// ClientID: clientId,
|
||||||
|
Includes: ctx.QueryArray("includes"),
|
||||||
|
}
|
||||||
|
filter.BindPagination(ctx)
|
||||||
|
ctx.ShouldBindQuery(filter)
|
||||||
|
groups, total, err := pagination.PaginatedQueryWithIncludableAndOptions[query.M_Client](
|
||||||
|
c.db,
|
||||||
|
filter,
|
||||||
|
pagination.PaginatedQueryOptions{
|
||||||
|
EnableSoftDelete: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_CLIENT, err.Error(), nil)
|
||||||
|
ctx.JSON(http.StatusBadRequest, res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
paginationResponse := pagination.CalculatePagination(filter.Pagination, total)
|
||||||
|
|
||||||
|
response := pagination.NewPaginatedResponse(http.StatusOK, dto.MESSAGE_SUCCESS_GET_CLIENT, groups, paginationResponse)
|
||||||
|
ctx.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MESSAGE_FAILED_CREATE_CLIENT = "failed create client"
|
||||||
|
MESSAGE_SUCCESS_CREATE_CLIENT = "success create client"
|
||||||
|
MESSAGE_FAILED_GET_CLIENT = "failed get client"
|
||||||
|
MESSAGE_SUCCESS_GET_CLIENT = "success get client"
|
||||||
|
MESSAGE_FAILED_UPDATE_CLIENT = "failed update client"
|
||||||
|
MESSAGE_SUCCESS_UPDATE_CLIENT = "success update client"
|
||||||
|
MESSAGE_FAILED_DELETE_CLIENT = "failed delete client"
|
||||||
|
MESSAGE_SUCCESS_DELETE_CLIENT = "success delete client"
|
||||||
|
MESSAGE_FAILED_GET_DATA_FROM_BODY = "failed get data from body"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrCreateClient = errors.New("failed to create client")
|
||||||
|
ErrGetClientById = errors.New("failed to get client by id")
|
||||||
|
ErrUpdateClient = errors.New("failed to update client")
|
||||||
|
ErrDeleteClient = errors.New("failed to delete client")
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
ClientCreateRequest struct {
|
||||||
|
Name string `json:"name" form:"name" binding:"required,min=2,max=100"`
|
||||||
|
PIC string `json:"pic" form:"pic" binding:"omitempty,min=2,max=100"`
|
||||||
|
Phone string `json:"phone" form:"phone" binding:"omitempty,min=6,max=20"`
|
||||||
|
Email string `json:"email" form:"email" binding:"omitempty,email,max=100"`
|
||||||
|
Address string `json:"address" form:"address" binding:"omitempty"`
|
||||||
|
Logo string `form:"-"` // diisi manual dari file, tidak di-bind otomatis
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
PIC string `json:"pic"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Logo string `json:"logo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientUpdateRequest struct {
|
||||||
|
Name *string `json:"name" form:"name" binding:"omitempty,min=2,max=100"`
|
||||||
|
PIC *string `json:"pic" form:"pic" binding:"omitempty,min=2,max=100"`
|
||||||
|
Phone *string `json:"phone" form:"phone" binding:"omitempty,min=6,max=20"`
|
||||||
|
Email *string `json:"email" form:"email" binding:"omitempty,email,max=100"`
|
||||||
|
Address *string `json:"address" form:"address" binding:"omitempty"`
|
||||||
|
Logo *string `form:"-"` // jika update logo, isi manual dari file
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Caknoooo/go-pagination"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type M_Client struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
PIC string `json:"pic"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Logo string `json:"logo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClientFilter struct {
|
||||||
|
pagination.BaseFilter
|
||||||
|
Name string `form:"name"` // tambahkan ini
|
||||||
|
PIC string `form:"pic"` // tambahkan ini
|
||||||
|
Phone string `form:"phone"` // tambahkan ini
|
||||||
|
Email string `form:"email"` // tambahkan ini
|
||||||
|
Address string `form:"address"` // tambahkan ini
|
||||||
|
ClientID string `form:"client_id"` // tambahkan ini
|
||||||
|
Includes []string `form:"includes"` // tambahkan ini
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ClientFilter) ApplyFilters(query *gorm.DB) *gorm.DB {
|
||||||
|
// Apply your filters here
|
||||||
|
if f.Name != "" {
|
||||||
|
query = query.Where("name ILIKE ?", "%"+f.Name+"%")
|
||||||
|
}
|
||||||
|
if f.ClientID != "" {
|
||||||
|
query = query.Where("client_id = ?", f.ClientID)
|
||||||
|
}
|
||||||
|
if f.PIC != "" {
|
||||||
|
query = query.Where("pic ILIKE ?", "%"+f.PIC+"%")
|
||||||
|
}
|
||||||
|
if f.Phone != "" {
|
||||||
|
query = query.Where("phone ILIKE ?", "%"+f.Phone+"%")
|
||||||
|
}
|
||||||
|
if f.Email != "" {
|
||||||
|
query = query.Where("email ILIKE ?", "%"+f.Email+"%")
|
||||||
|
}
|
||||||
|
if f.Address != "" {
|
||||||
|
query = query.Where("address ILIKE ?", "%"+f.Address+"%")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manual preload untuk roles dengan field terbatas
|
||||||
|
// for _, include := range f.Includes {
|
||||||
|
// if include == "Roles" {
|
||||||
|
// query = query.Preload("Roles", func(db *gorm.DB) *gorm.DB {
|
||||||
|
// return db.Select("id", "name") // Hanya ambil id dan name
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ClientFilter) GetTableName() string {
|
||||||
|
return "m_clients"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ClientFilter) GetSearchFields() []string {
|
||||||
|
return []string{"name"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ClientFilter) GetDefaultSort() string {
|
||||||
|
return "id asc"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ClientFilter) GetIncludes() []string {
|
||||||
|
return f.Includes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ClientFilter) GetPagination() pagination.PaginationRequest {
|
||||||
|
return f.Pagination
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ClientFilter) Validate() {
|
||||||
|
var validIncludes []string
|
||||||
|
allowedIncludes := f.GetAllowedIncludes()
|
||||||
|
for _, include := range f.Includes {
|
||||||
|
if allowedIncludes[include] {
|
||||||
|
validIncludes = append(validIncludes, include)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.Includes = validIncludes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ClientFilter) GetAllowedIncludes() map[string]bool {
|
||||||
|
return map[string]bool{
|
||||||
|
// "Roles": true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/database/entities"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
ClientRepository interface {
|
||||||
|
Create(ctx context.Context, tx *gorm.DB, client entities.M_Client) (entities.M_Client, error)
|
||||||
|
GetById(ctx context.Context, tx *gorm.DB, clientId string) (entities.M_Client, error)
|
||||||
|
GetByName(ctx context.Context, tx *gorm.DB, name string) (entities.M_Client, error)
|
||||||
|
Update(ctx context.Context, tx *gorm.DB, client entities.M_Client) (entities.M_Client, error)
|
||||||
|
Delete(ctx context.Context, tx *gorm.DB, clientId string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
clientRepository struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *clientRepository) Create(ctx context.Context, tx *gorm.DB, client entities.M_Client) (entities.M_Client, error) {
|
||||||
|
if tx == nil {
|
||||||
|
tx = r.db
|
||||||
|
}
|
||||||
|
if client.ID == uuid.Nil {
|
||||||
|
client.ID = uuid.New()
|
||||||
|
}
|
||||||
|
if err := tx.WithContext(ctx).Create(&client).Error; err != nil {
|
||||||
|
return entities.M_Client{}, err
|
||||||
|
}
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *clientRepository) GetById(ctx context.Context, tx *gorm.DB, clientId string) (entities.M_Client, error) {
|
||||||
|
if tx == nil {
|
||||||
|
tx = r.db
|
||||||
|
}
|
||||||
|
var client entities.M_Client
|
||||||
|
if err := tx.WithContext(ctx).First(&client, "id = ?", clientId).Error; err != nil {
|
||||||
|
return entities.M_Client{}, err
|
||||||
|
}
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *clientRepository) GetByName(ctx context.Context, tx *gorm.DB, name string) (entities.M_Client, error) {
|
||||||
|
if tx == nil {
|
||||||
|
tx = r.db
|
||||||
|
}
|
||||||
|
var client entities.M_Client
|
||||||
|
if err := tx.WithContext(ctx).Where("name = ?", name).First(&client).Error; err != nil {
|
||||||
|
return entities.M_Client{}, err
|
||||||
|
}
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *clientRepository) Update(ctx context.Context, tx *gorm.DB, client entities.M_Client) (entities.M_Client, error) {
|
||||||
|
if tx == nil {
|
||||||
|
tx = r.db
|
||||||
|
}
|
||||||
|
if err := tx.WithContext(ctx).Updates(&client).Error; err != nil {
|
||||||
|
return entities.M_Client{}, err
|
||||||
|
}
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *clientRepository) Delete(ctx context.Context, tx *gorm.DB, clientId string) error {
|
||||||
|
if tx == nil {
|
||||||
|
tx = r.db
|
||||||
|
}
|
||||||
|
if err := tx.WithContext(ctx).Delete(&entities.M_Client{}, "id = ?", clientId).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClientRepository(db *gorm.DB) ClientRepository {
|
||||||
|
return &clientRepository{db: db}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/middlewares"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/modules/auth/service"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/modules/client/controller"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/pkg/constants"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterRoutes(server *gin.Engine, injector *do.Injector) {
|
||||||
|
clientController := do.MustInvoke[controller.ClientController](injector)
|
||||||
|
jwtService := do.MustInvokeNamed[service.JWTService](injector, constants.JWTService)
|
||||||
|
|
||||||
|
clientRoutes := server.Group("/api/v1/clients")
|
||||||
|
{
|
||||||
|
clientRoutes.POST("", middlewares.Authenticate(jwtService), clientController.Create)
|
||||||
|
clientRoutes.GET("/:id", middlewares.Authenticate(jwtService), clientController.GetById)
|
||||||
|
clientRoutes.PUT("/:id", middlewares.Authenticate(jwtService), clientController.Update)
|
||||||
|
clientRoutes.DELETE("/:id", middlewares.Authenticate(jwtService), clientController.Delete)
|
||||||
|
clientRoutes.GET("", middlewares.Authenticate(jwtService), clientController.GetAll)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,190 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/database/entities"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/modules/client/dto"
|
||||||
|
"github.com/Caknoooo/go-gin-clean-starter/modules/client/repository"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClientService interface {
|
||||||
|
Create(ctx context.Context, client dto.ClientCreateRequest) (dto.ClientResponse, error)
|
||||||
|
GetById(ctx context.Context, clientId string) (dto.ClientResponse, error)
|
||||||
|
GetByName(ctx context.Context, name string) (dto.ClientResponse, error)
|
||||||
|
Update(ctx context.Context, client dto.ClientUpdateRequest, clientId string) (dto.ClientResponse, error)
|
||||||
|
Delete(ctx context.Context, clientId string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type clientService struct {
|
||||||
|
db *gorm.DB
|
||||||
|
clientRepo repository.ClientRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientService) Create(ctx context.Context, req dto.ClientCreateRequest) (dto.ClientResponse, error) {
|
||||||
|
tx := s.db.Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
client := entities.M_Client{
|
||||||
|
Name: req.Name,
|
||||||
|
PIC: req.PIC,
|
||||||
|
Phone: req.Phone,
|
||||||
|
Email: req.Email,
|
||||||
|
Address: req.Address,
|
||||||
|
Logo: req.Logo, // []byte, sudah benar untuk simpan file
|
||||||
|
}
|
||||||
|
|
||||||
|
createdClient, err := s.clientRepo.Create(ctx, tx, client)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return dto.ClientResponse{}, err
|
||||||
|
}
|
||||||
|
err = tx.Commit().Error
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return dto.ClientResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping entity ke response (Logo bisa dikonversi ke base64 jika perlu)
|
||||||
|
// logoBase64 := ""
|
||||||
|
// if len(createdClient.Logo) > 0 {
|
||||||
|
// logoBase64 = base64.StdEncoding.EncodeToString(createdClient.Logo)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return dto.ClientResponse{
|
||||||
|
ID: createdClient.ID.String(),
|
||||||
|
Name: createdClient.Name,
|
||||||
|
PIC: createdClient.PIC,
|
||||||
|
Phone: createdClient.Phone,
|
||||||
|
Email: createdClient.Email,
|
||||||
|
Address: createdClient.Address,
|
||||||
|
Logo: req.Logo,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientService) GetById(ctx context.Context, clientId string) (dto.ClientResponse, error) {
|
||||||
|
client, err := s.clientRepo.GetById(ctx, nil, clientId)
|
||||||
|
if err != nil {
|
||||||
|
return dto.ClientResponse{}, err
|
||||||
|
}
|
||||||
|
// logoBase64 := ""
|
||||||
|
// if len(client.Logo) > 0 {
|
||||||
|
// logoBase64 = base64.StdEncoding.EncodeToString(client.Logo)
|
||||||
|
// }
|
||||||
|
return dto.ClientResponse{
|
||||||
|
ID: client.ID.String(),
|
||||||
|
Name: client.Name,
|
||||||
|
PIC: client.PIC,
|
||||||
|
Phone: client.Phone,
|
||||||
|
Email: client.Email,
|
||||||
|
Address: client.Address,
|
||||||
|
Logo: client.Logo,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientService) GetByName(ctx context.Context, name string) (dto.ClientResponse, error) {
|
||||||
|
client, err := s.clientRepo.GetByName(ctx, nil, name)
|
||||||
|
if err != nil {
|
||||||
|
return dto.ClientResponse{}, err
|
||||||
|
}
|
||||||
|
// logoBase64 := ""
|
||||||
|
// if len(client.Logo) > 0 {
|
||||||
|
// logoBase64 = base64.StdEncoding.EncodeToString(client.Logo)
|
||||||
|
// }
|
||||||
|
return dto.ClientResponse{
|
||||||
|
ID: client.ID.String(),
|
||||||
|
Name: client.Name,
|
||||||
|
PIC: client.PIC,
|
||||||
|
Phone: client.Phone,
|
||||||
|
Email: client.Email,
|
||||||
|
Address: client.Address,
|
||||||
|
Logo: client.Logo,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientService) Update(ctx context.Context, req dto.ClientUpdateRequest, clientId string) (dto.ClientResponse, error) {
|
||||||
|
tx := s.db.Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
client, err := s.clientRepo.GetById(ctx, tx, clientId)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return dto.ClientResponse{}, err
|
||||||
|
}
|
||||||
|
if req.Name != nil {
|
||||||
|
client.Name = *req.Name
|
||||||
|
}
|
||||||
|
if req.PIC != nil {
|
||||||
|
client.PIC = *req.PIC
|
||||||
|
}
|
||||||
|
if req.Phone != nil {
|
||||||
|
client.Phone = *req.Phone
|
||||||
|
}
|
||||||
|
if req.Email != nil {
|
||||||
|
client.Email = *req.Email
|
||||||
|
}
|
||||||
|
if req.Address != nil {
|
||||||
|
client.Address = *req.Address
|
||||||
|
}
|
||||||
|
if req.Logo != nil {
|
||||||
|
client.Logo = *req.Logo
|
||||||
|
}
|
||||||
|
updatedClient, err := s.clientRepo.Update(ctx, tx, client)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return dto.ClientResponse{}, err
|
||||||
|
}
|
||||||
|
err = tx.Commit().Error
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return dto.ClientResponse{}, err
|
||||||
|
}
|
||||||
|
// logoBase64 := ""
|
||||||
|
// if len(updatedClient.Logo) > 0 {
|
||||||
|
// logoBase64 = base64.StdEncoding.EncodeToString(updatedClient.Logo)
|
||||||
|
// }
|
||||||
|
return dto.ClientResponse{
|
||||||
|
ID: updatedClient.ID.String(),
|
||||||
|
Name: updatedClient.Name,
|
||||||
|
PIC: updatedClient.PIC,
|
||||||
|
Phone: updatedClient.Phone,
|
||||||
|
Email: updatedClient.Email,
|
||||||
|
Address: updatedClient.Address,
|
||||||
|
Logo: updatedClient.Logo,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *clientService) Delete(ctx context.Context, clientId string) error {
|
||||||
|
tx := s.db.Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err := s.clientRepo.Delete(ctx, tx, clientId)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tx.Commit().Error
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClientService(clientRepo repository.ClientRepository, db *gorm.DB) ClientService {
|
||||||
|
return &clientService{
|
||||||
|
clientRepo: clientRepo,
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,9 @@ import (
|
||||||
"github.com/Caknoooo/go-gin-clean-starter/config"
|
"github.com/Caknoooo/go-gin-clean-starter/config"
|
||||||
authRepo "github.com/Caknoooo/go-gin-clean-starter/modules/auth/repository"
|
authRepo "github.com/Caknoooo/go-gin-clean-starter/modules/auth/repository"
|
||||||
"github.com/Caknoooo/go-gin-clean-starter/modules/auth/service"
|
"github.com/Caknoooo/go-gin-clean-starter/modules/auth/service"
|
||||||
|
clientController "github.com/Caknoooo/go-gin-clean-starter/modules/client/controller"
|
||||||
|
clientRepo "github.com/Caknoooo/go-gin-clean-starter/modules/client/repository"
|
||||||
|
clientService "github.com/Caknoooo/go-gin-clean-starter/modules/client/service"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
// productController "github.com/Caknoooo/go-gin-clean-starter/modules/product/controller"
|
// productController "github.com/Caknoooo/go-gin-clean-starter/modules/product/controller"
|
||||||
|
|
@ -58,8 +61,9 @@ func RegisterDependencies(injector *do.Injector) {
|
||||||
userRepository := repository.NewUserRepository(db)
|
userRepository := repository.NewUserRepository(db)
|
||||||
refreshTokenRepository := authRepo.NewRefreshTokenRepository(db)
|
refreshTokenRepository := authRepo.NewRefreshTokenRepository(db)
|
||||||
// productRepository := productRepo.NewProductRepository(db)
|
// productRepository := productRepo.NewProductRepository(db)
|
||||||
roleRepository := roleRepo.NewRoleRepository(db)
|
|
||||||
menuRepository := menuRepo.NewMenuRepository(db)
|
menuRepository := menuRepo.NewMenuRepository(db)
|
||||||
|
roleRepository := roleRepo.NewRoleRepository(db)
|
||||||
|
clientRepository := clientRepo.NewClientRepository(db)
|
||||||
maintenanceGroupRepository := maintGroupRepo.NewMaintGroupRepository(db)
|
maintenanceGroupRepository := maintGroupRepo.NewMaintGroupRepository(db)
|
||||||
maintenanceGroupRoleRepository := maintGroupRepoRole.NewMaintGroupRoleRepository(db)
|
maintenanceGroupRoleRepository := maintGroupRepoRole.NewMaintGroupRoleRepository(db)
|
||||||
maintenanceGroupRoleUserRepository := maintGroupRepoRoleUser.NewMaintGroupRoleUserRepository(db)
|
maintenanceGroupRoleUserRepository := maintGroupRepoRoleUser.NewMaintGroupRoleUserRepository(db)
|
||||||
|
|
@ -70,8 +74,14 @@ func RegisterDependencies(injector *do.Injector) {
|
||||||
roleService := roleService.NewRoleService(roleRepository, refreshTokenRepository, jwtService, userServ, db)
|
roleService := roleService.NewRoleService(roleRepository, refreshTokenRepository, jwtService, userServ, db)
|
||||||
menuSvc := menuService.NewMenuService(menuRepository, jwtService, db)
|
menuSvc := menuService.NewMenuService(menuRepository, jwtService, db)
|
||||||
maintenanceGroupServ := maintGroupService.NewMaintenanceGroupService(maintenanceGroupRepository, maintenanceGroupRoleRepository, maintenanceGroupRoleUserRepository, db)
|
maintenanceGroupServ := maintGroupService.NewMaintenanceGroupService(maintenanceGroupRepository, maintenanceGroupRoleRepository, maintenanceGroupRoleUserRepository, db)
|
||||||
|
clientServ := clientService.NewClientService(clientRepository, db)
|
||||||
|
|
||||||
// Controller
|
// Controller
|
||||||
|
do.Provide(
|
||||||
|
injector, func(i *do.Injector) (clientController.ClientController, error) {
|
||||||
|
return clientController.NewClientController(i, clientServ), nil
|
||||||
|
},
|
||||||
|
)
|
||||||
do.Provide(
|
do.Provide(
|
||||||
injector, func(i *do.Injector) (controller.UserController, error) {
|
injector, func(i *do.Injector) (controller.UserController, error) {
|
||||||
return controller.NewUserController(i, userServ), nil
|
return controller.NewUserController(i, userServ), nil
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue