✨ develop basic APIs / override reverse geolocation
This commit is contained in:
@@ -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"` // 删除时间
|
||||
|
@@ -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
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
}
|
||||
|
||||
|
@@ -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",
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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"),
|
||||
})
|
||||
|
||||
// 重新存储更新后的图像列表
|
||||
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
||||
|
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
@@ -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"`
|
||||
}
|
||||
|
@@ -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"`
|
||||
|
@@ -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()
|
||||
|
@@ -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"` // 更新时间
|
||||
|
35
app/auth/model/mysql/model/sca_storage_location.gen.go
Normal file
35
app/auth/model/mysql/model/sca_storage_location.gen.go
Normal 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
|
||||
}
|
@@ -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),
|
||||
|
@@ -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
|
||||
|
424
app/auth/model/mysql/query/sca_storage_location.gen.go
Normal file
424
app/auth/model/mysql/query/sca_storage_location.gen.go
Normal 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
|
||||
}
|
1
app/auth/resources/geo_json/china_city.json
Normal file
1
app/auth/resources/geo_json/china_city.json
Normal file
File diff suppressed because one or more lines are too long
1
app/auth/resources/geo_json/china_province.json
Normal file
1
app/auth/resources/geo_json/china_province.json
Normal file
File diff suppressed because one or more lines are too long
242
app/auth/resources/geo_json/world.zh.json
Normal file
242
app/auth/resources/geo_json/world.zh.json
Normal file
File diff suppressed because one or more lines are too long
@@ -23,4 +23,5 @@ const (
|
||||
const (
|
||||
ImageListPrefix = "image:list:"
|
||||
ImageListMetaPrefix = "image:meta:"
|
||||
ImageRecentPrefix = "image:recent:"
|
||||
)
|
||||
|
172
common/geo_json/geo_json.go
Normal file
172
common/geo_json/geo_json.go
Normal 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
|
||||
}
|
35
common/geo_json/geo_test.go
Normal file
35
common/geo_json/geo_test.go
Normal 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
4
go.mod
@@ -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
33
go.sum
@@ -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=
|
||||
|
Reference in New Issue
Block a user