From 3298602a23bd9c343664d8d4a18cb8b9780fef64 Mon Sep 17 00:00:00 2001 From: nquidox Date: Sun, 19 Oct 2025 19:43:33 +0300 Subject: [PATCH] switch from pre-signed to public images --- internal/api/merch/controller.go | 2 +- internal/api/merch/helper.go | 12 +++++++++ internal/api/merch/service.go | 32 +++++++++++++++-------- internal/interfaces/mediaStorage.go | 3 ++- internal/mediaStorage/handler.go | 3 +-- internal/mediaStorage/service.go | 39 ++++++++++++++++++++++++----- 6 files changed, 71 insertions(+), 20 deletions(-) diff --git a/internal/api/merch/controller.go b/internal/api/merch/controller.go index 6d7cd5d..3fc8124 100644 --- a/internal/api/merch/controller.go +++ b/internal/api/merch/controller.go @@ -356,7 +356,7 @@ func (co *controller) getMerchImage(c *gin.Context) { ctx, cancel := context.WithTimeout(c.Request.Context(), co.expires) defer cancel() - link, err := co.service.getMerchImage(ctx, userUuid, merchUuid, typeQuery) + link, err := co.service.getPublicImageLink(ctx, userUuid, merchUuid, typeQuery) if err != nil { c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()}) log.WithError(err).Error("Merch | Failed to get merch image") diff --git a/internal/api/merch/helper.go b/internal/api/merch/helper.go index 704cbbd..58e1866 100644 --- a/internal/api/merch/helper.go +++ b/internal/api/merch/helper.go @@ -1,6 +1,7 @@ package merch import ( + "fmt" "strconv" "time" ) @@ -17,3 +18,14 @@ func getPeriod(days string) time.Time { return time.Now().UTC().Add(-(time.Duration(daysInt) * time.Hour * 24)) } + +func (s *service) makeObject(userUuid, merchUuid, imageType string) (string, error) { + switch imageType { + case "thumbnail": + return fmt.Sprintf("%s/merch/%s/thumbnail.jpg", userUuid, merchUuid), nil + case "full": + return fmt.Sprintf("%s/merch/%s/full.jpg", userUuid, merchUuid), nil + default: + return "", fmt.Errorf("unknown image type %s", imageType) + } +} diff --git a/internal/api/merch/service.go b/internal/api/merch/service.go index 31aced3..481ca60 100644 --- a/internal/api/merch/service.go +++ b/internal/api/merch/service.go @@ -303,7 +303,24 @@ func (s *service) uploadMerchImage(ctx context.Context, userUuid, merchUuid, ima return nil } -func (s *service) getMerchImage(ctx context.Context, userUuid, merchUuid, imageType string) (ImageLink, error) { +func (s *service) getPublicImageLink(ctx context.Context, userUuid, merchUuid, imageType string) (ImageLink, error) { + object, err := s.makeObject(userUuid, merchUuid, imageType) + if err != nil { + return ImageLink{}, err + } + + link, etag, err := s.media.GetPublicLink(ctx, s.bucketName, object) + if err != nil { + return ImageLink{}, err + } + + return ImageLink{ + Link: link, + ETag: etag, + }, nil +} + +func (s *service) getPresignedImageLink(ctx context.Context, userUuid, merchUuid, imageType string) (ImageLink, error) { exists, err := s.repo.merchRecordExists(userUuid, merchUuid) if err != nil { return ImageLink{}, err @@ -313,17 +330,12 @@ func (s *service) getMerchImage(ctx context.Context, userUuid, merchUuid, imageT return ImageLink{}, fmt.Errorf("no merch found for user %s with uuid %s", userUuid, merchUuid) } - var object string - switch imageType { - case "thumbnail": - object = fmt.Sprintf("%s/merch/%s/thumbnail.jpg", userUuid, merchUuid) - case "full": - object = fmt.Sprintf("%s/merch/%s/full.jpg", userUuid, merchUuid) - default: - return ImageLink{}, fmt.Errorf("unknown image type %s", imageType) + object, err := s.makeObject(userUuid, merchUuid, imageType) + if err != nil { + return ImageLink{}, err } - link, err := s.media.Get(ctx, s.bucketName, object, s.expires, nil) + link, err := s.media.GetPresignedLink(ctx, s.bucketName, object, s.expires, nil) if err != nil { return ImageLink{}, err } diff --git a/internal/interfaces/mediaStorage.go b/internal/interfaces/mediaStorage.go index b332a5f..64fb50b 100644 --- a/internal/interfaces/mediaStorage.go +++ b/internal/interfaces/mediaStorage.go @@ -10,7 +10,8 @@ import ( type MediaStorage interface { CheckBucketExists(bucketName string) (bool, error) Upload(ctx context.Context, bucket, object string, reader io.Reader, size int64) error - Get(ctx context.Context, bucket, object string, expires time.Duration, params url.Values) (string, error) + GetPublicLink(ctx context.Context, bucket, object string) (string, string, error) + GetPresignedLink(ctx context.Context, bucket, object string, expires time.Duration, params url.Values) (string, error) Delete(ctx context.Context, bucket, object string) error GetObjectEtag(ctx context.Context, bucketName, object string) (string, error) } diff --git a/internal/mediaStorage/handler.go b/internal/mediaStorage/handler.go index c1586eb..ca88475 100644 --- a/internal/mediaStorage/handler.go +++ b/internal/mediaStorage/handler.go @@ -14,7 +14,6 @@ type Deps struct { Endpoint string User string Password string - Domain string Secure string } @@ -38,6 +37,6 @@ func NewHandler(deps Deps) *Handler { }).Debug("Media storage | Created minio client") return &Handler{ - newService(minioClient), + newService(minioClient, deps.Endpoint, secureMode), } } diff --git a/internal/mediaStorage/service.go b/internal/mediaStorage/service.go index 6c4b03a..a67a20c 100644 --- a/internal/mediaStorage/service.go +++ b/internal/mediaStorage/service.go @@ -2,22 +2,26 @@ package mediaStorage import ( "context" + "fmt" "github.com/minio/minio-go/v7" log "github.com/sirupsen/logrus" "io" "net/url" + "strings" "time" ) type Service struct { - client *minio.Client - domain string - endpoint string + client *minio.Client + endpoint string + secureMode bool } -func newService(client *minio.Client) *Service { +func newService(client *minio.Client, endpoint string, secureMode bool) *Service { return &Service{ - client: client, + client: client, + endpoint: endpoint, + secureMode: secureMode, } } @@ -37,7 +41,30 @@ func (s *Service) Upload(ctx context.Context, bucket, object string, reader io.R return err } -func (s *Service) Get(ctx context.Context, bucket, object string, expires time.Duration, params url.Values) (string, error) { +func (s *Service) GetPublicLink(ctx context.Context, bucket, object string) (string, string, error) { + stat, err := s.client.StatObject(ctx, bucket, object, minio.StatObjectOptions{}) + if err != nil { + log.WithFields(log.Fields{ + "error": err, + "key": bucket + "/" + object, + }).Error("Media storage | Failed to get public link") + return "", "", err + } + + var scheme string + if s.secureMode { + scheme = "https" + } else { + scheme = "http" + } + + link := fmt.Sprintf("%s://%s/%s/%s", scheme, strings.TrimRight(s.endpoint, "/"), bucket, object) + log.WithFields(log.Fields{"link": link}).Debug("Media storage | Get public link") + + return link, stat.ETag, nil +} + +func (s *Service) GetPresignedLink(ctx context.Context, bucket, object string, expires time.Duration, params url.Values) (string, error) { presigned, err := s.client.PresignedGetObject(ctx, bucket, object, expires, params) if err != nil { return "", err