- POST /api/v1/me/photo (multipart, field 'photo')
- MinIO upload via storage.UploadAvatar (avatars/{userID}/{uuid}-{ts})
- /storage/* backend route reads from MinIO + serves with proper headers
- nginx unchanged: /storage/* proxied to backend like everything else
- Bumped to v0.5.0
54 lines
1.7 KiB
Go
54 lines
1.7 KiB
Go
package storage
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"io"
|
||
"time"
|
||
|
||
"github.com/google/uuid"
|
||
"github.com/minio/minio-go/v7"
|
||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||
)
|
||
|
||
type Storage struct {
|
||
Client *minio.Client
|
||
Bucket string
|
||
}
|
||
|
||
func New(ctx context.Context, endpoint, accessKey, secretKey, bucket string, useSSL bool) (*Storage, error) {
|
||
client, err := minio.New(endpoint, &minio.Options{
|
||
Creds: credentials.NewStaticV4(accessKey, secretKey, ""),
|
||
Secure: useSSL,
|
||
})
|
||
if err != nil {
|
||
return nil, fmt.Errorf("minio: %w", err)
|
||
}
|
||
|
||
exists, err := client.BucketExists(ctx, bucket)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("bucket exists check: %w", err)
|
||
}
|
||
if !exists {
|
||
if err := client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}); err != nil {
|
||
return nil, fmt.Errorf("make bucket: %w", err)
|
||
}
|
||
}
|
||
|
||
return &Storage{Client: client, Bucket: bucket}, nil
|
||
}
|
||
|
||
// UploadAvatar — загружает аватар в MinIO и возвращает публичный URL
|
||
// (для MinIO нужен bucket policy или presigned URL — пока делаем простой PUT с публичным доступом через наш backend).
|
||
func (s *Storage) UploadAvatar(ctx context.Context, userID uuid.UUID, contentType string, data io.Reader, size int64) (string, error) {
|
||
key := fmt.Sprintf("avatars/%s/%s-%d", userID.String(), uuid.NewString(), time.Now().Unix())
|
||
_, err := s.Client.PutObject(ctx, s.Bucket, key, data, size, minio.PutObjectOptions{
|
||
ContentType: contentType,
|
||
})
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
// возвращаем относительный URL — бэкенд сам раздаёт через nginx (proxy_pass /storage → MinIO)
|
||
return "/storage/" + key, nil
|
||
}
|