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

@@ -19,7 +19,7 @@ type ScaStorageFace struct {
FaceName string `gorm:"column:face_name;type:varchar(255);comment:人脸名称" json:"face_name"` // 人脸名称
FaceVector string `gorm:"column:face_vector;type:json;comment:人脸特征向量" json:"face_vector"` // 人脸特征向量
FaceImagePath string `gorm:"column:face_image_path;type:varchar(255);comment:人脸图像路径" json:"face_image_path"` // 人脸图像路径
FaceType int64 `gorm:"column:face_type;type:int(10);comment:人脸类型标识" json:"face_type"` // 人脸类型标识
FaceShow int64 `gorm:"column:face_show;type:int(10);comment:人脸是否展示" json:"face_show"` // 人脸是否展示
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

@@ -32,7 +32,7 @@ func newScaStorageFace(db *gorm.DB, opts ...gen.DOOption) scaStorageFace {
_scaStorageFace.FaceName = field.NewString(tableName, "face_name")
_scaStorageFace.FaceVector = field.NewString(tableName, "face_vector")
_scaStorageFace.FaceImagePath = field.NewString(tableName, "face_image_path")
_scaStorageFace.FaceType = field.NewInt64(tableName, "face_type")
_scaStorageFace.FaceShow = field.NewInt64(tableName, "face_show")
_scaStorageFace.CreatedAt = field.NewTime(tableName, "created_at")
_scaStorageFace.UpdatedAt = field.NewTime(tableName, "updated_at")
_scaStorageFace.DeletedAt = field.NewField(tableName, "deleted_at")
@@ -52,7 +52,7 @@ type scaStorageFace struct {
FaceName field.String // 人脸名称
FaceVector field.String // 人脸特征向量
FaceImagePath field.String // 人脸图像路径
FaceType field.Int64 // 人脸类型标识
FaceShow field.Int64 // 人脸是否展示
CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间
DeletedAt field.Field // 删除时间
@@ -77,7 +77,7 @@ func (s *scaStorageFace) updateTableName(table string) *scaStorageFace {
s.FaceName = field.NewString(table, "face_name")
s.FaceVector = field.NewString(table, "face_vector")
s.FaceImagePath = field.NewString(table, "face_image_path")
s.FaceType = field.NewInt64(table, "face_type")
s.FaceShow = field.NewInt64(table, "face_show")
s.CreatedAt = field.NewTime(table, "created_at")
s.UpdatedAt = field.NewTime(table, "updated_at")
s.DeletedAt = field.NewField(table, "deleted_at")
@@ -103,7 +103,7 @@ func (s *scaStorageFace) fillFieldMap() {
s.fieldMap["face_name"] = s.FaceName
s.fieldMap["face_vector"] = s.FaceVector
s.fieldMap["face_image_path"] = s.FaceImagePath
s.fieldMap["face_type"] = s.FaceType
s.fieldMap["face_show"] = s.FaceShow
s.fieldMap["created_at"] = s.CreatedAt
s.fieldMap["updated_at"] = s.UpdatedAt
s.fieldMap["deleted_at"] = s.DeletedAt

View File

@@ -197,6 +197,8 @@ func (l *FaceRecognitionLogic) loadExistingFaces(userId string) ([]face.Descript
const (
minFaceWidth = 50 // 最小允许的人脸宽度
minFaceHeight = 50 // 最小允许的人脸高度
FaceShow = 0 // 人脸展示状态
FaceHide = 1
)
// 判断人脸是否有效
@@ -216,6 +218,7 @@ func (l *FaceRecognitionLogic) saveFaceToDatabase(userId string, descriptor face
FaceVector: string(jsonBytes),
FaceImagePath: faceImagePath,
UserID: userId,
FaceShow: FaceShow,
}
err = l.svcCtx.DB.ScaStorageFace.Create(&storageFace)
if err != nil {

View File

@@ -28,7 +28,7 @@ func NewModifyFaceTypeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Mo
func (l *ModifyFaceTypeLogic) ModifyFaceType(in *pb.ModifyFaceTypeRequest) (*pb.ModifyFaceTypeResponse, error) {
storageFace := l.svcCtx.DB.ScaStorageFace
faceIds := in.GetFaceId()
info, err := storageFace.Where(storageFace.ID.In(faceIds...), storageFace.UserID.Eq(in.GetUserId())).Update(storageFace.FaceType, in.GetType())
info, err := storageFace.Where(storageFace.ID.In(faceIds...), storageFace.UserID.Eq(in.GetUserId())).Update(storageFace.FaceShow, in.GetType())
if err != nil {
return nil, err
}

View File

@@ -51,7 +51,7 @@ func (l *QueryFaceLibraryLogic) QueryFaceLibrary(in *pb.QueryFaceLibraryRequest)
storageFace.FaceVector,
storageFace.FaceImagePath,
storageFace.FaceName).
Where(storageFace.UserID.Eq(in.GetUserId()), storageFace.FaceType.Eq(in.GetType())).
Where(storageFace.UserID.Eq(in.GetUserId()), storageFace.FaceShow.Eq(in.GetType())).
Find()
if err != nil {
return nil, fmt.Errorf("failed to query face library: %v", err)

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

View File

@@ -23,4 +23,5 @@ const (
const (
ImageListPrefix = "image:list:"
ImageListMetaPrefix = "image:meta:"
ImageRecentPrefix = "image:recent:"
)

172
common/geo_json/geo_json.go Normal file
View File

@@ -0,0 +1,172 @@
package geo_json
import (
"fmt"
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
"github.com/paulmach/orb/planar"
"os"
"path/filepath"
"sync"
)
// RegionType 定义一个类型,用来标识区域是国家、省份还是城市
type RegionType string
const (
Country RegionType = "country"
Province RegionType = "province"
City RegionType = "city"
)
// CityRegion 结构体,包含几何数据和城市名称
type CityRegion struct {
Geometry orb.Geometry
Name string
Bounds orb.Bound // 缓存边界
RegionType RegionType
}
// RegionData 结构体,包含国家、省份和城市的数据
type RegionData struct {
Countries []CityRegion
Provinces []CityRegion
Cities []CityRegion
}
// LoadGeoJSONFileData 加载三个GeoJSON文件并返回RegionData
func LoadGeoJSONFileData(countryFile, provinceFile, cityFile string) (*RegionData, error) {
// 创建RegionData实例来存储国家、省份、城市数据
regionData := &RegionData{}
// 加载国家数据
countries, err := loadGeoJSONData(countryFile, Country)
if err != nil {
return nil, fmt.Errorf("failed to load countries from %s: %v", countryFile, err)
}
regionData.Countries = countries
// 加载省份数据
provinces, err := loadGeoJSONData(provinceFile, Province)
if err != nil {
return nil, fmt.Errorf("failed to load provinces from %s: %v", provinceFile, err)
}
regionData.Provinces = provinces
// 加载城市数据
cities, err := loadGeoJSONData(cityFile, City)
if err != nil {
return nil, fmt.Errorf("failed to load cities from %s: %v", cityFile, err)
}
regionData.Cities = cities
return regionData, nil
}
// loadGeoJSONData 读取GeoJSON文件并根据给定的区域类型返回CityRegion数据
func loadGeoJSONData(filename string, regionType RegionType) ([]CityRegion, error) {
file, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("failed to read %s: %v", filename, err)
}
var cityRegions []CityRegion
fc, err := geojson.UnmarshalFeatureCollection(file)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal %s: %v", filename, err)
}
for _, feature := range fc.Features {
if feature.Geometry != nil {
// 将区域名称和几何数据一起保存,附加区域类型
cityRegions = append(cityRegions, CityRegion{
Geometry: feature.Geometry,
Name: feature.Properties["name"].(string),
RegionType: regionType,
})
} else {
return nil, fmt.Errorf("feature has no geometry %v", feature.ID)
}
}
return cityRegions, nil
}
// GetCityName 根据经纬度和给定的CityRegion判断城市
func getCityName(lat, lon float64, cityRegions []CityRegion) (string, error) {
point := orb.Point{lon, lat}
// 遍历城市区域
for _, region := range cityRegions {
switch geo := region.Geometry.(type) {
case orb.Polygon:
// 如果是Polygon检查点是否在多边形内
if planar.PolygonContains(geo, point) {
return region.Name, nil
}
case orb.MultiPolygon:
// 如果是MultiPolygon检查点是否在任何一个多边形内
if planar.MultiPolygonContains(geo, point) {
return region.Name, nil
}
default:
return "", fmt.Errorf("unsupported geometry type: %v", geo.GeoJSONType())
}
}
return "", fmt.Errorf("point not found in any city region")
}
// GetAddress 根据经纬度识别国家、省份和市
func GetAddress(lat, lon float64, regionData *RegionData) (string, string, string, error) {
// Step 1: 识别国家
country, err := getCityName(lat, lon, regionData.Countries)
if err != nil {
return "", "", "", fmt.Errorf("failed to identify country: %v", err)
}
if country != "中国" {
return country, "", "", nil
}
var wg sync.WaitGroup
var province, city string
var provinceErr, cityErr error
wg.Add(2)
go func() {
defer wg.Done()
province, provinceErr = getCityName(lat, lon, regionData.Provinces)
}()
go func() {
defer wg.Done()
city, cityErr = getCityName(lat, lon, regionData.Cities)
}()
wg.Wait()
if provinceErr != nil {
return country, "", "", fmt.Errorf("failed to identify province: %v", provinceErr)
}
if cityErr != nil {
return country, province, "", fmt.Errorf("failed to identify city: %v", cityErr)
}
return country, province, city, nil
}
func NewGeoJSON() *RegionData {
dir, err := os.Getwd()
if err != nil {
panic(err)
return nil
}
countryFile := filepath.Join(dir, "/resources/geo_json/world.zh.json")
provinceFile := filepath.Join(dir, "/resources/geo_json/china_province.json")
cityFile := filepath.Join(dir, "/resources/geo_json/china_city.json")
regionData, err := LoadGeoJSONFileData(countryFile, provinceFile, cityFile)
if err != nil {
panic(err)
return nil
}
return regionData
}

View File

@@ -0,0 +1,35 @@
package geo_json
import (
"fmt"
"testing"
)
func TestGen(t *testing.T) {
// 假设我们要查询的经纬度为乌鲁木齐
//lat := 43.792818
//lon := 87.617733
lat := 28.19409
lon := 112.982279
// 初始化时加载GeoJSON数据文件
cityRegions, err := LoadGeoJSONFileData(
"E:\\Go_WorkSpace\\schisandra-album-cloud-microservices\\app\\auth\\resources\\geo_json\\world.zh.json",
"E:\\Go_WorkSpace\\schisandra-album-cloud-microservices\\app\\auth\\resources\\geo_json\\china_province.json",
"E:\\Go_WorkSpace\\schisandra-album-cloud-microservices\\app\\auth\\resources\\geo_json\\china_city.json",
)
if err != nil {
fmt.Println("Error reading GeoJSON:", err)
return
}
// 获取城市名称
address, s, s2, err := GetAddress(lat, lon, cityRegions)
if err != nil {
fmt.Println("Error finding city:", err)
}
fmt.Println("Address:", address)
fmt.Println("Province:", s)
fmt.Println("City:", s2)
}

4
go.mod
View File

@@ -122,6 +122,7 @@ require (
github.com/openzipkin/zipkin-go v0.4.3 // indirect
github.com/orcaman/concurrent-map/v2 v2.0.1 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/paulmach/orb v0.11.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg6/go-requests v0.2.3 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
@@ -134,10 +135,13 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/tidwall/geoindex v1.7.0 // indirect
github.com/tidwall/rtree v1.10.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.etcd.io/etcd/api/v3 v3.5.18 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.18 // indirect
go.etcd.io/etcd/client/v3 v3.5.18 // indirect
go.mongodb.org/mongo-driver v1.17.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.34.0 // indirect
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect

33
go.sum
View File

@@ -144,11 +144,14 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -208,13 +211,17 @@ github.com/karlseguin/ccache/v3 v3.0.6 h1:6wC04CXSdptebuSUBgsQixNrrRMUdimtwmjlJU
github.com/karlseguin/ccache/v3 v3.0.6/go.mod h1:b0qfdUOHl4vJgKFQN41paXIdBb3acAtyX2uWrBAZs1w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
@@ -252,6 +259,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
github.com/mozillazg/go-httpheader v0.4.0 h1:aBn6aRXtFzyDLZ4VIRLsZbbJloagQfMnCiYgOq6hK4w=
@@ -276,6 +284,9 @@ github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/
github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
@@ -325,6 +336,7 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -336,16 +348,27 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
github.com/tencentyun/cos-go-sdk-v5 v0.7.60 h1:/e/tmvRmfKexr/QQIBzWhOkZWsmY3EK72NrI6G/Tv0o=
github.com/tencentyun/cos-go-sdk-v5 v0.7.60/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0=
github.com/tidwall/cities v0.1.0/go.mod h1:lV/HDp2gCcRcHJWqgt6Di54GiDrTZwh1aG2ZUPNbqa4=
github.com/tidwall/geoindex v1.7.0 h1:jtk41sfgwIt8MEDyC3xyKSj75iXXf6rjReJGDNPtR5o=
github.com/tidwall/geoindex v1.7.0/go.mod h1:rvVVNEFfkJVWGUdEfU8QaoOg/9zFX0h9ofWzA60mz1I=
github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/rtree v1.10.0 h1:+EcI8fboEaW1L3/9oW/6AMoQ8HiEIHyR7bQOGnmz4Mg=
github.com/tidwall/rtree v1.10.0/go.mod h1:iDJQ9NBRtbfKkzZu02za+mIlaP+bjYPnunbSNidpbCQ=
github.com/wenlng/go-captcha-assets v1.0.1 h1:AdjRFMKmadPRWRTv0XEYfjDvcaayZ2yExITDvlK/7bk=
github.com/wenlng/go-captcha-assets v1.0.1/go.mod h1:yQqc7rRbxgLCg+tWtVp+7Y317D1wIZDan/yIwt8wSac=
github.com/wenlng/go-captcha/v2 v2.0.2 h1:8twz6pI6xZwPvEGFezoFX395oFso1MuOlJt/tLiv7pk=
github.com/wenlng/go-captcha/v2 v2.0.2/go.mod h1:5hac1em3uXoyC5ipZ0xFv9umNM/waQvYAQdr0cx/h34=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yitter/idgenerator-go v1.3.3 h1:i6rzmpbCL0vlmr/tuW5+lSQzNuDG9vYBjIYRvnRcHE8=
github.com/yitter/idgenerator-go v1.3.3/go.mod h1:VVjbqFjGUsIkaXVkXEdmx1LiXUL3K1NvyxWPJBPbBpE=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -362,6 +385,9 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.18 h1:mZPOYw4h8rTk7TeJ5+3udUkfVGBqc+GCjOJYd68
go.etcd.io/etcd/client/pkg/v3 v3.5.18/go.mod h1:BxVf2o5wXG9ZJV+/Cu7QNUiJYk4A29sAhoI5tIRsCu4=
go.etcd.io/etcd/client/v3 v3.5.18 h1:nvvYmNHGumkDjZhTHgVU36A9pykGa2K4lAJ0yY7hcXA=
go.etcd.io/etcd/client/v3 v3.5.18/go.mod h1:kmemwOsPU9broExyhYsBxX4spCTDX3yLgPMWtpBXG6E=
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
@@ -404,6 +430,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
@@ -433,6 +460,7 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
@@ -460,6 +488,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -490,6 +519,7 @@ golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
@@ -523,9 +553,12 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=