develop basic APIs / optimize database organization

This commit is contained in:
2025-02-13 18:13:08 +08:00
parent 3e51ab8e3f
commit ab4e9c4d59
23 changed files with 1159 additions and 246 deletions

View File

@@ -17,7 +17,6 @@ func GetAlbumDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := storage.NewGetAlbumDetailLogic(r.Context(), svcCtx)
resp, err := l.GetAlbumDetail(&req)
if err != nil {

View File

@@ -3,15 +3,23 @@ package storage
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/storage"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
"schisandra-album-cloud-microservices/common/xhttp"
)
func QueryLocationImageListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.LocationListRequest
if err := httpx.Parse(r, &req); err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := storage.NewQueryLocationImageListLogic(r.Context(), svcCtx)
resp, err := l.QueryLocationImageList()
resp, err := l.QueryLocationImageList(&req)
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {

View File

@@ -3,15 +3,23 @@ package storage
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/storage"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
"schisandra-album-cloud-microservices/common/xhttp"
)
func QueryThingImageListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ThingListRequest
if err := httpx.Parse(r, &req); err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := storage.NewQueryThingImageListLogic(r.Context(), svcCtx)
resp, err := l.QueryThingImageList()
resp, err := l.QueryThingImageList(&req)
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {

View File

@@ -2,6 +2,18 @@ package storage
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/redis/go-redis/v9"
"math/rand"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/app/auth/model/mysql/query"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
"sync"
"time"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
@@ -23,8 +35,172 @@ func NewGetAlbumDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Ge
}
}
func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest) (resp string, err error) {
// todo: add your logic here and delete this line
func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest) (resp *types.AlbumDetailListResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
// 缓存获取数据 v1.0.0
cacheKey := fmt.Sprintf("%s%s:%s:%s:%v", constant.ImageListPrefix, uid, req.Provider, req.Bucket, req.ID)
// 尝试从缓存获取
cachedResult, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err == nil {
var cachedResponse types.AlbumDetailListResponse
if err := json.Unmarshal([]byte(cachedResult), &cachedResponse); err == nil {
return &cachedResponse, nil
}
logx.Error("Failed to unmarshal cached image list:", err)
return nil, errors.New("get cached image list failed")
} else if !errors.Is(err, redis.Nil) {
logx.Error("Redis error:", err)
return nil, errors.New("get cached image list failed")
}
return
// 缓存未命中,从数据库中查询
storageInfo := l.svcCtx.DB.ScaStorageInfo
// 数据库查询文件信息列表
var storageInfoQuery query.IScaStorageInfoDo
storageInfoQuery = storageInfo.Where(
storageInfo.UserID.Eq(uid),
storageInfo.Provider.Eq(req.Provider),
storageInfo.Bucket.Eq(req.Bucket),
storageInfo.AlbumID.Eq(req.ID)).
Order(storageInfo.CreatedAt.Desc())
storageInfoList, err := storageInfoQuery.Find()
if err != nil {
return nil, err
}
if len(storageInfoList) == 0 {
return &types.AlbumDetailListResponse{}, nil
}
// 加载用户oss配置信息
cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider)
if err != nil {
return nil, err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return nil, errors.New("get storage failed")
}
// 按日期进行分组
var wg sync.WaitGroup
groupedImages := sync.Map{}
for _, dbFileInfo := range storageInfoList {
wg.Add(1)
go func(dbFileInfo *model.ScaStorageInfo) {
defer wg.Done()
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
if err != nil {
logx.Error(err)
return
}
// 使用 Load 或 Store 确保原子操作
value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{})
images := value.([]types.ImageMeta)
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
URL: url,
Width: dbFileInfo.Width,
Height: dbFileInfo.Height,
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
})
// 重新存储更新后的图像列表
groupedImages.Store(date, images)
}(dbFileInfo)
}
wg.Wait()
var imageList []types.AllImageDetail
groupedImages.Range(func(key, value interface{}) bool {
imageList = append(imageList, types.AllImageDetail{
Date: key.(string),
List: value.([]types.ImageMeta),
})
return true
})
resp = &types.AlbumDetailListResponse{
Records: imageList,
}
// 缓存结果
if data, err := json.Marshal(resp); err == nil {
expireTime := 7*24*time.Hour - time.Duration(rand.Intn(60))*time.Minute
if err := l.svcCtx.RedisClient.Set(l.ctx, cacheKey, data, expireTime).Err(); err != nil {
logx.Error("Failed to cache image list:", err)
}
} else {
logx.Error("Failed to marshal image list for caching:", err)
}
return resp, nil
}
// 提取解密操作为函数
func (l *GetAlbumDetailLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt access key failed")
}
secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
BucketName: config.Bucket,
Region: config.Region,
}, nil
}
// 从缓存或数据库中获取 OSS 配置
func (l *GetAlbumDetailLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) {
result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil && !errors.Is(err, redis.Nil) {
return nil, errors.New("get oss config failed")
}
var ossConfig *storageConfig.StorageConfig
if result != "" {
var redisOssConfig model.ScaStorageConfig
if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil {
return nil, errors.New("unmarshal oss config failed")
}
return l.decryptConfig(&redisOssConfig)
}
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}
// 缓存数据库配置
ossConfig, err = l.decryptConfig(dbOssConfig)
if err != nil {
return nil, err
}
marshalData, err := json.Marshal(dbOssConfig)
if err != nil {
return nil, errors.New("marshal oss config failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err()
if err != nil {
return nil, errors.New("set oss config failed")
}
return ossConfig, nil
}

View File

@@ -2,6 +2,18 @@ package storage
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/redis/go-redis/v9"
"math/rand"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/app/auth/model/mysql/query"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
"sync"
"time"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
@@ -23,8 +35,172 @@ func NewGetFaceDetailListLogic(ctx context.Context, svcCtx *svc.ServiceContext)
}
}
func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequest) (resp string, err error) {
// todo: add your logic here and delete this line
func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequest) (resp *types.FaceDetailListResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
// 缓存获取数据 v1.0.0
cacheKey := fmt.Sprintf("%s%s:%s:%s:%v", constant.ImageFaceListPrefix, uid, req.Provider, req.Bucket, req.FaceID)
// 尝试从缓存获取
cachedResult, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err == nil {
var cachedResponse types.FaceDetailListResponse
if err := json.Unmarshal([]byte(cachedResult), &cachedResponse); err == nil {
return &cachedResponse, nil
}
logx.Error("Failed to unmarshal cached image list:", err)
return nil, errors.New("get cached image list failed")
} else if !errors.Is(err, redis.Nil) {
logx.Error("Redis error:", err)
return nil, errors.New("get cached image list failed")
}
return
// 缓存未命中,从数据库中查询
storageInfo := l.svcCtx.DB.ScaStorageInfo
// 数据库查询文件信息列表
var storageInfoQuery query.IScaStorageInfoDo
storageInfoQuery = storageInfo.Where(
storageInfo.UserID.Eq(uid),
storageInfo.Provider.Eq(req.Provider),
storageInfo.Bucket.Eq(req.Bucket),
storageInfo.FaceID.Eq(req.FaceID)).
Order(storageInfo.CreatedAt.Desc())
storageInfoList, err := storageInfoQuery.Find()
if err != nil {
return nil, err
}
if len(storageInfoList) == 0 {
return &types.FaceDetailListResponse{}, nil
}
// 加载用户oss配置信息
cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider)
if err != nil {
return nil, err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return nil, errors.New("get storage failed")
}
// 按日期进行分组
var wg sync.WaitGroup
groupedImages := sync.Map{}
for _, dbFileInfo := range storageInfoList {
wg.Add(1)
go func(dbFileInfo *model.ScaStorageInfo) {
defer wg.Done()
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
if err != nil {
logx.Error(err)
return
}
// 使用 Load 或 Store 确保原子操作
value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{})
images := value.([]types.ImageMeta)
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
URL: url,
Width: dbFileInfo.Width,
Height: dbFileInfo.Height,
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
})
// 重新存储更新后的图像列表
groupedImages.Store(date, images)
}(dbFileInfo)
}
wg.Wait()
var imageList []types.AllImageDetail
groupedImages.Range(func(key, value interface{}) bool {
imageList = append(imageList, types.AllImageDetail{
Date: key.(string),
List: value.([]types.ImageMeta),
})
return true
})
resp = &types.FaceDetailListResponse{
Records: imageList,
}
// 缓存结果
if data, err := json.Marshal(resp); err == nil {
expireTime := 7*24*time.Hour - time.Duration(rand.Intn(60))*time.Minute
if err := l.svcCtx.RedisClient.Set(l.ctx, cacheKey, data, expireTime).Err(); err != nil {
logx.Error("Failed to cache image list:", err)
}
} else {
logx.Error("Failed to marshal image list for caching:", err)
}
return resp, nil
}
// 提取解密操作为函数
func (l *GetFaceDetailListLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt access key failed")
}
secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
BucketName: config.Bucket,
Region: config.Region,
}, nil
}
// 从缓存或数据库中获取 OSS 配置
func (l *GetFaceDetailListLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) {
result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil && !errors.Is(err, redis.Nil) {
return nil, errors.New("get oss config failed")
}
var ossConfig *storageConfig.StorageConfig
if result != "" {
var redisOssConfig model.ScaStorageConfig
if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil {
return nil, errors.New("unmarshal oss config failed")
}
return l.decryptConfig(&redisOssConfig)
}
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}
// 缓存数据库配置
ossConfig, err = l.decryptConfig(dbOssConfig)
if err != nil {
return nil, err
}
marshalData, err := json.Marshal(dbOssConfig)
if err != nil {
return nil, errors.New("marshal oss config failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err()
if err != nil {
return nil, errors.New("set oss config failed")
}
return ossConfig, nil
}

View File

@@ -35,7 +35,7 @@ func (l *ModifyFaceLibraryTypeLogic) ModifyFaceLibraryType(req *types.ModifyFace
return nil, err
}
storageInfo := l.svcCtx.DB.ScaStorageInfo
resultInfo, err := storageInfo.Where(storageInfo.FaceID.In(req.IDs...)).Update(storageInfo.ImgShow, req.FaceType)
resultInfo, err := storageInfo.Where(storageInfo.FaceID.In(req.IDs...)).Update(storageInfo.IsDisplayed, req.FaceType)
if err != nil {
return nil, err
}

View File

@@ -173,7 +173,7 @@ func (l *QueryAllImageListLogic) decryptConfig(config *model.ScaStorageConfig) (
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Type,
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
@@ -200,7 +200,7 @@ func (l *QueryAllImageListLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provid
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Type.Eq(provider)).First()
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}

View File

@@ -2,6 +2,18 @@ package storage
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/redis/go-redis/v9"
"math/rand"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/app/auth/model/mysql/query"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
"sync"
"time"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
@@ -24,7 +36,171 @@ func NewQueryLocationDetailListLogic(ctx context.Context, svcCtx *svc.ServiceCon
}
func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.LocationDetailListRequest) (resp *types.LocationDetailListResponse, err error) {
// todo: add your logic here and delete this line
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
// 缓存获取数据 v1.0.0
cacheKey := fmt.Sprintf("%s%s:%s:%s:%v", constant.ImageListPrefix, uid, req.Provider, req.Bucket, req.ID)
// 尝试从缓存获取
cachedResult, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err == nil {
var cachedResponse types.LocationDetailListResponse
if err := json.Unmarshal([]byte(cachedResult), &cachedResponse); err == nil {
return &cachedResponse, nil
}
logx.Error("Failed to unmarshal cached image list:", err)
return nil, errors.New("get cached image list failed")
} else if !errors.Is(err, redis.Nil) {
logx.Error("Redis error:", err)
return nil, errors.New("get cached image list failed")
}
return
// 缓存未命中,从数据库中查询
storageInfo := l.svcCtx.DB.ScaStorageInfo
// 数据库查询文件信息列表
var storageInfoQuery query.IScaStorageInfoDo
storageInfoQuery = storageInfo.Where(
storageInfo.UserID.Eq(uid),
storageInfo.Provider.Eq(req.Provider),
storageInfo.Bucket.Eq(req.Bucket),
storageInfo.LocationID.Eq(req.ID)).
Order(storageInfo.CreatedAt.Desc())
storageInfoList, err := storageInfoQuery.Find()
if err != nil {
return nil, err
}
if len(storageInfoList) == 0 {
return &types.LocationDetailListResponse{}, nil
}
// 加载用户oss配置信息
cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider)
if err != nil {
return nil, err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return nil, errors.New("get storage failed")
}
// 按日期进行分组
var wg sync.WaitGroup
groupedImages := sync.Map{}
for _, dbFileInfo := range storageInfoList {
wg.Add(1)
go func(dbFileInfo *model.ScaStorageInfo) {
defer wg.Done()
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
if err != nil {
logx.Error(err)
return
}
// 使用 Load 或 Store 确保原子操作
value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{})
images := value.([]types.ImageMeta)
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
URL: url,
Width: dbFileInfo.Width,
Height: dbFileInfo.Height,
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
})
// 重新存储更新后的图像列表
groupedImages.Store(date, images)
}(dbFileInfo)
}
wg.Wait()
var imageList []types.AllImageDetail
groupedImages.Range(func(key, value interface{}) bool {
imageList = append(imageList, types.AllImageDetail{
Date: key.(string),
List: value.([]types.ImageMeta),
})
return true
})
resp = &types.LocationDetailListResponse{
Records: imageList,
}
// 缓存结果
if data, err := json.Marshal(resp); err == nil {
expireTime := 7*24*time.Hour - time.Duration(rand.Intn(60))*time.Minute
if err := l.svcCtx.RedisClient.Set(l.ctx, cacheKey, data, expireTime).Err(); err != nil {
logx.Error("Failed to cache image list:", err)
}
} else {
logx.Error("Failed to marshal image list for caching:", err)
}
return resp, nil
}
// 提取解密操作为函数
func (l *QueryLocationDetailListLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt access key failed")
}
secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
BucketName: config.Bucket,
Region: config.Region,
}, nil
}
// 从缓存或数据库中获取 OSS 配置
func (l *QueryLocationDetailListLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) {
result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil && !errors.Is(err, redis.Nil) {
return nil, errors.New("get oss config failed")
}
var ossConfig *storageConfig.StorageConfig
if result != "" {
var redisOssConfig model.ScaStorageConfig
if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil {
return nil, errors.New("unmarshal oss config failed")
}
return l.decryptConfig(&redisOssConfig)
}
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}
// 缓存数据库配置
ossConfig, err = l.decryptConfig(dbOssConfig)
if err != nil {
return nil, err
}
marshalData, err := json.Marshal(dbOssConfig)
if err != nil {
return nil, errors.New("marshal oss config failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err()
if err != nil {
return nil, errors.New("set oss config failed")
}
return ossConfig, nil
}

View File

@@ -2,10 +2,17 @@ package storage
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/redis/go-redis/v9"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
"time"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -24,7 +31,7 @@ func NewQueryLocationImageListLogic(ctx context.Context, svcCtx *svc.ServiceCont
}
}
func (l *QueryLocationImageListLogic) QueryLocationImageList() (resp *types.LocationListResponse, err error) {
func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.LocationListRequest) (resp *types.LocationListResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
@@ -36,11 +43,26 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList() (resp *types.Loca
storageLocation.Country,
storageLocation.City,
storageLocation.Province,
storageLocation.Total).Where(storageLocation.UserID.Eq(uid)).
storageLocation.CoverImage,
storageLocation.Total).Where(storageLocation.UserID.Eq(uid),
storageLocation.Provider.Eq(req.Provider),
storageLocation.Bucket.Eq(req.Bucket)).
Order(storageLocation.CreatedAt.Desc()).Find()
if err != nil {
return nil, err
}
// 加载用户oss配置信息
cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider)
if err != nil {
return nil, err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return nil, errors.New("get storage failed")
}
locationMap := make(map[string][]types.LocationMeta)
for _, loc := range locations {
@@ -55,10 +77,15 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList() (resp *types.Loca
if city == "" {
city = loc.Country
}
url, err := service.PresignedURL(l.ctx, req.Bucket, loc.CoverImage, 7*24*time.Hour)
if err != nil {
return nil, errors.New("get presigned url failed")
}
locationMeta := types.LocationMeta{
ID: loc.ID,
City: city,
Total: loc.Total,
ID: loc.ID,
City: city,
Total: loc.Total,
CoverImage: url,
}
locationMap[locationKey] = append(locationMap[locationKey], locationMeta)
}
@@ -74,3 +101,63 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList() (resp *types.Loca
return &types.LocationListResponse{Records: locationListData}, nil
}
// 提取解密操作为函数
func (l *QueryLocationImageListLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt access key failed")
}
secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
BucketName: config.Bucket,
Region: config.Region,
}, nil
}
// 从缓存或数据库中获取 OSS 配置
func (l *QueryLocationImageListLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) {
result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil && !errors.Is(err, redis.Nil) {
return nil, errors.New("get oss config failed")
}
var ossConfig *storageConfig.StorageConfig
if result != "" {
var redisOssConfig model.ScaStorageConfig
if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil {
return nil, errors.New("unmarshal oss config failed")
}
return l.decryptConfig(&redisOssConfig)
}
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}
// 缓存数据库配置
ossConfig, err = l.decryptConfig(dbOssConfig)
if err != nil {
return nil, err
}
marshalData, err := json.Marshal(dbOssConfig)
if err != nil {
return nil, errors.New("marshal oss config failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err()
if err != nil {
return nil, errors.New("set oss config failed")
}
return ossConfig, nil
}

View File

@@ -2,6 +2,18 @@ package storage
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/redis/go-redis/v9"
"math/rand"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/app/auth/model/mysql/query"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
"sync"
"time"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
@@ -24,7 +36,171 @@ func NewQueryThingDetailListLogic(ctx context.Context, svcCtx *svc.ServiceContex
}
func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailListRequest) (resp *types.ThingDetailListResponse, err error) {
// todo: add your logic here and delete this line
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
// 缓存获取数据 v1.0.0
cacheKey := fmt.Sprintf("%s%s:%s:%s:%v", constant.ImageListPrefix, uid, req.Provider, req.Bucket, req.TagName)
// 尝试从缓存获取
cachedResult, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err == nil {
var cachedResponse types.ThingDetailListResponse
if err := json.Unmarshal([]byte(cachedResult), &cachedResponse); err == nil {
return &cachedResponse, nil
}
logx.Error("Failed to unmarshal cached image list:", err)
return nil, errors.New("get cached image list failed")
} else if !errors.Is(err, redis.Nil) {
logx.Error("Redis error:", err)
return nil, errors.New("get cached image list failed")
}
return
// 缓存未命中,从数据库中查询
storageInfo := l.svcCtx.DB.ScaStorageInfo
// 数据库查询文件信息列表
var storageInfoQuery query.IScaStorageInfoDo
storageInfoQuery = storageInfo.Where(
storageInfo.UserID.Eq(uid),
storageInfo.Provider.Eq(req.Provider),
storageInfo.Bucket.Eq(req.Bucket),
storageInfo.Tag.Eq(req.TagName)).
Order(storageInfo.CreatedAt.Desc())
storageInfoList, err := storageInfoQuery.Find()
if err != nil {
return nil, err
}
if len(storageInfoList) == 0 {
return &types.ThingDetailListResponse{}, nil
}
// 加载用户oss配置信息
cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider)
if err != nil {
return nil, err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return nil, errors.New("get storage failed")
}
// 按日期进行分组
var wg sync.WaitGroup
groupedImages := sync.Map{}
for _, dbFileInfo := range storageInfoList {
wg.Add(1)
go func(dbFileInfo *model.ScaStorageInfo) {
defer wg.Done()
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
if err != nil {
logx.Error(err)
return
}
// 使用 Load 或 Store 确保原子操作
value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{})
images := value.([]types.ImageMeta)
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
URL: url,
Width: dbFileInfo.Width,
Height: dbFileInfo.Height,
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
})
// 重新存储更新后的图像列表
groupedImages.Store(date, images)
}(dbFileInfo)
}
wg.Wait()
var imageList []types.AllImageDetail
groupedImages.Range(func(key, value interface{}) bool {
imageList = append(imageList, types.AllImageDetail{
Date: key.(string),
List: value.([]types.ImageMeta),
})
return true
})
resp = &types.ThingDetailListResponse{
Records: imageList,
}
// 缓存结果
if data, err := json.Marshal(resp); err == nil {
expireTime := 7*24*time.Hour - time.Duration(rand.Intn(60))*time.Minute
if err := l.svcCtx.RedisClient.Set(l.ctx, cacheKey, data, expireTime).Err(); err != nil {
logx.Error("Failed to cache image list:", err)
}
} else {
logx.Error("Failed to marshal image list for caching:", err)
}
return resp, nil
}
// 提取解密操作为函数
func (l *QueryThingDetailListLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt access key failed")
}
secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
BucketName: config.Bucket,
Region: config.Region,
}, nil
}
// 从缓存或数据库中获取 OSS 配置
func (l *QueryThingDetailListLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) {
result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil && !errors.Is(err, redis.Nil) {
return nil, errors.New("get oss config failed")
}
var ossConfig *storageConfig.StorageConfig
if result != "" {
var redisOssConfig model.ScaStorageConfig
if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil {
return nil, errors.New("unmarshal oss config failed")
}
return l.decryptConfig(&redisOssConfig)
}
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}
// 缓存数据库配置
ossConfig, err = l.decryptConfig(dbOssConfig)
if err != nil {
return nil, err
}
marshalData, err := json.Marshal(dbOssConfig)
if err != nil {
return nil, errors.New("marshal oss config failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err()
if err != nil {
return nil, errors.New("set oss config failed")
}
return ossConfig, nil
}

View File

@@ -2,8 +2,15 @@ package storage
import (
"context"
"encoding/json"
"errors"
"github.com/redis/go-redis/v9"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
"sync"
"time"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
@@ -25,7 +32,7 @@ func NewQueryThingImageListLogic(ctx context.Context, svcCtx *svc.ServiceContext
}
}
func (l *QueryThingImageListLogic) QueryThingImageList() (resp *types.ThingListResponse, err error) {
func (l *QueryThingImageListLogic) QueryThingImageList(req *types.ThingListRequest) (resp *types.ThingListResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
@@ -34,33 +41,60 @@ func (l *QueryThingImageListLogic) QueryThingImageList() (resp *types.ThingListR
storageInfos, err := storageInfo.Select(
storageInfo.ID,
storageInfo.Category,
storageInfo.Tags,
storageInfo.Tag,
storageInfo.Path,
storageInfo.CreatedAt).
Where(storageInfo.UserID.Eq(uid),
storageInfo.Provider.Eq(req.Provider),
storageInfo.Bucket.Eq(req.Bucket),
storageInfo.Category.IsNotNull(),
storageInfo.Tags.IsNotNull()).
storageInfo.Tag.IsNotNull(),
storageInfo.Category.Length().Gt(0),
storageInfo.Tag.Length().Gte(0)).
Order(storageInfo.CreatedAt.Desc()).
Find()
if err != nil {
return nil, err
}
// 加载用户oss配置信息
cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider)
if err != nil {
return nil, err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return nil, errors.New("get storage failed")
}
categoryMap := sync.Map{}
tagCountMap := sync.Map{}
tagCoverMap := sync.Map{} // 用于存储每个 Tag 的封面图片路径
for _, info := range storageInfos {
tagKey := info.Category + "::" + info.Tags
tagKey := info.Category + "::" + info.Tag
if _, exists := tagCountMap.Load(tagKey); !exists {
tagCountMap.Store(tagKey, int64(0))
categoryEntry, _ := categoryMap.LoadOrStore(info.Category, &sync.Map{})
tagMap := categoryEntry.(*sync.Map)
tagMap.Store(info.Tags, types.ThingMeta{
TagName: info.Tags,
tagMap.Store(info.Tag, types.ThingMeta{
TagName: info.Tag,
CreatedAt: info.CreatedAt.Format("2006-01-02 15:04:05"),
})
}
tagCount, _ := tagCountMap.Load(tagKey)
tagCountMap.Store(tagKey, tagCount.(int64)+1)
// 为每个 Tag 存储封面图片路径
if _, exists := tagCoverMap.Load(tagKey); !exists {
// 使用服务生成预签名 URL
coverImageURL, err := service.PresignedURL(l.ctx, req.Bucket, info.Path, 7*24*time.Hour)
if err == nil {
tagCoverMap.Store(tagKey, coverImageURL)
}
}
}
var thingListData []types.ThingListData
@@ -71,6 +105,11 @@ func (l *QueryThingImageListLogic) QueryThingImageList() (resp *types.ThingListR
tagCount, _ := tagCountMap.Load(tagKey)
meta := item.(types.ThingMeta)
meta.TagCount = tagCount.(int64)
// 获取封面图片 URL
if coverImageURL, ok := tagCoverMap.Load(tagKey); ok {
meta.CoverImage = coverImageURL.(string)
}
metas = append(metas, meta)
return true
})
@@ -83,3 +122,63 @@ func (l *QueryThingImageListLogic) QueryThingImageList() (resp *types.ThingListR
return &types.ThingListResponse{Records: thingListData}, nil
}
// 提取解密操作为函数
func (l *QueryThingImageListLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt access key failed")
}
secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
BucketName: config.Bucket,
Region: config.Region,
}, nil
}
// 从缓存或数据库中获取 OSS 配置
func (l *QueryThingImageListLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) {
result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil && !errors.Is(err, redis.Nil) {
return nil, errors.New("get oss config failed")
}
var ossConfig *storageConfig.StorageConfig
if result != "" {
var redisOssConfig model.ScaStorageConfig
if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil {
return nil, errors.New("unmarshal oss config failed")
}
return l.decryptConfig(&redisOssConfig)
}
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}
// 缓存数据库配置
ossConfig, err = l.decryptConfig(dbOssConfig)
if err != nil {
return nil, err
}
marshalData, err := json.Marshal(dbOssConfig)
if err != nil {
return nil, errors.New("marshal oss config failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err()
if err != nil {
return nil, errors.New("set oss config failed")
}
return ossConfig, nil
}

View File

@@ -40,7 +40,7 @@ func (l *SetStorageConfigLogic) SetStorageConfig(req *types.StorageConfigRequest
}
ossConfig := &model.ScaStorageConfig{
UserID: uid,
Type: req.Type,
Provider: req.Type,
Endpoint: req.Endpoint,
Bucket: req.Bucket,
AccessKey: accessKey,

View File

@@ -83,29 +83,8 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
}
}
// 解析 EXIF 信息
exif, err := l.parseExifData(result.Exif)
if err != nil {
return "", err
}
// 提取拍摄时间
originalDateTime, err := l.extractOriginalDateTime(exif)
if err != nil {
return "", err
}
// 提取 GPS 信息
latitude, longitude := l.extractGPSCoordinates(exif)
// 根据 GPS 信息获取地理位置信息
country, province, city, err := l.getGeoLocation(latitude, longitude)
if err != nil {
return "", err
}
// 将地址信息保存到数据库
locationId, err := l.saveFileLocationInfoToDB(uid, latitude, longitude, country, province, city)
country, province, city, err := l.getGeoLocation(result.Latitude, result.Longitude)
if err != nil {
return "", err
}
@@ -120,8 +99,14 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
return "", err
}
// 将地址信息保存到数据库
locationId, err := l.saveFileLocationInfoToDB(uid, result.Provider, result.Bucket, result.Latitude, result.Longitude, country, province, city, filePath)
if err != nil {
return "", err
}
// 将 EXIF 和文件信息存入数据库
id, err := l.saveFileInfoToDB(uid, bucket, provider, header, result, originalDateTime, locationId, exif, faceId, filePath)
id, err := l.saveFileInfoToDB(uid, bucket, provider, header, result, locationId, faceId, filePath)
if err != nil {
return "", err
}
@@ -175,23 +160,6 @@ func (l *UploadFileLogic) parseAIRecognitionResult(r *http.Request) (types.File,
return result, nil
}
// 解析 EXIF 数据
func (l *UploadFileLogic) parseExifData(exifData interface{}) (map[string]interface{}, error) {
if exifData == "" {
return nil, nil
}
marshaledExif, err := json.Marshal(exifData)
if err != nil {
return nil, errors.New("invalid exif")
}
var exif map[string]interface{}
if err = json.Unmarshal(marshaledExif, &exif); err != nil {
return nil, errors.New("invalid exif")
}
return exif, nil
}
// 提取拍摄时间
func (l *UploadFileLogic) extractOriginalDateTime(exif map[string]interface{}) (string, error) {
if dateTimeOriginal, ok := exif["DateTimeOriginal"].(string); ok {
@@ -203,18 +171,6 @@ func (l *UploadFileLogic) extractOriginalDateTime(exif map[string]interface{}) (
return "", nil
}
// 提取 GPS 信息
func (l *UploadFileLogic) extractGPSCoordinates(exif map[string]interface{}) (float64, float64) {
var latitude, longitude float64
if lat, ok := exif["latitude"].(float64); ok {
latitude = lat
}
if long, ok := exif["longitude"].(float64); ok {
longitude = long
}
return latitude, longitude
}
// 根据 GPS 信息获取地理位置信息
func (l *UploadFileLogic) getGeoLocation(latitude, longitude float64) (string, string, string, error) {
if latitude == 0.000000 || longitude == 0.000000 {
@@ -284,7 +240,7 @@ func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHead
return ossConfig.BucketName, ossConfig.Provider, objectKey, url, nil
}
func (l *UploadFileLogic) saveFileLocationInfoToDB(uid string, latitude float64, longitude float64, country string, province string, city string) (int64, error) {
func (l *UploadFileLogic) saveFileLocationInfoToDB(uid string, provider string, bucket string, latitude float64, longitude float64, country string, province string, city string, filePath string) (int64, error) {
if latitude == 0.000000 || longitude == 0.000000 {
return 0, nil
}
@@ -295,13 +251,16 @@ func (l *UploadFileLogic) saveFileLocationInfoToDB(uid string, latitude float64,
}
if storageLocations == nil {
locationInfo := model.ScaStorageLocation{
UserID: uid,
Country: country,
City: city,
Province: province,
Latitude: fmt.Sprintf("%f", latitude),
Longitude: fmt.Sprintf("%f", longitude),
Total: 1,
Provider: provider,
Bucket: bucket,
UserID: uid,
Country: country,
City: city,
Province: province,
Latitude: fmt.Sprintf("%f", latitude),
Longitude: fmt.Sprintf("%f", longitude),
Total: 1,
CoverImage: filePath,
}
err = locationDB.Create(&locationInfo)
if err != nil {
@@ -309,7 +268,7 @@ func (l *UploadFileLogic) saveFileLocationInfoToDB(uid string, latitude float64,
}
return locationInfo.ID, nil
} else {
info, err := locationDB.Where(locationDB.ID.Eq(storageLocations.ID), locationDB.UserID.Eq(uid)).Update(locationDB.Total, locationDB.Total.Add(1))
info, err := locationDB.Where(locationDB.ID.Eq(storageLocations.ID), locationDB.UserID.Eq(uid)).UpdateColumnSimple(locationDB.Total.Add(1), locationDB.CoverImage.Value(filePath))
if err != nil {
return 0, err
}
@@ -321,35 +280,29 @@ func (l *UploadFileLogic) saveFileLocationInfoToDB(uid string, latitude float64,
}
// 将 EXIF 和文件信息存入数据库
func (l *UploadFileLogic) saveFileInfoToDB(uid, bucket, provider string, header *multipart.FileHeader, result types.File, originalDateTime string, locationId int64, exif map[string]interface{}, faceId int64, filePath string) (int64, error) {
exifJSON, err := json.Marshal(exif)
if err != nil {
return 0, errors.New("marshal exif failed")
}
func (l *UploadFileLogic) saveFileInfoToDB(uid, bucket, provider string, header *multipart.FileHeader, result types.File, locationId, faceId int64, filePath string) (int64, error) {
typeName := l.classifyFile(result.FileType, result.IsScreenshot)
scaStorageInfo := &model.ScaStorageInfo{
UserID: uid,
Provider: provider,
Bucket: bucket,
FileName: header.Filename,
FileSize: strconv.FormatInt(header.Size, 10),
FileType: result.FileType,
Path: filePath,
Landscape: result.Landscape,
Tags: result.TagName,
Anime: strconv.FormatBool(result.IsAnime),
Category: result.TopCategory,
Screenshot: strconv.FormatBool(result.IsScreenshot),
OriginalTime: originalDateTime,
LocationID: locationId,
Exif: string(exifJSON),
FaceID: faceId,
Type: typeName,
Width: result.Width,
Height: result.Height,
UserID: uid,
Provider: provider,
Bucket: bucket,
FileName: header.Filename,
FileSize: strconv.FormatInt(header.Size, 10),
FileType: result.FileType,
Path: filePath,
Landscape: result.Landscape,
Tag: result.TagName,
IsAnime: strconv.FormatBool(result.IsAnime),
Category: result.TopCategory,
LocationID: locationId,
FaceID: faceId,
Type: typeName,
Width: result.Width,
Height: result.Height,
}
err = l.svcCtx.DB.ScaStorageInfo.Create(scaStorageInfo)
err := l.svcCtx.DB.ScaStorageInfo.Create(scaStorageInfo)
if err != nil {
return 0, errors.New("create storage info failed")
}
@@ -367,7 +320,7 @@ func (l *UploadFileLogic) decryptConfig(dbConfig *model.ScaStorageConfig) (*conf
return nil, errors.New("decrypt secret key failed")
}
return &config.StorageConfig{
Provider: dbConfig.Type,
Provider: dbConfig.Provider,
Endpoint: dbConfig.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
@@ -394,7 +347,7 @@ func (l *UploadFileLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider stri
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Type.Eq(provider)).First()
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}

View File

@@ -10,7 +10,8 @@ type File struct {
Landscape string `json:"landscape"`
TopCategory string `json:"topCategory"`
IsScreenshot bool `json:"isScreenshot"`
Exif any `json:"exif"`
Width float64 `json:"width"`
Height float64 `json:"height"`
Longitude float64 `json:"longitude"`
Latitude float64 `json:"latitude"`
}

View File

@@ -32,7 +32,13 @@ type AlbumDeleteRequest struct {
}
type AlbumDetailListRequest struct {
ID int64 `json:"id"`
ID int64 `json:"id"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
}
type AlbumDetailListResponse struct {
Records []AllImageDetail `json:"records"`
}
type AlbumListRequest struct {
@@ -142,7 +148,13 @@ type CommentResponse struct {
}
type FaceDetailListRequest struct {
FaceID int64 `json:"face_id"`
FaceID int64 `json:"face_id"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
}
type FaceDetailListResponse struct {
Records []AllImageDetail `json:"records"`
}
type FaceSampleLibrary struct {
@@ -169,7 +181,9 @@ type ImageMeta struct {
}
type LocationDetailListRequest struct {
ID int64 `json:"id"`
ID int64 `json:"id"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
}
type LocationDetailListResponse struct {
@@ -181,14 +195,20 @@ type LocationListData struct {
List []LocationMeta `json:"list"` // 图片列表
}
type LocationListRequest struct {
Provider string `json:"provider"`
Bucket string `json:"bucket"`
}
type LocationListResponse struct {
Records []LocationListData `json:"records"`
}
type LocationMeta struct {
ID int64 `json:"id"`
City string `json:"city"`
Total int64 `json:"total"`
ID int64 `json:"id"`
City string `json:"city"`
Total int64 `json:"total"`
CoverImage string `json:"cover_image"`
}
type LoginResponse struct {
@@ -311,7 +331,9 @@ type StorageConfigRequest struct {
}
type ThingDetailListRequest struct {
ID int64 `json:"id"`
TagName string `json:"tag_name"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
}
type ThingDetailListResponse struct {
@@ -323,14 +345,20 @@ type ThingListData struct {
List []ThingMeta `json:"list"` // 图片列表
}
type ThingListRequest struct {
Provider string `json:"provider"`
Bucket string `json:"bucket"`
}
type ThingListResponse struct {
Records []ThingListData `json:"records"`
}
type ThingMeta struct {
TagName string `json:"tag_name"`
CreatedAt string `json:"created_at"`
TagCount int64 `json:"tag_count"`
TagName string `json:"tag_name"`
CreatedAt string `json:"created_at"`
TagCount int64 `json:"tag_count"`
CoverImage string `json:"cover_image"`
}
type UploadRequest struct {