develop basic APIs / override reverse geolocation

This commit is contained in:
2025-02-12 01:12:13 +08:00
parent 1d27c6ee8a
commit 3e51ab8e3f
38 changed files with 1737 additions and 118 deletions

View File

@@ -505,12 +505,10 @@ type (
ImageMeta {
ID int64 `json:"id"`
fileName string `json:"file_name"`
filePath string `json:"file_path"`
URL string `json:"url"`
fileSize string `json:"file_size"`
CreatedAt string `json:"created_at"`
Width float64 `json:"width"`
Height float64 `json:"height"`
CreatedAt string `json:"created_at"`
}
AllImageDetail {
Date string `json:"date"`
@@ -519,6 +517,52 @@ type (
AllImageListResponse {
records []AllImageDetail `json:"records"`
}
// 最近上传图片列表请求参数
RecentListResponse {
records []AllImageDetail `json:"records"`
}
LocationMeta {
ID int64 `json:"id"`
City string `json:"city"`
Total int64 `json:"total"`
}
LocationListData {
location string `json:"location"` // 中国 新疆维吾尔自治区
list []LocationMeta `json:"list"` // 图片列表
}
// 地点相册列表响应参数
LocationListResponse {
records []LocationListData `json:"records"`
}
// 地点详情列表请求参数
LocationDetailListRequest {
ID int64 `json:"id"`
}
// 地点详情列表响应参数
LocationDetailListResponse {
records []AllImageDetail `json:"records"`
}
ThingMeta {
TagName string `json:"tag_name"`
CreatedAt string `json:"created_at"`
TagCount int64 `json:"tag_count"`
}
ThingListData {
Category string `json:"category"` // 分类
list []ThingMeta `json:"list"` // 图片列表
}
// 事物相册列表响应参数
ThingListResponse {
records []ThingListData `json:"records"`
}
// 事物详情列表请求参数
ThingDetailListRequest {
ID int64 `json:"id"`
}
// 事物详情列表响应参数
ThingDetailListResponse {
records []AllImageDetail `json:"records"`
}
)
// 文件上传
@@ -581,5 +625,25 @@ service auth {
// 获取所有图片列表
@handler queryAllImageList
post /image/all/list (AllImageListRequest) returns (AllImageListResponse)
// 获取最近上传图片列表
@handler queryRecentImageList
post /image/recent/list returns (RecentListResponse)
// 获取地点相册列表
@handler queryLocationImageList
post /image/location/list returns (LocationListResponse)
// 获取地点详情列表
@handler queryLocationDetailList
post /image/location/detail/list (LocationDetailListRequest) returns (LocationDetailListResponse)
// 获取事物相册列表
@handler queryThingImageList
post /image/thing/list returns (ThingListResponse)
// 获取事物详情列表
@handler queryThingDetailList
post /image/thing/detail/list (ThingDetailListRequest) returns (ThingDetailListResponse)
}

View File

@@ -243,6 +243,31 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/image/all/list",
Handler: storage.QueryAllImageListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/image/location/detail/list",
Handler: storage.QueryLocationDetailListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/image/location/list",
Handler: storage.QueryLocationImageListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/image/recent/list",
Handler: storage.QueryRecentImageListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/image/thing/detail/list",
Handler: storage.QueryThingDetailListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/image/thing/list",
Handler: storage.QueryThingImageListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/uploads",

View File

@@ -0,0 +1,29 @@
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 QueryLocationDetailListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.LocationDetailListRequest
if err := httpx.Parse(r, &req); err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := storage.NewQueryLocationDetailListLogic(r.Context(), svcCtx)
resp, err := l.QueryLocationDetailList(&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 QueryLocationImageListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := storage.NewQueryLocationImageListLogic(r.Context(), svcCtx)
resp, err := l.QueryLocationImageList()
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 QueryRecentImageListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := storage.NewQueryRecentImageListLogic(r.Context(), svcCtx)
resp, err := l.QueryRecentImageList()
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
}
}
}

View File

@@ -0,0 +1,29 @@
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 QueryThingDetailListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ThingDetailListRequest
if err := httpx.Parse(r, &req); err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := storage.NewQueryThingDetailListLogic(r.Context(), svcCtx)
resp, err := l.QueryThingDetailList(&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 QueryThingImageListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := storage.NewQueryThingImageListLogic(r.Context(), svcCtx)
resp, err := l.QueryThingImageList()
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
}
}
}

View File

@@ -16,8 +16,6 @@ type DeleteAlbumLogic struct {
svcCtx *svc.ServiceContext
}
//43454A
func NewDeleteAlbumLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteAlbumLogic {
return &DeleteAlbumLogic{
Logger: logx.WithContext(ctx),
@@ -39,7 +37,7 @@ func (l *DeleteAlbumLogic) DeleteAlbum(req *types.AlbumDeleteRequest) (resp stri
return "", errors.New("album not found")
}
storageInfo := l.svcCtx.DB.ScaStorageInfo
_, err = storageInfo.Where(storageInfo.AlbumID.Eq(req.ID), storageInfo.UserID.Eq(uid)).Update(storageInfo.AlbumID, nil)
_, err = storageInfo.Where(storageInfo.AlbumID.Eq(req.ID), storageInfo.UserID.Eq(uid)).Update(storageInfo.AlbumID, 0)
if err != nil {
return "", err
}

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.Show, req.FaceType)
resultInfo, err := storageInfo.Where(storageInfo.FaceID.In(req.IDs...)).Update(storageInfo.ImgShow, req.FaceType)
if err != nil {
return nil, err
}

View File

@@ -25,6 +25,16 @@ type QueryAllImageListLogic struct {
svcCtx *svc.ServiceContext
}
var WeekdayMap = map[time.Weekday]string{
time.Sunday: "日",
time.Monday: "一",
time.Tuesday: "二",
time.Wednesday: "三",
time.Thursday: "四",
time.Friday: "五",
time.Saturday: "六",
}
func NewQueryAllImageListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryAllImageListLogic {
return &QueryAllImageListLogic{
Logger: logx.WithContext(ctx),
@@ -102,7 +112,8 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques
wg.Add(1)
go func(dbFileInfo *model.ScaStorageInfo) {
defer wg.Done()
date := dbFileInfo.CreatedAt.Format("2006-01-02")
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)
@@ -115,12 +126,10 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
FilePath: dbFileInfo.Path,
URL: url,
FileSize: dbFileInfo.FileSize,
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
Width: dbFileInfo.Width,
Height: dbFileInfo.Height,
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
})
// 重新存储更新后的图像列表

View File

@@ -0,0 +1,30 @@
package storage
import (
"context"
"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 QueryLocationDetailListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryLocationDetailListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryLocationDetailListLogic {
return &QueryLocationDetailListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.LocationDetailListRequest) (resp *types.LocationDetailListResponse, err error) {
// todo: add your logic here and delete this line
return
}

View File

@@ -0,0 +1,76 @@
package storage
import (
"context"
"errors"
"fmt"
"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 QueryLocationImageListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryLocationImageListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryLocationImageListLogic {
return &QueryLocationImageListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryLocationImageListLogic) QueryLocationImageList() (resp *types.LocationListResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
storageLocation := l.svcCtx.DB.ScaStorageLocation
locations, err := storageLocation.Select(
storageLocation.ID,
storageLocation.Country,
storageLocation.City,
storageLocation.Province,
storageLocation.Total).Where(storageLocation.UserID.Eq(uid)).
Order(storageLocation.CreatedAt.Desc()).Find()
if err != nil {
return nil, err
}
locationMap := make(map[string][]types.LocationMeta)
for _, loc := range locations {
var locationKey string
if loc.Province == "" {
locationKey = loc.Country
} else {
locationKey = fmt.Sprintf("%s %s", loc.Country, loc.Province)
}
city := loc.City
if city == "" {
city = loc.Country
}
locationMeta := types.LocationMeta{
ID: loc.ID,
City: city,
Total: loc.Total,
}
locationMap[locationKey] = append(locationMap[locationKey], locationMeta)
}
var locationListData []types.LocationListData
for location, list := range locationMap {
locationListData = append(locationListData, types.LocationListData{
Location: location,
List: list,
})
}
return &types.LocationListResponse{Records: locationListData}, nil
}

View File

@@ -0,0 +1,111 @@
package storage
import (
"context"
"encoding/json"
"errors"
"schisandra-album-cloud-microservices/common/constant"
"sync"
"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 QueryRecentImageListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryRecentImageListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryRecentImageListLogic {
return &QueryRecentImageListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryRecentImageListLogic) QueryRecentImageList() (resp *types.RecentListResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
redisKeyPattern := constant.ImageRecentPrefix + uid + ":*"
iter := l.svcCtx.RedisClient.Scan(l.ctx, 0, redisKeyPattern, 0).Iterator()
var keys []string
for iter.Next(l.ctx) {
keys = append(keys, iter.Val())
}
if err := iter.Err(); err != nil {
logx.Error(err)
return nil, errors.New("scan recent file list failed")
}
if len(keys) == 0 {
return &types.RecentListResponse{Records: []types.AllImageDetail{}}, nil
}
cmds, err := l.svcCtx.RedisClient.MGet(l.ctx, keys...).Result()
if err != nil {
logx.Error(err)
return nil, errors.New("get recent file list failed")
}
var wg sync.WaitGroup
groupedImages := sync.Map{}
for _, cmd := range cmds {
if cmd == nil {
continue
}
wg.Add(1)
go func(cmd interface{}) {
defer wg.Done()
val, ok := cmd.(string)
if !ok {
logx.Error("invalid value type")
return
}
var imageMeta types.ImageMeta
err = json.Unmarshal([]byte(val), &imageMeta)
if err != nil {
logx.Error(err)
return
}
parse, err := time.Parse("2006-01-02 15:04:05", imageMeta.CreatedAt)
if err != nil {
logx.Error(err)
return
}
date := parse.Format("2006年1月2日 星期" + WeekdayMap[parse.Weekday()])
groupedImages.Range(func(key, value interface{}) bool {
if key == date {
images := value.([]types.ImageMeta)
images = append(images, imageMeta)
groupedImages.Store(date, images)
return false
}
return true
})
groupedImages.Store(date, []types.ImageMeta{imageMeta})
}(cmd)
}
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
})
return &types.RecentListResponse{
Records: imageList,
}, nil
}

View File

@@ -0,0 +1,30 @@
package storage
import (
"context"
"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 QueryThingDetailListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryThingDetailListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryThingDetailListLogic {
return &QueryThingDetailListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailListRequest) (resp *types.ThingDetailListResponse, err error) {
// todo: add your logic here and delete this line
return
}

View File

