merch images crud
This commit is contained in:
parent
e708c92d18
commit
dec89435a3
5 changed files with 387 additions and 13 deletions
|
|
@ -1,23 +1,27 @@
|
||||||
package merch
|
package merch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"merch-parser-api/internal/interfaces"
|
"merch-parser-api/internal/interfaces"
|
||||||
"merch-parser-api/pkg/responses"
|
"merch-parser-api/pkg/responses"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type controller struct {
|
type controller struct {
|
||||||
service *service
|
service *service
|
||||||
utils interfaces.Utils
|
utils interfaces.Utils
|
||||||
|
expires time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func newController(service *service, utils interfaces.Utils) *controller {
|
func newController(service *service, utils interfaces.Utils, expires time.Duration) *controller {
|
||||||
return &controller{
|
return &controller{
|
||||||
service: service,
|
service: service,
|
||||||
utils: utils,
|
utils: utils,
|
||||||
|
expires: expires,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,6 +38,10 @@ func (h *Handler) RegisterRoutes(r *gin.RouterGroup, authMW gin.HandlerFunc, ref
|
||||||
chartsGroup.GET("", h.controller.getChartsPrices)
|
chartsGroup.GET("", h.controller.getChartsPrices)
|
||||||
chartsGroup.GET("/:uuid", h.controller.getDistinctPrices)
|
chartsGroup.GET("/:uuid", h.controller.getDistinctPrices)
|
||||||
|
|
||||||
|
imagesGroup := merchGroup.Group("/images")
|
||||||
|
imagesGroup.POST("/:uuid", h.controller.uploadMerchImage)
|
||||||
|
imagesGroup.GET("/:uuid", h.controller.getMerchImage)
|
||||||
|
imagesGroup.DELETE("/:uuid", h.controller.deleteMerchImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Добавить новый мерч
|
// @Summary Добавить новый мерч
|
||||||
|
|
@ -134,10 +142,10 @@ func (co *controller) getAllMerch(c *gin.Context) {
|
||||||
// @Description Обновить информацию про мерч по его uuid в json-е
|
// @Description Обновить информацию про мерч по его uuid в json-е
|
||||||
// @Tags Merch
|
// @Tags Merch
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
// @Param body body UpdateMerchDTO true "merch_uuid"
|
// @Param body body UpdateMerchDTO true "merch_uuid"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Failure 400 {object} responses.ErrorResponse400
|
// @Failure 400 {object} responses.ErrorResponse400
|
||||||
// @Failure 500 {object} responses.ErrorResponse500
|
// @Failure 500 {object} responses.ErrorResponse500
|
||||||
// @Router /merch/ [put]
|
// @Router /merch/ [put]
|
||||||
func (co *controller) updateMerch(c *gin.Context) {
|
func (co *controller) updateMerch(c *gin.Context) {
|
||||||
var payload UpdateMerchDTO
|
var payload UpdateMerchDTO
|
||||||
|
|
@ -227,10 +235,10 @@ func (co *controller) getChartsPrices(c *gin.Context) {
|
||||||
// @Tags Merch
|
// @Tags Merch
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
// @Param uuid path string true "merch_uuid"
|
// @Param uuid path string true "merch_uuid"
|
||||||
// @Param days query string false "period in days"
|
// @Param days query string false "period in days"
|
||||||
// @Success 200 {object} PricesResponse
|
// @Success 200 {object} PricesResponse
|
||||||
// @Failure 400 {object} responses.ErrorResponse400
|
// @Failure 400 {object} responses.ErrorResponse400
|
||||||
// @Failure 500 {object} responses.ErrorResponse500
|
// @Failure 500 {object} responses.ErrorResponse500
|
||||||
// @Router /prices/{uuid} [get]
|
// @Router /prices/{uuid} [get]
|
||||||
func (co *controller) getDistinctPrices(c *gin.Context) {
|
func (co *controller) getDistinctPrices(c *gin.Context) {
|
||||||
daysQuery := strings.ToLower(c.DefaultQuery("days", ""))
|
daysQuery := strings.ToLower(c.DefaultQuery("days", ""))
|
||||||
|
|
@ -257,3 +265,138 @@ func (co *controller) getDistinctPrices(c *gin.Context) {
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Загрузить картинки по merch_uuid и query параметрам
|
||||||
|
// @Description Загрузить картинки по merch_uuid и query параметрам
|
||||||
|
// @Tags Merch images
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Accept multipart/form-data
|
||||||
|
// @Produce json
|
||||||
|
// @Param uuid path string true "Merch UUID"
|
||||||
|
// @Param file formData file true "Image file"
|
||||||
|
// @Param imageType formData string true "Image type: thumbnail, full or all" Enums(thumbnail, full, all)
|
||||||
|
// @Success 200
|
||||||
|
// @Failure 400 {object} responses.ErrorResponse400
|
||||||
|
// @Failure 500 {object} responses.ErrorResponse500
|
||||||
|
// @Router /merch/images/{uuid} [post]
|
||||||
|
func (co *controller) uploadMerchImage(c *gin.Context) {
|
||||||
|
userUuid, err := co.utils.GetUserUuidFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
|
||||||
|
log.WithError(err).Error("Merch | Failed to get user uuid from context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
merchUuid := c.Param("uuid")
|
||||||
|
if merchUuid == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: "MerchUuid is empty"})
|
||||||
|
log.Error("Merch | Failed to get single merch")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
imageType := c.PostForm("imageType")
|
||||||
|
types := map[string]struct{}{"thumbnail": {}, "full": {}, "all": {}}
|
||||||
|
if _, allowed := types[imageType]; !allowed {
|
||||||
|
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: "imageType must be one of: thumbnail, full, all"})
|
||||||
|
log.WithError(err).Error("Merch | imageType must be one of: thumbnail, full, all")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := c.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: "file is required"})
|
||||||
|
log.WithError(err).Error("Merch | File is required")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c.Request.Context(), co.expires)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
err = co.service.uploadMerchImage(ctx, userUuid, merchUuid, imageType, file)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
|
||||||
|
log.WithError(err).Error("Merch | Failed to upload merch image")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Status(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Получить картинки по merch_uuid и query параметрам
|
||||||
|
// @Description Получить картинки по merch_uuid и query параметрам
|
||||||
|
// @Tags Merch images
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param uuid path string true "merch_uuid"
|
||||||
|
// @Param type query string true "image type"
|
||||||
|
// @Success 200 {object} ImageLink
|
||||||
|
// @Failure 400 {object} responses.ErrorResponse400
|
||||||
|
// @Failure 500 {object} responses.ErrorResponse500
|
||||||
|
// @Router /merch/images/{uuid} [get]
|
||||||
|
func (co *controller) getMerchImage(c *gin.Context) {
|
||||||
|
typeQuery := strings.ToLower(c.Query("type"))
|
||||||
|
if typeQuery == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: "Image type query param is empty"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userUuid, err := co.utils.GetUserUuidFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
|
||||||
|
log.WithError(err).Error("Merch | Failed to get user uuid from context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
merchUuid := c.Param("uuid")
|
||||||
|
if merchUuid == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: "MerchUuid is empty"})
|
||||||
|
log.WithError(err).Error("Merch | Failed to get single merch")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c.Request.Context(), co.expires)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
link, err := co.service.getMerchImage(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")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, ImageLink{Link: link.String()})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Удалить (безвозвратно) картинки по merch_uuid и query параметрам
|
||||||
|
// @Description Удалить (безвозвратно) картинки по merch_uuid и query параметрам
|
||||||
|
// @Tags Merch images
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param uuid path string true "merch_uuid"
|
||||||
|
// @Param type query string true "image type"
|
||||||
|
// @Success 200 {object} PricesResponse
|
||||||
|
// @Failure 400 {object} responses.ErrorResponse400
|
||||||
|
// @Failure 500 {object} responses.ErrorResponse500
|
||||||
|
// @Router /merch/images/{uuid} [delete]
|
||||||
|
func (co *controller) deleteMerchImage(c *gin.Context) {
|
||||||
|
userUuid, err := co.utils.GetUserUuidFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
|
||||||
|
log.WithError(err).Error("Merch | Failed to get user uuid from context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
merchUuid := c.Param("uuid")
|
||||||
|
if merchUuid == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: "MerchUuid is empty"})
|
||||||
|
log.WithError(err).Error("Merch | Failed to get single merch")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c.Request.Context(), co.expires)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := co.service.deleteMerchImage(ctx, userUuid, merchUuid); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
|
||||||
|
log.WithError(err).Error("Merch | Failed to delete merch image")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Status(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,3 +53,7 @@ type UpdateMerchDTO struct {
|
||||||
Origin string `json:"origin"`
|
Origin string `json:"origin"`
|
||||||
Link string `json:"link"`
|
Link string `json:"link"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ImageLink struct {
|
||||||
|
Link string `json:"link"`
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package merch
|
package merch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"merch-parser-api/internal/interfaces"
|
"merch-parser-api/internal/interfaces"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
|
|
@ -14,12 +16,25 @@ type Handler struct {
|
||||||
type Deps struct {
|
type Deps struct {
|
||||||
DB *gorm.DB
|
DB *gorm.DB
|
||||||
Utils interfaces.Utils
|
Utils interfaces.Utils
|
||||||
|
Media interfaces.MediaStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(deps Deps) *Handler {
|
func NewHandler(deps Deps) *Handler {
|
||||||
|
packageBucketName := "user-merch-images"
|
||||||
|
expires := time.Minute * 1
|
||||||
|
|
||||||
r := NewRepo(deps.DB)
|
r := NewRepo(deps.DB)
|
||||||
s := newService(r)
|
s := newService(r, deps.Media, packageBucketName, expires)
|
||||||
c := newController(s, deps.Utils)
|
c := newController(s, deps.Utils, expires)
|
||||||
|
|
||||||
|
media := deps.Media
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"addr": media,
|
||||||
|
}).Debug("Merch handler constructor | Media provider")
|
||||||
|
|
||||||
|
if err := media.СreateBucketIfNotExists(packageBucketName); err != nil {
|
||||||
|
log.WithError(err).Fatal("Merch handler constructor | Failed to ensure bucket exists")
|
||||||
|
}
|
||||||
|
|
||||||
return &Handler{
|
return &Handler{
|
||||||
repo: r,
|
repo: r,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ func NewRepo(db *gorm.DB) *Repo {
|
||||||
type repository interface {
|
type repository interface {
|
||||||
addMerch(bundle merchBundle) error
|
addMerch(bundle merchBundle) error
|
||||||
|
|
||||||
|
merchRecordExists(userUuid, merchUuid string) (bool, error)
|
||||||
getSingleMerch(userUuid, merchUuid string) (merchBundle, error)
|
getSingleMerch(userUuid, merchUuid string) (merchBundle, error)
|
||||||
getAllMerch(userUuid string) ([]ListResponse, error)
|
getAllMerch(userUuid string) ([]ListResponse, error)
|
||||||
|
|
||||||
|
|
@ -54,6 +55,19 @@ func (r *Repo) addMerch(bundle merchBundle) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Repo) merchRecordExists(userUuid, merchUuid string) (bool, error) {
|
||||||
|
var exists bool
|
||||||
|
err := r.db.Raw(`
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM merch
|
||||||
|
WHERE user_uuid = ?
|
||||||
|
AND merch_uuid = ?
|
||||||
|
);`, userUuid, merchUuid).Scan(&exists).Error
|
||||||
|
|
||||||
|
return exists, err
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Repo) getSingleMerch(userUuid, merchUuid string) (merchBundle, error) {
|
func (r *Repo) getSingleMerch(userUuid, merchUuid string) (merchBundle, error) {
|
||||||
var merch Merch
|
var merch Merch
|
||||||
if err := r.db.
|
if err := r.db.
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,49 @@
|
||||||
package merch
|
package merch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/disintegration/imaging"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"image"
|
||||||
|
"image/jpeg"
|
||||||
|
"io"
|
||||||
|
"merch-parser-api/internal/interfaces"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
repo repository
|
repo repository
|
||||||
|
media interfaces.MediaStorage
|
||||||
|
bucketName string
|
||||||
|
expires time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func newService(repo repository) *service {
|
func newService(repo repository, media interfaces.MediaStorage, bucketName string, expires time.Duration) *service {
|
||||||
return &service{
|
return &service{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
|
media: media,
|
||||||
|
bucketName: bucketName,
|
||||||
|
expires: expires,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type uploadImageParams struct {
|
||||||
|
ctx context.Context
|
||||||
|
src io.Reader
|
||||||
|
imageType string
|
||||||
|
object string
|
||||||
|
quality int
|
||||||
|
}
|
||||||
|
|
||||||
func (s *service) addMerch(payload MerchDTO, userUuid string) error {
|
func (s *service) addMerch(payload MerchDTO, userUuid string) error {
|
||||||
merchUuid := uuid.NewString()
|
merchUuid := uuid.NewString()
|
||||||
|
|
||||||
|
|
@ -80,6 +107,13 @@ func (s *service) updateMerch(payload UpdateMerchDTO, userUuid string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) deleteMerch(userUuid, merchUuid string) error {
|
func (s *service) deleteMerch(userUuid, merchUuid string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), s.expires)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := s.deleteMerchImage(ctx, userUuid, merchUuid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return s.repo.deleteMerch(userUuid, merchUuid)
|
return s.repo.deleteMerch(userUuid, merchUuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,3 +210,167 @@ func (s *service) getDistinctPrices(userUuid, merchUuid, days string) (PricesRes
|
||||||
Origins: []OriginWithPrices{originSurugaya, originMandarake},
|
Origins: []OriginWithPrices{originSurugaya, originMandarake},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) uploadMerchImage(ctx context.Context, userUuid, merchUuid, imageType string, file *multipart.FileHeader) error {
|
||||||
|
exists, err := s.repo.merchRecordExists(userUuid, merchUuid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return fmt.Errorf("no merch found for user %s with uuid %s", userUuid, merchUuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
rawExt := filepath.Ext(file.Filename)
|
||||||
|
if rawExt == "" {
|
||||||
|
return errors.New("no file extension")
|
||||||
|
}
|
||||||
|
|
||||||
|
ext := strings.ToLower(rawExt[1:])
|
||||||
|
allowedTypes := map[string]struct{}{"jpeg": {}, "jpg": {}, "png": {}, "gif": {}}
|
||||||
|
if _, ok := allowedTypes[ext]; !ok {
|
||||||
|
return errors.New("invalid file type")
|
||||||
|
}
|
||||||
|
|
||||||
|
getSrc := func() (io.ReadCloser, error) {
|
||||||
|
f, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Merch | Failed to open file")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch imageType {
|
||||||
|
case "thumbnail":
|
||||||
|
src, err := getSrc()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s._uploadToStorage(uploadImageParams{
|
||||||
|
ctx: ctx,
|
||||||
|
src: src,
|
||||||
|
imageType: "thumbnail",
|
||||||
|
object: fmt.Sprintf("%s/merch/%s/thumbnail.jpg", userUuid, merchUuid),
|
||||||
|
quality: 80,
|
||||||
|
})
|
||||||
|
|
||||||
|
case "full":
|
||||||
|
src, err := getSrc()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s._uploadToStorage(uploadImageParams{
|
||||||
|
ctx: ctx,
|
||||||
|
src: src,
|
||||||
|
imageType: "full",
|
||||||
|
object: fmt.Sprintf("%s/merch/%s/full.jpg", userUuid, merchUuid),
|
||||||
|
quality: 90,
|
||||||
|
})
|
||||||
|
|
||||||
|
case "all":
|
||||||
|
src, err := getSrc()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = s._uploadToStorage(uploadImageParams{
|
||||||
|
ctx: ctx,
|
||||||
|
src: src,
|
||||||
|
imageType: "thumbnail",
|
||||||
|
object: fmt.Sprintf("%s/merch/%s/thumbnail.jpg", userUuid, merchUuid),
|
||||||
|
quality: 80,
|
||||||
|
}); err != nil {
|
||||||
|
log.WithError(err).Error("Merch | Upload thumbnail and full image")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
src2, err := getSrc()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = s._uploadToStorage(uploadImageParams{
|
||||||
|
ctx: ctx,
|
||||||
|
src: src2,
|
||||||
|
imageType: "full",
|
||||||
|
object: fmt.Sprintf("%s/merch/%s/full.jpg", userUuid, merchUuid),
|
||||||
|
quality: 90,
|
||||||
|
}); err != nil {
|
||||||
|
log.WithError(err).Error("Merch | Upload thumbnail and full image")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return errors.New("invalid file type")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) getMerchImage(ctx context.Context, userUuid, merchUuid, imageType string) (*url.URL, error) {
|
||||||
|
exists, err := s.repo.merchRecordExists(userUuid, merchUuid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return nil, 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 nil, fmt.Errorf("unknown image type %s", imageType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.media.Get(ctx, s.bucketName, object, s.expires, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) deleteMerchImage(ctx context.Context, userUuid, merchUuid string) error {
|
||||||
|
exists, err := s.repo.merchRecordExists(userUuid, merchUuid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return fmt.Errorf("no merch found for user %s with uuid %s", userUuid, merchUuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = s.media.Delete(ctx, s.bucketName, fmt.Sprintf("%s/merch/%s/thumbnail.jpg", userUuid, merchUuid)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = s.media.Delete(ctx, s.bucketName, fmt.Sprintf("%s/merch/%s/full.jpg", userUuid, merchUuid)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) _uploadToStorage(params uploadImageParams) error {
|
||||||
|
img, _, err := image.Decode(params.src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode image: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.imageType == "thumbnail" {
|
||||||
|
img = imaging.Resize(img, 300, 300, imaging.Lanczos)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err = jpeg.Encode(&buf, img, &jpeg.Options{Quality: params.quality}); err != nil {
|
||||||
|
return fmt.Errorf("failed to encode full image: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.media.Upload(params.ctx, s.bucketName, params.object, &buf, -1)
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"error": err,
|
||||||
|
"img type": "full",
|
||||||
|
}).Error("Merch | Failed to upload file to media storage")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue