improve image sharing function

This commit is contained in:
2025-02-20 23:04:58 +08:00
parent b196e50aee
commit db4c59f6f6
37 changed files with 2188 additions and 95 deletions

View File

@@ -467,15 +467,15 @@ type (
}
// 相册列表请求参数
AlbumListRequest {
Type string `json:"type"`
Sort bool `json:"sort"`
Type int64 `json:"type,omitempty"`
Sort bool `json:"sort"`
}
// 相册列表响应参数
Album {
ID int64 `json:"id"`
Name string `json:"name"`
CreatedAt string `json:"created_at"`
Type string `json:"type"`
Type int64 `json:"type"`
CoverImage string `json:"cover_image"`
}
AlbumListResponse {
@@ -593,6 +593,18 @@ type (
SingleImageRequest {
ID int64 `json:"id"`
}
StorageMeta {
Name string `json:"name"`
Value string `json:"value"`
}
StroageNode {
Value string `json:"value"`
Name string `json:"name"`
Children []StorageMeta `json:"children"`
}
StorageListResponse {
Records []StroageNode `json:"records"`
}
)
// 文件上传
@@ -679,5 +691,88 @@ service auth {
// 获取单张图片连接
@handler getImageUrl
post /image/url/single (SingleImageRequest) returns (string)
// 获取用户存储配置列表
@handler getUserStorageList
post /user/config/list returns (StorageListResponse)
}
type (
ShareImageMeta {
FileName string `json:"file_name"`
OriginImage string `json:"origin_image"`
FileType string `json:"file_type"`
Thumbnail string `json:"thumbnail"`
ThumbW float64 `json:"thumb_w"`
ThumbH float64 `json:"thumb_h"`
ThumbSize int64 `json:"thumb_size"`
}
ShareImageRequest {
Title string `json:"title,omitempty"`
ExpireDate string `json:"expire_date"`
AccessLimit int64 `json:"access_limit,omitempty"`
AccessPassword string `json:"access_password,omitempty"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
Images []ShareImageMeta `json:"images"`
}
QueryShareImageRequest {
ShareCode string `json:"share_code"`
AccessPassword string `json:"access_password,omitempty"`
}
ShareImageListMeta {
ID int64 `json:"id"`
FileName string `json:"file_name"`
URL string `json:"url"`
Thumbnail string `json:"thumbnail"`
ThumbW float64 `json:"thumb_w"`
ThumbH float64 `json:"thumb_h"`
ThumbSize float64 `json:"thumb_size"`
CreatedAt string `json:"created_at"`
}
QueryShareImageResponse {
List []ShareImageListMeta `json:"list"`
}
ShareRecordListRequest {
DateRange []string `json:"date_range"`
}
// 分享记录列表响应参数
ShareRecord {
ID int64 `json:"id"`
CoverImage string `json:"cover_image"`
CreatedAt string `json:"created_at"`
ShareCode string `json:"share_code"`
VisitLimit int64 `json:"visit_limit"`
AccessPassword string `json:"access_password"`
ValidityPeriod int64 `json:"validity_period"`
}
ShareRecordListResponse {
records []ShareRecord `json:"records"`
}
)
// 分享服务
@server (
group: share // 微服务分组
prefix: /api/auth/share // 微服务前缀
timeout: 10s // 超时时间
maxBytes: 104857600 // 最大请求大小
signature: false // 是否开启签名验证
middleware: SecurityHeadersMiddleware,CasbinVerifyMiddleware,NonceMiddleware // 注册中间件
MaxConns: true // 是否开启最大连接数限制
Recover: true // 是否开启自动恢复
jwt: Auth // 是否开启jwt验证
)
service auth {
@handler uploadShareImage
post /upload (ShareImageRequest) returns (string)
//查看分享图片
@handler queryShareImage
post /image/list (QueryShareImageRequest) returns (QueryShareImageResponse)
// 列出分享记录
@handler listShareRecord
post /record/list (ShareRecordListRequest) returns (ShareRecordListResponse)
}

View File

@@ -11,6 +11,7 @@ import (
client "schisandra-album-cloud-microservices/app/auth/api/internal/handler/client"
comment "schisandra-album-cloud-microservices/app/auth/api/internal/handler/comment"
oauth "schisandra-album-cloud-microservices/app/auth/api/internal/handler/oauth"
share "schisandra-album-cloud-microservices/app/auth/api/internal/handler/share"
sms "schisandra-album-cloud-microservices/app/auth/api/internal/handler/sms"
storage "schisandra-album-cloud-microservices/app/auth/api/internal/handler/storage"
token "schisandra-album-cloud-microservices/app/auth/api/internal/handler/token"
@@ -158,6 +159,33 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
rest.WithMaxBytes(1048576),
)
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.CasbinVerifyMiddleware, serverCtx.NonceMiddleware},
[]rest.Route{
{
Method: http.MethodPost,
Path: "/image/list",
Handler: share.QueryShareImageHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/record/list",
Handler: share.ListShareRecordHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/upload",
Handler: share.UploadShareImageHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/auth/share"),
rest.WithTimeout(10000*time.Millisecond),
rest.WithMaxBytes(104857600),
)
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.NonceMiddleware},
@@ -278,6 +306,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/uploads",
Handler: storage.UploadFileHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/user/config/list",
Handler: storage.GetUserStorageListHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),

View File

@@ -0,0 +1,29 @@
package share
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/share"
"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 ListShareRecordHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ShareRecordListRequest
if err := httpx.Parse(r, &req); err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := share.NewListShareRecordLogic(r.Context(), svcCtx)
resp, err := l.ListShareRecord(&req)
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
}
}
}

View File

@@ -0,0 +1,29 @@
package share
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/share"
"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 QueryShareImageHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.QueryShareImageRequest
if err := httpx.Parse(r, &req); err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := share.NewQueryShareImageLogic(r.Context(), svcCtx)
resp, err := l.QueryShareImage(&req)
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
}
}
}

View File

@@ -0,0 +1,29 @@
package share
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/share"
"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 UploadShareImageHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ShareImageRequest
if err := httpx.Parse(r, &req); err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := share.NewUploadShareImageLogic(r.Context(), svcCtx)
resp, err := l.UploadShareImage(&req)
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
}
}
}

View File

@@ -0,0 +1,21 @@
package storage
import (
"net/http"
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/storage"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/common/xhttp"
)
func GetUserStorageListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := storage.NewGetUserStorageListLogic(r.Context(), svcCtx)
resp, err := l.GetUserStorageList()
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
}
}
}

View File

@@ -0,0 +1,67 @@
package share
import (
"context"
"errors"
"time"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ListShareRecordLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewListShareRecordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListShareRecordLogic {
return &ListShareRecordLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ListShareRecordLogic) ListShareRecord(req *types.ShareRecordListRequest) (resp *types.ShareRecordListResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
storageShare := l.svcCtx.DB.ScaStorageShare
storageAlbum := l.svcCtx.DB.ScaStorageAlbum
var recordList []types.ShareRecord
query := storageShare.
Select(storageShare.ID,
storageShare.ShareCode,
storageShare.VisitLimit,
storageShare.AccessPassword,
storageShare.ValidityPeriod,
storageShare.CreatedAt,
storageAlbum.CoverImage).
LeftJoin(storageAlbum, storageShare.AlbumID.EqCol(storageAlbum.ID)).
Where(storageShare.UserID.Eq(uid)).
Order(storageShare.CreatedAt.Desc())
if len(req.DateRange) == 2 {
startDate, errStart := time.Parse("2006-01-02", req.DateRange[0])
endDate, errEnd := time.Parse("2006-01-02", req.DateRange[1])
if errStart != nil || errEnd != nil {
return nil, errors.New("invalid date format")
}
// Ensure endDate is inclusive by adding 24 hours
endDate = endDate.AddDate(0, 0, 1)
query = query.Where(storageShare.CreatedAt.Between(startDate, endDate))
}
err = query.Scan(&recordList)
if err != nil {
return nil, err
}
resp = &types.ShareRecordListResponse{
Records: recordList,
}
return resp, nil
}

View File

@@ -0,0 +1,316 @@
package share
import (
"context"
"encoding/json"
"errors"
"github.com/redis/go-redis/v9"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
"gorm.io/gorm"
"net/url"
"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"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type QueryShareImageLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryShareImageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryShareImageLogic {
return &QueryShareImageLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryShareImageLogic) QueryShareImage(req *types.QueryShareImageRequest) (resp *types.QueryShareImageResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
// 获取分享记录
cacheKey := constant.ImageSharePrefix + req.ShareCode
shareData, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.New("share code not found")
}
return nil, err
}
var storageShare model.ScaStorageShare
if err := json.Unmarshal([]byte(shareData), &storageShare); err != nil {
return nil, errors.New("unmarshal share data failed")
}
// 验证密码
if storageShare.AccessPassword != "" && storageShare.AccessPassword != req.AccessPassword {
return nil, errors.New("incorrect password")
}
// 检查分享是否过期
if storageShare.ExpireTime.Before(time.Now()) {
return nil, errors.New("share link has expired")
}
// 检查访问限制
if storageShare.VisitLimit > 0 {
err = l.incrementVisitCount(req.ShareCode, storageShare.VisitLimit)
if err != nil {
return nil, err
}
}
// 记录用户访问
err = l.recordUserVisit(storageShare.ID, uid)
if err != nil {
logx.Error("Failed to record user visit:", err)
return nil, err
}
// 生成缓存键(在验证通过后)
resultCacheKey := constant.ImageListPrefix + req.ShareCode + ":" + req.AccessPassword
// 尝试从缓存中获取结果
cachedResult, err := l.svcCtx.RedisClient.Get(l.ctx, resultCacheKey).Result()
if err == nil {
// 缓存命中,直接返回缓存结果
var cachedResponse types.QueryShareImageResponse
if err := json.Unmarshal([]byte(cachedResult), &cachedResponse); err == nil {
return &cachedResponse, nil
}
logx.Error("Failed to unmarshal cached result:", err)
} else if !errors.Is(err, redis.Nil) {
// 如果 Redis 查询出错(非缓存未命中),记录错误并继续回源查询
logx.Error("Failed to get cached result from Redis:", err)
}
// 缓存未命中,执行回源查询逻辑
resp, err = l.queryShareImageFromSource(&storageShare)
if err != nil {
return nil, err
}
// 将查询结果缓存到 Redis
respBytes, err := json.Marshal(resp)
if err != nil {
logx.Error("Failed to marshal response for caching:", err)
} else {
// 设置缓存,过期时间为 5 分钟
err = l.svcCtx.RedisClient.Set(l.ctx, resultCacheKey, respBytes, 5*time.Minute).Err()
if err != nil {
logx.Error("Failed to cache result in Redis:", err)
}
}
return resp, nil
}
func (l *QueryShareImageLogic) queryShareImageFromSource(storageShare *model.ScaStorageShare) (resp *types.QueryShareImageResponse, err error) {
// 查询相册图片列表
storageInfo := l.svcCtx.DB.ScaStorageInfo
storageThumb := l.svcCtx.DB.ScaStorageThumb
var storageInfoList []types.ShareFileInfoResult
err = storageInfo.Select(
storageInfo.ID,
storageInfo.FileName,
storageInfo.CreatedAt,
storageInfo.Provider,
storageInfo.Bucket,
storageInfo.Path,
storageThumb.ThumbPath,
storageThumb.ThumbW,
storageThumb.ThumbH,
storageThumb.ThumbSize).
LeftJoin(storageThumb, storageInfo.ThumbID.EqCol(storageThumb.ID)).
Where(
storageInfo.Type.Eq(constant.ImageTypeShared),
storageInfo.AlbumID.Eq(storageShare.AlbumID)).
Order(storageInfo.CreatedAt.Desc()).Scan(&storageInfoList)
if err != nil {
return nil, err
}
// 使用 errgroup 和 semaphore 并发处理图片信息
var ResultList []types.ShareImageListMeta
g, ctx := errgroup.WithContext(l.ctx)
sem := semaphore.NewWeighted(10) // 限制并发数为 10
for _, imgInfo := range storageInfoList {
imgInfo := imgInfo // 创建局部变量,避免闭包问题
if err := sem.Acquire(ctx, 1); err != nil {
return nil, err
}
g.Go(func() error {
defer sem.Release(1)
// 加载用户oss配置信息
cacheOssConfigKey := constant.UserOssConfigPrefix + storageShare.UserID + ":" + imgInfo.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, storageShare.UserID, imgInfo.Provider)
if err != nil {
return err
}
service, err := l.svcCtx.StorageManager.GetStorage(storageShare.UserID, ossConfig)
if err != nil {
return errors.New("get storage failed")
}
ossURL, err := service.PresignedURL(ctx, ossConfig.BucketName, imgInfo.Path, 30*time.Minute)
if err != nil {
return errors.New("get presigned url failed")
}
reqParams := make(url.Values)
presignedURL, err := l.svcCtx.MinioClient.PresignedGetObject(ctx, constant.ThumbnailBucketName, imgInfo.ThumbPath, 30*time.Minute, reqParams)
if err != nil {
return errors.New("get presigned thumbnail url failed")
}
ResultList = append(ResultList, types.ShareImageListMeta{
ID: imgInfo.ID,
FileName: imgInfo.FileName,
ThumbH: imgInfo.ThumbH,
ThumbW: imgInfo.ThumbW,
ThumbSize: imgInfo.ThumbSize,
CreatedAt: imgInfo.CreatedAt.Format(constant.TimeFormat),
URL: ossURL,
Thumbnail: presignedURL.String(),
})
return nil
})
}
// 等待所有并发任务完成
if err := g.Wait(); err != nil {
return nil, err
}
return &types.QueryShareImageResponse{
List: ResultList}, nil
}
func (l *QueryShareImageLogic) recordUserVisit(shareID int64, userID string) error {
// 查询是否已经存在该用户对该分享的访问记录
var visitRecord model.ScaStorageShareVisit
scaStorageShareVisit := l.svcCtx.DB.ScaStorageShareVisit
_, err := scaStorageShareVisit.
Where(scaStorageShareVisit.ShareID.Eq(shareID), scaStorageShareVisit.UserID.Eq(userID)).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// 如果记录不存在,创建新的访问记录
visitRecord = model.ScaStorageShareVisit{
UserID: userID,
ShareID: shareID,
Views: 1,
}
err = l.svcCtx.DB.ScaStorageShareVisit.Create(&visitRecord)
if err != nil {
return errors.New("failed to create visit record")
}
return nil
}
return errors.New("failed to query visit record")
}
// 如果记录存在,增加访问次数
info, err := scaStorageShareVisit.
Where(scaStorageShareVisit.UserID.Eq(userID), scaStorageShareVisit.ShareID.Eq(shareID)).
Update(scaStorageShareVisit.Views, scaStorageShareVisit.Views.Add(1))
if err != nil {
return errors.New("failed to update visit record")
}
if info.RowsAffected == 0 {
return errors.New("failed to update visit record")
}
return nil
}
func (l *QueryShareImageLogic) incrementVisitCount(shareCode string, limit int64) error {
// Redis 键值
cacheKey := constant.ImageShareVisitPrefix + shareCode
currentVisitCount, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Int64()
if err != nil && !errors.Is(err, redis.Nil) {
return err
}
// 如果访问次数超过限制,返回错误
if currentVisitCount >= limit {
return errors.New("access limit reached")
}
// 增加访问次数
err = l.svcCtx.RedisClient.Incr(l.ctx, cacheKey).Err()
if err != nil {
return err
}
return nil
}
// 提取解密操作为函数
func (l *QueryShareImageLogic) 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 *QueryShareImageLogic) 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

@@ -0,0 +1,347 @@
package share
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/ccpwcn/kgo"
"github.com/minio/minio-go/v7"
"github.com/redis/go-redis/v9"
"github.com/zeromicro/go-zero/core/logx"
"golang.org/x/sync/errgroup"
"image"
"path"
"path/filepath"
"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/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"
"strconv"
"time"
)
type UploadShareImageLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUploadShareImageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadShareImageLogic {
return &UploadShareImageLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *UploadShareImageLogic) UploadShareImage(req *types.ShareImageRequest) (resp string, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return "", errors.New("user_id not found")
}
// 启动事务,确保插入操作的原子性
tx := l.svcCtx.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback() // 如果有panic发生回滚事务
logx.Errorf("transaction rollback: %v", r)
}
}()
albumName := req.Title
if albumName == "" {
albumName = "快传照片"
}
// 创建一个相册
album := model.ScaStorageAlbum{
UserID: uid,
AlbumName: albumName,
CoverImage: req.Images[0].Thumbnail,
AlbumType: constant.AlbumTypeShared,
}
err = tx.ScaStorageAlbum.Create(&album)
if err != nil {
return "", err
}
var g errgroup.Group
// 为每张图片启动一个协程
for _, img := range req.Images {
img := img // 确保每个协程有独立的 img 参数副本
g.Go(func() error {
return l.uploadImageAndRecord(tx, uid, album, img, req)
})
}
// 等待所有任务完成并返回第一个错误
if err = g.Wait(); err != nil {
tx.Rollback()
return "", err
}
duration, err := strconv.Atoi(req.ExpireDate)
if err != nil {
return "", errors.New("invalid expire date")
}
expiryTime := l.GenerateExpiryTime(time.Now(), duration)
storageShare := model.ScaStorageShare{
UserID: uid,
AlbumID: album.ID,
ShareCode: kgo.SimpleUuid(),
Status: 0,
AccessPassword: req.AccessPassword,
VisitLimit: req.AccessLimit,
ValidityPeriod: int64(duration),
ExpireTime: expiryTime,
}
err = tx.ScaStorageShare.Create(&storageShare)
if err != nil {
tx.Rollback()
return "", err
}
// 缓存分享码
marshal, err := json.Marshal(storageShare)
if err != nil {
tx.Rollback()
return "", err
}
cacheKey := constant.ImageSharePrefix + storageShare.ShareCode
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshal, time.Duration(duration)*time.Hour*24).Err()
if err != nil {
tx.Rollback()
return "", err
}
// 提交事务
if err = tx.Commit(); err != nil {
tx.Rollback()
logx.Errorf("Transaction commit failed: %v", err)
return "", err
}
return storageShare.ShareCode, nil
}
func (l *UploadShareImageLogic) uploadImageAndRecord(tx *query.QueryTx, uid string, album model.ScaStorageAlbum, img types.ShareImageMeta, req *types.ShareImageRequest) error {
// 上传缩略图到 Minio
thumbnail, err := base64.StdEncoding.DecodeString(img.Thumbnail)
if err != nil {
return fmt.Errorf("base64 decode failed: %v", err)
}
thumbObjectKey := path.Join(
uid,
time.Now().Format("2006/01"),
l.classifyFile(img.FileType),
fmt.Sprintf("%s_%s.jpg", time.Now().Format("20060102150405"), kgo.SimpleUuid()),
)
exists, err := l.svcCtx.MinioClient.BucketExists(l.ctx, constant.ThumbnailBucketName)
if err != nil || !exists {
err = l.svcCtx.MinioClient.MakeBucket(l.ctx, constant.ThumbnailBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
if err != nil {
logx.Errorf("Failed to create MinIO bucket: %v", err)
return err
}
}
_, err = l.svcCtx.MinioClient.PutObject(
l.ctx,
constant.ThumbnailBucketName,
thumbObjectKey,
bytes.NewReader(thumbnail),
int64(len(thumbnail)),
minio.PutObjectOptions{
ContentType: "image/jpeg",
},
)
if err != nil {
logx.Errorf("Failed to upload MinIO object: %v", err)
return err
}
// 记录缩略图
thumbRecord := model.ScaStorageThumb{
UserID: uid,
ThumbPath: thumbObjectKey,
ThumbW: img.ThumbW,
ThumbH: img.ThumbH,
ThumbSize: float64(len(thumbnail)),
}
err = tx.ScaStorageThumb.Create(&thumbRecord)
if err != nil {
return err
}
// 上传原始图片到用户的存储桶
originImage, err := base64.StdEncoding.DecodeString(img.OriginImage)
if err != nil {
return fmt.Errorf("base64 decode failed: %v", err)
}
originObjectKey := path.Join(
"share_space",
uid,
time.Now().Format("2006/01"),
fmt.Sprintf("%s_%s%s", img.FileName, kgo.SimpleUuid(), filepath.Ext(img.FileName)),
)
// 获取存储服务
ossConfig, err := l.getOssConfigFromCacheOrDb(constant.UserOssConfigPrefix+uid+":"+req.Provider, uid, req.Provider)
if err != nil {
return err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return errors.New("get storage failed")
}
_, err = service.UploadFileSimple(l.ctx, ossConfig.BucketName, originObjectKey, bytes.NewReader(originImage), map[string]string{
"Content-Type": img.FileType,
})
if err != nil {
logx.Errorf("Failed to upload object to storage: %v", err)
return err
}
// 获取图片信息
width, height, size, err := l.GetImageInfo(img.OriginImage)
if err != nil {
return err
}
// 记录原始图片信息
imageRecord := model.ScaStorageInfo{
UserID: uid,
Provider: req.Provider,
Bucket: req.Bucket,
Path: originObjectKey,
FileName: img.FileName,
FileSize: strconv.Itoa(size),
FileType: img.FileType,
Width: float64(width),
Height: float64(height),
Type: constant.ImageTypeShared,
AlbumID: album.ID,
ThumbID: thumbRecord.ID,
}
err = tx.ScaStorageInfo.Create(&imageRecord)
if err != nil {
return err
}
return nil
}
func (l *UploadShareImageLogic) GetImageInfo(base64Str string) (width, height int, size int, err error) {
// 解码 Base64
data, err := base64.StdEncoding.DecodeString(base64Str)
if err != nil {
return 0, 0, 0, fmt.Errorf("base64 decode failed: %v", err)
}
// 获取图片大小
size = len(data)
// 解析图片宽高
reader := bytes.NewReader(data)
imgCfg, _, err := image.DecodeConfig(reader)
if err != nil {
return 0, 0, 0, fmt.Errorf("decode image config failed: %v", err)
}
return imgCfg.Width, imgCfg.Height, size, nil
}
// 提取解密操作为函数
func (l *UploadShareImageLogic) 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 *UploadShareImageLogic) 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
}
// GenerateExpiryTime 函数接受当前时间和有效期(天为单位),返回过期时间
func (l *UploadShareImageLogic) GenerateExpiryTime(currentTime time.Time, durationInDays int) time.Time {
// 创建一个持续时间对象
duration := time.Duration(durationInDays) * 24 * time.Hour
// 将当前时间加上持续时间,得到过期时间
expiryTime := currentTime.Add(duration)
return expiryTime
}
func (l *UploadShareImageLogic) classifyFile(mimeType string) string {
// 使用map存储MIME类型及其对应的分类
typeMap := map[string]string{
"image/jpeg": "image",
"image/png": "image",
"image/gif": "gif",
"image/bmp": "image",
"image/tiff": "image",
"image/webp": "image",
"video/mp4": "video",
"video/avi": "video",
"video/mpeg": "video",
"video/quicktime": "video",
"video/x-msvideo": "video",
"video/x-flv": "video",
"video/x-matroska": "video",
}
// 根据MIME类型从map中获取分类
if classification, exists := typeMap[mimeType]; exists {
return classification
}
return "other"
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
@@ -33,7 +34,7 @@ func (l *CreateAlbumLogic) CreateAlbum(req *types.AlbumCreateRequest) (resp *typ
storageAlbum := &model.ScaStorageAlbum{
UserID: uid,
AlbumName: req.Name,
AlbumType: "0",
AlbumType: constant.AlbumTypeMine,
}
err = l.svcCtx.DB.ScaStorageAlbum.Create(storageAlbum)
if err != nil {

View File

@@ -68,6 +68,7 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
storageInfo.FileName,
storageInfo.CreatedAt,
storageThumb.ThumbPath,
storageInfo.Path,
storageThumb.ThumbW,
storageThumb.ThumbH,
storageThumb.ThumbSize).
@@ -86,17 +87,17 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
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")
//}
// 加载用户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
@@ -114,6 +115,11 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
logx.Error(err)
return
}
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)
@@ -121,7 +127,8 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
URL: presignedUrl.String(),
Thumbnail: presignedUrl.String(),
URL: url,
Width: dbFileInfo.ThumbW,
Height: dbFileInfo.ThumbH,
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),

View File

@@ -3,6 +3,7 @@ package storage
import (
"context"
"errors"
"gorm.io/gen"
"gorm.io/gen/field"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
@@ -37,7 +38,15 @@ func (l *GetAlbumListLogic) GetAlbumList(req *types.AlbumListRequest) (resp *typ
} else {
orderConditions = append(orderConditions, storageAlbum.AlbumName.Desc())
}
albums, err := storageAlbum.Where(storageAlbum.UserID.Eq(uid), storageAlbum.AlbumType.Eq(req.Type)).Order(orderConditions...).Find()
var typeConditions []gen.Condition
if req.Type != -1 {
// 获取全部相册
typeConditions = append(typeConditions, storageAlbum.AlbumType.Eq(req.Type))
typeConditions = append(typeConditions, storageAlbum.UserID.Eq(uid))
}
albums, err := storageAlbum.Where(
typeConditions...).
Order(orderConditions...).Find()
if err != nil {
return nil, err
}

View File

@@ -0,0 +1,80 @@
package storage
import (
"context"
"errors"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetUserStorageListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetUserStorageListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserStorageListLogic {
return &GetUserStorageListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// providerNameMap 存储商映射表
var providerNameMap = map[string]string{
"ali": "阿里云OSS",
"tencent": "腾讯云COS",
"aws": "Amazon S3",
"qiniu": "七牛云",
"huawei": "华为云OBS",
}
func (l *GetUserStorageListLogic) GetUserStorageList() (resp *types.StorageListResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
storageConfig := l.svcCtx.DB.ScaStorageConfig
storageConfigs, err := storageConfig.Select(
storageConfig.Provider,
storageConfig.Bucket).
Where(
storageConfig.UserID.Eq(uid)).Find()
if err != nil {
return nil, err
}
// 使用 map 组织数据
providerMap := make(map[string][]types.StorageMeta)
for _, config := range storageConfigs {
providerMap[config.Provider] = append(providerMap[config.Provider], types.StorageMeta{
Value: config.Bucket,
Name: config.Bucket,
})
}
// 组装返回结构
var records []types.StroageNode
for provider, buckets := range providerMap {
records = append(records, types.StroageNode{
Value: provider,
Name: l.getProviderName(provider),
Children: buckets,
})
}
// 返回数据
return &types.StorageListResponse{
Records: records,
}, nil
}
// getProviderName 获取存储商的中文名称
func (l *GetUserStorageListLogic) getProviderName(provider string) string {
if name, exists := providerNameMap[provider]; exists {
return name
}
return provider
}

View File

@@ -288,6 +288,7 @@ func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHead
}
objectKey := path.Join(
"image_space",
uid,
time.Now().Format("2006/01"), // 按年/月划分目录
l.classifyFile(result.FileType, result.IsScreenshot),

View File

@@ -3,7 +3,9 @@ package middleware
import (
"github.com/casbin/casbin/v2"
"net/http"
"schisandra-album-cloud-microservices/common/middleware"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/errors"
"schisandra-album-cloud-microservices/common/xhttp"
)
type CasbinVerifyMiddleware struct {
@@ -18,7 +20,12 @@ func NewCasbinVerifyMiddleware(casbin *casbin.SyncedCachedEnforcer) *CasbinVerif
func (m *CasbinVerifyMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
middleware.CasbinMiddleware(w, r, m.casbin)
userId := r.Header.Get(constant.UID_HEADER_KEY)
correct, err := m.casbin.Enforce(userId, r.URL.Path, r.Method)
if err != nil || !correct {
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusNotFound, "not found"))
return
}
next(w, r)
}
}

View File

@@ -3,7 +3,10 @@ package middleware
import (
"github.com/redis/go-redis/v9"
"net/http"
"schisandra-album-cloud-microservices/common/middleware"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/errors"
"schisandra-album-cloud-microservices/common/xhttp"
"time"
)
type NonceMiddleware struct {
@@ -18,7 +21,25 @@ func NewNonceMiddleware(redisClient *redis.Client) *NonceMiddleware {
func (m *NonceMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
middleware.NonceMiddleware(w, r, m.RedisClient)
nonce := r.Header.Get("X-Nonce")
if nonce == "" {
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusBadRequest, "bad request!"))
return
}
if len(nonce) != 32 {
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusBadRequest, "bad request!"))
return
}
result := m.RedisClient.Get(r.Context(), constant.SystemApiNoncePrefix+nonce).Val()
if result != "" {
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusBadRequest, "bad request!"))
return
}
err := m.RedisClient.Set(r.Context(), constant.SystemApiNoncePrefix+nonce, nonce, time.Minute*1).Err()
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusInternalServerError, "internal server error!"))
return
}
next(w, r)
}
}

View File

@@ -54,3 +54,12 @@ type ThingImageList struct {
ThumbPath string `json:"thumb_path"`
Path string `json:"path"`
}
type ShareImageInfo struct {
Title string `json:"title"`
ExpireDate string `json:"expire_date"`
AccessLimit int64 `json:"access_limit"`
AccessPassword string `json:"access_password"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
}

View File

@@ -0,0 +1,16 @@
package types
import "time"
type ShareFileInfoResult struct {
ID int64 `json:"id"`
FileName string `json:"file_name"`
ThumbPath string `json:"thumb_path"`
ThumbW float64 `json:"thumb_w"`
ThumbH float64 `json:"thumb_h"`
ThumbSize float64 `json:"thumb_size"`
CreatedAt time.Time `json:"created_at"`
Path string `json:"path"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
}

View File

@@ -15,7 +15,7 @@ type Album struct {
ID int64 `json:"id"`
Name string `json:"name"`
CreatedAt string `json:"created_at"`
Type string `json:"type"`
Type int64 `json:"type"`
CoverImage string `json:"cover_image"`
}
@@ -42,8 +42,8 @@ type AlbumDetailListResponse struct {
}
type AlbumListRequest struct {
Type string `json:"type"`
Sort bool `json:"sort"`
Type int64 `json:"type,omitempty"`
Sort bool `json:"sort"`
}
type AlbumListResponse struct {
@@ -254,6 +254,15 @@ type PhoneLoginRequest struct {
AutoLogin bool `json:"auto_login"`
}
type QueryShareImageRequest struct {
ShareCode string `json:"share_code"`
AccessPassword string `json:"access_password,omitempty"`
}
type QueryShareImageResponse struct {
List []ShareImageListMeta `json:"list"`
}
type RecentListResponse struct {
Records []AllImageDetail `json:"records"`
}
@@ -306,6 +315,55 @@ type RotateCaptchaResponse struct {
Thumb string `json:"thumb"`
}
type ShareImageListMeta struct {
ID int64 `json:"id"`
FileName string `json:"file_name"`
URL string `json:"url"`
Thumbnail string `json:"thumbnail"`
ThumbW float64 `json:"thumb_w"`
ThumbH float64 `json:"thumb_h"`
ThumbSize float64 `json:"thumb_size"`
CreatedAt string `json:"created_at"`
}
type ShareImageMeta struct {
FileName string `json:"file_name"`
OriginImage string `json:"origin_image"`
FileType string `json:"file_type"`
Thumbnail string `json:"thumbnail"`
ThumbW float64 `json:"thumb_w"`
ThumbH float64 `json:"thumb_h"`
ThumbSize int64 `json:"thumb_size"`
}
type ShareImageRequest struct {
Title string `json:"title,omitempty"`
ExpireDate string `json:"expire_date"`
AccessLimit int64 `json:"access_limit,omitempty"`
AccessPassword string `json:"access_password,omitempty"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
Images []ShareImageMeta `json:"images"`
}
type ShareRecord struct {
ID int64 `json:"id"`
CoverImage string `json:"cover_image"`
CreatedAt string `json:"created_at"`
ShareCode string `json:"share_code"`
VisitLimit int64 `json:"visit_limit"`
AccessPassword string `json:"access_password"`
ValidityPeriod int64 `json:"validity_period"`
}
type ShareRecordListRequest struct {
DateRange []string `json:"date_range"`
}
type ShareRecordListResponse struct {
Records []ShareRecord `json:"records"`
}
type SingleImageRequest struct {
ID int64 `json:"id"`
}
@@ -335,6 +393,21 @@ type StorageConfigRequest struct {
Region string `json:"region"`
}
type StorageListResponse struct {
Records []StroageNode `json:"records"`
}
type StorageMeta struct {
Name string `json:"name"`
Value string `json:"value"`
}
type StroageNode struct {
Value string `json:"value"`
Name string `json:"name"`
Children []StorageMeta `json:"children"`
}
type ThingDetailListRequest struct {
TagName string `json:"tag_name"`
Provider string `json:"provider"`

View File

@@ -118,6 +118,8 @@ func main() {
scaStorageAlbum := g.GenerateModel("sca_storage_album", fieldOpts...)
scaStorageLocation := g.GenerateModel("sca_storage_location", fieldOpts...)
scaStorageThumb := g.GenerateModel("sca_storage_thumb", fieldOpts...)
scaStorageShare := g.GenerateModel("sca_storage_share", fieldOpts...)
scaStorageShareVisit := g.GenerateModel("sca_storage_share_visit", fieldOpts...)
g.ApplyBasic(
scaAuthMenu,
@@ -139,6 +141,8 @@ func main() {
scaStorageAlbum,
scaStorageLocation,
scaStorageThumb,
scaStorageShare,
scaStorageShareVisit,
)
g.Execute()

View File

@@ -17,8 +17,8 @@ type ScaStorageAlbum struct {
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
UserID string `gorm:"column:user_id;type:varchar(50);comment:用户ID" json:"user_id"` // 用户ID
AlbumName string `gorm:"column:album_name;type:varchar(50);comment:相册名称" json:"album_name"` // 相册名称
AlbumType string `gorm:"column:album_type;type:varchar(50);comment:相册类型" json:"album_type"` // 相册类型
CoverImage string `gorm:"column:cover_image;type:text;comment:封面图片" json:"cover_image"` // 封面图片
AlbumType int64 `gorm:"column:album_type;type:tinyint(4);comment:相册类型(0 我的 1 分享 2 收藏)" json:"album_type"` // 相册类型(0 我的 1 分享 2 收藏)
CoverImage string `gorm:"column:cover_image;type:longtext;comment:封面图片" json:"cover_image"` // 封面图片
CreatedAt time.Time `gorm:"column:created_at;type:timestamp;autoCreateTime;comment:创建时间" json:"created_at"` // 创建时间
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp;autoUpdateTime;comment:更新时间" json:"updated_at"` // 更新时间
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp;comment:删除时间" json:"deleted_at"` // 删除时间

View File

@@ -0,0 +1,36 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"time"
"gorm.io/gorm"
"gorm.io/plugin/optimisticlock"
)
const TableNameScaStorageShare = "sca_storage_share"
// ScaStorageShare 快传分享表
type ScaStorageShare struct {
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
UserID string `gorm:"column:user_id;type:varchar(50);comment:用户ID" json:"user_id"` // 用户ID
AlbumID int64 `gorm:"column:album_id;type:bigint(20);comment:相册ID" json:"album_id"` // 相册ID
ShareCode string `gorm:"column:share_code;type:varchar(50);comment:分享码(用于访问分享链接)" json:"share_code"` // 分享码(用于访问分享链接)
ExpireTime time.Time `gorm:"column:expire_time;type:datetime;comment:过期时间" json:"expire_time"` // 过期时间
ValidityPeriod int64 `gorm:"column:validity_period;type:int(11);comment:有效期" json:"validity_period"` // 有效期
Status int64 `gorm:"column:status;type:tinyint(4);comment:是否失效0 有效 -1已失效 1 永久)" json:"status"` // 是否失效0 有效 -1已失效 1 永久)
AccessPassword string `gorm:"column:access_password;type:varchar(50);comment:访问密码" json:"access_password"` // 访问密码
VisitLimit int64 `gorm:"column:visit_limit;type:bigint(20);comment:限制次数" json:"visit_limit"` // 限制次数
Version optimisticlock.Version `gorm:"column:version;type:bigint(20);comment:版本" json:"version"` // 版本
CreatedAt time.Time `gorm:"column:created_at;type:timestamp;autoCreateTime;comment:创建时间" json:"created_at"` // 创建时间
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp;autoUpdateTime;comment:更新时间" json:"updated_at"` // 更新时间
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp;comment:删除时间" json:"deleted_at"` // 删除时间
}
// TableName ScaStorageShare's table name
func (*ScaStorageShare) TableName() string {
return TableNameScaStorageShare
}

View File

@@ -0,0 +1,31 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"time"
"gorm.io/gorm"
"gorm.io/plugin/optimisticlock"
)
const TableNameScaStorageShareVisit = "sca_storage_share_visit"
// ScaStorageShareVisit 分享浏览记录
type ScaStorageShareVisit struct {
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
UserID string `gorm:"column:user_id;type:varchar(50);comment:用户ID" json:"user_id"` // 用户ID
ShareID int64 `gorm:"column:share_id;type:bigint(20);comment:分享ID" json:"share_id"` // 分享ID
Views int64 `gorm:"column:views;type:bigint(20);comment:浏览次数" json:"views"` // 浏览次数
Version optimisticlock.Version `gorm:"column:version;type:bigint(20);comment:版本" json:"version"` // 版本
CreatedAt time.Time `gorm:"column:created_at;type:timestamp;autoCreateTime;comment:创建时间" json:"created_at"` // 创建时间
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp;autoUpdateTime;comment:更新时间" json:"updated_at"` // 更新时间
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp;comment:删除时间" json:"deleted_at"` // 删除时间
}
// TableName ScaStorageShareVisit's table name
func (*ScaStorageShareVisit) TableName() string {
return TableNameScaStorageShareVisit
}

View File

@@ -12,7 +12,7 @@ import (
const TableNameScaStorageThumb = "sca_storage_thumb"
// ScaStorageThumb mapped from table <sca_storage_thumb>
// ScaStorageThumb 缩略图表
type ScaStorageThumb struct {
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
UserID string `gorm:"column:user_id;type:varchar(50);not null;comment:用户ID" json:"user_id"` // 用户ID

View File

@@ -30,6 +30,8 @@ var (
ScaStorageConfig *scaStorageConfig
ScaStorageInfo *scaStorageInfo
ScaStorageLocation *scaStorageLocation
ScaStorageShare *scaStorageShare
ScaStorageShareVisit *scaStorageShareVisit
ScaStorageTag *scaStorageTag
ScaStorageTagInfo *scaStorageTagInfo
ScaStorageThumb *scaStorageThumb
@@ -53,6 +55,8 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
ScaStorageConfig = &Q.ScaStorageConfig
ScaStorageInfo = &Q.ScaStorageInfo
ScaStorageLocation = &Q.ScaStorageLocation
ScaStorageShare = &Q.ScaStorageShare
ScaStorageShareVisit = &Q.ScaStorageShareVisit
ScaStorageTag = &Q.ScaStorageTag
ScaStorageTagInfo = &Q.ScaStorageTagInfo
ScaStorageThumb = &Q.ScaStorageThumb
@@ -77,6 +81,8 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
ScaStorageConfig: newScaStorageConfig(db, opts...),
ScaStorageInfo: newScaStorageInfo(db, opts...),
ScaStorageLocation: newScaStorageLocation(db, opts...),
ScaStorageShare: newScaStorageShare(db, opts...),
ScaStorageShareVisit: newScaStorageShareVisit(db, opts...),
ScaStorageTag: newScaStorageTag(db, opts...),
ScaStorageTagInfo: newScaStorageTagInfo(db, opts...),
ScaStorageThumb: newScaStorageThumb(db, opts...),
@@ -102,6 +108,8 @@ type Query struct {
ScaStorageConfig scaStorageConfig
ScaStorageInfo scaStorageInfo
ScaStorageLocation scaStorageLocation
ScaStorageShare scaStorageShare
ScaStorageShareVisit scaStorageShareVisit
ScaStorageTag scaStorageTag
ScaStorageTagInfo scaStorageTagInfo
ScaStorageThumb scaStorageThumb
@@ -128,6 +136,8 @@ func (q *Query) clone(db *gorm.DB) *Query {
ScaStorageConfig: q.ScaStorageConfig.clone(db),
ScaStorageInfo: q.ScaStorageInfo.clone(db),
ScaStorageLocation: q.ScaStorageLocation.clone(db),
ScaStorageShare: q.ScaStorageShare.clone(db),
ScaStorageShareVisit: q.ScaStorageShareVisit.clone(db),
ScaStorageTag: q.ScaStorageTag.clone(db),
ScaStorageTagInfo: q.ScaStorageTagInfo.clone(db),
ScaStorageThumb: q.ScaStorageThumb.clone(db),
@@ -161,6 +171,8 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
ScaStorageConfig: q.ScaStorageConfig.replaceDB(db),
ScaStorageInfo: q.ScaStorageInfo.replaceDB(db),
ScaStorageLocation: q.ScaStorageLocation.replaceDB(db),
ScaStorageShare: q.ScaStorageShare.replaceDB(db),
ScaStorageShareVisit: q.ScaStorageShareVisit.replaceDB(db),
ScaStorageTag: q.ScaStorageTag.replaceDB(db),
ScaStorageTagInfo: q.ScaStorageTagInfo.replaceDB(db),
ScaStorageThumb: q.ScaStorageThumb.replaceDB(db),
@@ -184,6 +196,8 @@ type queryCtx struct {
ScaStorageConfig IScaStorageConfigDo
ScaStorageInfo IScaStorageInfoDo
ScaStorageLocation IScaStorageLocationDo
ScaStorageShare IScaStorageShareDo
ScaStorageShareVisit IScaStorageShareVisitDo
ScaStorageTag IScaStorageTagDo
ScaStorageTagInfo IScaStorageTagInfoDo
ScaStorageThumb IScaStorageThumbDo
@@ -207,6 +221,8 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx {
ScaStorageConfig: q.ScaStorageConfig.WithContext(ctx),
ScaStorageInfo: q.ScaStorageInfo.WithContext(ctx),
ScaStorageLocation: q.ScaStorageLocation.WithContext(ctx),
ScaStorageShare: q.ScaStorageShare.WithContext(ctx),
ScaStorageShareVisit: q.ScaStorageShareVisit.WithContext(ctx),
ScaStorageTag: q.ScaStorageTag.WithContext(ctx),
ScaStorageTagInfo: q.ScaStorageTagInfo.WithContext(ctx),
ScaStorageThumb: q.ScaStorageThumb.WithContext(ctx),

View File

@@ -30,7 +30,7 @@ func newScaStorageAlbum(db *gorm.DB, opts ...gen.DOOption) scaStorageAlbum {
_scaStorageAlbum.ID = field.NewInt64(tableName, "id")
_scaStorageAlbum.UserID = field.NewString(tableName, "user_id")
_scaStorageAlbum.AlbumName = field.NewString(tableName, "album_name")
_scaStorageAlbum.AlbumType = field.NewString(tableName, "album_type")
_scaStorageAlbum.AlbumType = field.NewInt64(tableName, "album_type")
_scaStorageAlbum.CoverImage = field.NewString(tableName, "cover_image")
_scaStorageAlbum.CreatedAt = field.NewTime(tableName, "created_at")
_scaStorageAlbum.UpdatedAt = field.NewTime(tableName, "updated_at")
@@ -49,7 +49,7 @@ type scaStorageAlbum struct {
ID field.Int64 // 主键
UserID field.String // 用户ID
AlbumName field.String // 相册名称
AlbumType field.String // 相册类型
AlbumType field.Int64 // 相册类型(0 我的 1 分享 2 收藏)
CoverImage field.String // 封面图片
CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间
@@ -73,7 +73,7 @@ func (s *scaStorageAlbum) updateTableName(table string) *scaStorageAlbum {
s.ID = field.NewInt64(table, "id")
s.UserID = field.NewString(table, "user_id")
s.AlbumName = field.NewString(table, "album_name")
s.AlbumType = field.NewString(table, "album_type")
s.AlbumType = field.NewInt64(table, "album_type")
s.CoverImage = field.NewString(table, "cover_image")
s.CreatedAt = field.NewTime(table, "created_at")
s.UpdatedAt = field.NewTime(table, "updated_at")

View File

@@ -0,0 +1,429 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
)
func newScaStorageShare(db *gorm.DB, opts ...gen.DOOption) scaStorageShare {
_scaStorageShare := scaStorageShare{}
_scaStorageShare.scaStorageShareDo.UseDB(db, opts...)
_scaStorageShare.scaStorageShareDo.UseModel(&model.ScaStorageShare{})
tableName := _scaStorageShare.scaStorageShareDo.TableName()
_scaStorageShare.ALL = field.NewAsterisk(tableName)
_scaStorageShare.ID = field.NewInt64(tableName, "id")
_scaStorageShare.UserID = field.NewString(tableName, "user_id")
_scaStorageShare.AlbumID = field.NewInt64(tableName, "album_id")
_scaStorageShare.ShareCode = field.NewString(tableName, "share_code")
_scaStorageShare.ExpireTime = field.NewTime(tableName, "expire_time")
_scaStorageShare.ValidityPeriod = field.NewInt64(tableName, "validity_period")
_scaStorageShare.Status = field.NewInt64(tableName, "status")
_scaStorageShare.AccessPassword = field.NewString(tableName, "access_password")
_scaStorageShare.VisitLimit = field.NewInt64(tableName, "visit_limit")
_scaStorageShare.Version = field.NewField(tableName, "version")
_scaStorageShare.CreatedAt = field.NewTime(tableName, "created_at")
_scaStorageShare.UpdatedAt = field.NewTime(tableName, "updated_at")
_scaStorageShare.DeletedAt = field.NewField(tableName, "deleted_at")
_scaStorageShare.fillFieldMap()
return _scaStorageShare
}
// scaStorageShare 快传分享表
type scaStorageShare struct {
scaStorageShareDo
ALL field.Asterisk
ID field.Int64 // 主键
UserID field.String // 用户ID
AlbumID field.Int64 // 相册ID
ShareCode field.String // 分享码(用于访问分享链接)
ExpireTime field.Time // 过期时间
ValidityPeriod field.Int64 // 有效期
Status field.Int64 // 是否失效0 有效 -1已失效 1 永久)
AccessPassword field.String // 访问密码
VisitLimit field.Int64 // 限制次数
Version field.Field // 版本
CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间
DeletedAt field.Field // 删除时间
fieldMap map[string]field.Expr
}
func (s scaStorageShare) Table(newTableName string) *scaStorageShare {
s.scaStorageShareDo.UseTable(newTableName)
return s.updateTableName(newTableName)
}
func (s scaStorageShare) As(alias string) *scaStorageShare {
s.scaStorageShareDo.DO = *(s.scaStorageShareDo.As(alias).(*gen.DO))
return s.updateTableName(alias)
}
func (s *scaStorageShare) updateTableName(table string) *scaStorageShare {
s.ALL = field.NewAsterisk(table)
s.ID = field.NewInt64(table, "id")
s.UserID = field.NewString(table, "user_id")
s.AlbumID = field.NewInt64(table, "album_id")
s.ShareCode = field.NewString(table, "share_code")
s.ExpireTime = field.NewTime(table, "expire_time")
s.ValidityPeriod = field.NewInt64(table, "validity_period")
s.Status = field.NewInt64(table, "status")
s.AccessPassword = field.NewString(table, "access_password")
s.VisitLimit = field.NewInt64(table, "visit_limit")
s.Version = field.NewField(table, "version")
s.CreatedAt = field.NewTime(table, "created_at")
s.UpdatedAt = field.NewTime(table, "updated_at")
s.DeletedAt = field.NewField(table, "deleted_at")
s.fillFieldMap()
return s
}
func (s *scaStorageShare) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := s.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (s *scaStorageShare) fillFieldMap() {
s.fieldMap = make(map[string]field.Expr, 13)
s.fieldMap["id"] = s.ID
s.fieldMap["user_id"] = s.UserID
s.fieldMap["album_id"] = s.AlbumID
s.fieldMap["share_code"] = s.ShareCode
s.fieldMap["expire_time"] = s.ExpireTime
s.fieldMap["validity_period"] = s.ValidityPeriod
s.fieldMap["status"] = s.Status
s.fieldMap["access_password"] = s.AccessPassword
s.fieldMap["visit_limit"] = s.VisitLimit
s.fieldMap["version"] = s.Version
s.fieldMap["created_at"] = s.CreatedAt
s.fieldMap["updated_at"] = s.UpdatedAt
s.fieldMap["deleted_at"] = s.DeletedAt
}
func (s scaStorageShare) clone(db *gorm.DB) scaStorageShare {
s.scaStorageShareDo.ReplaceConnPool(db.Statement.ConnPool)
return s
}
func (s scaStorageShare) replaceDB(db *gorm.DB) scaStorageShare {
s.scaStorageShareDo.ReplaceDB(db)
return s
}
type scaStorageShareDo struct{ gen.DO }
type IScaStorageShareDo interface {
gen.SubQuery
Debug() IScaStorageShareDo
WithContext(ctx context.Context) IScaStorageShareDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IScaStorageShareDo
WriteDB() IScaStorageShareDo
As(alias string) gen.Dao
Session(config *gorm.Session) IScaStorageShareDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IScaStorageShareDo
Not(conds ...gen.Condition) IScaStorageShareDo
Or(conds ...gen.Condition) IScaStorageShareDo
Select(conds ...field.Expr) IScaStorageShareDo
Where(conds ...gen.Condition) IScaStorageShareDo
Order(conds ...field.Expr) IScaStorageShareDo
Distinct(cols ...field.Expr) IScaStorageShareDo
Omit(cols ...field.Expr) IScaStorageShareDo
Join(table schema.Tabler, on ...field.Expr) IScaStorageShareDo
LeftJoin(table schema.Tabler, on ...field.Expr) IScaStorageShareDo
RightJoin(table schema.Tabler, on ...field.Expr) IScaStorageShareDo
Group(cols ...field.Expr) IScaStorageShareDo
Having(conds ...gen.Condition) IScaStorageShareDo
Limit(limit int) IScaStorageShareDo
Offset(offset int) IScaStorageShareDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IScaStorageShareDo
Unscoped() IScaStorageShareDo
Create(values ...*model.ScaStorageShare) error
CreateInBatches(values []*model.ScaStorageShare, batchSize int) error
Save(values ...*model.ScaStorageShare) error
First() (*model.ScaStorageShare, error)
Take() (*model.ScaStorageShare, error)
Last() (*model.ScaStorageShare, error)
Find() ([]*model.ScaStorageShare, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ScaStorageShare, err error)
FindInBatches(result *[]*model.ScaStorageShare, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.ScaStorageShare) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IScaStorageShareDo
Assign(attrs ...field.AssignExpr) IScaStorageShareDo
Joins(fields ...field.RelationField) IScaStorageShareDo
Preload(fields ...field.RelationField) IScaStorageShareDo
FirstOrInit() (*model.ScaStorageShare, error)
FirstOrCreate() (*model.ScaStorageShare, error)
FindByPage(offset int, limit int) (result []*model.ScaStorageShare, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IScaStorageShareDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (s scaStorageShareDo) Debug() IScaStorageShareDo {
return s.withDO(s.DO.Debug())
}
func (s scaStorageShareDo) WithContext(ctx context.Context) IScaStorageShareDo {
return s.withDO(s.DO.WithContext(ctx))
}
func (s scaStorageShareDo) ReadDB() IScaStorageShareDo {
return s.Clauses(dbresolver.Read)
}
func (s scaStorageShareDo) WriteDB() IScaStorageShareDo {
return s.Clauses(dbresolver.Write)
}
func (s scaStorageShareDo) Session(config *gorm.Session) IScaStorageShareDo {
return s.withDO(s.DO.Session(config))
}
func (s scaStorageShareDo) Clauses(conds ...clause.Expression) IScaStorageShareDo {
return s.withDO(s.DO.Clauses(conds...))
}
func (s scaStorageShareDo) Returning(value interface{}, columns ...string) IScaStorageShareDo {
return s.withDO(s.DO.Returning(value, columns...))
}
func (s scaStorageShareDo) Not(conds ...gen.Condition) IScaStorageShareDo {
return s.withDO(s.DO.Not(conds...))
}
func (s scaStorageShareDo) Or(conds ...gen.Condition) IScaStorageShareDo {
return s.withDO(s.DO.Or(conds...))
}
func (s scaStorageShareDo) Select(conds ...field.Expr) IScaStorageShareDo {
return s.withDO(s.DO.Select(conds...))
}
func (s scaStorageShareDo) Where(conds ...gen.Condition) IScaStorageShareDo {
return s.withDO(s.DO.Where(conds...))
}
func (s scaStorageShareDo) Order(conds ...field.Expr) IScaStorageShareDo {
return s.withDO(s.DO.Order(conds...))
}
func (s scaStorageShareDo) Distinct(cols ...field.Expr) IScaStorageShareDo {
return s.withDO(s.DO.Distinct(cols...))
}
func (s scaStorageShareDo) Omit(cols ...field.Expr) IScaStorageShareDo {
return s.withDO(s.DO.Omit(cols...))
}
func (s scaStorageShareDo) Join(table schema.Tabler, on ...field.Expr) IScaStorageShareDo {
return s.withDO(s.DO.Join(table, on...))
}
func (s scaStorageShareDo) LeftJoin(table schema.Tabler, on ...field.Expr) IScaStorageShareDo {
return s.withDO(s.DO.LeftJoin(table, on...))
}
func (s scaStorageShareDo) RightJoin(table schema.Tabler, on ...field.Expr) IScaStorageShareDo {
return s.withDO(s.DO.RightJoin(table, on...))
}
func (s scaStorageShareDo) Group(cols ...field.Expr) IScaStorageShareDo {
return s.withDO(s.DO.Group(cols...))
}
func (s scaStorageShareDo) Having(conds ...gen.Condition) IScaStorageShareDo {
return s.withDO(s.DO.Having(conds...))
}
func (s scaStorageShareDo) Limit(limit int) IScaStorageShareDo {
return s.withDO(s.DO.Limit(limit))
}
func (s scaStorageShareDo) Offset(offset int) IScaStorageShareDo {
return s.withDO(s.DO.Offset(offset))
}
func (s scaStorageShareDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IScaStorageShareDo {
return s.withDO(s.DO.Scopes(funcs...))
}
func (s scaStorageShareDo) Unscoped() IScaStorageShareDo {
return s.withDO(s.DO.Unscoped())
}
func (s scaStorageShareDo) Create(values ...*model.ScaStorageShare) error {
if len(values) == 0 {
return nil
}
return s.DO.Create(values)
}
func (s scaStorageShareDo) CreateInBatches(values []*model.ScaStorageShare, batchSize int) error {
return s.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (s scaStorageShareDo) Save(values ...*model.ScaStorageShare) error {
if len(values) == 0 {
return nil
}
return s.DO.Save(values)
}
func (s scaStorageShareDo) First() (*model.ScaStorageShare, error) {
if result, err := s.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShare), nil
}
}
func (s scaStorageShareDo) Take() (*model.ScaStorageShare, error) {
if result, err := s.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShare), nil
}
}
func (s scaStorageShareDo) Last() (*model.ScaStorageShare, error) {
if result, err := s.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShare), nil
}
}
func (s scaStorageShareDo) Find() ([]*model.ScaStorageShare, error) {
result, err := s.DO.Find()
return result.([]*model.ScaStorageShare), err
}
func (s scaStorageShareDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ScaStorageShare, err error) {
buf := make([]*model.ScaStorageShare, 0, batchSize)
err = s.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (s scaStorageShareDo) FindInBatches(result *[]*model.ScaStorageShare, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return s.DO.FindInBatches(result, batchSize, fc)
}
func (s scaStorageShareDo) Attrs(attrs ...field.AssignExpr) IScaStorageShareDo {
return s.withDO(s.DO.Attrs(attrs...))
}
func (s scaStorageShareDo) Assign(attrs ...field.AssignExpr) IScaStorageShareDo {
return s.withDO(s.DO.Assign(attrs...))
}
func (s scaStorageShareDo) Joins(fields ...field.RelationField) IScaStorageShareDo {
for _, _f := range fields {
s = *s.withDO(s.DO.Joins(_f))
}
return &s
}
func (s scaStorageShareDo) Preload(fields ...field.RelationField) IScaStorageShareDo {
for _, _f := range fields {
s = *s.withDO(s.DO.Preload(_f))
}
return &s
}
func (s scaStorageShareDo) FirstOrInit() (*model.ScaStorageShare, error) {
if result, err := s.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShare), nil
}
}
func (s scaStorageShareDo) FirstOrCreate() (*model.ScaStorageShare, error) {
if result, err := s.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShare), nil
}
}
func (s scaStorageShareDo) FindByPage(offset int, limit int) (result []*model.ScaStorageShare, count int64, err error) {
result, err = s.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = s.Offset(-1).Limit(-1).Count()
return
}
func (s scaStorageShareDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = s.Count()
if err != nil {
return
}
err = s.Offset(offset).Limit(limit).Scan(result)
return
}
func (s scaStorageShareDo) Scan(result interface{}) (err error) {
return s.DO.Scan(result)
}
func (s scaStorageShareDo) Delete(models ...*model.ScaStorageShare) (result gen.ResultInfo, err error) {
return s.DO.Delete(models)
}
func (s *scaStorageShareDo) withDO(do gen.Dao) *scaStorageShareDo {
s.DO = *do.(*gen.DO)
return s
}

View File

@@ -0,0 +1,409 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
)
func newScaStorageShareVisit(db *gorm.DB, opts ...gen.DOOption) scaStorageShareVisit {
_scaStorageShareVisit := scaStorageShareVisit{}
_scaStorageShareVisit.scaStorageShareVisitDo.UseDB(db, opts...)
_scaStorageShareVisit.scaStorageShareVisitDo.UseModel(&model.ScaStorageShareVisit{})
tableName := _scaStorageShareVisit.scaStorageShareVisitDo.TableName()
_scaStorageShareVisit.ALL = field.NewAsterisk(tableName)
_scaStorageShareVisit.ID = field.NewInt64(tableName, "id")
_scaStorageShareVisit.UserID = field.NewString(tableName, "user_id")
_scaStorageShareVisit.ShareID = field.NewInt64(tableName, "share_id")
_scaStorageShareVisit.Views = field.NewInt64(tableName, "views")
_scaStorageShareVisit.Version = field.NewField(tableName, "version")
_scaStorageShareVisit.CreatedAt = field.NewTime(tableName, "created_at")
_scaStorageShareVisit.UpdatedAt = field.NewTime(tableName, "updated_at")
_scaStorageShareVisit.DeletedAt = field.NewField(tableName, "deleted_at")
_scaStorageShareVisit.fillFieldMap()
return _scaStorageShareVisit
}
// scaStorageShareVisit 分享浏览记录
type scaStorageShareVisit struct {
scaStorageShareVisitDo
ALL field.Asterisk
ID field.Int64 // 主键
UserID field.String // 用户ID
ShareID field.Int64 // 分享ID
Views field.Int64 // 浏览次数
Version field.Field // 版本
CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间
DeletedAt field.Field // 删除时间
fieldMap map[string]field.Expr
}
func (s scaStorageShareVisit) Table(newTableName string) *scaStorageShareVisit {
s.scaStorageShareVisitDo.UseTable(newTableName)
return s.updateTableName(newTableName)
}
func (s scaStorageShareVisit) As(alias string) *scaStorageShareVisit {
s.scaStorageShareVisitDo.DO = *(s.scaStorageShareVisitDo.As(alias).(*gen.DO))
return s.updateTableName(alias)
}
func (s *scaStorageShareVisit) updateTableName(table string) *scaStorageShareVisit {
s.ALL = field.NewAsterisk(table)
s.ID = field.NewInt64(table, "id")
s.UserID = field.NewString(table, "user_id")
s.ShareID = field.NewInt64(table, "share_id")
s.Views = field.NewInt64(table, "views")
s.Version = field.NewField(table, "version")
s.CreatedAt = field.NewTime(table, "created_at")
s.UpdatedAt = field.NewTime(table, "updated_at")
s.DeletedAt = field.NewField(table, "deleted_at")
s.fillFieldMap()
return s
}
func (s *scaStorageShareVisit) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := s.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (s *scaStorageShareVisit) fillFieldMap() {
s.fieldMap = make(map[string]field.Expr, 8)
s.fieldMap["id"] = s.ID
s.fieldMap["user_id"] = s.UserID
s.fieldMap["share_id"] = s.ShareID
s.fieldMap["views"] = s.Views
s.fieldMap["version"] = s.Version
s.fieldMap["created_at"] = s.CreatedAt
s.fieldMap["updated_at"] = s.UpdatedAt
s.fieldMap["deleted_at"] = s.DeletedAt
}
func (s scaStorageShareVisit) clone(db *gorm.DB) scaStorageShareVisit {
s.scaStorageShareVisitDo.ReplaceConnPool(db.Statement.ConnPool)
return s
}
func (s scaStorageShareVisit) replaceDB(db *gorm.DB) scaStorageShareVisit {
s.scaStorageShareVisitDo.ReplaceDB(db)
return s
}
type scaStorageShareVisitDo struct{ gen.DO }
type IScaStorageShareVisitDo interface {
gen.SubQuery
Debug() IScaStorageShareVisitDo
WithContext(ctx context.Context) IScaStorageShareVisitDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IScaStorageShareVisitDo
WriteDB() IScaStorageShareVisitDo
As(alias string) gen.Dao
Session(config *gorm.Session) IScaStorageShareVisitDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IScaStorageShareVisitDo
Not(conds ...gen.Condition) IScaStorageShareVisitDo
Or(conds ...gen.Condition) IScaStorageShareVisitDo
Select(conds ...field.Expr) IScaStorageShareVisitDo
Where(conds ...gen.Condition) IScaStorageShareVisitDo
Order(conds ...field.Expr) IScaStorageShareVisitDo
Distinct(cols ...field.Expr) IScaStorageShareVisitDo
Omit(cols ...field.Expr) IScaStorageShareVisitDo
Join(table schema.Tabler, on ...field.Expr) IScaStorageShareVisitDo
LeftJoin(table schema.Tabler, on ...field.Expr) IScaStorageShareVisitDo
RightJoin(table schema.Tabler, on ...field.Expr) IScaStorageShareVisitDo
Group(cols ...field.Expr) IScaStorageShareVisitDo
Having(conds ...gen.Condition) IScaStorageShareVisitDo
Limit(limit int) IScaStorageShareVisitDo
Offset(offset int) IScaStorageShareVisitDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IScaStorageShareVisitDo
Unscoped() IScaStorageShareVisitDo
Create(values ...*model.ScaStorageShareVisit) error
CreateInBatches(values []*model.ScaStorageShareVisit, batchSize int) error
Save(values ...*model.ScaStorageShareVisit) error
First() (*model.ScaStorageShareVisit, error)
Take() (*model.ScaStorageShareVisit, error)
Last() (*model.ScaStorageShareVisit, error)
Find() ([]*model.ScaStorageShareVisit, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ScaStorageShareVisit, err error)
FindInBatches(result *[]*model.ScaStorageShareVisit, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.ScaStorageShareVisit) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IScaStorageShareVisitDo
Assign(attrs ...field.AssignExpr) IScaStorageShareVisitDo
Joins(fields ...field.RelationField) IScaStorageShareVisitDo
Preload(fields ...field.RelationField) IScaStorageShareVisitDo
FirstOrInit() (*model.ScaStorageShareVisit, error)
FirstOrCreate() (*model.ScaStorageShareVisit, error)
FindByPage(offset int, limit int) (result []*model.ScaStorageShareVisit, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IScaStorageShareVisitDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (s scaStorageShareVisitDo) Debug() IScaStorageShareVisitDo {
return s.withDO(s.DO.Debug())
}
func (s scaStorageShareVisitDo) WithContext(ctx context.Context) IScaStorageShareVisitDo {
return s.withDO(s.DO.WithContext(ctx))
}
func (s scaStorageShareVisitDo) ReadDB() IScaStorageShareVisitDo {
return s.Clauses(dbresolver.Read)
}
func (s scaStorageShareVisitDo) WriteDB() IScaStorageShareVisitDo {
return s.Clauses(dbresolver.Write)
}
func (s scaStorageShareVisitDo) Session(config *gorm.Session) IScaStorageShareVisitDo {
return s.withDO(s.DO.Session(config))
}
func (s scaStorageShareVisitDo) Clauses(conds ...clause.Expression) IScaStorageShareVisitDo {
return s.withDO(s.DO.Clauses(conds...))
}
func (s scaStorageShareVisitDo) Returning(value interface{}, columns ...string) IScaStorageShareVisitDo {
return s.withDO(s.DO.Returning(value, columns...))
}
func (s scaStorageShareVisitDo) Not(conds ...gen.Condition) IScaStorageShareVisitDo {
return s.withDO(s.DO.Not(conds...))
}
func (s scaStorageShareVisitDo) Or(conds ...gen.Condition) IScaStorageShareVisitDo {
return s.withDO(s.DO.Or(conds...))
}
func (s scaStorageShareVisitDo) Select(conds ...field.Expr) IScaStorageShareVisitDo {
return s.withDO(s.DO.Select(conds...))
}
func (s scaStorageShareVisitDo) Where(conds ...gen.Condition) IScaStorageShareVisitDo {
return s.withDO(s.DO.Where(conds...))
}
func (s scaStorageShareVisitDo) Order(conds ...field.Expr) IScaStorageShareVisitDo {
return s.withDO(s.DO.Order(conds...))
}
func (s scaStorageShareVisitDo) Distinct(cols ...field.Expr) IScaStorageShareVisitDo {
return s.withDO(s.DO.Distinct(cols...))
}
func (s scaStorageShareVisitDo) Omit(cols ...field.Expr) IScaStorageShareVisitDo {
return s.withDO(s.DO.Omit(cols...))
}
func (s scaStorageShareVisitDo) Join(table schema.Tabler, on ...field.Expr) IScaStorageShareVisitDo {
return s.withDO(s.DO.Join(table, on...))
}
func (s scaStorageShareVisitDo) LeftJoin(table schema.Tabler, on ...field.Expr) IScaStorageShareVisitDo {
return s.withDO(s.DO.LeftJoin(table, on...))
}
func (s scaStorageShareVisitDo) RightJoin(table schema.Tabler, on ...field.Expr) IScaStorageShareVisitDo {
return s.withDO(s.DO.RightJoin(table, on...))
}
func (s scaStorageShareVisitDo) Group(cols ...field.Expr) IScaStorageShareVisitDo {
return s.withDO(s.DO.Group(cols...))
}
func (s scaStorageShareVisitDo) Having(conds ...gen.Condition) IScaStorageShareVisitDo {
return s.withDO(s.DO.Having(conds...))
}
func (s scaStorageShareVisitDo) Limit(limit int) IScaStorageShareVisitDo {
return s.withDO(s.DO.Limit(limit))
}
func (s scaStorageShareVisitDo) Offset(offset int) IScaStorageShareVisitDo {
return s.withDO(s.DO.Offset(offset))
}
func (s scaStorageShareVisitDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IScaStorageShareVisitDo {
return s.withDO(s.DO.Scopes(funcs...))
}
func (s scaStorageShareVisitDo) Unscoped() IScaStorageShareVisitDo {
return s.withDO(s.DO.Unscoped())
}
func (s scaStorageShareVisitDo) Create(values ...*model.ScaStorageShareVisit) error {
if len(values) == 0 {
return nil
}
return s.DO.Create(values)
}
func (s scaStorageShareVisitDo) CreateInBatches(values []*model.ScaStorageShareVisit, batchSize int) error {
return s.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (s scaStorageShareVisitDo) Save(values ...*model.ScaStorageShareVisit) error {
if len(values) == 0 {
return nil
}
return s.DO.Save(values)
}
func (s scaStorageShareVisitDo) First() (*model.ScaStorageShareVisit, error) {
if result, err := s.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShareVisit), nil
}
}
func (s scaStorageShareVisitDo) Take() (*model.ScaStorageShareVisit, error) {
if result, err := s.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShareVisit), nil
}
}
func (s scaStorageShareVisitDo) Last() (*model.ScaStorageShareVisit, error) {
if result, err := s.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShareVisit), nil
}
}
func (s scaStorageShareVisitDo) Find() ([]*model.ScaStorageShareVisit, error) {
result, err := s.DO.Find()
return result.([]*model.ScaStorageShareVisit), err
}
func (s scaStorageShareVisitDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ScaStorageShareVisit, err error) {
buf := make([]*model.ScaStorageShareVisit, 0, batchSize)
err = s.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (s scaStorageShareVisitDo) FindInBatches(result *[]*model.ScaStorageShareVisit, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return s.DO.FindInBatches(result, batchSize, fc)
}
func (s scaStorageShareVisitDo) Attrs(attrs ...field.AssignExpr) IScaStorageShareVisitDo {
return s.withDO(s.DO.Attrs(attrs...))
}
func (s scaStorageShareVisitDo) Assign(attrs ...field.AssignExpr) IScaStorageShareVisitDo {
return s.withDO(s.DO.Assign(attrs...))
}
func (s scaStorageShareVisitDo) Joins(fields ...field.RelationField) IScaStorageShareVisitDo {
for _, _f := range fields {
s = *s.withDO(s.DO.Joins(_f))
}
return &s
}
func (s scaStorageShareVisitDo) Preload(fields ...field.RelationField) IScaStorageShareVisitDo {
for _, _f := range fields {
s = *s.withDO(s.DO.Preload(_f))
}
return &s
}
func (s scaStorageShareVisitDo) FirstOrInit() (*model.ScaStorageShareVisit, error) {
if result, err := s.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShareVisit), nil
}
}
func (s scaStorageShareVisitDo) FirstOrCreate() (*model.ScaStorageShareVisit, error) {
if result, err := s.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageShareVisit), nil
}
}
func (s scaStorageShareVisitDo) FindByPage(offset int, limit int) (result []*model.ScaStorageShareVisit, count int64, err error) {
result, err = s.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = s.Offset(-1).Limit(-1).Count()
return
}
func (s scaStorageShareVisitDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = s.Count()
if err != nil {
return
}
err = s.Offset(offset).Limit(limit).Scan(result)
return
}
func (s scaStorageShareVisitDo) Scan(result interface{}) (err error) {
return s.DO.Scan(result)
}
func (s scaStorageShareVisitDo) Delete(models ...*model.ScaStorageShareVisit) (result gen.ResultInfo, err error) {
return s.DO.Delete(models)
}
func (s *scaStorageShareVisitDo) withDO(do gen.Dao) *scaStorageShareVisitDo {
s.DO = *do.(*gen.DO)
return s
}

View File

@@ -42,6 +42,7 @@ func newScaStorageThumb(db *gorm.DB, opts ...gen.DOOption) scaStorageThumb {
return _scaStorageThumb
}
// scaStorageThumb 缩略图表
type scaStorageThumb struct {
scaStorageThumbDo