@@ -0,0 +1,85 @@
package storage
import (
"context"
"errors"
"sync"
"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 QueryThingImageListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryThingImageListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryThingImageListLogic {
return &QueryThingImageListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryThingImageListLogic) QueryThingImageList() (resp *types.ThingListResponse, err error) {
uid, ok := l.ctx.Value("user_id").(string)
if !ok {
return nil, errors.New("user_id not found")
}
storageInfo := l.svcCtx.DB.ScaStorageInfo
storageInfos, err := storageInfo.Select(
storageInfo.ID,
storageInfo.Category,
storageInfo.Tags,
storageInfo.CreatedAt).
Where(storageInfo.UserID.Eq(uid),
storageInfo.Category.IsNotNull(),
storageInfo.Tags.IsNotNull()).
Order(storageInfo.CreatedAt.Desc()).
Find()
if err != nil {
return nil, err
}
categoryMap := sync.Map{}
tagCountMap := sync.Map{}
for _, info := range storageInfos {
tagKey := info.Category + "::" + info.Tags
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,
CreatedAt: info.CreatedAt.Format("2006-01-02 15:04:05"),
})
}
tagCount, _ := tagCountMap.Load(tagKey)
tagCountMap.Store(tagKey, tagCount.(int64)+1)
}
var thingListData []types.ThingListData
categoryMap.Range(func(category, tagData interface{}) bool {
var metas []types.ThingMeta
tagData.(*sync.Map).Range(func(tag, item interface{}) bool {
tagKey := category.(string) + "::" + tag.(string)
tagCount, _ := tagCountMap.Load(tagKey)
meta := item.(types.ThingMeta)
meta.TagCount = tagCount.(int64)
metas = append(metas, meta)
return true
})
thingListData = append(thingListData, types.ThingListData{
Category: category.(string),
List: metas,
})
return true
})
return &types.ThingListResponse{Records: thingListData}, nil
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/ccpwcn/kgo"
"github.com/redis/go-redis/v9"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
"io"
"mime/multipart"
"net/http"
@@ -19,10 +20,11 @@ import (
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
"schisandra-album-cloud-microservices/common/gao_map"
"schisandra-album-cloud-microservices/common/geo_json"
"schisandra-album-cloud-microservices/common/storage/config"
"strconv"
"strings"
"sync"
"time"
)
@@ -30,6 +32,7 @@ type UploadFileLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
wg sync.WaitGroup
}
func NewUploadFileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadFileLogic {
@@ -37,6 +40,7 @@ func NewUploadFileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Upload
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
wg: sync.WaitGroup{},
}
}
@@ -67,6 +71,7 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
if err != nil {
return "", err
}
// 人脸识别
if result.FileType == "image/png" || result.FileType == "image/jpeg" {
face, err := l.svcCtx.AiSvcRpc.FaceRecognition(l.ctx, &pb.FaceRecognitionRequest{Face: bytes, UserId: uid})
@@ -76,13 +81,6 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
if face != nil {
faceId = face.GetFaceId()
}
//// 图像分类
//classification, err := l.svcCtx.AiSvcRpc.TfClassification(l.ctx, &pb.TfClassificationRequest{Image: bytes})
//if err != nil {
// return "", err
//}
//className = classification.GetClassName()
}
// 解析 EXIF 信息
@@ -101,7 +99,13 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
latitude, longitude := l.extractGPSCoordinates(exif)
// 根据 GPS 信息获取地理位置信息
locationString, gpsString, err := l.getGeoLocation(latitude, longitude)
country, province, city, err := l.getGeoLocation(latitude, longitude)
if err != nil {
return "", err
}
// 将地址信息保存到数据库
locationId, err := l.saveFileLocationInfoToDB(uid, latitude, longitude, country, province, city)
if err != nil {
return "", err
}
@@ -111,19 +115,25 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
if _, err = file.Seek(0, 0); err != nil {
return "", err
}
bucket, provider, filePath, err := l.uploadFileToOSS(uid, header, file, result)
bucket, provider, filePath, url, err := l.uploadFileToOSS(uid, header, file, result)
if err != nil {
return "", err
}
// 将 EXIF 和文件信息存入数据库
if err = l.saveFileInfoToDB(uid, bucket, provider, header, result, originalDateTime, gpsString, locationString, exif, faceId, filePath); err != nil {
id, err := l.saveFileInfoToDB(uid, bucket, provider, header, result, originalDateTime, locationId, exif, faceId, filePath)
if err != nil {
return "", err
}
// 删除缓存
l.afterImageUpload(uid, provider, bucket)
// redis 保存最近7天上传的文件列表
err = l.saveRecentFileList(uid, url, id, result, header.Filename)
if err != nil {
return "", err
}
return "success", nil
}
@@ -138,16 +148,10 @@ func (l *UploadFileLogic) getUserID() (string, error) {
// 在UploadImageLogic或其他需要使缓存失效的逻辑中添加
func (l *UploadFileLogic) afterImageUpload(uid, provider, bucket string) {
// 构造所有可能的缓存键组合sort为true/false
keysToDelete := []string{
fmt.Sprintf("%s%s:%s:%s:true", constant.ImageListPrefix, uid, provider, bucket),
fmt.Sprintf("%s%s:%s:%s:false", constant.ImageListPrefix, uid, provider, bucket),
}
// 批量删除缓存
for _, key := range keysToDelete {
for _, sort := range []bool{true, false} {
key := fmt.Sprintf("%s%s:%s:%s:%v", constant.ImageListPrefix, uid, provider, bucket, sort)
if err := l.svcCtx.RedisClient.Del(l.ctx, key).Err(); err != nil {
logx.Errorf("Failed to delete cache key %s: %v", key, err)
logx.Errorf("删除缓存键 %s 失败: %v", key, err)
}
}
}
@@ -173,6 +177,9 @@ func (l *UploadFileLogic) parseAIRecognitionResult(r *http.Request) (types.File,
// 解析 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")
@@ -209,58 +216,53 @@ func (l *UploadFileLogic) extractGPSCoordinates(exif map[string]interface{}) (fl
}
// 根据 GPS 信息获取地理位置信息
func (l *UploadFileLogic) getGeoLocation(latitude, longitude float64) (string, string, error) {
if latitude == 0 || longitude == 0 {
return "", "", nil
func (l *UploadFileLogic) getGeoLocation(latitude, longitude float64) (string, string, string, error) {
if latitude == 0.000000 || longitude == 0.000000 {
return "", "", "", nil
}
gpsString := fmt.Sprintf("[%f,%f]", latitude, longitude)
request := gao_map.ReGeoRequest{Location: fmt.Sprintf("%f,%f", latitude, longitude)}
//request := gao_map.ReGeoRequest{Location: fmt.Sprintf("%f,%f", latitude, longitude)}
//
//location, err := l.svcCtx.GaoMap.Location.ReGeo(&request)
//if err != nil {
// return nil, errors.New("regeo failed")
//}
//
//addressInfo := map[string]string{}
//if location.ReGeoCode.AddressComponent.Country != "" {
// addressInfo["country"] = location.ReGeoCode.AddressComponent.Country
//}
//if location.ReGeoCode.AddressComponent.Province != "" {
// addressInfo["province"] = location.ReGeoCode.AddressComponent.Province
//}
//if location.ReGeoCode.AddressComponent.City != "" {
// addressInfo["city"] = location.ReGeoCode.AddressComponent.City.(string)
//}
//if location.ReGeoCode.AddressComponent.District != "" {
// addressInfo["district"] = location.ReGeoCode.AddressComponent.District.(string)
//}
//if location.ReGeoCode.AddressComponent.Township != "" {
// addressInfo["township"] = location.ReGeoCode.AddressComponent.Township
//}
location, err := l.svcCtx.GaoMap.Location.ReGeo(&request)
country, province, city, err := geo_json.GetAddress(latitude, longitude, l.svcCtx.GeoRegionData)
if err != nil {
return "", "", errors.New("regeo failed")
return "", "", "", errors.New("get geo location failed")
}
addressInfo := map[string]string{}
if location.ReGeoCode.AddressComponent.Country != "" {
addressInfo["county"] = location.ReGeoCode.AddressComponent.Country
}
if location.ReGeoCode.AddressComponent.Province != "" {
addressInfo["province"] = location.ReGeoCode.AddressComponent.Province
}
if location.ReGeoCode.AddressComponent.City != "" {
addressInfo["city"] = location.ReGeoCode.AddressComponent.City.(string)
}
if location.ReGeoCode.AddressComponent.District != "" {
addressInfo["district"] = location.ReGeoCode.AddressComponent.District.(string)
}
if location.ReGeoCode.AddressComponent.Township != "" {
addressInfo["township"] = location.ReGeoCode.AddressComponent.Township
}
locationString := ""
if len(addressInfo) > 0 {
addressJSON, err := json.Marshal(addressInfo)
if err != nil {
return "", "", errors.New("marshal address info failed")
}
locationString = string(addressJSON)
}
return locationString, gpsString, nil
return country, province, city, nil
}
// 上传文件到 OSS
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (string, string, string, error) {
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (string, string, string, string, error) {
cacheKey := constant.UserOssConfigPrefix + uid + ":" + result.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheKey, uid, result.Provider)
if err != nil {
return "", "", "", errors.New("get oss config failed")
return "", "", "", "", errors.New("get oss config failed")
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return "", "", "", errors.New("get storage failed")
return "", "", "", "", errors.New("get storage failed")
}
objectKey := path.Join(
@@ -273,16 +275,56 @@ func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHead
"Content-Type": header.Header.Get("Content-Type"),
})
if err != nil {
return "", "", "", errors.New("upload file failed")
return "", "", "", "", errors.New("upload file failed")
}
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, objectKey, time.Hour*24*7)
if err != nil {
return "", "", "", "", errors.New("presigned url failed")
}
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) {
if latitude == 0.000000 || longitude == 0.000000 {
return 0, nil
}
locationDB := l.svcCtx.DB.ScaStorageLocation
storageLocations, err := locationDB.Where(locationDB.UserID.Eq(uid), locationDB.Province.Eq(province), locationDB.City.Eq(city)).First()
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return 0, err
}
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,
}
err = locationDB.Create(&locationInfo)
if err != nil {
return 0, err
}
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))
if err != nil {
return 0, err
}
if info.RowsAffected == 0 {
return 0, errors.New("update location failed")
}
return storageLocations.ID, nil
}
return ossConfig.BucketName, ossConfig.Provider, objectKey, nil
}
// 将 EXIF 和文件信息存入数据库
func (l *UploadFileLogic) saveFileInfoToDB(uid, bucket, provider string, header *multipart.FileHeader, result types.File, originalDateTime, gpsString, locationString string, exif map[string]interface{}, faceId int64, filePath string) error {
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 errors.New("marshal exif failed")
return 0, errors.New("marshal exif failed")
}
typeName := l.classifyFile(result.FileType, result.IsScreenshot)
scaStorageInfo := &model.ScaStorageInfo{
@@ -294,13 +336,12 @@ func (l *UploadFileLogic) saveFileInfoToDB(uid, bucket, provider string, header
FileType: result.FileType,
Path: filePath,
Landscape: result.Landscape,
Tags: strings.Join(result.ObjectArray, ","),
Tags: result.TagName,
Anime: strconv.FormatBool(result.IsAnime),
Category: result.TopCategory,
Screenshot: strconv.FormatBool(result.IsScreenshot),
OriginalTime: originalDateTime,
Gps: gpsString,
Location: locationString,
LocationID: locationId,
Exif: string(exifJSON),
FaceID: faceId,
Type: typeName,
@@ -310,9 +351,9 @@ func (l *UploadFileLogic) saveFileInfoToDB(uid, bucket, provider string, header
err = l.svcCtx.DB.ScaStorageInfo.Create(scaStorageInfo)
if err != nil {
return errors.New("create storage info failed")
return 0, errors.New("create storage info failed")
}
return nil
return scaStorageInfo.ID, nil
}
// 提取解密操作为函数
@@ -404,3 +445,28 @@ func (l *UploadFileLogic) classifyFile(mimeType string, isScreenshot bool) strin
}
return "unknown"
}
// 保存最近7天上传的文件列表
func (l *UploadFileLogic) saveRecentFileList(uid, url string, id int64, result types.File, filename string) error {
redisKey := constant.ImageRecentPrefix + uid + ":" + strconv.FormatInt(id, 10)
imageMeta := types.ImageMeta{
ID: id,
URL: url,
FileName: filename,
Width: result.Width,
Height: result.Height,
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
marshal, err := json.Marshal(imageMeta)
if err != nil {
logx.Error(err)
return errors.New("marshal image meta failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, redisKey, marshal, time.Hour*24*7).Err()
if err != nil {
logx.Error(err)
return errors.New("save recent file list failed")
}
return nil
}

View File

@@ -18,7 +18,7 @@ import (
"schisandra-album-cloud-microservices/app/auth/model/mysql/query"
"schisandra-album-cloud-microservices/common/captcha/initialize"
"schisandra-album-cloud-microservices/common/casbinx"
"schisandra-album-cloud-microservices/common/gao_map"
"schisandra-album-cloud-microservices/common/geo_json"
"schisandra-album-cloud-microservices/common/ip2region"
"schisandra-album-cloud-microservices/common/miniox"
"schisandra-album-cloud-microservices/common/redisx"
@@ -43,8 +43,8 @@ type ServiceContext struct {
SlideCaptcha slide.Captcha
Sensitive *sensitive.Manager
StorageManager *manager.Manager
GaoMap *gao_map.AmapClient
MinioClient *minio.Client
GeoRegionData *geo_json.RegionData
}
func NewServiceContext(c config.Config) *ServiceContext {
@@ -65,8 +65,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
SlideCaptcha: initialize.NewSlideCaptcha(),
Sensitive: sensitivex.NewSensitive(),
StorageManager: storage.InitStorageManager(),
GaoMap: gao_map.NewAmapClient(c.Map.Key, ""),
AiSvcRpc: aiservice.NewAiService(zrpc.MustNewClient(c.AiSvcRpc)),
MinioClient: miniox.NewMinio(c.Minio.Endpoint, c.Minio.AccessKeyID, c.Minio.SecretAccessKey, c.Minio.UseSSL),
GeoRegionData: geo_json.NewGeoJSON(),
}
}

View File

@@ -2,15 +2,15 @@ package types
// File represents a file uploaded by the user.
type File struct {
Provider string `json:"provider"`
Bucket string `json:"bucket"`
FileType string `json:"fileType"`
IsAnime bool `json:"isAnime"`
ObjectArray []string `json:"objectArray"`
Landscape string `json:"landscape"`
TopCategory string `json:"topCategory"`
IsScreenshot bool `json:"isScreenshot"`
Exif any `json:"exif"`
Width float64 `json:"width"`
Height float64 `json:"height"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
FileType string `json:"fileType"`
IsAnime bool `json:"isAnime"`
TagName string `json:"tagName"`
Landscape string `json:"landscape"`
TopCategory string `json:"topCategory"`
IsScreenshot bool `json:"isScreenshot"`
Exif any `json:"exif"`
Width float64 `json:"width"`
Height float64 `json:"height"`
}

View File

@@ -162,12 +162,33 @@ type FaceSampleLibraryListResponse struct {
type ImageMeta struct {
ID int64 `json:"id"`
FileName string `json:"file_name"`
FilePath string `json:"file_path"`
URL string `json:"url"`
FileSize string `json:"file_size"`
CreatedAt string `json:"created_at"`
Width float64 `json:"width"`
Height float64 `json:"height"`
CreatedAt string `json:"created_at"`
}
type LocationDetailListRequest struct {
ID int64 `json:"id"`
}
type LocationDetailListResponse struct {
Records []AllImageDetail `json:"records"`
}
type LocationListData struct {
Location string `json:"location"` // 中国 新疆维吾尔自治区
List []LocationMeta `json:"list"` // 图片列表
}
type LocationListResponse struct {
Records []LocationListData `json:"records"`
}
type LocationMeta struct {
ID int64 `json:"id"`
City string `json:"city"`
Total int64 `json:"total"`
}
type LoginResponse struct {
@@ -212,6 +233,10 @@ type PhoneLoginRequest struct {
AutoLogin bool `json:"auto_login"`
}
type RecentListResponse struct {
Records []AllImageDetail `json:"records"`
}
type RefreshTokenResponse struct {
AccessToken string `json:"access_token"`
ExpireAt int64 `json:"expire_at"`
@@ -285,6 +310,29 @@ type StorageConfigRequest struct {
Region string `json:"region"`
}
type ThingDetailListRequest struct {
ID int64 `json:"id"`
}
type ThingDetailListResponse struct {
Records []AllImageDetail `json:"records"`
}
type ThingListData struct {
Category string `json:"category"` // 分类
List []ThingMeta `json:"list"` // 图片列表
}
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"`
}
type UploadRequest struct {
Image string `json:"image"`
AccessToken string `json:"access_token"`

View File

@@ -116,6 +116,7 @@ func main() {
scaUserLevel := g.GenerateModel("sca_user_level", fieldOpts...)
scaUserMessage := g.GenerateModel("sca_user_message", fieldOpts...)
scaStorageAlbum := g.GenerateModel("sca_storage_album", fieldOpts...)
scaStorageLocation := g.GenerateModel("sca_storage_location", fieldOpts...)
g.ApplyBasic(
scaAuthMenu,
@@ -135,6 +136,7 @@ func main() {
scaUserLevel,
scaUserMessage,
scaStorageAlbum,
scaStorageLocation,
)
g.Execute()

View File

@@ -27,16 +27,15 @@ type ScaStorageInfo struct {
Category string `gorm:"column:category;type:varchar(50);comment:分类" json:"category"` // 分类
Tags string `gorm:"column:tags;type:varchar(255);comment:标签" json:"tags"` // 标签
Type string `gorm:"column:type;type:varchar(50);comment:类型" json:"type"` // 类型
Location string `gorm:"column:location;type:varchar(100);comment:地址" json:"location"` // 地址
LocationID int64 `gorm:"column:location_id;type:bigint(20);comment:地址ID" json:"location_id"` // 地址ID
Hash string `gorm:"column:hash;type:varchar(255);comment:哈希值" json:"hash"` // 哈希值
Anime string `gorm:"column:anime;type:varchar(50);comment:是否是动漫图片" json:"anime"` // 是否是动漫图片
FaceID int64 `gorm:"column:face_id;type:bigint(20);comment:人像ID" json:"face_id"` // 人像ID
Landscape string `gorm:"column:landscape;type:varchar(50);comment:风景类型" json:"landscape"` // 风景类型
OriginalTime string `gorm:"column:original_time;type:varchar(50);comment:拍摄时间" json:"original_time"` // 拍摄时间
Gps string `gorm:"column:gps;type:varchar(255);comment:GPS" json:"gps"` // GPS
Screenshot string `gorm:"column:screenshot;type:varchar(50);comment:是否是截图" json:"screenshot"` // 是否是截图
Exif string `gorm:"column:exif;type:json;comment:exif 信息" json:"exif"` // exif 信息
Show string `gorm:"column:show;type:varchar(50);comment:是否隐藏0 不隐藏 1 隐藏)" json:"show"` // 是否隐藏0 不隐藏 1 隐藏)
ImgShow int64 `gorm:"column:img_show;type:tinyint(4);comment:是否隐藏0 不隐藏 1 隐藏)" json:"img_show"` // 是否隐藏0 不隐藏 1 隐藏)
AlbumID int64 `gorm:"column:album_id;type:bigint(20);comment:相册ID" json:"album_id"` // 相册ID
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"` // 更新时间

View File

@@ -0,0 +1,35 @@
// 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 TableNameScaStorageLocation = "sca_storage_location"
// ScaStorageLocation mapped from table <sca_storage_location>
type ScaStorageLocation 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
Country string `gorm:"column:country;type:varchar(100);comment:国家" json:"country"` // 国家
Province string `gorm:"column:province;type:varchar(100);comment:省" json:"province"` // 省
City string `gorm:"column:city;type:varchar(100);comment:城市" json:"city"` // 城市
Latitude string `gorm:"column:latitude;type:varchar(50);comment:纬度" json:"latitude"` // 纬度
Longitude string `gorm:"column:longitude;type:varchar(50);comment:经度" json:"longitude"` // 经度
Total int64 `gorm:"column:total;type:bigint(20);comment:数量" json:"total"` // 数量
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 ScaStorageLocation's table name
func (*ScaStorageLocation) TableName() string {
return TableNameScaStorageLocation
}

View File

@@ -29,6 +29,7 @@ var (
ScaStorageAlbum *scaStorageAlbum
ScaStorageConfig *scaStorageConfig
ScaStorageInfo *scaStorageInfo
ScaStorageLocation *scaStorageLocation
ScaStorageTag *scaStorageTag
ScaStorageTagInfo *scaStorageTagInfo
ScaUserFollow *scaUserFollow
@@ -50,6 +51,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
ScaStorageAlbum = &Q.ScaStorageAlbum
ScaStorageConfig = &Q.ScaStorageConfig
ScaStorageInfo = &Q.ScaStorageInfo
ScaStorageLocation = &Q.ScaStorageLocation
ScaStorageTag = &Q.ScaStorageTag
ScaStorageTagInfo = &Q.ScaStorageTagInfo
ScaUserFollow = &Q.ScaUserFollow
@@ -72,6 +74,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
ScaStorageAlbum: newScaStorageAlbum(db, opts...),
ScaStorageConfig: newScaStorageConfig(db, opts...),
ScaStorageInfo: newScaStorageInfo(db, opts...),
ScaStorageLocation: newScaStorageLocation(db, opts...),
ScaStorageTag: newScaStorageTag(db, opts...),
ScaStorageTagInfo: newScaStorageTagInfo(db, opts...),
ScaUserFollow: newScaUserFollow(db, opts...),
@@ -95,6 +98,7 @@ type Query struct {
ScaStorageAlbum scaStorageAlbum
ScaStorageConfig scaStorageConfig
ScaStorageInfo scaStorageInfo
ScaStorageLocation scaStorageLocation
ScaStorageTag scaStorageTag
ScaStorageTagInfo scaStorageTagInfo
ScaUserFollow scaUserFollow
@@ -119,6 +123,7 @@ func (q *Query) clone(db *gorm.DB) *Query {
ScaStorageAlbum: q.ScaStorageAlbum.clone(db),
ScaStorageConfig: q.ScaStorageConfig.clone(db),
ScaStorageInfo: q.ScaStorageInfo.clone(db),
ScaStorageLocation: q.ScaStorageLocation.clone(db),
ScaStorageTag: q.ScaStorageTag.clone(db),
ScaStorageTagInfo: q.ScaStorageTagInfo.clone(db),
ScaUserFollow: q.ScaUserFollow.clone(db),
@@ -150,6 +155,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
ScaStorageAlbum: q.ScaStorageAlbum.replaceDB(db),
ScaStorageConfig: q.ScaStorageConfig.replaceDB(db),
ScaStorageInfo: q.ScaStorageInfo.replaceDB(db),
ScaStorageLocation: q.ScaStorageLocation.replaceDB(db),
ScaStorageTag: q.ScaStorageTag.replaceDB(db),
ScaStorageTagInfo: q.ScaStorageTagInfo.replaceDB(db),
ScaUserFollow: q.ScaUserFollow.replaceDB(db),
@@ -171,6 +177,7 @@ type queryCtx struct {
ScaStorageAlbum IScaStorageAlbumDo
ScaStorageConfig IScaStorageConfigDo
ScaStorageInfo IScaStorageInfoDo
ScaStorageLocation IScaStorageLocationDo
ScaStorageTag IScaStorageTagDo
ScaStorageTagInfo IScaStorageTagInfoDo
ScaUserFollow IScaUserFollowDo
@@ -192,6 +199,7 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx {
ScaStorageAlbum: q.ScaStorageAlbum.WithContext(ctx),
ScaStorageConfig: q.ScaStorageConfig.WithContext(ctx),
ScaStorageInfo: q.ScaStorageInfo.WithContext(ctx),
ScaStorageLocation: q.ScaStorageLocation.WithContext(ctx),
ScaStorageTag: q.ScaStorageTag.WithContext(ctx),
ScaStorageTagInfo: q.ScaStorageTagInfo.WithContext(ctx),
ScaUserFollow: q.ScaUserFollow.WithContext(ctx),

View File

@@ -40,16 +40,15 @@ func newScaStorageInfo(db *gorm.DB, opts ...gen.DOOption) scaStorageInfo {
_scaStorageInfo.Category = field.NewString(tableName, "category")
_scaStorageInfo.Tags = field.NewString(tableName, "tags")
_scaStorageInfo.Type = field.NewString(tableName, "type")
_scaStorageInfo.Location = field.NewString(tableName, "location")
_scaStorageInfo.LocationID = field.NewInt64(tableName, "location_id")
_scaStorageInfo.Hash = field.NewString(tableName, "hash")
_scaStorageInfo.Anime = field.NewString(tableName, "anime")
_scaStorageInfo.FaceID = field.NewInt64(tableName, "face_id")
_scaStorageInfo.Landscape = field.NewString(tableName, "landscape")
_scaStorageInfo.OriginalTime = field.NewString(tableName, "original_time")
_scaStorageInfo.Gps = field.NewString(tableName, "gps")
_scaStorageInfo.Screenshot = field.NewString(tableName, "screenshot")
_scaStorageInfo.Exif = field.NewString(tableName, "exif")
_scaStorageInfo.Show = field.NewString(tableName, "show")
_scaStorageInfo.ImgShow = field.NewInt64(tableName, "img_show")
_scaStorageInfo.AlbumID = field.NewInt64(tableName, "album_id")
_scaStorageInfo.CreatedAt = field.NewTime(tableName, "created_at")
_scaStorageInfo.UpdatedAt = field.NewTime(tableName, "updated_at")
@@ -77,16 +76,15 @@ type scaStorageInfo struct {
Category field.String // 分类
Tags field.String // 标签
Type field.String // 类型
Location field.String // 地址
LocationID field.Int64 // 地址ID
Hash field.String // 哈希值
Anime field.String // 是否是动漫图片
FaceID field.Int64 // 人像ID
Landscape field.String // 风景类型
OriginalTime field.String // 拍摄时间
Gps field.String // GPS
Screenshot field.String // 是否是截图
Exif field.String // exif 信息
Show field.String // 是否隐藏0 不隐藏 1 隐藏)
ImgShow field.Int64 // 是否隐藏0 不隐藏 1 隐藏)
AlbumID field.Int64 // 相册ID
CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间
@@ -120,16 +118,15 @@ func (s *scaStorageInfo) updateTableName(table string) *scaStorageInfo {
s.Category = field.NewString(table, "category")
s.Tags = field.NewString(table, "tags")
s.Type = field.NewString(table, "type")
s.Location = field.NewString(table, "location")
s.LocationID = field.NewInt64(table, "location_id")
s.Hash = field.NewString(table, "hash")
s.Anime = field.NewString(table, "anime")
s.FaceID = field.NewInt64(table, "face_id")
s.Landscape = field.NewString(table, "landscape")
s.OriginalTime = field.NewString(table, "original_time")
s.Gps = field.NewString(table, "gps")
s.Screenshot = field.NewString(table, "screenshot")
s.Exif = field.NewString(table, "exif")
s.Show = field.NewString(table, "show")
s.ImgShow = field.NewInt64(table, "img_show")
s.AlbumID = field.NewInt64(table, "album_id")
s.CreatedAt = field.NewTime(table, "created_at")
s.UpdatedAt = field.NewTime(table, "updated_at")
@@ -150,7 +147,7 @@ func (s *scaStorageInfo) GetFieldByName(fieldName string) (field.OrderExpr, bool
}
func (s *scaStorageInfo) fillFieldMap() {
s.fieldMap = make(map[string]field.Expr, 27)
s.fieldMap = make(map[string]field.Expr, 26)
s.fieldMap["id"] = s.ID
s.fieldMap["user_id"] = s.UserID
s.fieldMap["provider"] = s.Provider
@@ -164,16 +161,15 @@ func (s *scaStorageInfo) fillFieldMap() {
s.fieldMap["category"] = s.Category
s.fieldMap["tags"] = s.Tags
s.fieldMap["type"] = s.Type
s.fieldMap["location"] = s.Location
s.fieldMap["location_id"] = s.LocationID
s.fieldMap["hash"] = s.Hash
s.fieldMap["anime"] = s.Anime
s.fieldMap["face_id"] = s.FaceID
s.fieldMap["landscape"] = s.Landscape
s.fieldMap["original_time"] = s.OriginalTime
s.fieldMap["gps"] = s.Gps
s.fieldMap["screenshot"] = s.Screenshot
s.fieldMap["exif"] = s.Exif
s.fieldMap["show"] = s.Show
s.fieldMap["img_show"] = s.ImgShow
s.fieldMap["album_id"] = s.AlbumID
s.fieldMap["created_at"] = s.CreatedAt
s.fieldMap["updated_at"] = s.UpdatedAt

View File

@@ -0,0 +1,424 @@
// 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 newScaStorageLocation(db *gorm.DB, opts ...gen.DOOption) scaStorageLocation {
_scaStorageLocation := scaStorageLocation{}
_scaStorageLocation.scaStorageLocationDo.UseDB(db, opts...)
_scaStorageLocation.scaStorageLocationDo.UseModel(&model.ScaStorageLocation{})
tableName := _scaStorageLocation.scaStorageLocationDo.TableName()
_scaStorageLocation.ALL = field.NewAsterisk(tableName)
_scaStorageLocation.ID = field.NewInt64(tableName, "id")
_scaStorageLocation.UserID = field.NewString(tableName, "user_id")
_scaStorageLocation.Country = field.NewString(tableName, "country")
_scaStorageLocation.Province = field.NewString(tableName, "province")
_scaStorageLocation.City = field.NewString(tableName, "city")
_scaStorageLocation.Latitude = field.NewString(tableName, "latitude")
_scaStorageLocation.Longitude = field.NewString(tableName, "longitude")
_scaStorageLocation.Total = field.NewInt64(tableName, "total")
_scaStorageLocation.Version = field.NewField(tableName, "version")
_scaStorageLocation.CreatedAt = field.NewTime(tableName, "created_at")
_scaStorageLocation.UpdatedAt = field.NewTime(tableName, "updated_at")
_scaStorageLocation.DeletedAt = field.NewField(tableName, "deleted_at")
_scaStorageLocation.fillFieldMap()
return _scaStorageLocation
}
type scaStorageLocation struct {
scaStorageLocationDo
ALL field.Asterisk
ID field.Int64 // 主键
UserID field.String // 用户id
Country field.String // 国家
Province field.String // 省
City field.String // 城市
Latitude field.String // 纬度
Longitude field.String // 经度
Total field.Int64 // 数量
Version field.Field // 版本
CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间
DeletedAt field.Field // 删除时间
fieldMap map[string]field.Expr
}
func (s scaStorageLocation) Table(newTableName string) *scaStorageLocation {
s.scaStorageLocationDo.UseTable(newTableName)
return s.updateTableName(newTableName)
}
func (s scaStorageLocation) As(alias string) *scaStorageLocation {
s.scaStorageLocationDo.DO = *(s.scaStorageLocationDo.As(alias).(*gen.DO))
return s.updateTableName(alias)
}
func (s *scaStorageLocation) updateTableName(table string) *scaStorageLocation {
s.ALL = field.NewAsterisk(table)
s.ID = field.NewInt64(table, "id")
s.UserID = field.NewString(table, "user_id")
s.Country = field.NewString(table, "country")
s.Province = field.NewString(table, "province")
s.City = field.NewString(table, "city")
s.Latitude = field.NewString(table, "latitude")
s.Longitude = field.NewString(table, "longitude")
s.Total = field.NewInt64(table, "total")
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 *scaStorageLocation) 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 *scaStorageLocation) fillFieldMap() {
s.fieldMap = make(map[string]field.Expr, 12)
s.fieldMap["id"] = s.ID
s.fieldMap["user_id"] = s.UserID
s.fieldMap["country"] = s.Country
s.fieldMap["province"] = s.Province
s.fieldMap["city"] = s.City
s.fieldMap["latitude"] = s.Latitude
s.fieldMap["longitude"] = s.Longitude
s.fieldMap["total"] = s.Total
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 scaStorageLocation) clone(db *gorm.DB) scaStorageLocation {
s.scaStorageLocationDo.ReplaceConnPool(db.Statement.ConnPool)
return s
}
func (s scaStorageLocation) replaceDB(db *gorm.DB) scaStorageLocation {
s.scaStorageLocationDo.ReplaceDB(db)
return s
}
type scaStorageLocationDo struct{ gen.DO }
type IScaStorageLocationDo interface {
gen.SubQuery
Debug() IScaStorageLocationDo
WithContext(ctx context.Context) IScaStorageLocationDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IScaStorageLocationDo
WriteDB() IScaStorageLocationDo
As(alias string) gen.Dao
Session(config *gorm.Session) IScaStorageLocationDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IScaStorageLocationDo
Not(conds ...gen.Condition) IScaStorageLocationDo
Or(conds ...gen.Condition) IScaStorageLocationDo
Select(conds ...field.Expr) IScaStorageLocationDo
Where(conds ...gen.Condition) IScaStorageLocationDo
Order(conds ...field.Expr) IScaStorageLocationDo
Distinct(cols ...field.Expr) IScaStorageLocationDo
Omit(cols ...field.Expr) IScaStorageLocationDo
Join(table schema.Tabler, on ...field.Expr) IScaStorageLocationDo
LeftJoin(table schema.Tabler, on ...field.Expr) IScaStorageLocationDo
RightJoin(table schema.Tabler, on ...field.Expr) IScaStorageLocationDo
Group(cols ...field.Expr) IScaStorageLocationDo
Having(conds ...gen.Condition) IScaStorageLocationDo
Limit(limit int) IScaStorageLocationDo
Offset(offset int) IScaStorageLocationDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IScaStorageLocationDo
Unscoped() IScaStorageLocationDo
Create(values ...*model.ScaStorageLocation) error
CreateInBatches(values []*model.ScaStorageLocation, batchSize int) error
Save(values ...*model.ScaStorageLocation) error
First() (*model.ScaStorageLocation, error)
Take() (*model.ScaStorageLocation, error)
Last() (*model.ScaStorageLocation, error)
Find() ([]*model.ScaStorageLocation, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ScaStorageLocation, err error)
FindInBatches(result *[]*model.ScaStorageLocation, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.ScaStorageLocation) (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) IScaStorageLocationDo
Assign(attrs ...field.AssignExpr) IScaStorageLocationDo
Joins(fields ...field.RelationField) IScaStorageLocationDo
Preload(fields ...field.RelationField) IScaStorageLocationDo
FirstOrInit() (*model.ScaStorageLocation, error)
FirstOrCreate() (*model.ScaStorageLocation, error)
FindByPage(offset int, limit int) (result []*model.ScaStorageLocation, 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) IScaStorageLocationDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (s scaStorageLocationDo) Debug() IScaStorageLocationDo {
return s.withDO(s.DO.Debug())
}
func (s scaStorageLocationDo) WithContext(ctx context.Context) IScaStorageLocationDo {
return s.withDO(s.DO.WithContext(ctx))
}
func (s scaStorageLocationDo) ReadDB() IScaStorageLocationDo {
return s.Clauses(dbresolver.Read)
}
func (s scaStorageLocationDo) WriteDB() IScaStorageLocationDo {
return s.Clauses(dbresolver.Write)
}
func (s scaStorageLocationDo) Session(config *gorm.Session) IScaStorageLocationDo {
return s.withDO(s.DO.Session(config))
}
func (s scaStorageLocationDo) Clauses(conds ...clause.Expression) IScaStorageLocationDo {
return s.withDO(s.DO.Clauses(conds...))
}
func (s scaStorageLocationDo) Returning(value interface{}, columns ...string) IScaStorageLocationDo {
return s.withDO(s.DO.Returning(value, columns...))
}
func (s scaStorageLocationDo) Not(conds ...gen.Condition) IScaStorageLocationDo {
return s.withDO(s.DO.Not(conds...))
}
func (s scaStorageLocationDo) Or(conds ...gen.Condition) IScaStorageLocationDo {
return s.withDO(s.DO.Or(conds...))
}
func (s scaStorageLocationDo) Select(conds ...field.Expr) IScaStorageLocationDo {
return s.withDO(s.DO.Select(conds...))
}
func (s scaStorageLocationDo) Where(conds ...gen.Condition) IScaStorageLocationDo {
return s.withDO(s.DO.Where(conds...))
}
func (s scaStorageLocationDo) Order(conds ...field.Expr) IScaStorageLocationDo {
return s.withDO(s.DO.Order(conds...))
}
func (s scaStorageLocationDo) Distinct(cols ...field.Expr) IScaStorageLocationDo {
return s.withDO(s.DO.Distinct(cols...))
}
func (s scaStorageLocationDo) Omit(cols ...field.Expr) IScaStorageLocationDo {
return s.withDO(s.DO.Omit(cols...))
}
func (s scaStorageLocationDo) Join(table schema.Tabler, on ...field.Expr) IScaStorageLocationDo {
return s.withDO(s.DO.Join(table, on...))
}
func (s scaStorageLocationDo) LeftJoin(table schema.Tabler, on ...field.Expr) IScaStorageLocationDo {
return s.withDO(s.DO.LeftJoin(table, on...))
}
func (s scaStorageLocationDo) RightJoin(table schema.Tabler, on ...field.Expr) IScaStorageLocationDo {
return s.withDO(s.DO.RightJoin(table, on...))
}
func (s scaStorageLocationDo) Group(cols ...field.Expr) IScaStorageLocationDo {
return s.withDO(s.DO.Group(cols...))
}
func (s scaStorageLocationDo) Having(conds ...gen.Condition) IScaStorageLocationDo {
return s.withDO(s.DO.Having(conds...))
}
func (s scaStorageLocationDo) Limit(limit int) IScaStorageLocationDo {
return s.withDO(s.DO.Limit(limit))
}
func (s scaStorageLocationDo) Offset(offset int) IScaStorageLocationDo {
return s.withDO(s.DO.Offset(offset))
}
func (s scaStorageLocationDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IScaStorageLocationDo {
return s.withDO(s.DO.Scopes(funcs...))
}
func (s scaStorageLocationDo) Unscoped() IScaStorageLocationDo {
return s.withDO(s.DO.Unscoped())
}
func (s scaStorageLocationDo) Create(values ...*model.ScaStorageLocation) error {
if len(values) == 0 {
return nil
}
return s.DO.Create(values)
}
func (s scaStorageLocationDo) CreateInBatches(values []*model.ScaStorageLocation, 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 scaStorageLocationDo) Save(values ...*model.ScaStorageLocation) error {
if len(values) == 0 {
return nil
}
return s.DO.Save(values)
}
func (s scaStorageLocationDo) First() (*model.ScaStorageLocation, error) {
if result, err := s.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageLocation), nil
}
}
func (s scaStorageLocationDo) Take() (*model.ScaStorageLocation, error) {
if result, err := s.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageLocation), nil
}
}
func (s scaStorageLocationDo) Last() (*model.ScaStorageLocation, error) {
if result, err := s.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageLocation), nil
}
}
func (s scaStorageLocationDo) Find() ([]*model.ScaStorageLocation, error) {
result, err := s.DO.Find()
return result.([]*model.ScaStorageLocation), err
}
func (s scaStorageLocationDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ScaStorageLocation, err error) {
buf := make([]*model.ScaStorageLocation, 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 scaStorageLocationDo) FindInBatches(result *[]*model.ScaStorageLocation, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return s.DO.FindInBatches(result, batchSize, fc)
}
func (s scaStorageLocationDo) Attrs(attrs ...field.AssignExpr) IScaStorageLocationDo {
return s.withDO(s.DO.Attrs(attrs...))
}
func (s scaStorageLocationDo) Assign(attrs ...field.AssignExpr) IScaStorageLocationDo {
return s.withDO(s.DO.Assign(attrs...))
}
func (s scaStorageLocationDo) Joins(fields ...field.RelationField) IScaStorageLocationDo {
for _, _f := range fields {
s = *s.withDO(s.DO.Joins(_f))
}
return &s
}
func (s scaStorageLocationDo) Preload(fields ...field.RelationField) IScaStorageLocationDo {
for _, _f := range fields {
s = *s.withDO(s.DO.Preload(_f))
}
return &s
}
func (s scaStorageLocationDo) FirstOrInit() (*model.ScaStorageLocation, error) {
if result, err := s.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageLocation), nil
}
}
func (s scaStorageLocationDo) FirstOrCreate() (*model.ScaStorageLocation, error) {
if result, err := s.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.ScaStorageLocation), nil
}
}
func (s scaStorageLocationDo) FindByPage(offset int, limit int) (result []*model.ScaStorageLocation, 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 scaStorageLocationDo) 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 scaStorageLocationDo) Scan(result interface{}) (err error) {
return s.DO.Scan(result)
}
func (s scaStorageLocationDo) Delete(models ...*model.ScaStorageLocation) (result gen.ResultInfo, err error) {
return s.DO.Delete(models)
}
func (s *scaStorageLocationDo) withDO(do gen.Dao) *scaStorageLocationDo {
s.DO = *do.(*gen.DO)
return s
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long