feat: update all cms modules
This commit is contained in:
parent
0987814407
commit
706b3a4585
|
|
@ -11,8 +11,7 @@ type AboutUsContentImage struct {
|
|||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
|
||||
// relation (optional tapi bagus)
|
||||
AboutUsContent AboutUsContent `json:"about_us_content" gorm:"foreignKey:AboutUsContentID"`
|
||||
AboutUsContent AboutUsContent `json:"-" gorm:"foreignKey:AboutUsContentID"`
|
||||
}
|
||||
|
||||
func (AboutUsContentImage) TableName() string {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ type AboutUsContent struct {
|
|||
IsActive *bool `json:"is_active" gorm:"type:bool;default:true"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
|
||||
Images []AboutUsContentImage `json:"images,omitempty" gorm:"foreignKey:AboutUsContentID"`
|
||||
}
|
||||
|
||||
func (AboutUsContent) TableName() string {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
type HeroContents struct {
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;default:uuid_generate_v4()"`
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
|
||||
PrimaryTitle string `json:"primary_title" gorm:"type:varchar(255)"`
|
||||
SecondaryTitle string `json:"secondary_title" gorm:"type:varchar(255)"`
|
||||
Description string `json:"description" gorm:"type:text"`
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
type HeroContentImages struct {
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;default:uuid_generate_v4()"`
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
|
||||
HeroContentID uuid.UUID `json:"hero_content_id" gorm:"type:uuid;not null"`
|
||||
ImagePath string `json:"image_path" gorm:"type:text"`
|
||||
ImageURL string `json:"image_url" gorm:"type:text"`
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
)
|
||||
|
||||
type OurProductContentImage struct {
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;default:uuid_generate_v4()"`
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
|
||||
OurProductContentID uuid.UUID `json:"our_product_content_id" gorm:"type:uuid"`
|
||||
ImagePath string `json:"image_path" gorm:"type:varchar(255)"`
|
||||
ImageURL string `json:"image_url" gorm:"type:text"`
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
type OurProductContent struct {
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;default:uuid_generate_v4()"`
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
|
||||
PrimaryTitle string `json:"primary_title" gorm:"type:varchar(255)"`
|
||||
SecondaryTitle string `json:"secondary_title" gorm:"type:varchar(255)"`
|
||||
Description string `json:"description" gorm:"type:text"`
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
type PartnerContent struct {
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;default:uuid_generate_v4()"`
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
|
||||
PrimaryTitle string `json:"primary_title" gorm:"type:varchar(255)"`
|
||||
ImagePath string `json:"image_path" gorm:"type:varchar(255)"`
|
||||
ImageURL string `json:"image_url" gorm:"type:text"`
|
||||
|
|
|
|||
|
|
@ -103,13 +103,13 @@ func Models() []interface{} {
|
|||
entity.Bookmarks{},
|
||||
entity.Cities{},
|
||||
entity.Clients{},
|
||||
entity.HeroContents{},
|
||||
entity.HeroContentImages{},
|
||||
entity.ClientApprovalSettings{},
|
||||
entity.CsrfTokenRecords{},
|
||||
entity.CustomStaticPages{},
|
||||
entity.Districts{},
|
||||
entity.Feedbacks{},
|
||||
entity.HeroContents{},
|
||||
entity.HeroContentImages{},
|
||||
entity.ForgotPasswords{},
|
||||
entity.Magazines{},
|
||||
entity.MagazineFiles{},
|
||||
|
|
@ -121,7 +121,11 @@ func Models() []interface{} {
|
|||
entity.OneTimePasswords{},
|
||||
entity.OurProductContent{},
|
||||
entity.OurProductContentImage{},
|
||||
entity.OurServiceContent{},
|
||||
entity.OurServiceContentImage{},
|
||||
entity.PartnerContent{},
|
||||
entity.PopupNewsContents{},
|
||||
entity.PopupNewsContentImages{},
|
||||
entity.Subscription{},
|
||||
entity.Schedules{},
|
||||
entity.UserLevels{},
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ func (_i *AboutUsContentImageRouter) RegisterAboutUsContentImageRoutes() {
|
|||
_i.App.Route("/about-us-content-images", func(router fiber.Router) {
|
||||
|
||||
router.Get("/", aboutUsContentImageController.All)
|
||||
router.Post("/url", aboutUsContentImageController.SaveRemote)
|
||||
router.Get("/:id", aboutUsContentImageController.Show)
|
||||
|
||||
// upload image (pakai form-data)
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ package controller
|
|||
import (
|
||||
"strconv"
|
||||
|
||||
"web-qudo-be/app/module/about_us_content_images/request"
|
||||
"web-qudo-be/app/module/about_us_content_images/service"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
utilRes "web-qudo-be/utils/response"
|
||||
utilVal "web-qudo-be/utils/validator"
|
||||
)
|
||||
|
||||
type aboutUsContentImageController struct {
|
||||
|
|
@ -20,6 +22,7 @@ type AboutUsContentImageController interface {
|
|||
All(c *fiber.Ctx) error
|
||||
Show(c *fiber.Ctx) error
|
||||
Save(c *fiber.Ctx) error
|
||||
SaveRemote(c *fiber.Ctx) error
|
||||
Delete(c *fiber.Ctx) error
|
||||
}
|
||||
|
||||
|
|
@ -95,6 +98,24 @@ func (_i *aboutUsContentImageController) Save(c *fiber.Ctx) error {
|
|||
})
|
||||
}
|
||||
|
||||
// SaveRemote JSON: public URL for image or video (e.g. CDN .mp4)
|
||||
func (_i *aboutUsContentImageController) SaveRemote(c *fiber.Ctx) error {
|
||||
req := new(request.AboutUsContentImageRemoteRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := _i.service.SaveRemoteURL(req.AboutUsContentID, req.MediaURL, req.MediaType)
|
||||
if err != nil {
|
||||
_i.Log.Error().Err(err).Msg("failed save remote about us media")
|
||||
return err
|
||||
}
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"About us media URL saved"},
|
||||
Data: result,
|
||||
})
|
||||
}
|
||||
|
||||
// DELETE
|
||||
func (_i *aboutUsContentImageController) Delete(c *fiber.Ctx) error {
|
||||
id, err := strconv.Atoi(c.Params("id"))
|
||||
|
|
|
|||
|
|
@ -35,9 +35,7 @@ func NewAboutUsContentImageRepository(db *database.Database, log zerolog.Logger)
|
|||
|
||||
// GET ALL
|
||||
func (_i *aboutUsContentImageRepository) GetAll() (images []*entity.AboutUsContentImage, err error) {
|
||||
err = _i.DB.DB.
|
||||
Where("is_active = ?", true).
|
||||
Find(&images).Error
|
||||
err = _i.DB.DB.Find(&images).Error
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +50,7 @@ func (_i *aboutUsContentImageRepository) FindOne(id uint) (image *entity.AboutUs
|
|||
// GET BY ABOUT US CONTENT ID
|
||||
func (_i *aboutUsContentImageRepository) FindByContentID(contentID uint) (images []*entity.AboutUsContentImage, err error) {
|
||||
err = _i.DB.DB.
|
||||
Where("about_us_content_id = ? AND is_active = ?", contentID, true).
|
||||
Where("about_us_content_id = ?", contentID).
|
||||
Find(&images).Error
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package request
|
||||
|
||||
type AboutUsContentImageRemoteRequest struct {
|
||||
AboutUsContentID uint `json:"about_us_content_id" validate:"required"`
|
||||
MediaURL string `json:"media_url" validate:"required"`
|
||||
MediaType string `json:"media_type"`
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"mime/multipart"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
"web-qudo-be/app/database/entity"
|
||||
"web-qudo-be/app/module/about_us_content_images/repository"
|
||||
|
|
@ -22,6 +23,7 @@ type AboutUsContentImageService interface {
|
|||
All() (images []*entity.AboutUsContentImage, err error)
|
||||
Show(id uint) (image *entity.AboutUsContentImage, err error)
|
||||
Save(aboutUsContentId uint, file *multipart.FileHeader) (image *entity.AboutUsContentImage, err error)
|
||||
SaveRemoteURL(aboutUsContentID uint, mediaURL, mediaType string) (image *entity.AboutUsContentImage, err error)
|
||||
Delete(id uint) error
|
||||
}
|
||||
|
||||
|
|
@ -50,9 +52,8 @@ func (_i *aboutUsContentImageService) Save(aboutUsContentId uint, file *multipar
|
|||
Str("filename", file.Filename).
|
||||
Msg("upload image")
|
||||
|
||||
// validasi file
|
||||
ext := filepath.Ext(file.Filename)
|
||||
if ext != ".jpg" && ext != ".jpeg" && ext != ".png" {
|
||||
ext := filepath.Ext(strings.ToLower(file.Filename))
|
||||
if ext != ".jpg" && ext != ".jpeg" && ext != ".png" && ext != ".mp4" && ext != ".webm" {
|
||||
return nil, fmt.Errorf("invalid file type")
|
||||
}
|
||||
|
||||
|
|
@ -68,10 +69,14 @@ func (_i *aboutUsContentImageService) Save(aboutUsContentId uint, file *multipar
|
|||
}
|
||||
|
||||
// save ke DB
|
||||
mt := "image/" + strings.TrimPrefix(ext, ".")
|
||||
if ext == ".mp4" || ext == ".webm" {
|
||||
mt = "video/" + strings.TrimPrefix(ext, ".")
|
||||
}
|
||||
data := &entity.AboutUsContentImage{
|
||||
AboutUsContentID: aboutUsContentId,
|
||||
MediaPath: filePath,
|
||||
MediaType: ext,
|
||||
MediaType: mt,
|
||||
MediaURL: "/uploads/" + filename,
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +89,27 @@ func (_i *aboutUsContentImageService) Save(aboutUsContentId uint, file *multipar
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (_i *aboutUsContentImageService) SaveRemoteURL(aboutUsContentID uint, mediaURL, mediaType string) (image *entity.AboutUsContentImage, err error) {
|
||||
if strings.TrimSpace(mediaURL) == "" {
|
||||
return nil, fmt.Errorf("media_url is required")
|
||||
}
|
||||
mt := mediaType
|
||||
if mt == "" {
|
||||
lower := strings.ToLower(mediaURL)
|
||||
if strings.HasSuffix(lower, ".mp4") || strings.Contains(lower, "video") {
|
||||
mt = "video/mp4"
|
||||
} else {
|
||||
mt = "image/url"
|
||||
}
|
||||
}
|
||||
data := &entity.AboutUsContentImage{
|
||||
AboutUsContentID: aboutUsContentID,
|
||||
MediaURL: mediaURL,
|
||||
MediaType: mt,
|
||||
}
|
||||
return _i.Repo.Create(data)
|
||||
}
|
||||
|
||||
func (_i *aboutUsContentImageService) Delete(id uint) error {
|
||||
return _i.Repo.Delete(id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package controller
|
|||
import (
|
||||
"strconv"
|
||||
|
||||
"web-qudo-be/app/module/about_us_contents/request"
|
||||
"web-qudo-be/app/module/about_us_contents/service"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
|
@ -71,13 +72,13 @@ func (_i *aboutUsContentController) Show(c *fiber.Ctx) error {
|
|||
|
||||
// CREATE
|
||||
func (_i *aboutUsContentController) Save(c *fiber.Ctx) error {
|
||||
req := new(map[string]interface{})
|
||||
req := new(request.AboutUsContentCreateRequest)
|
||||
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := _i.service.Save(*req)
|
||||
result, err := _i.service.Save(req.ToEntity())
|
||||
if err != nil {
|
||||
_i.Log.Error().Err(err).Msg("failed create about us content")
|
||||
return err
|
||||
|
|
@ -97,13 +98,13 @@ func (_i *aboutUsContentController) Update(c *fiber.Ctx) error {
|
|||
return err
|
||||
}
|
||||
|
||||
req := new(map[string]interface{})
|
||||
req := new(request.AboutUsContentUpdateRequest)
|
||||
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = _i.service.Update(uint(id), *req)
|
||||
err = _i.service.Update(uint(id), req.ToEntity())
|
||||
if err != nil {
|
||||
_i.Log.Error().Err(err).Msg("failed update about us content")
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ func (r *aboutUsContentRepository) GetAll() ([]*entity.AboutUsContent, error) {
|
|||
var results []*entity.AboutUsContent
|
||||
|
||||
err := r.DB.DB.
|
||||
Where("is_active = ?", true).
|
||||
Preload("Images").
|
||||
Where("is_active IS NULL OR is_active = ?", true).
|
||||
Order("id ASC").
|
||||
Find(&results).Error
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -69,12 +71,24 @@ func (r *aboutUsContentRepository) Create(data *entity.AboutUsContent) (*entity.
|
|||
return data, nil
|
||||
}
|
||||
|
||||
// UPDATE
|
||||
// Update uses a column map so we never SET primary key / created_at to zero values (breaks FK children).
|
||||
func (r *aboutUsContentRepository) Update(id uint, data *entity.AboutUsContent) error {
|
||||
updates := map[string]interface{}{
|
||||
"primary_title": data.PrimaryTitle,
|
||||
"secondary_title": data.SecondaryTitle,
|
||||
"description": data.Description,
|
||||
"primary_cta": data.PrimaryCta,
|
||||
"secondary_cta_text": data.SecondaryCtaText,
|
||||
"updated_at": data.UpdatedAt,
|
||||
}
|
||||
if data.IsActive != nil {
|
||||
updates["is_active"] = data.IsActive
|
||||
}
|
||||
|
||||
err := r.DB.DB.
|
||||
Model(&entity.AboutUsContent{}).
|
||||
Where("id = ?", id).
|
||||
Updates(data).Error
|
||||
Updates(updates).Error
|
||||
|
||||
if err != nil {
|
||||
r.Log.Error().Err(err).Msg("failed update about us content")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"web-qudo-be/app/database/entity"
|
||||
|
|
@ -15,8 +17,8 @@ type aboutUsContentService struct {
|
|||
type AboutUsContentService interface {
|
||||
All() ([]*entity.AboutUsContent, error)
|
||||
Show(id uint) (*entity.AboutUsContent, error)
|
||||
Save(data map[string]interface{}) (*entity.AboutUsContent, error)
|
||||
Update(id uint, data map[string]interface{}) error
|
||||
Save(data *entity.AboutUsContent) (*entity.AboutUsContent, error)
|
||||
Update(id uint, data *entity.AboutUsContent) error
|
||||
Delete(id uint) error
|
||||
}
|
||||
|
||||
|
|
@ -53,26 +55,8 @@ func (s *aboutUsContentService) Show(id uint) (*entity.AboutUsContent, error) {
|
|||
}
|
||||
|
||||
// CREATE
|
||||
func (s *aboutUsContentService) Save(data map[string]interface{}) (*entity.AboutUsContent, error) {
|
||||
entityData := &entity.AboutUsContent{}
|
||||
|
||||
if v, ok := data["primary_title"].(string); ok {
|
||||
entityData.PrimaryTitle = v
|
||||
}
|
||||
if v, ok := data["secondary_title"].(string); ok {
|
||||
entityData.SecondaryTitle = v
|
||||
}
|
||||
if v, ok := data["description"].(string); ok {
|
||||
entityData.Description = v
|
||||
}
|
||||
if v, ok := data["primary_cta"].(string); ok {
|
||||
entityData.PrimaryCta = v
|
||||
}
|
||||
if v, ok := data["secondary_cta_text"].(string); ok {
|
||||
entityData.SecondaryCtaText = v
|
||||
}
|
||||
|
||||
result, err := s.Repo.Create(entityData)
|
||||
func (s *aboutUsContentService) Save(data *entity.AboutUsContent) (*entity.AboutUsContent, error) {
|
||||
result, err := s.Repo.Create(data)
|
||||
if err != nil {
|
||||
s.Log.Error().Err(err).Msg("failed create about us content")
|
||||
return nil, err
|
||||
|
|
@ -82,26 +66,8 @@ func (s *aboutUsContentService) Save(data map[string]interface{}) (*entity.About
|
|||
}
|
||||
|
||||
// UPDATE
|
||||
func (s *aboutUsContentService) Update(id uint, data map[string]interface{}) error {
|
||||
entityData := &entity.AboutUsContent{}
|
||||
|
||||
if v, ok := data["primary_title"].(string); ok {
|
||||
entityData.PrimaryTitle = v
|
||||
}
|
||||
if v, ok := data["secondary_title"].(string); ok {
|
||||
entityData.SecondaryTitle = v
|
||||
}
|
||||
if v, ok := data["description"].(string); ok {
|
||||
entityData.Description = v
|
||||
}
|
||||
if v, ok := data["primary_cta"].(string); ok {
|
||||
entityData.PrimaryCta = v
|
||||
}
|
||||
if v, ok := data["secondary_cta_text"].(string); ok {
|
||||
entityData.SecondaryCtaText = v
|
||||
}
|
||||
|
||||
err := s.Repo.Update(id, entityData)
|
||||
func (s *aboutUsContentService) Update(id uint, data *entity.AboutUsContent) error {
|
||||
err := s.Repo.Update(id, data)
|
||||
if err != nil {
|
||||
s.Log.Error().Err(err).Msg("failed update about us content")
|
||||
return err
|
||||
|
|
@ -119,6 +85,7 @@ func (s *aboutUsContentService) Delete(id uint) error {
|
|||
|
||||
isActive := false
|
||||
result.IsActive = &isActive
|
||||
result.UpdatedAt = time.Now()
|
||||
|
||||
return s.Repo.Update(id, result)
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/google/uuid"
|
||||
"github.com/rs/zerolog"
|
||||
|
|
|
|||
|
|
@ -1,32 +1,41 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"mime/multipart"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"web-qudo-be/app/database/entity"
|
||||
"web-qudo-be/app/module/hero_content_images/repository"
|
||||
minioStorage "web-qudo-be/config/config"
|
||||
"web-qudo-be/utils/storage"
|
||||
)
|
||||
|
||||
type heroContentImagesService struct {
|
||||
Repo repository.HeroContentImagesRepository
|
||||
Log zerolog.Logger
|
||||
Repo repository.HeroContentImagesRepository
|
||||
MinioStorage *minioStorage.MinioStorage
|
||||
Log zerolog.Logger
|
||||
}
|
||||
|
||||
type HeroContentImagesService interface {
|
||||
FindByHeroID(heroID uuid.UUID) (*entity.HeroContentImages, error)
|
||||
Save(data *entity.HeroContentImages) (*entity.HeroContentImages, error)
|
||||
SaveWithFile(heroContentID uuid.UUID, file *multipart.FileHeader) (*entity.HeroContentImages, error)
|
||||
Update(id uuid.UUID, data *entity.HeroContentImages) error
|
||||
UpdateWithFile(id uuid.UUID, file *multipart.FileHeader) error
|
||||
Delete(id uuid.UUID) error
|
||||
}
|
||||
|
||||
func NewHeroContentImagesService(
|
||||
repo repository.HeroContentImagesRepository,
|
||||
minio *minioStorage.MinioStorage,
|
||||
log zerolog.Logger,
|
||||
) HeroContentImagesService {
|
||||
return &heroContentImagesService{
|
||||
Repo: repo,
|
||||
Log: log,
|
||||
Repo: repo,
|
||||
MinioStorage: minio,
|
||||
Log: log,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,6 +61,19 @@ func (s *heroContentImagesService) Save(data *entity.HeroContentImages) (*entity
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (s *heroContentImagesService) SaveWithFile(heroContentID uuid.UUID, file *multipart.FileHeader) (*entity.HeroContentImages, error) {
|
||||
key, url, err := storage.UploadCMSObject(s.MinioStorage, "hero", file, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := &entity.HeroContentImages{
|
||||
HeroContentID: heroContentID,
|
||||
ImagePath: key,
|
||||
ImageURL: url,
|
||||
}
|
||||
return s.Save(data)
|
||||
}
|
||||
|
||||
func (s *heroContentImagesService) Update(id uuid.UUID, data *entity.HeroContentImages) error {
|
||||
err := s.Repo.Update(id, data)
|
||||
if err != nil {
|
||||
|
|
@ -62,6 +84,17 @@ func (s *heroContentImagesService) Update(id uuid.UUID, data *entity.HeroContent
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *heroContentImagesService) UpdateWithFile(id uuid.UUID, file *multipart.FileHeader) error {
|
||||
key, url, err := storage.UploadCMSObject(s.MinioStorage, "hero", file, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Repo.Update(id, &entity.HeroContentImages{
|
||||
ImagePath: key,
|
||||
ImageURL: url,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *heroContentImagesService) Delete(id uuid.UUID) error {
|
||||
err := s.Repo.Delete(id)
|
||||
if err != nil {
|
||||
|
|
@ -70,4 +103,4 @@ func (s *heroContentImagesService) Delete(id uuid.UUID) error {
|
|||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"web-qudo-be/app/database"
|
||||
"web-qudo-be/app/database/entity"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/rs/zerolog"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type heroContentsRepository struct {
|
||||
|
|
@ -35,6 +37,9 @@ func (r *heroContentsRepository) Get() (*entity.HeroContents, error) {
|
|||
First(&data).Error
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
r.Log.Error().Err(err).Msg("failed get hero content")
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func NewOurProductContentImagesController(service service.OurProductContentImage
|
|||
}
|
||||
|
||||
func (_i *ourProductContentImagesController) FindByOurProductContentID(c *fiber.Ctx) error {
|
||||
contentIDStr := c.Params("our_product_content_id")
|
||||
contentIDStr := c.Params("content_id")
|
||||
|
||||
contentID, err := uuid.Parse(contentIDStr)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"web-qudo-be/app/database"
|
||||
"web-qudo-be/app/database/entity"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/rs/zerolog"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ourProductContentRepository struct {
|
||||
|
|
@ -15,6 +17,7 @@ type ourProductContentRepository struct {
|
|||
|
||||
type OurProductContentRepository interface {
|
||||
Get() (*entity.OurProductContent, error)
|
||||
GetAll() ([]entity.OurProductContent, error)
|
||||
Create(data *entity.OurProductContent) (*entity.OurProductContent, error)
|
||||
Update(id uuid.UUID, data *entity.OurProductContent) error
|
||||
Delete(id uuid.UUID) error
|
||||
|
|
@ -35,6 +38,9 @@ func (r *ourProductContentRepository) Get() (*entity.OurProductContent, error) {
|
|||
First(&data).Error
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
r.Log.Error().Err(err).Msg("failed get our product content")
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -42,6 +48,19 @@ func (r *ourProductContentRepository) Get() (*entity.OurProductContent, error) {
|
|||
return &data, nil
|
||||
}
|
||||
|
||||
func (r *ourProductContentRepository) GetAll() ([]entity.OurProductContent, error) {
|
||||
var rows []entity.OurProductContent
|
||||
err := r.DB.DB.
|
||||
Preload("Images").
|
||||
Order("created_at ASC").
|
||||
Find(&rows).Error
|
||||
if err != nil {
|
||||
r.Log.Error().Err(err).Msg("failed list our product contents")
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (r *ourProductContentRepository) Create(data *entity.OurProductContent) (*entity.OurProductContent, error) {
|
||||
data.ID = uuid.New()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ type ourProductContentService struct {
|
|||
}
|
||||
|
||||
type OurProductContentService interface {
|
||||
Show() (*entity.OurProductContent, error)
|
||||
Show() ([]entity.OurProductContent, error)
|
||||
Save(data *entity.OurProductContent) (*entity.OurProductContent, error)
|
||||
Update(id uuid.UUID, data *entity.OurProductContent) error
|
||||
Delete(id uuid.UUID) error
|
||||
|
|
@ -34,14 +34,13 @@ func NewOurProductContentService(
|
|||
}
|
||||
}
|
||||
|
||||
func (s *ourProductContentService) Show() (*entity.OurProductContent, error) {
|
||||
data, err := s.Repo.Get()
|
||||
func (s *ourProductContentService) Show() ([]entity.OurProductContent, error) {
|
||||
rows, err := s.Repo.GetAll()
|
||||
if err != nil {
|
||||
s.Log.Error().Err(err).Msg("failed get our product content")
|
||||
s.Log.Error().Err(err).Msg("failed list our product contents")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (s *ourProductContentService) Save(data *entity.OurProductContent) (*entity.OurProductContent, error) {
|
||||
|
|
@ -67,13 +66,5 @@ func (s *ourProductContentService) Update(id uuid.UUID, data *entity.OurProductC
|
|||
}
|
||||
|
||||
func (s *ourProductContentService) Delete(id uuid.UUID) error {
|
||||
result, err := s.Repo.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isActive := false
|
||||
result.IsActive = &isActive
|
||||
|
||||
return s.Repo.Update(id, result)
|
||||
return s.Repo.Delete(id)
|
||||
}
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"web-qudo-be/app/database"
|
||||
"web-qudo-be/app/database/entity"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ourServiceContentRepository struct {
|
||||
|
|
@ -14,6 +16,7 @@ type ourServiceContentRepository struct {
|
|||
|
||||
type OurServiceContentRepository interface {
|
||||
Get() (*entity.OurServiceContent, error)
|
||||
GetAll() ([]entity.OurServiceContent, error)
|
||||
Create(data *entity.OurServiceContent) (*entity.OurServiceContent, error)
|
||||
Update(id uint, data *entity.OurServiceContent) error
|
||||
Delete(id uint) error
|
||||
|
|
@ -34,6 +37,9 @@ func (r *ourServiceContentRepository) Get() (*entity.OurServiceContent, error) {
|
|||
First(&data).Error
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
r.Log.Error().Err(err).Msg("failed get our service content")
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -41,6 +47,19 @@ func (r *ourServiceContentRepository) Get() (*entity.OurServiceContent, error) {
|
|||
return &data, nil
|
||||
}
|
||||
|
||||
func (r *ourServiceContentRepository) GetAll() ([]entity.OurServiceContent, error) {
|
||||
var rows []entity.OurServiceContent
|
||||
err := r.DB.DB.
|
||||
Preload("Images").
|
||||
Order("created_at ASC").
|
||||
Find(&rows).Error
|
||||
if err != nil {
|
||||
r.Log.Error().Err(err).Msg("failed list our service contents")
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (r *ourServiceContentRepository) Create(data *entity.OurServiceContent) (*entity.OurServiceContent, error) {
|
||||
err := r.DB.DB.Create(data).Error
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ type ourServiceContentService struct {
|
|||
}
|
||||
|
||||
type OurServiceContentService interface {
|
||||
Show() (*entity.OurServiceContent, error)
|
||||
Show() ([]entity.OurServiceContent, error)
|
||||
Save(data *entity.OurServiceContent) (*entity.OurServiceContent, error)
|
||||
Update(id uint, data *entity.OurServiceContent) error
|
||||
Delete(id uint) error
|
||||
|
|
@ -33,14 +33,13 @@ func NewOurServiceContentService(
|
|||
}
|
||||
}
|
||||
|
||||
func (s *ourServiceContentService) Show() (*entity.OurServiceContent, error) {
|
||||
data, err := s.Repo.Get()
|
||||
func (s *ourServiceContentService) Show() ([]entity.OurServiceContent, error) {
|
||||
rows, err := s.Repo.GetAll()
|
||||
if err != nil {
|
||||
s.Log.Error().Err(err).Msg("failed get our service content")
|
||||
s.Log.Error().Err(err).Msg("failed list our service contents")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (s *ourServiceContentService) Save(data *entity.OurServiceContent) (*entity.OurServiceContent, error) {
|
||||
|
|
@ -75,13 +74,5 @@ func (s *ourServiceContentService) Update(id uint, data *entity.OurServiceConten
|
|||
}
|
||||
|
||||
func (s *ourServiceContentService) Delete(id uint) error {
|
||||
result, err := s.Repo.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isActive := false
|
||||
result.IsActive = &isActive
|
||||
|
||||
return s.Repo.Update(id, result)
|
||||
return s.Repo.Delete(id)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/minio/minio-go/v7"
|
||||
|
|
@ -69,3 +70,13 @@ func (_minio *MinioStorage) ConnectMinio() (*minio.Client, error) {
|
|||
log.Printf("[MinIO] Successfully connected to MinIO and bucket '%s' is ready", bucketName)
|
||||
return minioClient, nil
|
||||
}
|
||||
|
||||
// PublicObjectURL builds a path-style URL for public reads (bucket policy must allow GET).
|
||||
func (m *MinioStorage) PublicObjectURL(objectKey string) string {
|
||||
o := m.Cfg.ObjectStorage.MinioStorage
|
||||
scheme := "http"
|
||||
if o.UseSSL {
|
||||
scheme = "https"
|
||||
}
|
||||
return fmt.Sprintf("%s://%s/%s/%s", scheme, o.Endpoint, o.BucketName, objectKey)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ production = false
|
|||
body-limit = 1048576000 # "100 * 1024 * 1024"
|
||||
|
||||
[db.postgres]
|
||||
dsn = "postgresql://medols_user:MedolsDB@2025@38.47.185.79:5432/medols_db" # <driver>://<username>:<password>@<host>:<port>/<database>
|
||||
dsn = "postgresql://qudo_user:QudoDB@2026@38.47.185.79:5432/qudo_db" # <driver>://<username>:<password>@<host>:<port>/<database>
|
||||
log-mode = "ERROR"
|
||||
migrate = true
|
||||
seed = false
|
||||
|
|
@ -28,7 +28,7 @@ endpoint = "is3.cloudhost.id"
|
|||
access-key-id = "YRP1RM617986USRU6NN8"
|
||||
secret-access-key = "vfbwQDYb1m7nfzo4LVEz90BIyOWfBMZ6bfGQbqDO"
|
||||
use-ssl = true
|
||||
bucket-name = "mikulnews"
|
||||
bucket-name = "qudo"
|
||||
location = "us-east-1"
|
||||
|
||||
[middleware.compress]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/minio/minio-go/v7"
|
||||
|
||||
appcfg "web-qudo-be/config/config"
|
||||
)
|
||||
|
||||
var imageExts = map[string]bool{
|
||||
".jpg": true, ".jpeg": true, ".png": true, ".gif": true, ".webp": true,
|
||||
}
|
||||
|
||||
var mediaExts = map[string]bool{
|
||||
".jpg": true, ".jpeg": true, ".png": true, ".gif": true, ".webp": true,
|
||||
".mp4": true, ".webm": true,
|
||||
}
|
||||
|
||||
// UploadCMSObject stores a file in MinIO under cms/{folder}/YYYY/MM/{uuid}{ext} and returns object key + public URL.
|
||||
func UploadCMSObject(ms *appcfg.MinioStorage, folder string, file *multipart.FileHeader, allowVideo bool) (objectKey string, publicURL string, err error) {
|
||||
if file == nil {
|
||||
return "", "", fmt.Errorf("file is required")
|
||||
}
|
||||
ext := strings.ToLower(filepath.Ext(file.Filename))
|
||||
if allowVideo {
|
||||
if !mediaExts[ext] {
|
||||
return "", "", fmt.Errorf("unsupported file type (allowed: images, mp4, webm)")
|
||||
}
|
||||
} else if !imageExts[ext] {
|
||||
return "", "", fmt.Errorf("unsupported image type")
|
||||
}
|
||||
|
||||
client, err := ms.ConnectMinio()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
bucket := ms.Cfg.ObjectStorage.MinioStorage.BucketName
|
||||
now := time.Now()
|
||||
objectKey = fmt.Sprintf("cms/%s/%d/%02d/%s%s", folder, now.Year(), int(now.Month()), uuid.New().String(), ext)
|
||||
|
||||
contentType := mime.TypeByExtension(ext)
|
||||
if contentType == "" {
|
||||
contentType = "application/octet-stream"
|
||||
}
|
||||
|
||||
_, err = client.PutObject(context.Background(), bucket, objectKey, src, file.Size, minio.PutObjectOptions{
|
||||
ContentType: contentType,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return objectKey, ms.PublicObjectURL(objectKey), nil
|
||||
}
|
||||
BIN
web-qudo-be.exe
BIN
web-qudo-be.exe
Binary file not shown.
Loading…
Reference in New Issue