package service import ( "context" "github.com/gofiber/fiber/v2" "github.com/minio/minio-go/v7" "github.com/rs/zerolog" "go-humas-be/app/module/article_files/mapper" "go-humas-be/app/module/article_files/repository" "go-humas-be/app/module/article_files/request" "go-humas-be/app/module/article_files/response" minioStorage "go-humas-be/config/config" "go-humas-be/utils/paginator" "io" "log" "mime" "strings" "time" ) // ArticleFilesService type articleFilesService struct { Repo repository.ArticleFilesRepository Log zerolog.Logger MinioStorage *minioStorage.MinioStorage } // ArticleFilesService define interface of IArticleFilesService type ArticleFilesService interface { All(req request.ArticleFilesQueryRequest) (articleFiles []*response.ArticleFilesResponse, paging paginator.Pagination, err error) Show(id uint) (articleFiles *response.ArticleFilesResponse, err error) Save(req request.ArticleFilesCreateRequest) (err error) Update(id uint, req request.ArticleFilesUpdateRequest) (err error) Delete(id uint) error Uploader(c *fiber.Ctx, id uint) error Viewer(c *fiber.Ctx, id string) error } // NewArticleFilesService init ArticleFilesService func NewArticleFilesService(repo repository.ArticleFilesRepository, log zerolog.Logger, minioStorage *minioStorage.MinioStorage) ArticleFilesService { return &articleFilesService{ Repo: repo, Log: log, MinioStorage: minioStorage, } } // All implement interface of ArticleFilesService func (_i *articleFilesService) All(req request.ArticleFilesQueryRequest) (articleFiless []*response.ArticleFilesResponse, paging paginator.Pagination, err error) { results, paging, err := _i.Repo.GetAll(req) if err != nil { return } for _, result := range results { articleFiless = append(articleFiless, mapper.ArticleFilesResponseMapper(result)) } return } func (_i *articleFilesService) Show(id uint) (articleFiles *response.ArticleFilesResponse, err error) { result, err := _i.Repo.FindOne(id) if err != nil { return nil, err } return mapper.ArticleFilesResponseMapper(result), nil } func (_i *articleFilesService) Save(req request.ArticleFilesCreateRequest) (err error) { _i.Log.Info().Interface("data", req).Msg("") return _i.Repo.Create(req.ToEntity()) } func (_i *articleFilesService) Update(id uint, req request.ArticleFilesUpdateRequest) (err error) { _i.Log.Info().Interface("data", req).Msg("") return _i.Repo.Update(id, req.ToEntity()) } func (_i *articleFilesService) Delete(id uint) error { return _i.Repo.Delete(id) } func (_i *articleFilesService) Uploader(c *fiber.Ctx, id uint) (err error) { bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName form, err := c.MultipartForm() if err != nil { return err } files := form.File["files"] // Create minio connection. minioClient, err := _i.MinioStorage.ConnectMinio() if err != nil { // Return status 500 and minio connection error. return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "error": true, "msg": err.Error(), }) } // Iterasi semua file yang diunggah for _, file := range files { _i.Log.Info().Str("timestamp", time.Now(). Format(time.RFC3339)).Str("Service:Resource", "Uploader:: loop1"). Interface("data", file).Msg("") src, err := file.Open() if err != nil { return err } defer src.Close() // Upload file ke MinIO _, err = minioClient.PutObject(context.Background(), bucketName, file.Filename, src, file.Size, minio.PutObjectOptions{}) if err != nil { return err } } _i.Log.Info().Str("timestamp", time.Now(). Format(time.RFC3339)).Str("Service:Resource", "User:All"). Interface("data", "Successfully uploaded").Msg("") return } func (_i *articleFilesService) Viewer(c *fiber.Ctx, id string) (err error) { ctx := context.Background() bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName objectName := id _i.Log.Info().Str("timestamp", time.Now(). Format(time.RFC3339)).Str("Service:Resource", "Article:Uploads"). Interface("data", objectName).Msg("") // Create minio connection. minioClient, err := _i.MinioStorage.ConnectMinio() if err != nil { // Return status 500 and minio connection error. return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "error": true, "msg": err.Error(), }) } fileContent, err := minioClient.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{}) if err != nil { log.Fatalln(err) } defer fileContent.Close() // Tentukan Content-Type berdasarkan ekstensi file contentType := mime.TypeByExtension("." + getFileExtension(objectName)) if contentType == "" { contentType = "application/octet-stream" // fallback jika tidak ada tipe MIME yang cocok } c.Set("Content-Type", contentType) if _, err := io.Copy(c.Response().BodyWriter(), fileContent); err != nil { return err } return } func getFileExtension(filename string) string { // split file name parts := strings.Split(filename, ".") // jika tidak ada ekstensi, kembalikan string kosong if len(parts) == 1 || (len(parts) == 2 && parts[0] == "") { return "" } // ambil ekstensi terakhir return parts[len(parts)-1] }