feat&fix: add feature address and fixing some response format
This commit is contained in:
parent
2e8afdb365
commit
d997a75674
|
@ -42,6 +42,7 @@ func ConnectDatabase() {
|
|||
&model.User{},
|
||||
&model.Role{},
|
||||
&model.UserPin{},
|
||||
&model.Address{},
|
||||
// ==main feature==
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package dto
|
||||
|
||||
import "strings"
|
||||
|
||||
type AddressResponseDTO struct {
|
||||
UserID string `json:"user_id"`
|
||||
ID string `json:"address_id"`
|
||||
Province string `json:"province"`
|
||||
Regency string `json:"regency"`
|
||||
District string `json:"district"`
|
||||
Village string `json:"village"`
|
||||
PostalCode string `json:"postalCode"`
|
||||
Detail string `json:"detail"`
|
||||
Geography string `json:"geography"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type CreateAddressDTO struct {
|
||||
Province string `json:"province_id"`
|
||||
Regency string `json:"regency_id"`
|
||||
District string `json:"district_id"`
|
||||
Village string `json:"village_id"`
|
||||
PostalCode string `json:"postalCode"`
|
||||
Detail string `json:"detail"`
|
||||
Geography string `json:"geography"`
|
||||
}
|
||||
|
||||
func (r *CreateAddressDTO) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Province) == "" {
|
||||
errors["province_id"] = append(errors["province_id"], "Province ID is required")
|
||||
}
|
||||
if strings.TrimSpace(r.Regency) == "" {
|
||||
errors["regency_id"] = append(errors["regency_id"], "Regency ID is required")
|
||||
}
|
||||
if strings.TrimSpace(r.District) == "" {
|
||||
errors["district_id"] = append(errors["district_id"], "District ID is required")
|
||||
}
|
||||
if strings.TrimSpace(r.Village) == "" {
|
||||
errors["village_id"] = append(errors["village_id"], "Village ID is required")
|
||||
}
|
||||
if strings.TrimSpace(r.PostalCode) == "" {
|
||||
errors["postalCode"] = append(errors["village_id"], "PostalCode ID is required")
|
||||
} else if len(r.PostalCode) < 5 {
|
||||
errors["postalCode"] = append(errors["postalCode"], "kode pos belum sesuai")
|
||||
}
|
||||
if strings.TrimSpace(r.Detail) == "" {
|
||||
errors["detail"] = append(errors["detail"], "Detail address is required")
|
||||
}
|
||||
if strings.TrimSpace(r.Geography) == "" {
|
||||
errors["geography"] = append(errors["geography"], "Geographic coordinates are required")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/pahmiudahgede/senggoldong/dto"
|
||||
"github.com/pahmiudahgede/senggoldong/internal/services"
|
||||
"github.com/pahmiudahgede/senggoldong/utils"
|
||||
)
|
||||
|
||||
type AddressHandler struct {
|
||||
AddressService services.AddressService
|
||||
}
|
||||
|
||||
func NewAddressHandler(addressService services.AddressService) *AddressHandler {
|
||||
return &AddressHandler{AddressService: addressService}
|
||||
}
|
||||
|
||||
func (h *AddressHandler) CreateAddress(c *fiber.Ctx) error {
|
||||
var requestAddressDTO dto.CreateAddressDTO
|
||||
if err := c.BodyParser(&requestAddressDTO); err != nil {
|
||||
return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}})
|
||||
}
|
||||
|
||||
errors, valid := requestAddressDTO.Validate()
|
||||
if !valid {
|
||||
return utils.ValidationErrorResponse(c, errors)
|
||||
}
|
||||
|
||||
addressResponse, err := h.AddressService.CreateAddress(c.Locals("userID").(string), requestAddressDTO)
|
||||
if err != nil {
|
||||
return utils.GenericErrorResponse(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return utils.CreateResponse(c, addressResponse, "user address created successfully")
|
||||
}
|
|
@ -33,7 +33,7 @@ func (h *UserHandler) Login(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusUnauthorized, err.Error())
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, user, "Login successful")
|
||||
return utils.SuccessResponse(c, user, "Login successful")
|
||||
}
|
||||
|
||||
func (h *UserHandler) Register(c *fiber.Ctx) error {
|
||||
|
@ -67,7 +67,7 @@ func (h *UserHandler) Register(c *fiber.Ctx) error {
|
|||
UpdatedAt: updatedAt,
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, userResponse, "Registration successful")
|
||||
return utils.CreateResponse(c, userResponse, "Registration successful")
|
||||
}
|
||||
|
||||
func (h *UserHandler) Logout(c *fiber.Ctx) error {
|
||||
|
|
|
@ -26,7 +26,7 @@ func (h *RoleHandler) GetRoles(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, roles, "Roles fetched successfully")
|
||||
return utils.SuccessResponse(c, roles, "Roles fetched successfully")
|
||||
}
|
||||
|
||||
func (h *RoleHandler) GetRoleByID(c *fiber.Ctx) error {
|
||||
|
@ -42,5 +42,5 @@ func (h *RoleHandler) GetRoleByID(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusNotFound, "role id tidak ditemukan")
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, role, "Role fetched successfully")
|
||||
return utils.SuccessResponse(c, role, "Role fetched successfully")
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ func (h *UserProfileHandler) GetUserProfile(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusNotFound, err.Error())
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, userProfile, "User profile retrieved successfully")
|
||||
return utils.SuccessResponse(c, userProfile, "User profile retrieved successfully")
|
||||
}
|
||||
|
||||
func (h *UserProfileHandler) UpdateUserProfile(c *fiber.Ctx) error {
|
||||
|
@ -51,7 +51,7 @@ func (h *UserProfileHandler) UpdateUserProfile(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusConflict, err.Error())
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, userResponse, "User profile updated successfully")
|
||||
return utils.SuccessResponse(c, userResponse, "User profile updated successfully")
|
||||
}
|
||||
|
||||
func (h *UserProfileHandler) UpdateUserPassword(c *fiber.Ctx) error {
|
||||
|
@ -75,7 +75,7 @@ func (h *UserProfileHandler) UpdateUserPassword(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, userResponse, "Password updated successfully")
|
||||
return utils.SuccessResponse(c, userResponse, "Password updated successfully")
|
||||
}
|
||||
|
||||
func (h *UserProfileHandler) UpdateUserAvatar(c *fiber.Ctx) error {
|
||||
|
@ -94,5 +94,5 @@ func (h *UserProfileHandler) UpdateUserAvatar(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, userResponse, "Avatar updated successfully")
|
||||
return utils.SuccessResponse(c, userResponse, "Avatar updated successfully")
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ func (h *UserPinHandler) VerifyUserPin(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusUnauthorized, "pin yang anda masukkan salah")
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, map[string]string{"data": "pin yang anda masukkan benar"}, "Pin verification successful")
|
||||
return utils.SuccessResponse(c, map[string]string{"data": "pin yang anda masukkan benar"}, "Pin verification successful")
|
||||
}
|
||||
|
||||
func (h *UserPinHandler) CheckPinStatus(c *fiber.Ctx) error {
|
||||
|
@ -54,7 +54,7 @@ func (h *UserPinHandler) CheckPinStatus(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusBadRequest, "pin belum dibuat")
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, map[string]string{"data": "pin sudah dibuat"}, "Pin status retrieved successfully")
|
||||
return utils.SuccessResponse(c, map[string]string{"data": "pin sudah dibuat"}, "Pin status retrieved successfully")
|
||||
}
|
||||
|
||||
func (h *UserPinHandler) CreateUserPin(c *fiber.Ctx) error {
|
||||
|
@ -75,7 +75,7 @@ func (h *UserPinHandler) CreateUserPin(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusConflict, err.Error())
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, userPinResponse, "User pin created successfully")
|
||||
return utils.CreateResponse(c, userPinResponse, "User pin created successfully")
|
||||
}
|
||||
|
||||
func (h *UserPinHandler) UpdateUserPin(c *fiber.Ctx) error {
|
||||
|
@ -96,5 +96,5 @@ func (h *UserPinHandler) UpdateUserPin(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, userPinResponse, "User pin updated successfully")
|
||||
return utils.SuccessResponse(c, userPinResponse, "User pin updated successfully")
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ func (h *WilayahIndonesiaHandler) ImportWilayahData(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return utils.GenericErrorResponse(c, fiber.StatusCreated, "Data imported successfully")
|
||||
return utils.SuccessResponse(c, fiber.StatusCreated, "Data imported successfully")
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) GetProvinces(c *fiber.Ctx) error {
|
||||
|
@ -195,5 +195,5 @@ func (h *WilayahIndonesiaHandler) GetVillageByID(c *fiber.Ctx) error {
|
|||
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return utils.LogResponse(c, village, "Village fetched successfully")
|
||||
return utils.SuccessResponse(c, village, "Village fetched successfully")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package repositories
|
||||
|
||||
import (
|
||||
"github.com/pahmiudahgede/senggoldong/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type AddressRepository interface {
|
||||
CreateAddress(address *model.Address) error
|
||||
}
|
||||
|
||||
type addressRepository struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
func NewAddressRepository(db *gorm.DB) AddressRepository {
|
||||
return &addressRepository{DB: db}
|
||||
}
|
||||
|
||||
func (r *addressRepository) CreateAddress(address *model.Address) error {
|
||||
return r.DB.Create(address).Error
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pahmiudahgede/senggoldong/dto"
|
||||
"github.com/pahmiudahgede/senggoldong/internal/repositories"
|
||||
"github.com/pahmiudahgede/senggoldong/model"
|
||||
"github.com/pahmiudahgede/senggoldong/utils"
|
||||
)
|
||||
|
||||
type AddressService interface {
|
||||
CreateAddress(userID string, request dto.CreateAddressDTO) (*dto.AddressResponseDTO, error)
|
||||
}
|
||||
|
||||
type addressService struct {
|
||||
AddressRepo repositories.AddressRepository
|
||||
WilayahRepo repositories.WilayahIndonesiaRepository
|
||||
}
|
||||
|
||||
func NewAddressService(addressRepo repositories.AddressRepository, wilayahRepo repositories.WilayahIndonesiaRepository) AddressService {
|
||||
return &addressService{
|
||||
AddressRepo: addressRepo,
|
||||
WilayahRepo: wilayahRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *addressService) CreateAddress(userID string, request dto.CreateAddressDTO) (*dto.AddressResponseDTO, error) {
|
||||
|
||||
errors, valid := request.Validate()
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("validation failed: %v", errors)
|
||||
}
|
||||
|
||||
province, _, err := s.WilayahRepo.FindProvinceByID(request.Province, 0, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid province_id")
|
||||
}
|
||||
|
||||
regency, _, err := s.WilayahRepo.FindRegencyByID(request.Regency, 0, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid regency_id")
|
||||
}
|
||||
|
||||
district, _, err := s.WilayahRepo.FindDistrictByID(request.District, 0, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid district_id")
|
||||
}
|
||||
|
||||
village, err := s.WilayahRepo.FindVillageByID(request.Village)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid village_id")
|
||||
}
|
||||
|
||||
newAddress := &model.Address{
|
||||
UserID: userID,
|
||||
Province: province.Name,
|
||||
Regency: regency.Name,
|
||||
District: district.Name,
|
||||
Village: village.Name,
|
||||
PostalCode: request.PostalCode,
|
||||
Detail: request.Detail,
|
||||
Geography: request.Geography,
|
||||
}
|
||||
|
||||
err = s.AddressRepo.CreateAddress(newAddress)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create user address: %v", err)
|
||||
}
|
||||
|
||||
createdAt, _ := utils.FormatDateToIndonesianFormat(newAddress.CreatedAt)
|
||||
|
||||
addressResponse := &dto.AddressResponseDTO{
|
||||
UserID: newAddress.UserID,
|
||||
ID: newAddress.ID,
|
||||
Province: newAddress.Province,
|
||||
Regency: newAddress.Regency,
|
||||
District: newAddress.District,
|
||||
Village: newAddress.Village,
|
||||
PostalCode: newAddress.PostalCode,
|
||||
Detail: newAddress.Detail,
|
||||
Geography: newAddress.Geography,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: createdAt,
|
||||
}
|
||||
|
||||
return addressResponse, nil
|
||||
}
|
|
@ -3,16 +3,16 @@ package model
|
|||
import "time"
|
||||
|
||||
type Address struct {
|
||||
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"`
|
||||
UserID string `gorm:"not null" json:"userId"`
|
||||
User User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"user"`
|
||||
Province string `gorm:"not null" json:"province"`
|
||||
District string `gorm:"not null" json:"district"`
|
||||
Subdistrict string `gorm:"not null" json:"subdistrict"`
|
||||
PostalCode int `gorm:"not null" json:"postalCode"`
|
||||
Village string `gorm:"not null" json:"village"`
|
||||
Detail string `gorm:"not null" json:"detail"`
|
||||
Geography string `gorm:"not null" json:"geography"`
|
||||
CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"`
|
||||
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"`
|
||||
UserID string `gorm:"not null" json:"userId"`
|
||||
User User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"user"`
|
||||
Province string `gorm:"not null" json:"province"`
|
||||
Regency string `gorm:"not null" json:"regency"`
|
||||
District string `gorm:"not null" json:"district"`
|
||||
Village string `gorm:"not null" json:"village"`
|
||||
PostalCode string `gorm:"not null" json:"postalCode"`
|
||||
Detail string `gorm:"not null" json:"detail"`
|
||||
Geography string `gorm:"not null" json:"geography"`
|
||||
CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package presentation
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/pahmiudahgede/senggoldong/config"
|
||||
"github.com/pahmiudahgede/senggoldong/internal/handler"
|
||||
"github.com/pahmiudahgede/senggoldong/internal/repositories"
|
||||
"github.com/pahmiudahgede/senggoldong/internal/services"
|
||||
"github.com/pahmiudahgede/senggoldong/middleware"
|
||||
)
|
||||
|
||||
func AddressRouter(api fiber.Router) {
|
||||
addressRepo := repositories.NewAddressRepository(config.DB)
|
||||
wilayahRepo := repositories.NewWilayahIndonesiaRepository(config.DB)
|
||||
addressService := services.NewAddressService(addressRepo, wilayahRepo)
|
||||
addressHandler := handler.NewAddressHandler(addressService)
|
||||
|
||||
adddressAPI := api.Group("/user/address")
|
||||
|
||||
adddressAPI.Post("/create-address", middleware.AuthMiddleware, addressHandler.CreateAddress)
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
// presentation/role_route.go
|
||||
package presentation
|
||||
|
||||
import (
|
||||
|
|
|
@ -9,9 +9,11 @@ import (
|
|||
func SetupRoutes(app *fiber.App) {
|
||||
api := app.Group("/apirijikid")
|
||||
api.Use(middleware.APIKeyMiddleware)
|
||||
|
||||
presentation.AuthRouter(api)
|
||||
presentation.UserProfileRouter(api)
|
||||
presentation.UserPinRouter(api)
|
||||
presentation.RoleRouter(api)
|
||||
presentation.WilayahRouter(api)
|
||||
presentation.AddressRouter(api)
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ func GenericErrorResponse(c *fiber.Ctx, status int, message string) error {
|
|||
return c.Status(status).JSON(response)
|
||||
}
|
||||
|
||||
func LogResponse(c *fiber.Ctx, data interface{}, message string) error {
|
||||
func SuccessResponse(c *fiber.Ctx, data interface{}, message string) error {
|
||||
response := APIResponse{
|
||||
Meta: MetaData{
|
||||
Status: fiber.StatusOK,
|
||||
|
@ -94,3 +94,14 @@ func LogResponse(c *fiber.Ctx, data interface{}, message string) error {
|
|||
}
|
||||
return c.Status(fiber.StatusOK).JSON(response)
|
||||
}
|
||||
|
||||
func CreateResponse(c *fiber.Ctx, data interface{}, message string) error {
|
||||
response := APIResponse{
|
||||
Meta: MetaData{
|
||||
Status: fiber.StatusCreated,
|
||||
Message: message,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(response)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue