feat: add feature trash data
This commit is contained in:
parent
8f475d1a0b
commit
36595caebb
|
@ -46,6 +46,8 @@ func ConnectDatabase() {
|
|||
&model.Article{},
|
||||
&model.Banner{},
|
||||
&model.InitialCoint{},
|
||||
&model.TrashCategory{},
|
||||
&model.TrashDetail{},
|
||||
// ==main feature==
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package dto
|
||||
|
||||
import "strings"
|
||||
|
||||
type RequestTrashCategoryDTO struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ResponseTrashCategoryDTO struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
Details []ResponseTrashDetailDTO `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
type ResponseTrashDetailDTO struct {
|
||||
ID string `json:"id"`
|
||||
CategoryID string `json:"category_id"`
|
||||
Description string `json:"description"`
|
||||
Price float64 `json:"price"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type RequestTrashDetailDTO struct {
|
||||
CategoryID string `json:"category_id"`
|
||||
Description string `json:"description"`
|
||||
Price float64 `json:"price"`
|
||||
}
|
||||
|
||||
func (r *RequestTrashCategoryDTO) ValidateTrashCategoryInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Name) == "" {
|
||||
errors["name"] = append(errors["name"], "name is required")
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func (r *RequestTrashDetailDTO) ValidateTrashDetailInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Description) == "" {
|
||||
errors["description"] = append(errors["description"], "description is required")
|
||||
}
|
||||
if r.Price <= 0 {
|
||||
errors["price"] = append(errors["price"], "price must be greater than 0")
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
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 TrashHandler struct {
|
||||
TrashService services.TrashService
|
||||
}
|
||||
|
||||
func NewTrashHandler(trashService services.TrashService) *TrashHandler {
|
||||
return &TrashHandler{TrashService: trashService}
|
||||
}
|
||||
|
||||
func (h *TrashHandler) CreateCategory(c *fiber.Ctx) error {
|
||||
var request dto.RequestTrashCategoryDTO
|
||||
if err := c.BodyParser(&request); err != nil {
|
||||
return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}})
|
||||
}
|
||||
|
||||
categoryResponse, err := h.TrashService.CreateCategory(request)
|
||||
if err != nil {
|
||||
return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to create category: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.CreateResponse(c, categoryResponse, "Category created successfully")
|
||||
}
|
||||
|
||||
func (h *TrashHandler) AddDetailToCategory(c *fiber.Ctx) error {
|
||||
var request dto.RequestTrashDetailDTO
|
||||
if err := c.BodyParser(&request); err != nil {
|
||||
return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}})
|
||||
}
|
||||
|
||||
detailResponse, err := h.TrashService.AddDetailToCategory(request)
|
||||
if err != nil {
|
||||
return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to add detail to category: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.CreateResponse(c, detailResponse, "Trash detail added successfully")
|
||||
}
|
||||
|
||||
func (h *TrashHandler) GetCategories(c *fiber.Ctx) error {
|
||||
|
||||
categories, err := h.TrashService.GetCategories()
|
||||
if err != nil {
|
||||
return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch categories: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.NonPaginatedResponse(c, categories, len(categories), "Categories retrieved successfully")
|
||||
}
|
||||
|
||||
func (h *TrashHandler) GetCategoryByID(c *fiber.Ctx) error {
|
||||
id := c.Params("category_id")
|
||||
|
||||
category, err := h.TrashService.GetCategoryByID(id)
|
||||
if err != nil {
|
||||
return utils.GenericResponse(c, fiber.StatusNotFound, "Category not found: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.SuccessResponse(c, category, "Category retrieved successfully")
|
||||
}
|
||||
|
||||
func (h *TrashHandler) GetTrashDetailByID(c *fiber.Ctx) error {
|
||||
id := c.Params("detail_id")
|
||||
|
||||
detail, err := h.TrashService.GetTrashDetailByID(id)
|
||||
if err != nil {
|
||||
return utils.GenericResponse(c, fiber.StatusNotFound, "Trash detail not found: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.SuccessResponse(c, detail, "Trash detail retrieved successfully")
|
||||
}
|
||||
|
||||
func (h *TrashHandler) UpdateCategory(c *fiber.Ctx) error {
|
||||
id := c.Params("category_id")
|
||||
|
||||
var request dto.RequestTrashCategoryDTO
|
||||
if err := c.BodyParser(&request); err != nil {
|
||||
return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid request body"}})
|
||||
}
|
||||
|
||||
updatedCategory, err := h.TrashService.UpdateCategory(id, request)
|
||||
if err != nil {
|
||||
return utils.GenericResponse(c, fiber.StatusInternalServerError, "Error updating category: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.SuccessResponse(c, updatedCategory, "Category updated successfully")
|
||||
}
|
||||
|
||||
func (h *TrashHandler) UpdateDetail(c *fiber.Ctx) error {
|
||||
id := c.Params("detail_id")
|
||||
|
||||
var request dto.RequestTrashDetailDTO
|
||||
if err := c.BodyParser(&request); err != nil {
|
||||
return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid request body"}})
|
||||
}
|
||||
|
||||
updatedDetail, err := h.TrashService.UpdateDetail(id, request)
|
||||
if err != nil {
|
||||
return utils.GenericResponse(c, fiber.StatusInternalServerError, "Error updating detail: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.SuccessResponse(c, updatedDetail, "Trash detail updated successfully")
|
||||
}
|
||||
|
||||
func (h *TrashHandler) DeleteCategory(c *fiber.Ctx) error {
|
||||
id := c.Params("category_id")
|
||||
|
||||
if err := h.TrashService.DeleteCategory(id); err != nil {
|
||||
return utils.GenericResponse(c, fiber.StatusInternalServerError, "Error deleting category: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.GenericResponse(c, fiber.StatusOK, "Category deleted successfully")
|
||||
}
|
||||
|
||||
func (h *TrashHandler) DeleteDetail(c *fiber.Ctx) error {
|
||||
id := c.Params("detail_id")
|
||||
|
||||
if err := h.TrashService.DeleteDetail(id); err != nil {
|
||||
return utils.GenericResponse(c, fiber.StatusInternalServerError, "Error deleting detail: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.GenericResponse(c, fiber.StatusOK, "Trash detail deleted successfully")
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package repositories
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pahmiudahgede/senggoldong/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TrashRepository interface {
|
||||
CreateCategory(category *model.TrashCategory) error
|
||||
AddDetailToCategory(detail *model.TrashDetail) error
|
||||
GetCategories() ([]model.TrashCategory, error)
|
||||
GetCategoryByID(id string) (*model.TrashCategory, error)
|
||||
GetTrashDetailByID(id string) (*model.TrashDetail, error)
|
||||
UpdateCategoryName(id string, newName string) error
|
||||
UpdateTrashDetail(id string, description string, price float64) error
|
||||
DeleteCategory(id string) error
|
||||
DeleteTrashDetail(id string) error
|
||||
}
|
||||
|
||||
type trashRepository struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
func NewTrashRepository(db *gorm.DB) TrashRepository {
|
||||
return &trashRepository{DB: db}
|
||||
}
|
||||
|
||||
func (r *trashRepository) CreateCategory(category *model.TrashCategory) error {
|
||||
if err := r.DB.Create(category).Error; err != nil {
|
||||
return fmt.Errorf("failed to create category: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *trashRepository) AddDetailToCategory(detail *model.TrashDetail) error {
|
||||
if err := r.DB.Create(detail).Error; err != nil {
|
||||
return fmt.Errorf("failed to add detail to category: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *trashRepository) GetCategories() ([]model.TrashCategory, error) {
|
||||
var categories []model.TrashCategory
|
||||
if err := r.DB.Preload("Details").Find(&categories).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch categories: %v", err)
|
||||
}
|
||||
return categories, nil
|
||||
}
|
||||
|
||||
func (r *trashRepository) GetCategoryByID(id string) (*model.TrashCategory, error) {
|
||||
var category model.TrashCategory
|
||||
|
||||
if err := r.DB.Preload("Details").First(&category, "id = ?", id).Error; err != nil {
|
||||
return nil, fmt.Errorf("category not found: %v", err)
|
||||
}
|
||||
return &category, nil
|
||||
}
|
||||
|
||||
func (r *trashRepository) GetTrashDetailByID(id string) (*model.TrashDetail, error) {
|
||||
var detail model.TrashDetail
|
||||
if err := r.DB.First(&detail, "id = ?", id).Error; err != nil {
|
||||
return nil, fmt.Errorf("trash detail not found: %v", err)
|
||||
}
|
||||
return &detail, nil
|
||||
}
|
||||
|
||||
func (r *trashRepository) UpdateCategoryName(id string, newName string) error {
|
||||
if err := r.DB.Model(&model.TrashCategory{}).Where("id = ?", id).Update("name", newName).Error; err != nil {
|
||||
return fmt.Errorf("failed to update category name: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *trashRepository) UpdateTrashDetail(id string, description string, price float64) error {
|
||||
if err := r.DB.Model(&model.TrashDetail{}).Where("id = ?", id).Updates(model.TrashDetail{Description: description, Price: price}).Error; err != nil {
|
||||
return fmt.Errorf("failed to update trash detail: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *trashRepository) DeleteCategory(id string) error {
|
||||
if err := r.DB.Delete(&model.TrashCategory{}, "id = ?", id).Error; err != nil {
|
||||
return fmt.Errorf("failed to delete category: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *trashRepository) DeleteTrashDetail(id string) error {
|
||||
if err := r.DB.Delete(&model.TrashDetail{}, "id = ?", id).Error; err != nil {
|
||||
return fmt.Errorf("failed to delete trash detail: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,465 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pahmiudahgede/senggoldong/dto"
|
||||
"github.com/pahmiudahgede/senggoldong/internal/repositories"
|
||||
"github.com/pahmiudahgede/senggoldong/model"
|
||||
"github.com/pahmiudahgede/senggoldong/utils"
|
||||
)
|
||||
|
||||
type TrashService interface {
|
||||
CreateCategory(request dto.RequestTrashCategoryDTO) (*dto.ResponseTrashCategoryDTO, error)
|
||||
AddDetailToCategory(request dto.RequestTrashDetailDTO) (*dto.ResponseTrashDetailDTO, error)
|
||||
|
||||
GetCategories() ([]dto.ResponseTrashCategoryDTO, error)
|
||||
GetCategoryByID(id string) (*dto.ResponseTrashCategoryDTO, error)
|
||||
GetTrashDetailByID(id string) (*dto.ResponseTrashDetailDTO, error)
|
||||
|
||||
UpdateCategory(id string, request dto.RequestTrashCategoryDTO) (*dto.ResponseTrashCategoryDTO, error)
|
||||
UpdateDetail(id string, request dto.RequestTrashDetailDTO) (*dto.ResponseTrashDetailDTO, error)
|
||||
|
||||
DeleteCategory(id string) error
|
||||
DeleteDetail(id string) error
|
||||
}
|
||||
|
||||
type trashService struct {
|
||||
TrashRepo repositories.TrashRepository
|
||||
}
|
||||
|
||||
func NewTrashService(trashRepo repositories.TrashRepository) TrashService {
|
||||
return &trashService{TrashRepo: trashRepo}
|
||||
}
|
||||
|
||||
func (s *trashService) CreateCategory(request dto.RequestTrashCategoryDTO) (*dto.ResponseTrashCategoryDTO, error) {
|
||||
errors, valid := request.ValidateTrashCategoryInput()
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("validation error: %v", errors)
|
||||
}
|
||||
|
||||
category := model.TrashCategory{
|
||||
Name: request.Name,
|
||||
}
|
||||
|
||||
if err := s.TrashRepo.CreateCategory(&category); err != nil {
|
||||
return nil, fmt.Errorf("failed to create category: %v", err)
|
||||
}
|
||||
|
||||
categoryResponseDTO := &dto.ResponseTrashCategoryDTO{
|
||||
ID: category.ID,
|
||||
Name: category.Name,
|
||||
CreatedAt: category.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: category.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
if err := s.CacheCategoryAndDetails(category.ID, categoryResponseDTO, category.Details, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching category: %v\n", err)
|
||||
}
|
||||
|
||||
categories, err := s.TrashRepo.GetCategories()
|
||||
if err == nil {
|
||||
var categoriesDTO []dto.ResponseTrashCategoryDTO
|
||||
for _, c := range categories {
|
||||
categoriesDTO = append(categoriesDTO, dto.ResponseTrashCategoryDTO{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
CreatedAt: c.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: c.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
if err := s.CacheCategoryList(categoriesDTO, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching all categories: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
return categoryResponseDTO, nil
|
||||
}
|
||||
|
||||
func (s *trashService) AddDetailToCategory(request dto.RequestTrashDetailDTO) (*dto.ResponseTrashDetailDTO, error) {
|
||||
errors, valid := request.ValidateTrashDetailInput()
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("validation error: %v", errors)
|
||||
}
|
||||
|
||||
detail := model.TrashDetail{
|
||||
CategoryID: request.CategoryID,
|
||||
Description: request.Description,
|
||||
Price: request.Price,
|
||||
}
|
||||
|
||||
if err := s.TrashRepo.AddDetailToCategory(&detail); err != nil {
|
||||
return nil, fmt.Errorf("failed to add detail to category: %v", err)
|
||||
}
|
||||
|
||||
detailResponseDTO := &dto.ResponseTrashDetailDTO{
|
||||
ID: detail.ID,
|
||||
CategoryID: detail.CategoryID,
|
||||
Description: detail.Description,
|
||||
Price: detail.Price,
|
||||
CreatedAt: detail.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: detail.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
cacheKey := fmt.Sprintf("detail:%s", detail.ID)
|
||||
cacheData := map[string]interface{}{
|
||||
"data": detailResponseDTO,
|
||||
}
|
||||
if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching detail: %v\n", err)
|
||||
}
|
||||
|
||||
category, err := s.TrashRepo.GetCategoryByID(detail.CategoryID)
|
||||
if err == nil {
|
||||
categoryResponseDTO := &dto.ResponseTrashCategoryDTO{
|
||||
ID: category.ID,
|
||||
Name: category.Name,
|
||||
CreatedAt: category.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: category.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
if err := s.CacheCategoryAndDetails(detail.CategoryID, categoryResponseDTO, category.Details, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching updated category: %v\n", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Error fetching category for cache update: %v\n", err)
|
||||
}
|
||||
|
||||
return detailResponseDTO, nil
|
||||
}
|
||||
|
||||
func (s *trashService) GetCategories() ([]dto.ResponseTrashCategoryDTO, error) {
|
||||
|
||||
cacheKey := "categories:all"
|
||||
cachedCategories, err := utils.GetJSONData(cacheKey)
|
||||
if err == nil && cachedCategories != nil {
|
||||
var categoriesDTO []dto.ResponseTrashCategoryDTO
|
||||
for _, category := range cachedCategories["data"].([]interface{}) {
|
||||
categoryData := category.(map[string]interface{})
|
||||
categoriesDTO = append(categoriesDTO, dto.ResponseTrashCategoryDTO{
|
||||
ID: categoryData["id"].(string),
|
||||
Name: categoryData["name"].(string),
|
||||
CreatedAt: categoryData["createdAt"].(string),
|
||||
UpdatedAt: categoryData["updatedAt"].(string),
|
||||
})
|
||||
}
|
||||
return categoriesDTO, nil
|
||||
}
|
||||
|
||||
categories, err := s.TrashRepo.GetCategories()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch categories: %v", err)
|
||||
}
|
||||
|
||||
var categoriesDTO []dto.ResponseTrashCategoryDTO
|
||||
for _, category := range categories {
|
||||
categoriesDTO = append(categoriesDTO, dto.ResponseTrashCategoryDTO{
|
||||
ID: category.ID,
|
||||
Name: category.Name,
|
||||
CreatedAt: category.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: category.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
cacheData := map[string]interface{}{
|
||||
"data": categoriesDTO,
|
||||
}
|
||||
if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching categories: %v\n", err)
|
||||
}
|
||||
|
||||
return categoriesDTO, nil
|
||||
}
|
||||
|
||||
func (s *trashService) GetCategoryByID(id string) (*dto.ResponseTrashCategoryDTO, error) {
|
||||
|
||||
cacheKey := fmt.Sprintf("category:%s", id)
|
||||
cachedCategory, err := utils.GetJSONData(cacheKey)
|
||||
if err == nil && cachedCategory != nil {
|
||||
categoryData := cachedCategory["data"].(map[string]interface{})
|
||||
return &dto.ResponseTrashCategoryDTO{
|
||||
ID: categoryData["id"].(string),
|
||||
Name: categoryData["name"].(string),
|
||||
CreatedAt: categoryData["createdAt"].(string),
|
||||
UpdatedAt: categoryData["updatedAt"].(string),
|
||||
Details: mapDetails(cachedCategory["details"]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
category, err := s.TrashRepo.GetCategoryByID(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("category not found: %v", err)
|
||||
}
|
||||
|
||||
categoryDTO := &dto.ResponseTrashCategoryDTO{
|
||||
ID: category.ID,
|
||||
Name: category.Name,
|
||||
CreatedAt: category.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: category.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
if category.Details != nil {
|
||||
var detailsDTO []dto.ResponseTrashDetailDTO
|
||||
for _, detail := range category.Details {
|
||||
detailsDTO = append(detailsDTO, dto.ResponseTrashDetailDTO{
|
||||
ID: detail.ID,
|
||||
CategoryID: detail.CategoryID,
|
||||
Description: detail.Description,
|
||||
Price: detail.Price,
|
||||
CreatedAt: detail.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: detail.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
categoryDTO.Details = detailsDTO
|
||||
}
|
||||
|
||||
if err := s.CacheCategoryAndDetails(category.ID, categoryDTO, categoryDTO.Details, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching category and details: %v\n", err)
|
||||
}
|
||||
|
||||
return categoryDTO, nil
|
||||
}
|
||||
|
||||
func (s *trashService) GetTrashDetailByID(id string) (*dto.ResponseTrashDetailDTO, error) {
|
||||
|
||||
cacheKey := fmt.Sprintf("detail:%s", id)
|
||||
cachedDetail, err := utils.GetJSONData(cacheKey)
|
||||
if err == nil && cachedDetail != nil {
|
||||
detailData := cachedDetail["data"].(map[string]interface{})
|
||||
return &dto.ResponseTrashDetailDTO{
|
||||
ID: detailData["id"].(string),
|
||||
CategoryID: detailData["category_id"].(string),
|
||||
Description: detailData["description"].(string),
|
||||
Price: detailData["price"].(float64),
|
||||
CreatedAt: detailData["createdAt"].(string),
|
||||
UpdatedAt: detailData["updatedAt"].(string),
|
||||
}, nil
|
||||
}
|
||||
|
||||
detail, err := s.TrashRepo.GetTrashDetailByID(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("trash detail not found: %v", err)
|
||||
}
|
||||
|
||||
detailDTO := &dto.ResponseTrashDetailDTO{
|
||||
ID: detail.ID,
|
||||
CategoryID: detail.CategoryID,
|
||||
Description: detail.Description,
|
||||
Price: detail.Price,
|
||||
CreatedAt: detail.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: detail.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
cacheData := map[string]interface{}{
|
||||
"data": detailDTO,
|
||||
}
|
||||
if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil {
|
||||
fmt.Printf("Error caching detail: %v\n", err)
|
||||
}
|
||||
|
||||
return detailDTO, nil
|
||||
}
|
||||
|
||||
func (s *trashService) UpdateCategory(id string, request dto.RequestTrashCategoryDTO) (*dto.ResponseTrashCategoryDTO, error) {
|
||||
errors, valid := request.ValidateTrashCategoryInput()
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("validation error: %v", errors)
|
||||
}
|
||||
|
||||
if err := s.TrashRepo.UpdateCategoryName(id, request.Name); err != nil {
|
||||
return nil, fmt.Errorf("failed to update category: %v", err)
|
||||
}
|
||||
|
||||
category, err := s.TrashRepo.GetCategoryByID(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("category not found: %v", err)
|
||||
}
|
||||
|
||||
categoryResponseDTO := &dto.ResponseTrashCategoryDTO{
|
||||
ID: category.ID,
|
||||
Name: category.Name,
|
||||
CreatedAt: category.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: category.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
if err := s.CacheCategoryAndDetails(category.ID, categoryResponseDTO, category.Details, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching updated category: %v\n", err)
|
||||
}
|
||||
|
||||
allCategories, err := s.TrashRepo.GetCategories()
|
||||
if err == nil {
|
||||
var categoriesDTO []dto.ResponseTrashCategoryDTO
|
||||
for _, c := range allCategories {
|
||||
categoriesDTO = append(categoriesDTO, dto.ResponseTrashCategoryDTO{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
CreatedAt: c.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: c.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
if err := s.CacheCategoryList(categoriesDTO, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching all categories: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
return categoryResponseDTO, nil
|
||||
}
|
||||
|
||||
func (s *trashService) UpdateDetail(id string, request dto.RequestTrashDetailDTO) (*dto.ResponseTrashDetailDTO, error) {
|
||||
errors, valid := request.ValidateTrashDetailInput()
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("validation error: %v", errors)
|
||||
}
|
||||
|
||||
if err := s.TrashRepo.UpdateTrashDetail(id, request.Description, request.Price); err != nil {
|
||||
return nil, fmt.Errorf("failed to update detail: %v", err)
|
||||
}
|
||||
|
||||
detail, err := s.TrashRepo.GetTrashDetailByID(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("trash detail not found: %v", err)
|
||||
}
|
||||
|
||||
detailResponseDTO := &dto.ResponseTrashDetailDTO{
|
||||
ID: detail.ID,
|
||||
CategoryID: detail.CategoryID,
|
||||
Description: detail.Description,
|
||||
Price: detail.Price,
|
||||
CreatedAt: detail.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: detail.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
cacheKey := fmt.Sprintf("detail:%s", detail.ID)
|
||||
cacheData := map[string]interface{}{
|
||||
"data": detailResponseDTO,
|
||||
}
|
||||
if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching updated detail: %v\n", err)
|
||||
}
|
||||
|
||||
category, err := s.TrashRepo.GetCategoryByID(detail.CategoryID)
|
||||
if err == nil {
|
||||
categoryResponseDTO := &dto.ResponseTrashCategoryDTO{
|
||||
ID: category.ID,
|
||||
Name: category.Name,
|
||||
CreatedAt: category.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: category.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
if err := s.CacheCategoryAndDetails(detail.CategoryID, categoryResponseDTO, category.Details, time.Hour*6); err != nil {
|
||||
fmt.Printf("Error caching updated category: %v\n", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Error fetching category for cache update: %v\n", err)
|
||||
}
|
||||
|
||||
return detailResponseDTO, nil
|
||||
}
|
||||
|
||||
func (s *trashService) DeleteCategory(id string) error {
|
||||
|
||||
if err := s.TrashRepo.DeleteCategory(id); err != nil {
|
||||
return fmt.Errorf("failed to delete category: %v", err)
|
||||
}
|
||||
|
||||
cacheKey := fmt.Sprintf("category:%s", id)
|
||||
if err := utils.DeleteData(cacheKey); err != nil {
|
||||
fmt.Printf("Error clearing cache for deleted category: %v\n", err)
|
||||
}
|
||||
|
||||
allCategoriesCacheKey := "categories:all"
|
||||
if err := utils.DeleteData(allCategoriesCacheKey); err != nil {
|
||||
fmt.Printf("Error clearing categories list cache: %v\n", err)
|
||||
}
|
||||
|
||||
category, err := s.TrashRepo.GetCategoryByID(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("category not found after deletion: %v", err)
|
||||
}
|
||||
|
||||
if category.Details != nil {
|
||||
for _, detail := range category.Details {
|
||||
detailCacheKey := fmt.Sprintf("detail:%s", detail.ID)
|
||||
|
||||
if err := utils.DeleteData(detailCacheKey); err != nil {
|
||||
fmt.Printf("Error clearing cache for deleted detail: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *trashService) DeleteDetail(id string) error {
|
||||
|
||||
detail, err := s.TrashRepo.GetTrashDetailByID(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("trash detail not found: %v", err)
|
||||
}
|
||||
|
||||
if err := s.TrashRepo.DeleteTrashDetail(id); err != nil {
|
||||
return fmt.Errorf("failed to delete detail: %v", err)
|
||||
}
|
||||
|
||||
cacheKey := fmt.Sprintf("detail:%s", id)
|
||||
if err := utils.DeleteData(cacheKey); err != nil {
|
||||
fmt.Printf("Error clearing cache for deleted detail: %v\n", err)
|
||||
}
|
||||
|
||||
categoryCacheKey := fmt.Sprintf("category:%s", detail.CategoryID)
|
||||
if err := utils.DeleteData(categoryCacheKey); err != nil {
|
||||
fmt.Printf("Error clearing cache for category after detail deletion: %v\n", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mapDetails(details interface{}) []dto.ResponseTrashDetailDTO {
|
||||
var detailsDTO []dto.ResponseTrashDetailDTO
|
||||
if details != nil {
|
||||
for _, detail := range details.([]interface{}) {
|
||||
detailData := detail.(map[string]interface{})
|
||||
detailsDTO = append(detailsDTO, dto.ResponseTrashDetailDTO{
|
||||
ID: detailData["id"].(string),
|
||||
CategoryID: detailData["category_id"].(string),
|
||||
Description: detailData["description"].(string),
|
||||
Price: detailData["price"].(float64),
|
||||
CreatedAt: detailData["createdAt"].(string),
|
||||
UpdatedAt: detailData["updatedAt"].(string),
|
||||
})
|
||||
}
|
||||
}
|
||||
return detailsDTO
|
||||
}
|
||||
|
||||
func (s *trashService) CacheCategoryAndDetails(categoryID string, categoryData interface{}, detailsData interface{}, expiration time.Duration) error {
|
||||
cacheKey := fmt.Sprintf("category:%s", categoryID)
|
||||
cacheData := map[string]interface{}{
|
||||
"data": categoryData,
|
||||
"details": detailsData,
|
||||
}
|
||||
|
||||
err := utils.SetJSONData(cacheKey, cacheData, expiration)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error caching category and details: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *trashService) CacheCategoryList(categoriesData interface{}, expiration time.Duration) error {
|
||||
cacheKey := "categories:all"
|
||||
cacheData := map[string]interface{}{
|
||||
"data": categoriesData,
|
||||
}
|
||||
|
||||
err := utils.SetJSONData(cacheKey, cacheData, expiration)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error caching categories list: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type TrashCategory struct {
|
||||
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"`
|
||||
Name string `gorm:"not null" json:"name"`
|
||||
Details []TrashDetail `gorm:"foreignKey:CategoryID;constraint:OnDelete:CASCADE;" json:"details"`
|
||||
CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"`
|
||||
}
|
||||
|
||||
type TrashDetail struct {
|
||||
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"`
|
||||
CategoryID string `gorm:"type:uuid;not null" json:"category_id"`
|
||||
Description string `gorm:"not null" json:"description"`
|
||||
Price float64 `gorm:"not null" json:"price"`
|
||||
CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"`
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
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"
|
||||
"github.com/pahmiudahgede/senggoldong/utils"
|
||||
)
|
||||
|
||||
func TrashRouter(api fiber.Router) {
|
||||
|
||||
trashRepo := repositories.NewTrashRepository(config.DB)
|
||||
trashService := services.NewTrashService(trashRepo)
|
||||
trashHandler := handler.NewTrashHandler(trashService)
|
||||
|
||||
trashAPI := api.Group("/trash")
|
||||
|
||||
trashAPI.Post("/createcategory-with-details", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator), trashHandler.CreateCategory)
|
||||
trashAPI.Post("/add-detailinexistingcategory", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator), trashHandler.AddDetailToCategory)
|
||||
trashAPI.Get("/allcategory", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator, utils.RolePengelola, utils.RolePengepul), trashHandler.GetCategories)
|
||||
trashAPI.Get("/category/:category_id", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator, utils.RolePengelola, utils.RolePengepul), trashHandler.GetCategoryByID)
|
||||
trashAPI.Get("/detail/:detail_id", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator, utils.RolePengelola, utils.RolePengepul), trashHandler.GetTrashDetailByID)
|
||||
|
||||
trashAPI.Patch("/update-category/:category_id", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator), trashHandler.UpdateCategory)
|
||||
trashAPI.Put("/update-detail/:detail_id", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator), trashHandler.UpdateDetail)
|
||||
|
||||
trashAPI.Delete("delete-category/:category_id", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator), trashHandler.DeleteCategory)
|
||||
trashAPI.Delete("delete-detail/:detail_id", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator), trashHandler.DeleteDetail)
|
||||
}
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
func SetupRoutes(app *fiber.App) {
|
||||
api := app.Group("/apirijikid")
|
||||
api := app.Group("/apirijikid/v2")
|
||||
api.Use(middleware.APIKeyMiddleware)
|
||||
|
||||
presentation.AuthRouter(api)
|
||||
|
@ -19,4 +19,5 @@ func SetupRoutes(app *fiber.App) {
|
|||
presentation.ArticleRouter(api)
|
||||
presentation.BannerRouter(api)
|
||||
presentation.InitialCointRoute(api)
|
||||
presentation.TrashRouter(api)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue