feat (minio): done, upload wip

This commit is contained in:
dpurbosakti
2025-09-24 07:51:15 +07:00
parent 2586bf9b76
commit a50f62f5ec
9 changed files with 446 additions and 0 deletions
+149
View File
@@ -0,0 +1,149 @@
package miniohelper
import (
"context"
"errors"
"fmt"
"net/url"
m "simrs-vx/internal/infra/minio"
"github.com/minio/minio-go/v7"
)
type minioRepository struct {
client *minio.Client
}
var I minioRepository = minioRepository{}
func (repo *minioRepository) SetClient() {
repo.client = m.I
}
// Check exist bucket if not exist create Bucket
func (repo *minioRepository) createBucket(bucketName string, region string) error {
exist, err := repo.client.BucketExists(context.Background(), bucketName)
if err != nil {
return err
}
if exist {
return nil
}
if err := repo.client.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: region, ObjectLocking: true}); err != nil {
return err
}
return nil
}
// Upload file reader to MinIO
func (repo *minioRepository) PutObject(input m.UploadReaderInput) (*minio.UploadInfo, error) {
if err := repo.createBucket(input.BucketName, m.O.GetRegion()); err != nil {
return nil, err
}
options := minio.PutObjectOptions{
ContentType: input.ContentType,
UserMetadata: map[string]string{"x-amz-acl": "public-read"},
}
uploadInfo, err := repo.client.PutObject(context.Background(), input.BucketName, input.Name, input.File, input.Size, options)
if err != nil {
return nil, err
}
return &uploadInfo, err
}
// Upload file path to MinIO
func (repo *minioRepository) FPutObject(input m.UploadPathInput) (*minio.UploadInfo, error) {
if err := repo.createBucket(input.BucketName, m.O.GetRegion()); err != nil {
return nil, err
}
options := minio.PutObjectOptions{
ContentType: input.ContentType,
UserMetadata: map[string]string{"x-amz-acl": "public-read"},
}
uploadInfo, err := repo.client.FPutObject(context.Background(), input.BucketName, input.Name, input.Path, options)
if err != nil {
return nil, err
}
return &uploadInfo, err
}
// Move file from old to new MinIO path
func (repo *minioRepository) MoveObject(src minio.CopySrcOptions, dst minio.CopyDestOptions) (*minio.UploadInfo, error) {
uploadInfo, err := repo.client.CopyObject(context.Background(), dst, src)
if err != nil {
return nil, err
}
if err := repo.RemoveObject(src.Bucket, src.Object); err != nil {
return nil, err
}
return &uploadInfo, err
}
// Generatet public link MinIO
func (repo *minioRepository) GenerateUrl(bucket, object string) string {
mode := "http"
if m.O.GetUseSsl() {
mode = "https"
}
return fmt.Sprintf("%s://%s/%s/%s", mode, m.O.GetEndpoint(), bucket, object)
}
// Download file from MinIO
func (repo *minioRepository) GetObject(bucket string, fileName string) (*minio.Object, error) {
object, err := repo.client.GetObject(context.Background(), bucket, fileName, minio.GetObjectOptions{})
if err != nil {
return nil, err
}
return object, nil
}
// Delete file from MinIO
func (repo *minioRepository) RemoveObject(bucket string, fileName string) error {
if err := repo.client.RemoveObject(context.Background(), bucket, fileName, minio.RemoveObjectOptions{}); err != nil {
return err
}
return nil
}
// create presigned url to post object with custom policy
func (repo *minioRepository) GeneratePresignedPost(policy *minio.PostPolicy) (*url.URL, map[string]string, error) {
presignedUrl, formData, err := repo.client.PresignedPostPolicy(context.Background(), policy)
if err != nil {
return nil, nil, err
}
return presignedUrl, formData, nil
}
// create presigned url to get object
func (repo *minioRepository) GeneratePresignedGetObject(input m.PresignedGetInput) (*url.URL, error) {
presignedUrl, err := repo.client.PresignedGetObject(context.Background(), input.Bucket, input.Object, input.Expiry, input.ReqParams)
if err != nil {
return nil, err
}
return presignedUrl, nil
}
func getBucketName(idx int) string {
return m.O.GetBucketName()[idx]
}
func GetBucketPatient() (string, error) {
bucketName := getBucketName(0)
if bucketName == "" {
return "", errors.New("bucket name unknown")
}
return bucketName, nil
}
func GetEndpointUrl(bucket string) string {
mode := "http"
if m.O.GetUseSsl() {
mode = "https"
}
return fmt.Sprintf("%s://%s/%s", mode, m.O.GetEndpoint(), bucket)
}
+16
View File
@@ -0,0 +1,16 @@
package uploadhelper
type UploadResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
URL string `json:"url,omitempty"`
FileName string `json:"filename,omitempty"`
}
type MultipleUploadResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
TotalFiles int `json:"total_files"`
SuccessCount int `json:"success_count"`
Results []UploadResponse `json:"results"`
}
+75
View File
@@ -0,0 +1,75 @@
package uploadhelper
import (
"fmt"
"path/filepath"
"strings"
ere "simrs-vx/internal/domain/references/encounter"
)
func getBucketForType(docType string) (string, error) {
switch strings.ToLower(docType) {
case "resident", "resident-number", "ktp":
return string(ere.UCPRN), nil
case "driver-license", "sim", "license":
return string(ere.UCPDL), nil
case "passport", "paspor":
return string(ere.UCPP), nil
case "family-card", "kk", "family":
return string(ere.UCPFC), nil
case "mcu", "medical", "mcu-result":
return string(ere.UCMIR), nil
default:
return "", fmt.Errorf("unknown document type: %s", docType)
}
}
// getValidFileTypesForBucket returns allowed file types for each bucket
func getValidFileTypesForBucket(bucketName string) []string {
switch bucketName {
case string(ere.UCPRN), string(ere.UCPDL), string(ere.UCPP), string(ere.UCPFC):
return []string{".jpg", ".jpeg", ".png", ".pdf", ".gif"}
case string(ere.UCMIR):
return []string{".jpg", ".jpeg", ".png", ".pdf", ".gif", ".doc", ".docx", ".xls", ".xlsx"}
default:
return []string{".jpg", ".jpeg", ".png", ".pdf"}
}
}
// isValidFileType checks if the uploaded file type is allowed for the specific bucket
func isValidFileType(filename, bucketName string) bool {
allowedTypes := getValidFileTypesForBucket(bucketName)
ext := strings.ToLower(filepath.Ext(filename))
for _, allowedExt := range allowedTypes {
if ext == allowedExt {
return true
}
}
return false
}
// getContentType determines the content type based on file extension
func getContentType(filename string) string {
switch strings.ToLower(filepath.Ext(filename)) {
case ".jpg", ".jpeg":
return "image/jpeg"
case ".png":
return "image/png"
case ".pdf":
return "application/pdf"
case ".gif":
return "image/gif"
case ".doc":
return "application/msword"
case ".docx":
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
case ".xls":
return "application/vnd.ms-excel"
case ".xlsx":
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
default:
return "application/octet-stream"
}
}