refactor: reorganize modules and add Linux build tooling
This commit is contained in:
41
module/base/cloud/internal/config/config.go
Normal file
41
module/base/cloud/internal/config/config.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"git.apinb.com/bsm-sdk/core/conf"
|
||||
"git.apinb.com/bsm-sdk/core/crypto/encipher"
|
||||
"git.apinb.com/bsm-sdk/core/env"
|
||||
)
|
||||
|
||||
var (
|
||||
Spec SrvConfig
|
||||
)
|
||||
|
||||
type SrvConfig struct {
|
||||
conf.Base `yaml:",inline"`
|
||||
Databases *conf.DBConf `yaml:"Databases"`
|
||||
MicroService *conf.MicroServiceConf `yaml:"MicroService"`
|
||||
Rpc map[string]conf.RpcConf `yaml:"Rpc"`
|
||||
Gateway *conf.GatewayConf `yaml:"Gateway"`
|
||||
Apm *conf.ApmConf `yaml:"APM"`
|
||||
Etcd *conf.EtcdConf `yaml:"Etcd"`
|
||||
}
|
||||
|
||||
func New(srvKey string) {
|
||||
// 初始化配置 创建一个新的配置实例,用于服务配置
|
||||
conf.New(srvKey, &Spec)
|
||||
|
||||
// 配置校验 服务IP,端口; 端口如果不合规,则随机分配端口
|
||||
Spec.Port = conf.CheckPort(Spec.Port)
|
||||
Spec.BindIP = conf.CheckIP(Spec.BindIP)
|
||||
Spec.Addr = net.JoinHostPort(Spec.BindIP, Spec.Port)
|
||||
|
||||
// 配置校验 服务名称地址及监听地址不能为空
|
||||
conf.NotNil(Spec.Service, Spec.Cache)
|
||||
|
||||
// 初始化加密SecretKey
|
||||
encipher.New(env.Runtime.JwtSecretKey)
|
||||
|
||||
conf.PrintInfo(Spec.Addr)
|
||||
}
|
||||
25
module/base/cloud/internal/impl/impl.go
Normal file
25
module/base/cloud/internal/impl/impl.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package impl
|
||||
|
||||
import (
|
||||
"bsm/full/module/base/cloud/internal/config"
|
||||
"git.apinb.com/bsm-sdk/core/cache/redis"
|
||||
"git.apinb.com/bsm-sdk/core/with"
|
||||
cache "github.com/patrickmn/go-cache"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
RedisService *redis.RedisClient
|
||||
EtcdService *clientv3.Client
|
||||
DBService *gorm.DB
|
||||
MemorySerice *cache.Cache
|
||||
)
|
||||
|
||||
func NewImpl() {
|
||||
// with activating
|
||||
MemorySerice = with.Memory(nil)
|
||||
RedisService = with.RedisCache(config.Spec.Cache) // redis cache
|
||||
DBService = with.Databases(config.Spec.Databases, nil) // model
|
||||
EtcdService = with.Etcd(config.Spec.Etcd) // etcd
|
||||
}
|
||||
62
module/base/cloud/internal/logic/album/create_album.go
Normal file
62
module/base/cloud/internal/logic/album/create_album.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 创建相册
|
||||
func CreateAlbum(ctx context.Context, in *pb.CreateAlbumRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// valid code
|
||||
if strings.TrimSpace(in.Name) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.CloudIdentity) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
record := models.CloudAlbum{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
Std_Passport: types.Std_Passport{
|
||||
PassportID: auth.ID,
|
||||
PassportIdentity: auth.Identity,
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: uint(in.CloudId),
|
||||
CloudIdentity: in.CloudIdentity,
|
||||
},
|
||||
Name: in.Name,
|
||||
Description: in.Description,
|
||||
CoverPhoto: in.CoverPhoto,
|
||||
IsPrivate: in.IsPrivate,
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&record).Error; err != nil {
|
||||
printer.Error("Create album error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: record.Identity,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
60
module/base/cloud/internal/logic/album/delete_album.go
Normal file
60
module/base/cloud/internal/logic/album/delete_album.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 删除相册
|
||||
func DeleteAlbum(ctx context.Context, in *pb.IdentRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var album models.CloudAlbum
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&album).Error; err != nil {
|
||||
printer.Error("Album not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 删除相册下的所有照片
|
||||
if err := impl.DBService.Where("album_id = ?", album.ID).Delete(&models.CloudPhoto{}).Error; err != nil {
|
||||
printer.Error("Delete photos error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
// 删除相册
|
||||
if err := impl.DBService.Delete(&album).Error; err != nil {
|
||||
printer.Error("Delete album error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
55
module/base/cloud/internal/logic/album/delete_photo.go
Normal file
55
module/base/cloud/internal/logic/album/delete_photo.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 删除照片
|
||||
func DeletePhoto(ctx context.Context, in *pb.IdentRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var photo models.CloudPhoto
|
||||
query := impl.DBService.Joins("JOIN cloud_albums ON cloud_photos.album_id = cloud_albums.id").
|
||||
Where("cloud_albums.passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("cloud_photos.id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("cloud_photos.identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&photo).Error; err != nil {
|
||||
printer.Error("Photo not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 删除照片
|
||||
if err := impl.DBService.Delete(&photo).Error; err != nil {
|
||||
printer.Error("Delete photo error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
78
module/base/cloud/internal/logic/album/get_album.go
Normal file
78
module/base/cloud/internal/logic/album/get_album.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取相册详情
|
||||
func GetAlbum(ctx context.Context, in *pb.IdentRequest) (reply *pb.CloudAlbumItem, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var album models.CloudAlbum
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.Preload("Photos").First(&album).Error; err != nil {
|
||||
printer.Error("Album not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 转换照片数据
|
||||
var photos []*pb.CloudPhotoItem
|
||||
for _, photo := range album.Photos {
|
||||
photos = append(photos, &pb.CloudPhotoItem{
|
||||
Id: uint64(photo.ID),
|
||||
Identity: photo.Identity,
|
||||
AlbumId: uint64(photo.AlbumID),
|
||||
Title: photo.Title,
|
||||
Description: photo.Description,
|
||||
FilePath: photo.FilePath,
|
||||
FileSize: photo.FileSize,
|
||||
MimeType: photo.MimeType,
|
||||
Width: int32(photo.Width),
|
||||
Height: int32(photo.Height),
|
||||
TakenAt: photo.TakenAt.Format(time.RFC3339),
|
||||
Location: photo.Location,
|
||||
Tags: photo.Tags,
|
||||
CreatedAt: photo.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: photo.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.CloudAlbumItem{
|
||||
Id: uint64(album.ID),
|
||||
Identity: album.Identity,
|
||||
Name: album.Name,
|
||||
Description: album.Description,
|
||||
CoverPhoto: album.CoverPhoto,
|
||||
IsPrivate: album.IsPrivate,
|
||||
CreatedAt: album.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: album.UpdatedAt.Format(time.RFC3339),
|
||||
Photos: photos,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
76
module/base/cloud/internal/logic/album/get_photo.go
Normal file
76
module/base/cloud/internal/logic/album/get_photo.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取照片详情
|
||||
func GetPhoto(ctx context.Context, in *pb.IdentRequest) (reply *pb.CloudPhotoItem, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var photo models.CloudPhoto
|
||||
query := impl.DBService.Joins("JOIN cloud_albums ON cloud_photos.album_id = cloud_albums.id").
|
||||
Where("cloud_albums.passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("cloud_photos.id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("cloud_photos.identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.Preload("Album").First(&photo).Error; err != nil {
|
||||
printer.Error("Photo not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 转换相册数据
|
||||
albumItem := &pb.CloudAlbumItem{
|
||||
Id: uint64(photo.Album.ID),
|
||||
Identity: photo.Album.Identity,
|
||||
Name: photo.Album.Name,
|
||||
Description: photo.Album.Description,
|
||||
CoverPhoto: photo.Album.CoverPhoto,
|
||||
IsPrivate: photo.Album.IsPrivate,
|
||||
CreatedAt: photo.Album.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: photo.Album.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
reply = &pb.CloudPhotoItem{
|
||||
Id: uint64(photo.ID),
|
||||
Identity: photo.Identity,
|
||||
AlbumId: uint64(photo.AlbumID),
|
||||
Title: photo.Title,
|
||||
Description: photo.Description,
|
||||
FilePath: photo.FilePath,
|
||||
FileSize: photo.FileSize,
|
||||
MimeType: photo.MimeType,
|
||||
Width: int32(photo.Width),
|
||||
Height: int32(photo.Height),
|
||||
TakenAt: photo.TakenAt.Format(time.RFC3339),
|
||||
Location: photo.Location,
|
||||
Tags: photo.Tags,
|
||||
CreatedAt: photo.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: photo.UpdatedAt.Format(time.RFC3339),
|
||||
Album: albumItem,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
92
module/base/cloud/internal/logic/album/list_albums.go
Normal file
92
module/base/cloud/internal/logic/album/list_albums.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取相册列表
|
||||
func ListAlbums(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListAlbumsResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var albums []models.CloudAlbum
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
if err := impl.DBService.Model(&models.CloudAlbum{}).Where("passport_id = ?", auth.ID).Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := impl.DBService.Where("passport_id = ?", auth.ID).
|
||||
Preload("Photos").
|
||||
Order("created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&albums).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var albumItems []*pb.CloudAlbumItem
|
||||
for _, album := range albums {
|
||||
var photos []*pb.CloudPhotoItem
|
||||
for _, photo := range album.Photos {
|
||||
photos = append(photos, &pb.CloudPhotoItem{
|
||||
Id: uint64(photo.ID),
|
||||
Identity: photo.Identity,
|
||||
AlbumId: uint64(photo.AlbumID),
|
||||
Title: photo.Title,
|
||||
Description: photo.Description,
|
||||
FilePath: photo.FilePath,
|
||||
FileSize: photo.FileSize,
|
||||
MimeType: photo.MimeType,
|
||||
Width: int32(photo.Width),
|
||||
Height: int32(photo.Height),
|
||||
TakenAt: photo.TakenAt.Format(time.RFC3339),
|
||||
Location: photo.Location,
|
||||
Tags: photo.Tags,
|
||||
CreatedAt: photo.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: photo.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
albumItems = append(albumItems, &pb.CloudAlbumItem{
|
||||
Id: uint64(album.ID),
|
||||
Identity: album.Identity,
|
||||
Name: album.Name,
|
||||
Description: album.Description,
|
||||
CoverPhoto: album.CoverPhoto,
|
||||
IsPrivate: album.IsPrivate,
|
||||
CreatedAt: album.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: album.UpdatedAt.Format(time.RFC3339),
|
||||
Photos: photos,
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListAlbumsResponse{
|
||||
Albums: albumItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
94
module/base/cloud/internal/logic/album/list_photos.go
Normal file
94
module/base/cloud/internal/logic/album/list_photos.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取照片列表
|
||||
func ListPhotos(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListPhotosResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var photos []models.CloudPhoto
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
if err := impl.DBService.Model(&models.CloudPhoto{}).
|
||||
Joins("JOIN cloud_albums ON cloud_photos.album_id = cloud_albums.id").
|
||||
Where("cloud_albums.passport_id = ?", auth.ID).
|
||||
Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := impl.DBService.Joins("JOIN cloud_albums ON cloud_photos.album_id = cloud_albums.id").
|
||||
Where("cloud_albums.passport_id = ?", auth.ID).
|
||||
Preload("Album").
|
||||
Order("cloud_photos.created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&photos).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var photoItems []*pb.CloudPhotoItem
|
||||
for _, photo := range photos {
|
||||
// 转换相册数据
|
||||
albumItem := &pb.CloudAlbumItem{
|
||||
Id: uint64(photo.Album.ID),
|
||||
Identity: photo.Album.Identity,
|
||||
Name: photo.Album.Name,
|
||||
Description: photo.Album.Description,
|
||||
CoverPhoto: photo.Album.CoverPhoto,
|
||||
IsPrivate: photo.Album.IsPrivate,
|
||||
CreatedAt: photo.Album.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: photo.Album.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
photoItems = append(photoItems, &pb.CloudPhotoItem{
|
||||
Id: uint64(photo.ID),
|
||||
Identity: photo.Identity,
|
||||
AlbumId: uint64(photo.AlbumID),
|
||||
Title: photo.Title,
|
||||
Description: photo.Description,
|
||||
FilePath: photo.FilePath,
|
||||
FileSize: photo.FileSize,
|
||||
MimeType: photo.MimeType,
|
||||
Width: int32(photo.Width),
|
||||
Height: int32(photo.Height),
|
||||
TakenAt: photo.TakenAt.Format(time.RFC3339),
|
||||
Location: photo.Location,
|
||||
Tags: photo.Tags,
|
||||
CreatedAt: photo.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: photo.UpdatedAt.Format(time.RFC3339),
|
||||
Album: albumItem,
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListPhotosResponse{
|
||||
Photos: photoItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
60
module/base/cloud/internal/logic/album/move_photo.go
Normal file
60
module/base/cloud/internal/logic/album/move_photo.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 移动照片到其他相册
|
||||
func MovePhoto(ctx context.Context, in *pb.MovePhotoRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.PhotoId == 0 || in.NewAlbumId == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 验证照片是否存在且属于当前用户
|
||||
var photo models.CloudPhoto
|
||||
if err := impl.DBService.Joins("JOIN cloud_albums ON cloud_photos.album_id = cloud_albums.id").
|
||||
Where("cloud_photos.id = ? AND cloud_albums.passport_id = ?", in.PhotoId, auth.ID).
|
||||
First(&photo).Error; err != nil {
|
||||
printer.Error("Photo not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 验证目标相册是否存在且属于当前用户
|
||||
var newAlbum models.CloudAlbum
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.NewAlbumId, auth.ID).First(&newAlbum).Error; err != nil {
|
||||
printer.Error("Target album not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 更新照片的相册ID
|
||||
photo.AlbumID = uint(in.NewAlbumId)
|
||||
photo.CloudID = newAlbum.CloudID
|
||||
photo.CloudIdentity = newAlbum.CloudIdentity
|
||||
|
||||
if err := impl.DBService.Save(&photo).Error; err != nil {
|
||||
printer.Error("Move photo error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
55
module/base/cloud/internal/logic/album/set_cover_photo.go
Normal file
55
module/base/cloud/internal/logic/album/set_cover_photo.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 设置封面照片
|
||||
func SetCoverPhoto(ctx context.Context, in *pb.SetCoverPhotoRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.AlbumId == 0 || in.PhotoId == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 验证相册是否存在且属于当前用户
|
||||
var album models.CloudAlbum
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.AlbumId, auth.ID).First(&album).Error; err != nil {
|
||||
printer.Error("Album not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 验证照片是否存在且属于该相册
|
||||
var photo models.CloudPhoto
|
||||
if err := impl.DBService.Where("id = ? AND album_id = ?", in.PhotoId, in.AlbumId).First(&photo).Error; err != nil {
|
||||
printer.Error("Photo not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 更新相册的封面照片
|
||||
album.CoverPhoto = photo.FilePath
|
||||
if err := impl.DBService.Save(&album).Error; err != nil {
|
||||
printer.Error("Set cover photo error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
63
module/base/cloud/internal/logic/album/update_album.go
Normal file
63
module/base/cloud/internal/logic/album/update_album.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 更新相册
|
||||
func UpdateAlbum(ctx context.Context, in *pb.CloudAlbumItem) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Name) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var album models.CloudAlbum
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&album).Error; err != nil {
|
||||
printer.Error("Album not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
album.Name = in.Name
|
||||
album.Description = in.Description
|
||||
album.CoverPhoto = in.CoverPhoto
|
||||
album.IsPrivate = in.IsPrivate
|
||||
|
||||
if err := impl.DBService.Save(&album).Error; err != nil {
|
||||
printer.Error("Update album error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
67
module/base/cloud/internal/logic/album/update_photo.go
Normal file
67
module/base/cloud/internal/logic/album/update_photo.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 更新照片
|
||||
func UpdatePhoto(ctx context.Context, in *pb.CloudPhotoItem) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var photo models.CloudPhoto
|
||||
query := impl.DBService.Joins("JOIN cloud_albums ON cloud_photos.album_id = cloud_albums.id").
|
||||
Where("cloud_albums.passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("cloud_photos.id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("cloud_photos.identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&photo).Error; err != nil {
|
||||
printer.Error("Photo not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
photo.Title = in.Title
|
||||
photo.Description = in.Description
|
||||
photo.Location = in.Location
|
||||
photo.Tags = in.Tags
|
||||
|
||||
// 更新拍摄时间
|
||||
if in.TakenAt != "" {
|
||||
if t, err := time.Parse(time.RFC3339, in.TakenAt); err == nil {
|
||||
photo.TakenAt = t
|
||||
}
|
||||
}
|
||||
|
||||
if err := impl.DBService.Save(&photo).Error; err != nil {
|
||||
printer.Error("Update photo error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
84
module/base/cloud/internal/logic/album/upload_photo.go
Normal file
84
module/base/cloud/internal/logic/album/upload_photo.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package album
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 上传照片
|
||||
func UploadPhoto(ctx context.Context, in *pb.CloudPhotoItem) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.AlbumId == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.FilePath) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 验证相册是否存在且属于当前用户
|
||||
var album models.CloudAlbum
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.AlbumId, auth.ID).First(&album).Error; err != nil {
|
||||
printer.Error("Album not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 解析拍摄时间
|
||||
var takenAt time.Time
|
||||
if in.TakenAt != "" {
|
||||
if t, err := time.Parse(time.RFC3339, in.TakenAt); err == nil {
|
||||
takenAt = t
|
||||
} else {
|
||||
takenAt = time.Now()
|
||||
}
|
||||
} else {
|
||||
takenAt = time.Now()
|
||||
}
|
||||
|
||||
record := models.CloudPhoto{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: album.CloudID,
|
||||
CloudIdentity: album.CloudIdentity,
|
||||
},
|
||||
AlbumID: uint(in.AlbumId),
|
||||
Title: in.Title,
|
||||
Description: in.Description,
|
||||
FilePath: in.FilePath,
|
||||
FileSize: in.FileSize,
|
||||
MimeType: in.MimeType,
|
||||
Width: int(in.Width),
|
||||
Height: int(in.Height),
|
||||
TakenAt: takenAt,
|
||||
Location: in.Location,
|
||||
Tags: in.Tags,
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&record).Error; err != nil {
|
||||
printer.Error("Create photo error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: record.Identity,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
68
module/base/cloud/internal/logic/bookmark/create_bookmark.go
Normal file
68
module/base/cloud/internal/logic/bookmark/create_bookmark.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package bookmark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 创建书签
|
||||
func CreateBookmark(ctx context.Context, in *pb.CreateBookmarkRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// valid code
|
||||
if strings.TrimSpace(in.Title) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Url) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.CloudIdentity) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
record := models.CloudBookmark{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
Std_Passport: types.Std_Passport{
|
||||
PassportID: auth.ID,
|
||||
PassportIdentity: auth.Identity,
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: uint(in.CloudId),
|
||||
CloudIdentity: in.CloudIdentity,
|
||||
},
|
||||
Title: in.Title,
|
||||
URL: in.Url,
|
||||
Description: in.Description,
|
||||
Category: in.Category,
|
||||
Tags: in.Tags,
|
||||
Icon: in.Icon,
|
||||
IsPrivate: in.IsPrivate,
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&record).Error; err != nil {
|
||||
printer.Error("Create bookmark error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: record.Identity,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
48
module/base/cloud/internal/logic/bookmark/delete_bookmark.go
Normal file
48
module/base/cloud/internal/logic/bookmark/delete_bookmark.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package bookmark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 删除书签
|
||||
func DeleteBookmark(ctx context.Context, in *pb.IDRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id
|
||||
if in.Id == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var bookmark models.CloudBookmark
|
||||
query := impl.DBService.Where("passport_id = ? AND id = ?", auth.ID, in.Id)
|
||||
|
||||
if err := query.First(&bookmark).Error; err != nil {
|
||||
printer.Error("Bookmark not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 删除书签
|
||||
if err := impl.DBService.Delete(&bookmark).Error; err != nil {
|
||||
printer.Error("Delete bookmark error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
52
module/base/cloud/internal/logic/bookmark/get_bookmark.go
Normal file
52
module/base/cloud/internal/logic/bookmark/get_bookmark.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package bookmark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取书签详情
|
||||
func GetBookmark(ctx context.Context, in *pb.IDRequest) (reply *pb.CloudBookmarkItem, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id
|
||||
if in.Id == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var bookmark models.CloudBookmark
|
||||
query := impl.DBService.Where("passport_id = ? AND id = ?", auth.ID, in.Id)
|
||||
|
||||
if err := query.First(&bookmark).Error; err != nil {
|
||||
printer.Error("Bookmark not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
reply = &pb.CloudBookmarkItem{
|
||||
Id: uint64(bookmark.ID),
|
||||
Identity: bookmark.Identity,
|
||||
Title: bookmark.Title,
|
||||
Url: bookmark.URL,
|
||||
Description: bookmark.Description,
|
||||
Category: bookmark.Category,
|
||||
Tags: bookmark.Tags,
|
||||
Icon: bookmark.Icon,
|
||||
IsPrivate: bookmark.IsPrivate,
|
||||
CreatedAt: bookmark.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: bookmark.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package bookmark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 导入书签
|
||||
func ImportBookmarks(ctx context.Context, in *pb.ImportBookmarksRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if strings.TrimSpace(in.Data) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Format) == "" {
|
||||
in.Format = "json"
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 解析JSON数据
|
||||
var bookmarks []map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(in.Data), &bookmarks); err != nil {
|
||||
printer.Error("Parse bookmarks data error: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 批量创建书签
|
||||
var records []models.CloudBookmark
|
||||
for _, item := range bookmarks {
|
||||
title, _ := item["title"].(string)
|
||||
url, _ := item["url"].(string)
|
||||
description, _ := item["description"].(string)
|
||||
category, _ := item["category"].(string)
|
||||
tags, _ := item["tags"].(string)
|
||||
icon, _ := item["icon"].(string)
|
||||
isPrivate, _ := item["is_private"].(bool)
|
||||
|
||||
if title == "" || url == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
record := models.CloudBookmark{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
Std_Passport: types.Std_Passport{
|
||||
PassportID: auth.ID,
|
||||
PassportIdentity: auth.Identity,
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: 1, // 默认云空间ID
|
||||
CloudIdentity: "default",
|
||||
},
|
||||
Title: title,
|
||||
URL: url,
|
||||
Description: description,
|
||||
Category: category,
|
||||
Tags: tags,
|
||||
Icon: icon,
|
||||
IsPrivate: isPrivate,
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
if len(records) > 0 {
|
||||
if err := impl.DBService.CreateInBatches(records, 100).Error; err != nil {
|
||||
printer.Error("Import bookmarks error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
72
module/base/cloud/internal/logic/bookmark/list_bookmarks.go
Normal file
72
module/base/cloud/internal/logic/bookmark/list_bookmarks.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package bookmark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取书签列表
|
||||
func ListBookmarks(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListBookmarksResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var bookmarks []models.CloudBookmark
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
if err := impl.DBService.Model(&models.CloudBookmark{}).Where("passport_id = ?", auth.ID).Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := impl.DBService.Where("passport_id = ?", auth.ID).
|
||||
Order("created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&bookmarks).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var bookmarkItems []*pb.CloudBookmarkItem
|
||||
for _, bookmark := range bookmarks {
|
||||
bookmarkItems = append(bookmarkItems, &pb.CloudBookmarkItem{
|
||||
Id: uint64(bookmark.ID),
|
||||
Identity: bookmark.Identity,
|
||||
Title: bookmark.Title,
|
||||
Url: bookmark.URL,
|
||||
Description: bookmark.Description,
|
||||
Category: bookmark.Category,
|
||||
Tags: bookmark.Tags,
|
||||
Icon: bookmark.Icon,
|
||||
IsPrivate: bookmark.IsPrivate,
|
||||
CreatedAt: bookmark.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: bookmark.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListBookmarksResponse{
|
||||
Bookmarks: bookmarkItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
69
module/base/cloud/internal/logic/bookmark/update_bookmark.go
Normal file
69
module/base/cloud/internal/logic/bookmark/update_bookmark.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package bookmark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 更新书签
|
||||
func UpdateBookmark(ctx context.Context, in *pb.CloudBookmarkItem) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Title) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Url) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var bookmark models.CloudBookmark
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&bookmark).Error; err != nil {
|
||||
printer.Error("Bookmark not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
bookmark.Title = in.Title
|
||||
bookmark.URL = in.Url
|
||||
bookmark.Description = in.Description
|
||||
bookmark.Category = in.Category
|
||||
bookmark.Tags = in.Tags
|
||||
bookmark.Icon = in.Icon
|
||||
bookmark.IsPrivate = in.IsPrivate
|
||||
|
||||
if err := impl.DBService.Save(&bookmark).Error; err != nil {
|
||||
printer.Error("Update bookmark error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
83
module/base/cloud/internal/logic/disk/copy_file.go
Normal file
83
module/base/cloud/internal/logic/disk/copy_file.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 复制文件
|
||||
func CopyFile(ctx context.Context, in *pb.CopyFileRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.NewName) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var file models.CloudDiskFile
|
||||
if err := impl.DBService.Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_files.id = ? AND cloud_disk_dirs.passport_id = ?", in.Id, auth.ID).
|
||||
First(&file).Error; err != nil {
|
||||
printer.Error("File not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查目标目录是否存在且属于当前用户
|
||||
var targetDir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.TargetDirectoryId, auth.ID).First(&targetDir).Error; err != nil {
|
||||
printer.Error("Target directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查目标目录下是否已存在同名文件
|
||||
var existingFile models.CloudDiskFile
|
||||
if err := impl.DBService.Where("name = ? AND directory_id = ?", in.NewName, in.TargetDirectoryId).First(&existingFile).Error; err == nil {
|
||||
return nil, errcode.ErrAlreadyExists
|
||||
}
|
||||
|
||||
// 创建文件副本
|
||||
newFile := models.CloudDiskFile{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: file.CloudID,
|
||||
CloudIdentity: file.CloudIdentity,
|
||||
},
|
||||
DirectoryID: func() *uint { id := uint(in.TargetDirectoryId); return &id }(),
|
||||
Name: in.NewName,
|
||||
OriginalName: in.NewName,
|
||||
Size: file.Size,
|
||||
MimeType: file.MimeType,
|
||||
StoragePath: file.StoragePath, // 注意:实际存储中可能需要复制文件内容
|
||||
Hash: file.Hash,
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&newFile).Error; err != nil {
|
||||
printer.Error("Copy file error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: newFile.Identity,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
85
module/base/cloud/internal/logic/disk/create_dir.go
Normal file
85
module/base/cloud/internal/logic/disk/create_dir.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 创建目录
|
||||
func CreateDir(ctx context.Context, in *pb.CreateDirRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// valid code
|
||||
if strings.TrimSpace(in.Name) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.CloudIdentity) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 构建完整路径
|
||||
var fullPath string
|
||||
if in.ParentId > 0 {
|
||||
var parentDir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.ParentId, auth.ID).First(&parentDir).Error; err != nil {
|
||||
printer.Error("Parent directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
fullPath = filepath.Join(parentDir.Path, in.Name)
|
||||
} else {
|
||||
fullPath = "/" + in.Name
|
||||
}
|
||||
|
||||
// 检查目录是否已存在
|
||||
var existingDir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("path = ? AND passport_id = ?", fullPath, auth.ID).First(&existingDir).Error; err == nil {
|
||||
return nil, errcode.ErrAlreadyExists
|
||||
}
|
||||
|
||||
record := models.CloudDiskDir{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
Std_Passport: types.Std_Passport{
|
||||
PassportID: auth.ID,
|
||||
PassportIdentity: auth.Identity,
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: uint(in.CloudId),
|
||||
CloudIdentity: in.CloudIdentity,
|
||||
},
|
||||
Name: in.Name,
|
||||
Path: fullPath,
|
||||
}
|
||||
|
||||
if in.ParentId > 0 {
|
||||
parentId := uint(in.ParentId)
|
||||
record.ParentID = &parentId
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&record).Error; err != nil {
|
||||
printer.Error("Create directory error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: record.Identity,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
74
module/base/cloud/internal/logic/disk/delete_dir.go
Normal file
74
module/base/cloud/internal/logic/disk/delete_dir.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 删除目录
|
||||
func DeleteDir(ctx context.Context, in *pb.IdentRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var dir models.CloudDiskDir
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&dir).Error; err != nil {
|
||||
printer.Error("Directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查是否有子目录
|
||||
var subdirCount int64
|
||||
if err := impl.DBService.Model(&models.CloudDiskDir{}).Where("parent_id = ?", dir.ID).Count(&subdirCount).Error; err != nil {
|
||||
printer.Error("Check subdirectories error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
if subdirCount > 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查是否有文件
|
||||
var fileCount int64
|
||||
if err := impl.DBService.Model(&models.CloudDiskFile{}).Where("directory_id = ?", dir.ID).Count(&fileCount).Error; err != nil {
|
||||
printer.Error("Check files error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
if fileCount > 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 删除目录
|
||||
if err := impl.DBService.Delete(&dir).Error; err != nil {
|
||||
printer.Error("Delete directory error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
55
module/base/cloud/internal/logic/disk/delete_file.go
Normal file
55
module/base/cloud/internal/logic/disk/delete_file.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 删除文件
|
||||
func DeleteFile(ctx context.Context, in *pb.IdentRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var file models.CloudDiskFile
|
||||
query := impl.DBService.Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("cloud_disk_files.id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("cloud_disk_files.identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&file).Error; err != nil {
|
||||
printer.Error("File not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
if err := impl.DBService.Delete(&file).Error; err != nil {
|
||||
printer.Error("Delete file error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
102
module/base/cloud/internal/logic/disk/get_dir.go
Normal file
102
module/base/cloud/internal/logic/disk/get_dir.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取目录详情
|
||||
func GetDir(ctx context.Context, in *pb.IdentRequest) (reply *pb.CloudDiskDirItem, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var dir models.CloudDiskDir
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.Preload("Parent").Preload("Subdirectories").Preload("Files").First(&dir).Error; err != nil {
|
||||
printer.Error("Directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 转换子目录数据
|
||||
var subdirs []*pb.CloudDiskDirItem
|
||||
for _, subdir := range dir.Subdirectories {
|
||||
subdirs = append(subdirs, &pb.CloudDiskDirItem{
|
||||
Id: uint64(subdir.ID),
|
||||
Identity: subdir.Identity,
|
||||
ParentId: uint64(*subdir.ParentID),
|
||||
Name: subdir.Name,
|
||||
Path: subdir.Path,
|
||||
CreatedAt: subdir.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: subdir.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
// 转换文件数据
|
||||
var files []*pb.CloudDiskFileItem
|
||||
for _, file := range dir.Files {
|
||||
files = append(files, &pb.CloudDiskFileItem{
|
||||
Id: uint64(file.ID),
|
||||
Identity: file.Identity,
|
||||
DirectoryId: uint64(*file.DirectoryID),
|
||||
Name: file.Name,
|
||||
OriginalName: file.OriginalName,
|
||||
Size: file.Size,
|
||||
MimeType: file.MimeType,
|
||||
StoragePath: file.StoragePath,
|
||||
Hash: file.Hash,
|
||||
CreatedAt: file.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: file.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
// 构建父目录信息
|
||||
var parent *pb.CloudDiskDirItem
|
||||
if dir.Parent != nil {
|
||||
parent = &pb.CloudDiskDirItem{
|
||||
Id: uint64(dir.Parent.ID),
|
||||
Identity: dir.Parent.Identity,
|
||||
Name: dir.Parent.Name,
|
||||
Path: dir.Parent.Path,
|
||||
CreatedAt: dir.Parent.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: dir.Parent.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
reply = &pb.CloudDiskDirItem{
|
||||
Id: uint64(dir.ID),
|
||||
Identity: dir.Identity,
|
||||
ParentId: uint64(*dir.ParentID),
|
||||
Name: dir.Name,
|
||||
Path: dir.Path,
|
||||
CreatedAt: dir.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: dir.UpdatedAt.Format(time.RFC3339),
|
||||
Parent: parent,
|
||||
Subdirectories: subdirs,
|
||||
Files: files,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
108
module/base/cloud/internal/logic/disk/get_dir_tree.go
Normal file
108
module/base/cloud/internal/logic/disk/get_dir_tree.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取目录树
|
||||
func GetDirTree(ctx context.Context, in *pb.IdentRequest) (reply *pb.CloudDiskDirItem, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var dir models.CloudDiskDir
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.Preload("Parent").Preload("Subdirectories").Preload("Files").First(&dir).Error; err != nil {
|
||||
printer.Error("Directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 递归加载子目录树
|
||||
var loadSubdirs func(*models.CloudDiskDir) []*pb.CloudDiskDirItem
|
||||
loadSubdirs = func(d *models.CloudDiskDir) []*pb.CloudDiskDirItem {
|
||||
var subdirs []*pb.CloudDiskDirItem
|
||||
for _, subdir := range d.Subdirectories {
|
||||
subdirItem := &pb.CloudDiskDirItem{
|
||||
Id: uint64(subdir.ID),
|
||||
Identity: subdir.Identity,
|
||||
ParentId: uint64(*subdir.ParentID),
|
||||
Name: subdir.Name,
|
||||
Path: subdir.Path,
|
||||
CreatedAt: subdir.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: subdir.UpdatedAt.Format(time.RFC3339),
|
||||
Subdirectories: loadSubdirs(&subdir),
|
||||
}
|
||||
subdirs = append(subdirs, subdirItem)
|
||||
}
|
||||
return subdirs
|
||||
}
|
||||
|
||||
// 转换文件数据
|
||||
var files []*pb.CloudDiskFileItem
|
||||
for _, file := range dir.Files {
|
||||
files = append(files, &pb.CloudDiskFileItem{
|
||||
Id: uint64(file.ID),
|
||||
Identity: file.Identity,
|
||||
DirectoryId: uint64(*file.DirectoryID),
|
||||
Name: file.Name,
|
||||
OriginalName: file.OriginalName,
|
||||
Size: file.Size,
|
||||
MimeType: file.MimeType,
|
||||
StoragePath: file.StoragePath,
|
||||
Hash: file.Hash,
|
||||
CreatedAt: file.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: file.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
// 构建父目录信息
|
||||
var parent *pb.CloudDiskDirItem
|
||||
if dir.Parent != nil {
|
||||
parent = &pb.CloudDiskDirItem{
|
||||
Id: uint64(dir.Parent.ID),
|
||||
Identity: dir.Parent.Identity,
|
||||
Name: dir.Parent.Name,
|
||||
Path: dir.Parent.Path,
|
||||
CreatedAt: dir.Parent.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: dir.Parent.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
reply = &pb.CloudDiskDirItem{
|
||||
Id: uint64(dir.ID),
|
||||
Identity: dir.Identity,
|
||||
ParentId: uint64(*dir.ParentID),
|
||||
Name: dir.Name,
|
||||
Path: dir.Path,
|
||||
CreatedAt: dir.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: dir.UpdatedAt.Format(time.RFC3339),
|
||||
Parent: parent,
|
||||
Subdirectories: loadSubdirs(&dir),
|
||||
Files: files,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
73
module/base/cloud/internal/logic/disk/get_file.go
Normal file
73
module/base/cloud/internal/logic/disk/get_file.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取文件详情
|
||||
func GetFile(ctx context.Context, in *pb.IdentRequest) (reply *pb.CloudDiskFileItem, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var file models.CloudDiskFile
|
||||
query := impl.DBService.Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("cloud_disk_files.id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("cloud_disk_files.identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.Preload("Directory").First(&file).Error; err != nil {
|
||||
printer.Error("File not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 构建目录信息
|
||||
var directory *pb.CloudDiskDirItem
|
||||
if file.Directory != nil {
|
||||
directory = &pb.CloudDiskDirItem{
|
||||
Id: uint64(file.Directory.ID),
|
||||
Identity: file.Directory.Identity,
|
||||
Name: file.Directory.Name,
|
||||
Path: file.Directory.Path,
|
||||
CreatedAt: file.Directory.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: file.Directory.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
reply = &pb.CloudDiskFileItem{
|
||||
Id: uint64(file.ID),
|
||||
Identity: file.Identity,
|
||||
DirectoryId: uint64(*file.DirectoryID),
|
||||
Name: file.Name,
|
||||
OriginalName: file.OriginalName,
|
||||
Size: file.Size,
|
||||
MimeType: file.MimeType,
|
||||
StoragePath: file.StoragePath,
|
||||
Hash: file.Hash,
|
||||
CreatedAt: file.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: file.UpdatedAt.Format(time.RFC3339),
|
||||
Directory: directory,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
87
module/base/cloud/internal/logic/disk/list_dirs.go
Normal file
87
module/base/cloud/internal/logic/disk/list_dirs.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取目录列表
|
||||
func ListDirs(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListDirsResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var dirs []models.CloudDiskDir
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
if err := impl.DBService.Model(&models.CloudDiskDir{}).Where("passport_id = ?", auth.ID).Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := impl.DBService.Where("passport_id = ?", auth.ID).
|
||||
Preload("Parent").
|
||||
Order("created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&dirs).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var dirItems []*pb.CloudDiskDirItem
|
||||
for _, dir := range dirs {
|
||||
var parentId uint64
|
||||
if dir.ParentID != nil {
|
||||
parentId = uint64(*dir.ParentID)
|
||||
}
|
||||
|
||||
var parent *pb.CloudDiskDirItem
|
||||
if dir.Parent != nil {
|
||||
parent = &pb.CloudDiskDirItem{
|
||||
Id: uint64(dir.Parent.ID),
|
||||
Identity: dir.Parent.Identity,
|
||||
Name: dir.Parent.Name,
|
||||
Path: dir.Parent.Path,
|
||||
CreatedAt: dir.Parent.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: dir.Parent.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
dirItems = append(dirItems, &pb.CloudDiskDirItem{
|
||||
Id: uint64(dir.ID),
|
||||
Identity: dir.Identity,
|
||||
ParentId: parentId,
|
||||
Name: dir.Name,
|
||||
Path: dir.Path,
|
||||
CreatedAt: dir.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: dir.UpdatedAt.Format(time.RFC3339),
|
||||
Parent: parent,
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListDirsResponse{
|
||||
Dirs: dirItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
91
module/base/cloud/internal/logic/disk/list_files.go
Normal file
91
module/base/cloud/internal/logic/disk/list_files.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取文件列表
|
||||
func ListFiles(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListFilesResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var files []models.CloudDiskFile
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
if err := impl.DBService.Model(&models.CloudDiskFile{}).
|
||||
Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID).
|
||||
Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := impl.DBService.
|
||||
Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID).
|
||||
Preload("Directory").
|
||||
Order("cloud_disk_files.created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&files).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var fileItems []*pb.CloudDiskFileItem
|
||||
for _, file := range files {
|
||||
var directory *pb.CloudDiskDirItem
|
||||
if file.Directory != nil {
|
||||
directory = &pb.CloudDiskDirItem{
|
||||
Id: uint64(file.Directory.ID),
|
||||
Identity: file.Directory.Identity,
|
||||
Name: file.Directory.Name,
|
||||
Path: file.Directory.Path,
|
||||
CreatedAt: file.Directory.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: file.Directory.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
fileItems = append(fileItems, &pb.CloudDiskFileItem{
|
||||
Id: uint64(file.ID),
|
||||
Identity: file.Identity,
|
||||
DirectoryId: uint64(*file.DirectoryID),
|
||||
Name: file.Name,
|
||||
OriginalName: file.OriginalName,
|
||||
Size: file.Size,
|
||||
MimeType: file.MimeType,
|
||||
StoragePath: file.StoragePath,
|
||||
Hash: file.Hash,
|
||||
CreatedAt: file.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: file.UpdatedAt.Format(time.RFC3339),
|
||||
Directory: directory,
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListFilesResponse{
|
||||
Files: fileItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
108
module/base/cloud/internal/logic/disk/move_dir.go
Normal file
108
module/base/cloud/internal/logic/disk/move_dir.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 移动目录
|
||||
func MoveDir(ctx context.Context, in *pb.MoveDirRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var dir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.Id, auth.ID).First(&dir).Error; err != nil {
|
||||
printer.Error("Directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查目标父目录是否存在
|
||||
if in.NewParentId > 0 {
|
||||
var parentDir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.NewParentId, auth.ID).First(&parentDir).Error; err != nil {
|
||||
printer.Error("Parent directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查是否会形成循环引用
|
||||
if dir.ID == parentDir.ID {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查目标路径是否已存在
|
||||
newPath := filepath.Join(parentDir.Path, dir.Name)
|
||||
var existingDir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("path = ? AND passport_id = ? AND id != ?", newPath, auth.ID, dir.ID).First(&existingDir).Error; err == nil {
|
||||
return nil, errcode.ErrAlreadyExists
|
||||
}
|
||||
|
||||
// 更新目录
|
||||
oldPath := dir.Path
|
||||
newParentId := uint(in.NewParentId)
|
||||
dir.ParentID = &newParentId
|
||||
dir.Path = newPath
|
||||
|
||||
if err := impl.DBService.Save(&dir).Error; err != nil {
|
||||
printer.Error("Move directory error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
// 更新所有子目录的路径
|
||||
var subdirs []models.CloudDiskDir
|
||||
if err := impl.DBService.Where("path LIKE ? AND passport_id = ?", oldPath+"%", auth.ID).Find(&subdirs).Error; err == nil {
|
||||
for _, subdir := range subdirs {
|
||||
newSubPath := strings.Replace(subdir.Path, oldPath, newPath, 1)
|
||||
impl.DBService.Model(&subdir).Update("path", newSubPath)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 移动到根目录
|
||||
oldPath := dir.Path
|
||||
dir.ParentID = nil
|
||||
dir.Path = "/" + dir.Name
|
||||
|
||||
// 检查根目录下是否已存在同名目录
|
||||
var existingDir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("path = ? AND passport_id = ? AND id != ?", dir.Path, auth.ID, dir.ID).First(&existingDir).Error; err == nil {
|
||||
return nil, errcode.ErrAlreadyExists
|
||||
}
|
||||
|
||||
if err := impl.DBService.Save(&dir).Error; err != nil {
|
||||
printer.Error("Move directory error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
// 更新所有子目录的路径
|
||||
var subdirs []models.CloudDiskDir
|
||||
if err := impl.DBService.Where("path LIKE ? AND passport_id = ?", oldPath+"%", auth.ID).Find(&subdirs).Error; err == nil {
|
||||
for _, subdir := range subdirs {
|
||||
newSubPath := strings.Replace(subdir.Path, oldPath, dir.Path, 1)
|
||||
impl.DBService.Model(&subdir).Update("path", newSubPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
64
module/base/cloud/internal/logic/disk/move_file.go
Normal file
64
module/base/cloud/internal/logic/disk/move_file.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 移动文件
|
||||
func MoveFile(ctx context.Context, in *pb.MoveFileRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var file models.CloudDiskFile
|
||||
if err := impl.DBService.Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_files.id = ? AND cloud_disk_dirs.passport_id = ?", in.Id, auth.ID).
|
||||
First(&file).Error; err != nil {
|
||||
printer.Error("File not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查目标目录是否存在且属于当前用户
|
||||
var targetDir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.NewDirectoryId, auth.ID).First(&targetDir).Error; err != nil {
|
||||
printer.Error("Target directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查目标目录下是否已存在同名文件
|
||||
var existingFile models.CloudDiskFile
|
||||
if err := impl.DBService.Where("name = ? AND directory_id = ? AND id != ?", file.Name, in.NewDirectoryId, file.ID).First(&existingFile).Error; err == nil {
|
||||
return nil, errcode.ErrAlreadyExists
|
||||
}
|
||||
|
||||
// 更新文件目录
|
||||
newDirectoryId := uint(in.NewDirectoryId)
|
||||
file.DirectoryID = &newDirectoryId
|
||||
|
||||
if err := impl.DBService.Save(&file).Error; err != nil {
|
||||
printer.Error("Move file error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
98
module/base/cloud/internal/logic/disk/search_files.go
Normal file
98
module/base/cloud/internal/logic/disk/search_files.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 搜索文件
|
||||
func SearchFiles(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListFilesResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var files []models.CloudDiskFile
|
||||
var total int64
|
||||
|
||||
// 构建搜索查询
|
||||
query := impl.DBService.Model(&models.CloudDiskFile{}).
|
||||
Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID)
|
||||
|
||||
// 添加搜索条件
|
||||
if keyword, exists := in.Params["keyword"]; exists && keyword != "" {
|
||||
searchKeyword := "%" + strings.ToLower(keyword) + "%"
|
||||
query = query.Where("LOWER(cloud_disk_files.name) LIKE ? OR LOWER(cloud_disk_files.original_name) LIKE ?", searchKeyword, searchKeyword)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := query.
|
||||
Preload("Directory").
|
||||
Order("cloud_disk_files.created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&files).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var fileItems []*pb.CloudDiskFileItem
|
||||
for _, file := range files {
|
||||
var directory *pb.CloudDiskDirItem
|
||||
if file.Directory != nil {
|
||||
directory = &pb.CloudDiskDirItem{
|
||||
Id: uint64(file.Directory.ID),
|
||||
Identity: file.Directory.Identity,
|
||||
Name: file.Directory.Name,
|
||||
Path: file.Directory.Path,
|
||||
CreatedAt: file.Directory.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: file.Directory.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
fileItems = append(fileItems, &pb.CloudDiskFileItem{
|
||||
Id: uint64(file.ID),
|
||||
Identity: file.Identity,
|
||||
DirectoryId: uint64(*file.DirectoryID),
|
||||
Name: file.Name,
|
||||
OriginalName: file.OriginalName,
|
||||
Size: file.Size,
|
||||
MimeType: file.MimeType,
|
||||
StoragePath: file.StoragePath,
|
||||
Hash: file.Hash,
|
||||
CreatedAt: file.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: file.UpdatedAt.Format(time.RFC3339),
|
||||
Directory: directory,
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListFilesResponse{
|
||||
Files: fileItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
89
module/base/cloud/internal/logic/disk/update_dir.go
Normal file
89
module/base/cloud/internal/logic/disk/update_dir.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 更新目录
|
||||
func UpdateDir(ctx context.Context, in *pb.CloudDiskDirItem) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Name) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var dir models.CloudDiskDir
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&dir).Error; err != nil {
|
||||
printer.Error("Directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 更新目录名称和路径
|
||||
oldPath := dir.Path
|
||||
dir.Name = in.Name
|
||||
|
||||
// 重新构建路径
|
||||
if dir.ParentID != nil {
|
||||
var parentDir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("id = ?", *dir.ParentID).First(&parentDir).Error; err == nil {
|
||||
dir.Path = filepath.Join(parentDir.Path, in.Name)
|
||||
}
|
||||
} else {
|
||||
dir.Path = "/" + in.Name
|
||||
}
|
||||
|
||||
// 检查新路径是否已存在
|
||||
var existingDir models.CloudDiskDir
|
||||
if err := impl.DBService.Where("path = ? AND passport_id = ? AND id != ?", dir.Path, auth.ID, dir.ID).First(&existingDir).Error; err == nil {
|
||||
return nil, errcode.ErrAlreadyExists
|
||||
}
|
||||
|
||||
if err := impl.DBService.Save(&dir).Error; err != nil {
|
||||
printer.Error("Update directory error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
// 更新所有子目录的路径
|
||||
if oldPath != dir.Path {
|
||||
var subdirs []models.CloudDiskDir
|
||||
if err := impl.DBService.Where("path LIKE ? AND passport_id = ?", oldPath+"%", auth.ID).Find(&subdirs).Error; err == nil {
|
||||
for _, subdir := range subdirs {
|
||||
newSubPath := strings.Replace(subdir.Path, oldPath, dir.Path, 1)
|
||||
impl.DBService.Model(&subdir).Update("path", newSubPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
73
module/base/cloud/internal/logic/disk/update_file.go
Normal file
73
module/base/cloud/internal/logic/disk/update_file.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 更新文件
|
||||
func UpdateFile(ctx context.Context, in *pb.CloudDiskFileItem) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Name) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var file models.CloudDiskFile
|
||||
query := impl.DBService.Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("cloud_disk_files.id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("cloud_disk_files.identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&file).Error; err != nil {
|
||||
printer.Error("File not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查新文件名是否已存在(在同一目录下)
|
||||
if file.Name != in.Name {
|
||||
var existingFile models.CloudDiskFile
|
||||
if err := impl.DBService.Where("name = ? AND directory_id = ? AND id != ?", in.Name, file.DirectoryID, file.ID).First(&existingFile).Error; err == nil {
|
||||
return nil, errcode.ErrAlreadyExists
|
||||
}
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
file.Name = in.Name
|
||||
file.OriginalName = in.OriginalName
|
||||
file.MimeType = in.MimeType
|
||||
file.StoragePath = in.StoragePath
|
||||
file.Hash = in.Hash
|
||||
|
||||
if err := impl.DBService.Save(&file).Error; err != nil {
|
||||
printer.Error("Update file error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
87
module/base/cloud/internal/logic/disk/upload_file.go
Normal file
87
module/base/cloud/internal/logic/disk/upload_file.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 上传文件
|
||||
func UploadFile(ctx context.Context, in *pb.CloudDiskFileRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.DirectoryId == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Name) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.StoragePath) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.CloudIdentity) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 验证目录是否存在且属于当前用户
|
||||
var directory models.CloudDiskDir
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.DirectoryId, auth.ID).First(&directory).Error; err != nil {
|
||||
printer.Error("Directory not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查文件是否已存在(基于文件名和目录)
|
||||
var existingFile models.CloudDiskFile
|
||||
if err := impl.DBService.Where("name = ? AND directory_id = ?", in.Name, in.DirectoryId).First(&existingFile).Error; err == nil {
|
||||
// 文件已存在,可以选择覆盖或返回错误
|
||||
return nil, errcode.ErrAlreadyExists
|
||||
}
|
||||
|
||||
// 生成文件哈希(如果未提供)
|
||||
fileHash := in.Hash
|
||||
if fileHash == "" {
|
||||
fileHash = utils.UUID() // 使用UUID作为默认哈希
|
||||
}
|
||||
|
||||
record := models.CloudDiskFile{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: uint(in.CloudId),
|
||||
CloudIdentity: in.CloudIdentity,
|
||||
},
|
||||
DirectoryID: func() *uint { id := uint(in.DirectoryId); return &id }(),
|
||||
Name: in.Name,
|
||||
OriginalName: in.OriginalName,
|
||||
Size: in.Size,
|
||||
MimeType: in.MimeType,
|
||||
StoragePath: in.StoragePath,
|
||||
Hash: fileHash,
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&record).Error; err != nil {
|
||||
printer.Error("Upload file error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: record.Identity,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
66
module/base/cloud/internal/logic/note/create_note.go
Normal file
66
module/base/cloud/internal/logic/note/create_note.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 创建笔记
|
||||
func CreateNote(ctx context.Context, in *pb.CreateNoteRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// valid code
|
||||
if strings.TrimSpace(in.Title) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.CloudIdentity) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
record := models.CloudNote{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
Std_Passport: types.Std_Passport{
|
||||
PassportID: auth.ID,
|
||||
PassportIdentity: auth.Identity,
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: uint(in.CloudId),
|
||||
CloudIdentity: in.CloudIdentity,
|
||||
},
|
||||
Title: in.Title,
|
||||
Content: in.Content,
|
||||
Category: in.Category,
|
||||
Tags: in.Tags,
|
||||
IsMarkdown: in.IsMarkdown,
|
||||
IsPinned: in.IsPinned,
|
||||
IsPrivate: in.IsPrivate,
|
||||
Views: 0,
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&record).Error; err != nil {
|
||||
printer.Error("Create note error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: record.Identity,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
56
module/base/cloud/internal/logic/note/delete_attachment.go
Normal file
56
module/base/cloud/internal/logic/note/delete_attachment.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 删除附件
|
||||
func DeleteAttachment(ctx context.Context, in *pb.IdentRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var attachment models.NoteAttachment
|
||||
query := impl.DBService.Joins("JOIN cloud_notes ON note_attachments.note_id = cloud_notes.id").
|
||||
Where("cloud_notes.passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("note_attachments.id = ?", in.Id)
|
||||
} else {
|
||||
// 注意:NoteAttachment模型没有identity字段,这里假设通过ID删除
|
||||
query = query.Where("note_attachments.id = ?", in.Id)
|
||||
}
|
||||
|
||||
if err := query.First(&attachment).Error; err != nil {
|
||||
printer.Error("Attachment not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 删除附件
|
||||
if err := impl.DBService.Delete(&attachment).Error; err != nil {
|
||||
printer.Error("Delete attachment error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
60
module/base/cloud/internal/logic/note/delete_note.go
Normal file
60
module/base/cloud/internal/logic/note/delete_note.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 删除笔记
|
||||
func DeleteNote(ctx context.Context, in *pb.IdentRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var note models.CloudNote
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(¬e).Error; err != nil {
|
||||
printer.Error("Note not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 删除笔记下的所有附件
|
||||
if err := impl.DBService.Where("note_id = ?", note.ID).Delete(&models.NoteAttachment{}).Error; err != nil {
|
||||
printer.Error("Delete attachments error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
// 删除笔记
|
||||
if err := impl.DBService.Delete(¬e).Error; err != nil {
|
||||
printer.Error("Delete note error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
74
module/base/cloud/internal/logic/note/get_note.go
Normal file
74
module/base/cloud/internal/logic/note/get_note.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取笔记详情
|
||||
func GetNote(ctx context.Context, in *pb.IdentRequest) (reply *pb.CloudNoteItem, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var note models.CloudNote
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.Preload("Attachments").First(¬e).Error; err != nil {
|
||||
printer.Error("Note not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 转换附件数据
|
||||
var attachments []*pb.NoteAttachmentItem
|
||||
for _, attachment := range note.Attachments {
|
||||
attachments = append(attachments, &pb.NoteAttachmentItem{
|
||||
Id: uint64(attachment.ID),
|
||||
NoteId: uint64(attachment.NoteID),
|
||||
FileName: attachment.FileName,
|
||||
FilePath: attachment.FilePath,
|
||||
FileSize: attachment.FileSize,
|
||||
MimeType: attachment.MimeType,
|
||||
CreatedAt: attachment.CreatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.CloudNoteItem{
|
||||
Id: uint64(note.ID),
|
||||
Identity: note.Identity,
|
||||
Title: note.Title,
|
||||
Content: note.Content,
|
||||
Category: note.Category,
|
||||
Tags: note.Tags,
|
||||
IsMarkdown: note.IsMarkdown,
|
||||
IsPinned: note.IsPinned,
|
||||
IsPrivate: note.IsPrivate,
|
||||
Views: int32(note.Views),
|
||||
CreatedAt: note.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: note.UpdatedAt.Format(time.RFC3339),
|
||||
Attachments: attachments,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
56
module/base/cloud/internal/logic/note/increment_views.go
Normal file
56
module/base/cloud/internal/logic/note/increment_views.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 增加浏览次数
|
||||
func IncrementViews(ctx context.Context, in *pb.IdentRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var note models.CloudNote
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(¬e).Error; err != nil {
|
||||
printer.Error("Note not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 增加浏览次数
|
||||
note.Views++
|
||||
|
||||
if err := impl.DBService.Save(¬e).Error; err != nil {
|
||||
printer.Error("Increment views error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
62
module/base/cloud/internal/logic/note/insert_attachment.go
Normal file
62
module/base/cloud/internal/logic/note/insert_attachment.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 上传附件
|
||||
func InsertAttachment(ctx context.Context, in *pb.NoteAttachmentItem) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.NoteId == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.FileName) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.FilePath) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 验证笔记是否存在且属于当前用户
|
||||
var note models.CloudNote
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.NoteId, auth.ID).First(¬e).Error; err != nil {
|
||||
printer.Error("Note not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 创建附件记录
|
||||
attachment := models.NoteAttachment{
|
||||
NoteID: uint(in.NoteId),
|
||||
FileName: in.FileName,
|
||||
FilePath: in.FilePath,
|
||||
FileSize: in.FileSize,
|
||||
MimeType: in.MimeType,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&attachment).Error; err != nil {
|
||||
printer.Error("Insert attachment error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: string(rune(attachment.ID)),
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
89
module/base/cloud/internal/logic/note/list_notes.go
Normal file
89
module/base/cloud/internal/logic/note/list_notes.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取笔记列表
|
||||
func ListNotes(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListNotesResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var notes []models.CloudNote
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
if err := impl.DBService.Model(&models.CloudNote{}).Where("passport_id = ?", auth.ID).Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := impl.DBService.Where("passport_id = ?", auth.ID).
|
||||
Preload("Attachments").
|
||||
Order("is_pinned DESC, created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(¬es).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var noteItems []*pb.CloudNoteItem
|
||||
for _, note := range notes {
|
||||
// 转换附件数据
|
||||
var attachments []*pb.NoteAttachmentItem
|
||||
for _, attachment := range note.Attachments {
|
||||
attachments = append(attachments, &pb.NoteAttachmentItem{
|
||||
Id: uint64(attachment.ID),
|
||||
NoteId: uint64(attachment.NoteID),
|
||||
FileName: attachment.FileName,
|
||||
FilePath: attachment.FilePath,
|
||||
FileSize: attachment.FileSize,
|
||||
MimeType: attachment.MimeType,
|
||||
CreatedAt: attachment.CreatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
noteItems = append(noteItems, &pb.CloudNoteItem{
|
||||
Id: uint64(note.ID),
|
||||
Identity: note.Identity,
|
||||
Title: note.Title,
|
||||
Content: note.Content,
|
||||
Category: note.Category,
|
||||
Tags: note.Tags,
|
||||
IsMarkdown: note.IsMarkdown,
|
||||
IsPinned: note.IsPinned,
|
||||
IsPrivate: note.IsPrivate,
|
||||
Views: int32(note.Views),
|
||||
CreatedAt: note.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: note.UpdatedAt.Format(time.RFC3339),
|
||||
Attachments: attachments,
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListNotesResponse{
|
||||
Notes: noteItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
99
module/base/cloud/internal/logic/note/search_notes.go
Normal file
99
module/base/cloud/internal/logic/note/search_notes.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 搜索笔记
|
||||
func SearchNotes(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListNotesResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var notes []models.CloudNote
|
||||
var total int64
|
||||
|
||||
// 构建搜索查询
|
||||
query := impl.DBService.Model(&models.CloudNote{}).Where("passport_id = ?", auth.ID)
|
||||
|
||||
// 添加搜索条件
|
||||
if keyword, exists := in.Params["keyword"]; exists && keyword != "" {
|
||||
searchKeyword := "%" + strings.ToLower(keyword) + "%"
|
||||
query = query.Where("LOWER(title) LIKE ? OR LOWER(content) LIKE ? OR LOWER(tags) LIKE ?", searchKeyword, searchKeyword, searchKeyword)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := query.
|
||||
Preload("Attachments").
|
||||
Order("is_pinned DESC, created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(¬es).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var noteItems []*pb.CloudNoteItem
|
||||
for _, note := range notes {
|
||||
// 转换附件数据
|
||||
var attachments []*pb.NoteAttachmentItem
|
||||
for _, attachment := range note.Attachments {
|
||||
attachments = append(attachments, &pb.NoteAttachmentItem{
|
||||
Id: uint64(attachment.ID),
|
||||
NoteId: uint64(attachment.NoteID),
|
||||
FileName: attachment.FileName,
|
||||
FilePath: attachment.FilePath,
|
||||
FileSize: attachment.FileSize,
|
||||
MimeType: attachment.MimeType,
|
||||
CreatedAt: attachment.CreatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
noteItems = append(noteItems, &pb.CloudNoteItem{
|
||||
Id: uint64(note.ID),
|
||||
Identity: note.Identity,
|
||||
Title: note.Title,
|
||||
Content: note.Content,
|
||||
Category: note.Category,
|
||||
Tags: note.Tags,
|
||||
IsMarkdown: note.IsMarkdown,
|
||||
IsPinned: note.IsPinned,
|
||||
IsPrivate: note.IsPrivate,
|
||||
Views: int32(note.Views),
|
||||
CreatedAt: note.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: note.UpdatedAt.Format(time.RFC3339),
|
||||
Attachments: attachments,
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListNotesResponse{
|
||||
Notes: noteItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
48
module/base/cloud/internal/logic/note/toggle_pin.go
Normal file
48
module/base/cloud/internal/logic/note/toggle_pin.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 置顶/取消置顶笔记
|
||||
func TogglePin(ctx context.Context, in *pb.TogglePinRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var note models.CloudNote
|
||||
if err := impl.DBService.Where("id = ? AND passport_id = ?", in.Id, auth.ID).First(¬e).Error; err != nil {
|
||||
printer.Error("Note not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 更新置顶状态
|
||||
note.IsPinned = in.IsPinned
|
||||
|
||||
if err := impl.DBService.Save(¬e).Error; err != nil {
|
||||
printer.Error("Toggle pin error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
66
module/base/cloud/internal/logic/note/update_note.go
Normal file
66
module/base/cloud/internal/logic/note/update_note.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 更新笔记
|
||||
func UpdateNote(ctx context.Context, in *pb.CloudNoteItem) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Title) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var note models.CloudNote
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(¬e).Error; err != nil {
|
||||
printer.Error("Note not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
note.Title = in.Title
|
||||
note.Content = in.Content
|
||||
note.Category = in.Category
|
||||
note.Tags = in.Tags
|
||||
note.IsMarkdown = in.IsMarkdown
|
||||
note.IsPinned = in.IsPinned
|
||||
note.IsPrivate = in.IsPrivate
|
||||
|
||||
if err := impl.DBService.Save(¬e).Error; err != nil {
|
||||
printer.Error("Update note error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 创建隐私数据
|
||||
func CreatePrivateData(ctx context.Context, in *pb.CreatePrivateDataRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// valid code
|
||||
if strings.TrimSpace(in.DataType) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Title) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.CloudIdentity) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
record := models.CloudPrivate{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
Std_Passport: types.Std_Passport{
|
||||
PassportID: auth.ID,
|
||||
PassportIdentity: auth.Identity,
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: uint(in.CloudId),
|
||||
CloudIdentity: in.CloudIdentity,
|
||||
},
|
||||
DataType: in.DataType,
|
||||
Title: in.Title,
|
||||
Description: in.Description,
|
||||
Data: in.Data,
|
||||
IsEncrypted: in.IsEncrypted,
|
||||
Tags: in.Tags,
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&record).Error; err != nil {
|
||||
printer.Error("Create private data error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: record.Identity,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
81
module/base/cloud/internal/logic/private/decrypt_data.go
Normal file
81
module/base/cloud/internal/logic/private/decrypt_data.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 解密数据
|
||||
func DecryptData(ctx context.Context, in *pb.DataRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
_, err = service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if strings.TrimSpace(in.Data) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Key) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 解码base64数据
|
||||
ciphertext, err := base64.StdEncoding.DecodeString(in.Data)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
key := []byte(in.Key)
|
||||
if len(key) != 32 {
|
||||
// 如果密钥长度不是32字节,进行填充或截断
|
||||
if len(key) < 32 {
|
||||
for len(key) < 32 {
|
||||
key = append(key, 0)
|
||||
}
|
||||
} else {
|
||||
key = key[:32]
|
||||
}
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInternal
|
||||
}
|
||||
|
||||
// 使用GCM模式进行解密
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInternal
|
||||
}
|
||||
|
||||
// 检查数据长度
|
||||
if len(ciphertext) < gcm.NonceSize() {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 分离nonce和密文
|
||||
nonce := ciphertext[:gcm.NonceSize()]
|
||||
ciphertext = ciphertext[gcm.NonceSize():]
|
||||
|
||||
// 解密数据
|
||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: string(plaintext),
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 删除隐私数据
|
||||
func DeletePrivateData(ctx context.Context, in *pb.IdentRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var privateData models.CloudPrivate
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&privateData).Error; err != nil {
|
||||
printer.Error("Private data not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 删除隐私数据
|
||||
if err := impl.DBService.Delete(&privateData).Error; err != nil {
|
||||
printer.Error("Delete private data error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
75
module/base/cloud/internal/logic/private/encrypt_data.go
Normal file
75
module/base/cloud/internal/logic/private/encrypt_data.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 加密数据
|
||||
func EncryptData(ctx context.Context, in *pb.DataRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
_, err = service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if strings.TrimSpace(in.Data) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Key) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 简单的AES加密实现
|
||||
key := []byte(in.Key)
|
||||
if len(key) != 32 {
|
||||
// 如果密钥长度不是32字节,进行填充或截断
|
||||
if len(key) < 32 {
|
||||
for len(key) < 32 {
|
||||
key = append(key, 0)
|
||||
}
|
||||
} else {
|
||||
key = key[:32]
|
||||
}
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInternal
|
||||
}
|
||||
|
||||
// 使用GCM模式进行加密
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, errcode.ErrInternal
|
||||
}
|
||||
|
||||
// 生成随机nonce
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return nil, errcode.ErrInternal
|
||||
}
|
||||
|
||||
// 加密数据
|
||||
ciphertext := gcm.Seal(nonce, nonce, []byte(in.Data), nil)
|
||||
|
||||
// 返回base64编码的加密数据
|
||||
encryptedData := base64.StdEncoding.EncodeToString(ciphertext)
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: encryptedData,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
57
module/base/cloud/internal/logic/private/get_private_data.go
Normal file
57
module/base/cloud/internal/logic/private/get_private_data.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取隐私数据详情
|
||||
func GetPrivateData(ctx context.Context, in *pb.IdentRequest) (reply *pb.CloudPrivateItem, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var privateData models.CloudPrivate
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&privateData).Error; err != nil {
|
||||
printer.Error("Private data not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
reply = &pb.CloudPrivateItem{
|
||||
Id: uint64(privateData.ID),
|
||||
Identity: privateData.Identity,
|
||||
DataType: privateData.DataType,
|
||||
Title: privateData.Title,
|
||||
Description: privateData.Description,
|
||||
Data: privateData.Data,
|
||||
IsEncrypted: privateData.IsEncrypted,
|
||||
Tags: privateData.Tags,
|
||||
CreatedAt: privateData.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: privateData.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 按类型获取隐私数据
|
||||
func GetPrivateDataByType(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListPrivateDataResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// validate data type
|
||||
dataType, exists := in.Params["data_type"]
|
||||
if !exists || strings.TrimSpace(dataType) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var privateDataList []models.CloudPrivate
|
||||
var total int64
|
||||
|
||||
// 构建查询
|
||||
query := impl.DBService.Model(&models.CloudPrivate{}).Where("passport_id = ? AND data_type = ?", auth.ID, dataType)
|
||||
|
||||
// 获取总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := query.
|
||||
Order("created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&privateDataList).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var dataItems []*pb.CloudPrivateItem
|
||||
for _, data := range privateDataList {
|
||||
dataItems = append(dataItems, &pb.CloudPrivateItem{
|
||||
Id: uint64(data.ID),
|
||||
Identity: data.Identity,
|
||||
DataType: data.DataType,
|
||||
Title: data.Title,
|
||||
Description: data.Description,
|
||||
Data: data.Data,
|
||||
IsEncrypted: data.IsEncrypted,
|
||||
Tags: data.Tags,
|
||||
CreatedAt: data.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: data.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListPrivateDataResponse{
|
||||
Data: dataItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取隐私数据列表
|
||||
func ListPrivateData(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListPrivateDataResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var privateDataList []models.CloudPrivate
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
if err := impl.DBService.Model(&models.CloudPrivate{}).Where("passport_id = ?", auth.ID).Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := impl.DBService.Where("passport_id = ?", auth.ID).
|
||||
Order("created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&privateDataList).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var dataItems []*pb.CloudPrivateItem
|
||||
for _, data := range privateDataList {
|
||||
dataItems = append(dataItems, &pb.CloudPrivateItem{
|
||||
Id: uint64(data.ID),
|
||||
Identity: data.Identity,
|
||||
DataType: data.DataType,
|
||||
Title: data.Title,
|
||||
Description: data.Description,
|
||||
Data: data.Data,
|
||||
IsEncrypted: data.IsEncrypted,
|
||||
Tags: data.Tags,
|
||||
CreatedAt: data.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: data.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListPrivateDataResponse{
|
||||
Data: dataItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 搜索隐私数据
|
||||
func SearchPrivateData(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListPrivateDataResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var privateDataList []models.CloudPrivate
|
||||
var total int64
|
||||
|
||||
// 构建搜索查询
|
||||
query := impl.DBService.Model(&models.CloudPrivate{}).Where("passport_id = ?", auth.ID)
|
||||
|
||||
// 添加搜索条件
|
||||
if keyword, exists := in.Params["keyword"]; exists && keyword != "" {
|
||||
searchKeyword := "%" + strings.ToLower(keyword) + "%"
|
||||
query = query.Where("LOWER(title) LIKE ? OR LOWER(description) LIKE ? OR LOWER(tags) LIKE ?", searchKeyword, searchKeyword, searchKeyword)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := query.
|
||||
Order("created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&privateDataList).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var dataItems []*pb.CloudPrivateItem
|
||||
for _, data := range privateDataList {
|
||||
dataItems = append(dataItems, &pb.CloudPrivateItem{
|
||||
Id: uint64(data.ID),
|
||||
Identity: data.Identity,
|
||||
DataType: data.DataType,
|
||||
Title: data.Title,
|
||||
Description: data.Description,
|
||||
Data: data.Data,
|
||||
IsEncrypted: data.IsEncrypted,
|
||||
Tags: data.Tags,
|
||||
CreatedAt: data.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: data.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListPrivateDataResponse{
|
||||
Data: dataItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 更新隐私数据
|
||||
func UpdatePrivateData(ctx context.Context, in *pb.CloudPrivateItem) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.DataType) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.Title) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var privateData models.CloudPrivate
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&privateData).Error; err != nil {
|
||||
printer.Error("Private data not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
privateData.DataType = in.DataType
|
||||
privateData.Title = in.Title
|
||||
privateData.Description = in.Description
|
||||
privateData.Data = in.Data
|
||||
privateData.IsEncrypted = in.IsEncrypted
|
||||
privateData.Tags = in.Tags
|
||||
|
||||
if err := impl.DBService.Save(&privateData).Error; err != nil {
|
||||
printer.Error("Update private data error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
87
module/base/cloud/internal/logic/share/create_share.go
Normal file
87
module/base/cloud/internal/logic/share/create_share.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package share
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 创建分享
|
||||
func CreateShare(ctx context.Context, in *pb.CreateShareRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// valid code
|
||||
if strings.TrimSpace(in.ShareType) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if in.ResourceId == 0 {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
if strings.TrimSpace(in.CloudIdentity) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
// 生成分享令牌(如果未提供)
|
||||
shareToken := in.ShareToken
|
||||
if shareToken == "" {
|
||||
shareToken = utils.UUID()
|
||||
}
|
||||
|
||||
// 解析过期时间
|
||||
var expiresAt time.Time
|
||||
if in.ExpiresAt != "" {
|
||||
if t, err := time.Parse(time.RFC3339, in.ExpiresAt); err == nil {
|
||||
expiresAt = t
|
||||
} else {
|
||||
expiresAt = time.Now().Add(7 * 24 * time.Hour) // 默认7天过期
|
||||
}
|
||||
} else {
|
||||
expiresAt = time.Now().Add(7 * 24 * time.Hour) // 默认7天过期
|
||||
}
|
||||
|
||||
record := models.CloudShare{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: utils.UUID(),
|
||||
},
|
||||
Std_Passport: types.Std_Passport{
|
||||
PassportID: auth.ID,
|
||||
PassportIdentity: auth.Identity,
|
||||
},
|
||||
CloudBase: models.CloudBase{
|
||||
CloudID: uint(in.CloudId),
|
||||
CloudIdentity: in.CloudIdentity,
|
||||
},
|
||||
ShareType: in.ShareType,
|
||||
ResourceID: uint(in.ResourceId),
|
||||
ShareToken: shareToken,
|
||||
Password: in.Password,
|
||||
ExpiresAt: expiresAt,
|
||||
ViewCount: 0,
|
||||
DownloadCount: 0,
|
||||
IsPublic: in.IsPublic,
|
||||
}
|
||||
|
||||
if err := impl.DBService.Create(&record).Error; err != nil {
|
||||
printer.Error("Create share error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: record.Identity,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
54
module/base/cloud/internal/logic/share/delete_share.go
Normal file
54
module/base/cloud/internal/logic/share/delete_share.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package share
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 删除分享
|
||||
func DeleteShare(ctx context.Context, in *pb.IdentRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var share models.CloudShare
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&share).Error; err != nil {
|
||||
printer.Error("Share not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 删除分享
|
||||
if err := impl.DBService.Delete(&share).Error; err != nil {
|
||||
printer.Error("Delete share error: %v", err)
|
||||
return nil, errcode.ErrDB
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
64
module/base/cloud/internal/logic/share/get_share.go
Normal file
64
module/base/cloud/internal/logic/share/get_share.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package share
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取分享详情
|
||||
func GetShare(ctx context.Context, in *pb.IdentRequest) (reply *pb.CloudShareItem, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var share models.CloudShare
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("identity = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&share).Error; err != nil {
|
||||
printer.Error("Share not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
if time.Now().After(share.ExpiresAt) {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
reply = &pb.CloudShareItem{
|
||||
Id: uint64(share.ID),
|
||||
Identity: share.Identity,
|
||||
ShareType: share.ShareType,
|
||||
ResourceId: uint64(share.ResourceID),
|
||||
ShareToken: share.ShareToken,
|
||||
Password: share.Password,
|
||||
ExpiresAt: share.ExpiresAt.Format(time.RFC3339),
|
||||
ViewCount: int32(share.ViewCount),
|
||||
DownloadCount: int32(share.DownloadCount),
|
||||
IsPublic: share.IsPublic,
|
||||
CreatedAt: share.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: share.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
73
module/base/cloud/internal/logic/share/list_shares.go
Normal file
73
module/base/cloud/internal/logic/share/list_shares.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package share
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取分享列表
|
||||
func ListShares(ctx context.Context, in *pb.FetchRequest) (reply *pb.ListSharesResponse, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request page_no,page_size.
|
||||
if in.GetPageNo() < 1 {
|
||||
in.PageNo = 1
|
||||
}
|
||||
if in.GetPageSize() < 10 {
|
||||
in.PageSize = 50
|
||||
}
|
||||
|
||||
// logic code
|
||||
var shares []models.CloudShare
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
if err := impl.DBService.Model(&models.CloudShare{}).Where("passport_id = ?", auth.ID).Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (in.PageNo - 1) * in.PageSize
|
||||
if err := impl.DBService.Where("passport_id = ?", auth.ID).
|
||||
Order("created_at DESC").
|
||||
Offset(int(offset)).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&shares).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换数据
|
||||
var shareItems []*pb.CloudShareItem
|
||||
for _, share := range shares {
|
||||
shareItems = append(shareItems, &pb.CloudShareItem{
|
||||
Id: uint64(share.ID),
|
||||
Identity: share.Identity,
|
||||
ShareType: share.ShareType,
|
||||
ResourceId: uint64(share.ResourceID),
|
||||
ShareToken: share.ShareToken,
|
||||
Password: share.Password,
|
||||
ExpiresAt: share.ExpiresAt.Format(time.RFC3339),
|
||||
ViewCount: int32(share.ViewCount),
|
||||
DownloadCount: int32(share.DownloadCount),
|
||||
IsPublic: share.IsPublic,
|
||||
CreatedAt: share.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: share.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
reply = &pb.ListSharesResponse{
|
||||
Shares: shareItems,
|
||||
Total: total,
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package share
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
)
|
||||
|
||||
// 验证分享密码
|
||||
func ValidateSharePassword(ctx context.Context, in *pb.ValidateSharePasswordRequest) (reply *pb.StatusReply, err error) {
|
||||
// parse authorization meta.
|
||||
_, err = service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request
|
||||
if strings.TrimSpace(in.Identity) == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var share models.CloudShare
|
||||
if err := impl.DBService.Where("identity = ?", in.Identity).First(&share).Error; err != nil {
|
||||
printer.Error("Share not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
if time.Now().After(share.ExpiresAt) {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 检查密码(如果设置了密码)
|
||||
if share.Password != "" && share.Password != in.Password {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 增加浏览次数
|
||||
share.ViewCount++
|
||||
if err := impl.DBService.Save(&share).Error; err != nil {
|
||||
printer.Error("Update view count error: %v", err)
|
||||
// 不返回错误,继续执行
|
||||
}
|
||||
|
||||
return &pb.StatusReply{
|
||||
Details: vars.OK,
|
||||
Timeseq: time.Now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
119
module/base/cloud/internal/logic/space/get.go
Normal file
119
module/base/cloud/internal/logic/space/get.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package space
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 获取空间数据
|
||||
func Get(ctx context.Context, in *pb.Empty) (reply *pb.CloudSpace, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// logic code
|
||||
var space models.CloudSpace
|
||||
if err := impl.DBService.Where("passport_id = ?", auth.ID).First(&space).Error; err != nil {
|
||||
// 如果不存在,创建默认空间记录
|
||||
space = models.CloudSpace{
|
||||
Std_IICUDS: types.Std_IICUDS{
|
||||
Identity: "default",
|
||||
},
|
||||
Std_Passport: types.Std_Passport{
|
||||
PassportID: auth.ID,
|
||||
PassportIdentity: auth.Identity,
|
||||
},
|
||||
KeyIdentifier: "default",
|
||||
TotalStorage: 100 * 1024 * 1024 * 1024, // 100GB
|
||||
UsedStorage: 0,
|
||||
MaxStorage: 100 * 1024 * 1024 * 1024, // 100GB
|
||||
FileCount: 0,
|
||||
AlbumCount: 0,
|
||||
PhotoCount: 0,
|
||||
NoteCount: 0,
|
||||
BookmarkCount: 0,
|
||||
PrivateCount: 0,
|
||||
}
|
||||
if err := impl.DBService.Create(&space).Error; err != nil {
|
||||
printer.Error("Create space error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 统计各种数据
|
||||
var fileCount, albumCount, photoCount, noteCount, bookmarkCount, privateCount int64
|
||||
var usedStorage int64
|
||||
|
||||
// 统计文件数量和存储空间
|
||||
if err := impl.DBService.Model(&models.CloudDiskFile{}).
|
||||
Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID).
|
||||
Count(&fileCount).Error; err == nil {
|
||||
var files []models.CloudDiskFile
|
||||
impl.DBService.Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID).
|
||||
Find(&files)
|
||||
for _, file := range files {
|
||||
usedStorage += file.Size
|
||||
}
|
||||
}
|
||||
|
||||
// 统计相册数量
|
||||
impl.DBService.Model(&models.CloudAlbum{}).Where("passport_id = ?", auth.ID).Count(&albumCount)
|
||||
|
||||
// 统计照片数量
|
||||
impl.DBService.Model(&models.CloudPhoto{}).
|
||||
Joins("JOIN cloud_albums ON cloud_photos.album_id = cloud_albums.id").
|
||||
Where("cloud_albums.passport_id = ?", auth.ID).
|
||||
Count(&photoCount)
|
||||
|
||||
// 统计笔记数量
|
||||
impl.DBService.Model(&models.CloudNote{}).Where("passport_id = ?", auth.ID).Count(¬eCount)
|
||||
|
||||
// 统计书签数量
|
||||
impl.DBService.Model(&models.CloudBookmark{}).Where("passport_id = ?", auth.ID).Count(&bookmarkCount)
|
||||
|
||||
// 统计隐私数据数量
|
||||
impl.DBService.Model(&models.CloudPrivate{}).Where("passport_id = ?", auth.ID).Count(&privateCount)
|
||||
|
||||
// 更新统计数据
|
||||
space.UsedStorage = usedStorage
|
||||
space.FileCount = int(fileCount)
|
||||
space.AlbumCount = int(albumCount)
|
||||
space.PhotoCount = int(photoCount)
|
||||
space.NoteCount = int(noteCount)
|
||||
space.BookmarkCount = int(bookmarkCount)
|
||||
space.PrivateCount = int(privateCount)
|
||||
|
||||
if err := impl.DBService.Save(&space).Error; err != nil {
|
||||
printer.Error("Update space error: %v", err)
|
||||
// 不返回错误,继续执行
|
||||
}
|
||||
|
||||
reply = &pb.CloudSpace{
|
||||
Id: uint64(space.ID),
|
||||
Identity: space.Identity,
|
||||
TotalStorage: space.TotalStorage,
|
||||
UsedStorage: space.UsedStorage,
|
||||
MaxStorage: space.MaxStorage,
|
||||
FileCount: int32(space.FileCount),
|
||||
AlbumCount: int32(space.AlbumCount),
|
||||
PhotoCount: int32(space.PhotoCount),
|
||||
NoteCount: int32(space.NoteCount),
|
||||
BookmarkCount: int32(space.BookmarkCount),
|
||||
PrivateCount: int32(space.PrivateCount),
|
||||
CreatedAt: space.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: space.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
110
module/base/cloud/internal/logic/space/get_by_key_identifier.go
Normal file
110
module/base/cloud/internal/logic/space/get_by_key_identifier.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package space
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"bsm/full/module/base/cloud/internal/impl"
|
||||
"bsm/full/module/base/cloud/internal/models"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/printer"
|
||||
"git.apinb.com/bsm-sdk/core/service"
|
||||
)
|
||||
|
||||
// 获取空间数据
|
||||
func GetByKeyIdentifier(ctx context.Context, in *pb.IdentRequest) (reply *pb.CloudSpace, err error) {
|
||||
// parse authorization meta.
|
||||
auth, err := service.ParseMetaCtx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate request id,identity.
|
||||
if in.Id == 0 && in.Identity == "" {
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// logic code
|
||||
var space models.CloudSpace
|
||||
query := impl.DBService.Where("passport_id = ?", auth.ID)
|
||||
|
||||
if in.Id > 0 {
|
||||
query = query.Where("id = ?", in.Id)
|
||||
} else {
|
||||
query = query.Where("key_identifier = ?", in.Identity)
|
||||
}
|
||||
|
||||
if err := query.First(&space).Error; err != nil {
|
||||
printer.Error("Space not found: %v", err)
|
||||
return nil, errcode.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// 统计各种数据
|
||||
var fileCount, albumCount, photoCount, noteCount, bookmarkCount, privateCount int64
|
||||
var usedStorage int64
|
||||
|
||||
// 统计文件数量和存储空间
|
||||
if err := impl.DBService.Model(&models.CloudDiskFile{}).
|
||||
Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID).
|
||||
Count(&fileCount).Error; err == nil {
|
||||
var files []models.CloudDiskFile
|
||||
impl.DBService.Joins("JOIN cloud_disk_dirs ON cloud_disk_files.directory_id = cloud_disk_dirs.id").
|
||||
Where("cloud_disk_dirs.passport_id = ?", auth.ID).
|
||||
Find(&files)
|
||||
for _, file := range files {
|
||||
usedStorage += file.Size
|
||||
}
|
||||
}
|
||||
|
||||
// 统计相册数量
|
||||
impl.DBService.Model(&models.CloudAlbum{}).Where("passport_id = ?", auth.ID).Count(&albumCount)
|
||||
|
||||
// 统计照片数量
|
||||
impl.DBService.Model(&models.CloudPhoto{}).
|
||||
Joins("JOIN cloud_albums ON cloud_photos.album_id = cloud_albums.id").
|
||||
Where("cloud_albums.passport_id = ?", auth.ID).
|
||||
Count(&photoCount)
|
||||
|
||||
// 统计笔记数量
|
||||
impl.DBService.Model(&models.CloudNote{}).Where("passport_id = ?", auth.ID).Count(¬eCount)
|
||||
|
||||
// 统计书签数量
|
||||
impl.DBService.Model(&models.CloudBookmark{}).Where("passport_id = ?", auth.ID).Count(&bookmarkCount)
|
||||
|
||||
// 统计隐私数据数量
|
||||
impl.DBService.Model(&models.CloudPrivate{}).Where("passport_id = ?", auth.ID).Count(&privateCount)
|
||||
|
||||
// 更新统计数据
|
||||
space.UsedStorage = usedStorage
|
||||
space.FileCount = int(fileCount)
|
||||
space.AlbumCount = int(albumCount)
|
||||
space.PhotoCount = int(photoCount)
|
||||
space.NoteCount = int(noteCount)
|
||||
space.BookmarkCount = int(bookmarkCount)
|
||||
space.PrivateCount = int(privateCount)
|
||||
|
||||
if err := impl.DBService.Save(&space).Error; err != nil {
|
||||
printer.Error("Update space error: %v", err)
|
||||
// 不返回错误,继续执行
|
||||
}
|
||||
|
||||
reply = &pb.CloudSpace{
|
||||
Id: uint64(space.ID),
|
||||
Identity: space.Identity,
|
||||
TotalStorage: space.TotalStorage,
|
||||
UsedStorage: space.UsedStorage,
|
||||
MaxStorage: space.MaxStorage,
|
||||
FileCount: int32(space.FileCount),
|
||||
AlbumCount: int32(space.AlbumCount),
|
||||
PhotoCount: int32(space.PhotoCount),
|
||||
NoteCount: int32(space.NoteCount),
|
||||
BookmarkCount: int32(space.BookmarkCount),
|
||||
PrivateCount: int32(space.PrivateCount),
|
||||
CreatedAt: space.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: space.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
24
module/base/cloud/internal/models/cloud_album.go
Normal file
24
module/base/cloud/internal/models/cloud_album.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 相册模型
|
||||
type CloudAlbum struct {
|
||||
types.Std_IICUDS
|
||||
types.Std_Passport
|
||||
CloudBase
|
||||
Name string `gorm:"size:100" json:"name"` // 相册名称
|
||||
Description string `gorm:"size:500" json:"description"` // 相册描述
|
||||
CoverPhoto string `gorm:"size:255" json:"cover_photo"` // 封面照片URL
|
||||
IsPrivate bool `gorm:"default:false" json:"is_private"` // 是否私有
|
||||
|
||||
// 关联关系
|
||||
Photos []CloudPhoto `gorm:"foreignKey:AlbumID" json:"photos"` // 相册下的照片
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&CloudAlbum{})
|
||||
}
|
||||
24
module/base/cloud/internal/models/cloud_bookmark.go
Normal file
24
module/base/cloud/internal/models/cloud_bookmark.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 网址收藏夹模型
|
||||
type CloudBookmark struct {
|
||||
types.Std_IICUDS
|
||||
types.Std_Passport
|
||||
CloudBase
|
||||
Title string `gorm:"size:200" json:"title"` // 标题
|
||||
URL string `gorm:"size:500" json:"url"` // 网址
|
||||
Description string `gorm:"size:500" json:"description"` // 描述
|
||||
Category string `gorm:"size:50" json:"category"` // 分类
|
||||
Tags string `gorm:"size:500" json:"tags"` // 标签
|
||||
Icon string `gorm:"size:500" json:"icon"` // 网站图标URL
|
||||
IsPrivate bool `gorm:"default:false" json:"is_private"` // 是否私有
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&CloudBookmark{})
|
||||
}
|
||||
25
module/base/cloud/internal/models/cloud_disk_dir.go
Normal file
25
module/base/cloud/internal/models/cloud_disk_dir.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 云盘目录模型
|
||||
type CloudDiskDir struct {
|
||||
types.Std_IICUDS
|
||||
types.Std_Passport
|
||||
CloudBase
|
||||
ParentID *uint `gorm:"index" json:"parent_id"` // 支持嵌套目录
|
||||
Name string `gorm:"size:100" json:"name"` // 目录名称
|
||||
Path string `gorm:"size:500" json:"path"` // 完整路径
|
||||
|
||||
// 自关联
|
||||
Parent *CloudDiskDir `gorm:"foreignKey:ParentID" json:"parent"` // 父级目录
|
||||
Subdirectories []CloudDiskDir `gorm:"foreignKey:ParentID" json:"subdirectories"` // 子级目录
|
||||
Files []CloudDiskFile `gorm:"foreignKey:DirectoryID" json:"files"` // 文件
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&CloudDiskDir{})
|
||||
}
|
||||
27
module/base/cloud/internal/models/cloud_disk_file.go
Normal file
27
module/base/cloud/internal/models/cloud_disk_file.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 云盘文件
|
||||
type CloudDiskFile struct {
|
||||
types.Std_IICUDS
|
||||
types.Std_Passport
|
||||
CloudBase
|
||||
DirectoryID *uint `gorm:"index" json:"directory_id"` // 文件所属目录
|
||||
Name string `gorm:"size:255" json:"name"` // 文件名
|
||||
OriginalName string `gorm:"size:255" json:"original_name"` // 原始文件名
|
||||
Size int64 `json:"size"` // 文件大小 (bytes)
|
||||
MimeType string `gorm:"size:100" json:"mime_type"` // 文件类型
|
||||
StoragePath string `gorm:"size:500" json:"storage_path"` // 实际存储路径
|
||||
Hash string `gorm:"size:64" json:"hash"` // 文件哈希,用于去重
|
||||
|
||||
// 关联关系
|
||||
Directory *CloudDiskDir `gorm:"foreignKey:DirectoryID" json:"dir"` // 文件所属目录
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&CloudDiskFile{})
|
||||
}
|
||||
28
module/base/cloud/internal/models/cloud_note.go
Normal file
28
module/base/cloud/internal/models/cloud_note.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 知识笔记模型
|
||||
type CloudNote struct {
|
||||
types.Std_IICUDS
|
||||
types.Std_Passport
|
||||
CloudBase
|
||||
Title string `gorm:"size:200" json:"title"` // 标题
|
||||
Content string `gorm:"type:text" json:"content"` // 内容
|
||||
Category string `gorm:"size:50" json:"category"` // 分类
|
||||
Tags string `gorm:"size:500" json:"tags"` // 标签,逗号分隔
|
||||
IsMarkdown bool `gorm:"default:true" json:"is_markdown"` // 是否是markdown格式
|
||||
IsPinned bool `gorm:"default:false" json:"is_pinned"` // 是否是置顶
|
||||
IsPrivate bool `gorm:"default:false" json:"is_private"` // 是否是私有
|
||||
Views int `gorm:"default:0" json:"views"` // 浏览次数
|
||||
|
||||
// 关联关系
|
||||
Attachments []NoteAttachment `gorm:"foreignKey:NoteID" json:"attachments"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&CloudNote{})
|
||||
}
|
||||
22
module/base/cloud/internal/models/cloud_note_attach.go
Normal file
22
module/base/cloud/internal/models/cloud_note_attach.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
)
|
||||
|
||||
// 笔记附件模型
|
||||
type NoteAttachment struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
NoteID uint `gorm:"index" json:"note_id"` // 笔记ID
|
||||
FileName string `gorm:"size:255" json:"file_name"` // 文件名
|
||||
FilePath string `gorm:"size:500" json:"file_path"` // 文件路径
|
||||
FileSize int64 `json:"file_size"` // 文件大小
|
||||
MimeType string `gorm:"size:100" json:"mime_type"` // 文件类型
|
||||
CreatedAt time.Time `json:"created_at"` // 创建时间
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&NoteAttachment{})
|
||||
}
|
||||
32
module/base/cloud/internal/models/cloud_photo.go
Normal file
32
module/base/cloud/internal/models/cloud_photo.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 照片模型
|
||||
type CloudPhoto struct {
|
||||
types.Std_IICUDS
|
||||
CloudBase
|
||||
AlbumID uint `gorm:"index" json:"album_id"` // 专辑ID
|
||||
Title string `gorm:"size:100" json:"title"` // 照片标题
|
||||
Description string `gorm:"size:500" json:"description"` // 照片描述
|
||||
FilePath string `gorm:"size:500" json:"file_path"` // 文件路径
|
||||
FileSize int64 `json:"file_size"` // 文件大小
|
||||
MimeType string `gorm:"size:100" json:"mime_type"` // 文件类型
|
||||
Width int `json:"width"` // 图片宽度
|
||||
Height int `json:"height"` // 图片高度
|
||||
TakenAt time.Time `json:"taken_at"` // 拍摄时间
|
||||
Location string `gorm:"size:200" json:"location"` // 拍摄地点
|
||||
Tags string `gorm:"size:500" json:"tags"` // 标签,逗号分隔
|
||||
|
||||
// 关联关系
|
||||
Album CloudAlbum `gorm:"foreignKey:AlbumID" json:"album"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&CloudPhoto{})
|
||||
}
|
||||
23
module/base/cloud/internal/models/cloud_private.go
Normal file
23
module/base/cloud/internal/models/cloud_private.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 个人隐私数据模型
|
||||
type CloudPrivate struct {
|
||||
types.Std_IICUDS
|
||||
types.Std_Passport
|
||||
CloudBase
|
||||
DataType string `gorm:"size:50" json:"data_type"` // 数据类型: password, card, document, etc.
|
||||
Title string `gorm:"size:200" json:"title"` // 标题
|
||||
Description string `gorm:"size:500" json:"description"` // 描述
|
||||
Data string `gorm:"type:text" json:"data"` // 加密存储的实际数据
|
||||
IsEncrypted bool `gorm:"default:true" json:"is_encrypted"` // 是否已加密
|
||||
Tags string `gorm:"size:500" json:"tags"` // 标签
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&CloudPrivate{})
|
||||
}
|
||||
27
module/base/cloud/internal/models/cloud_share.go
Normal file
27
module/base/cloud/internal/models/cloud_share.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 分享系统模型
|
||||
type CloudShare struct {
|
||||
types.Std_IICUDS
|
||||
types.Std_Passport
|
||||
CloudBase
|
||||
ShareType string `gorm:"size:20" json:"share_type"` // file, album, note, etc.
|
||||
ResourceID uint `json:"resource_id"` // 对应资源的ID
|
||||
ShareToken string `gorm:"uniqueIndex;size:32" json:"share_token"` // 分享令牌
|
||||
Password string `gorm:"size:100" json:"password"` // 可选分享密码
|
||||
ExpiresAt time.Time `json:"expires_at"` // 过期时间
|
||||
ViewCount int `gorm:"default:0" json:"view_count"` // 浏览次数
|
||||
DownloadCount int `gorm:"default:0" json:"download_count"` // 下载次数
|
||||
IsPublic bool `gorm:"default:false" json:"is_public"` // 是否公开
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&CloudShare{})
|
||||
}
|
||||
33
module/base/cloud/internal/models/cloud_space.go
Normal file
33
module/base/cloud/internal/models/cloud_space.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"git.apinb.com/bsm-sdk/core/database"
|
||||
"git.apinb.com/bsm-sdk/engine/types"
|
||||
)
|
||||
|
||||
// 系统统计和配置模型
|
||||
type CloudSpace struct {
|
||||
types.Std_IICUDS
|
||||
types.Std_Passport
|
||||
KeyIdentifier string `gorm:"uniqueIndex;size:32" json:"key_identifier"`
|
||||
TotalStorage int64 `json:"total_storage"` // 总存储空间
|
||||
UsedStorage int64 `json:"used_storage"` // 已用存储空间
|
||||
MaxStorage int64 `json:"max_storage"` // 最大存储空间
|
||||
FileCount int `json:"file_count"` // 文件数量
|
||||
AlbumCount int `json:"album_count"` // 相册数量
|
||||
PhotoCount int `json:"photo_count"` // 照片数量
|
||||
NoteCount int `json:"note_count"` // 笔记数量
|
||||
BookmarkCount int `json:"bookmark_count"` // 书签数量
|
||||
PrivateCount int `json:"private_count"` // 私有数量
|
||||
|
||||
CloudDiskDirectorys []CloudDiskDir `gorm:"foreignKey:PassportID" json:"cloud_disk_dirs"` // 关联云盘目录
|
||||
Albums []CloudAlbum `gorm:"foreignKey:PassportID" json:"cloud_albums"` // 关联相册
|
||||
Notes []CloudNote `gorm:"foreignKey:PassportID" json:"cloud_notes"` // 关联笔记
|
||||
Bookmarks []CloudBookmark `gorm:"foreignKey:PassportID" json:"cloud_bookmarks"` // 关联书签
|
||||
PrivateData []CloudPrivate `gorm:"foreignKey:PassportID" json:"cloud_private"` // 关联私有数据
|
||||
Shares []CloudShare `gorm:"foreignKey:PassportID" json:"cloud_shares"` // 关联分享
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.AppendMigrate(&CloudSpace{})
|
||||
}
|
||||
7
module/base/cloud/internal/models/query.go
Normal file
7
module/base/cloud/internal/models/query.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package models
|
||||
|
||||
// CloudBase 云盘基础信息
|
||||
type CloudBase struct {
|
||||
CloudID uint `gorm:"column:cloud_id;Index;" json:"cloud_id"` // 云盘ID
|
||||
CloudIdentity string `gorm:"column:cloud_identity;type:varchar(36);Index;" json:"cloud_identity"` // 云盘唯一标识,24位NanoID,36位为ULID
|
||||
}
|
||||
76
module/base/cloud/internal/server/album_server.go
Normal file
76
module/base/cloud/internal/server/album_server.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// Code generated by protoc-gen-slc. DO NOT EDIT.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bsm/full/module/base/cloud/internal/logic/album"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
)
|
||||
|
||||
type AlbumServer struct {
|
||||
pb.UnimplementedAlbumServer
|
||||
}
|
||||
|
||||
func NewAlbumServer() *AlbumServer {
|
||||
return &AlbumServer{}
|
||||
}
|
||||
|
||||
// 创建相册
|
||||
func (s *AlbumServer) CreateAlbum(ctx context.Context, in *pb.CreateAlbumRequest) (*pb.StatusReply, error) {
|
||||
return album.CreateAlbum(ctx, in)
|
||||
}
|
||||
|
||||
// 获取相册详情
|
||||
func (s *AlbumServer) GetAlbum(ctx context.Context, in *pb.IdentRequest) (*pb.CloudAlbumItem, error) {
|
||||
return album.GetAlbum(ctx, in)
|
||||
}
|
||||
|
||||
// 更新相册
|
||||
func (s *AlbumServer) UpdateAlbum(ctx context.Context, in *pb.CloudAlbumItem) (*pb.StatusReply, error) {
|
||||
return album.UpdateAlbum(ctx, in)
|
||||
}
|
||||
|
||||
// 删除相册
|
||||
func (s *AlbumServer) DeleteAlbum(ctx context.Context, in *pb.IdentRequest) (*pb.StatusReply, error) {
|
||||
return album.DeleteAlbum(ctx, in)
|
||||
}
|
||||
|
||||
// 获取相册列表
|
||||
func (s *AlbumServer) ListAlbums(ctx context.Context, in *pb.FetchRequest) (*pb.ListAlbumsResponse, error) {
|
||||
return album.ListAlbums(ctx, in)
|
||||
}
|
||||
|
||||
// 设置封面照片
|
||||
func (s *AlbumServer) SetCoverPhoto(ctx context.Context, in *pb.SetCoverPhotoRequest) (*pb.StatusReply, error) {
|
||||
return album.SetCoverPhoto(ctx, in)
|
||||
}
|
||||
|
||||
// 上传照片
|
||||
func (s *AlbumServer) UploadPhoto(ctx context.Context, in *pb.CloudPhotoItem) (*pb.StatusReply, error) {
|
||||
return album.UploadPhoto(ctx, in)
|
||||
}
|
||||
|
||||
// 获取照片详情
|
||||
func (s *AlbumServer) GetPhoto(ctx context.Context, in *pb.IdentRequest) (*pb.CloudPhotoItem, error) {
|
||||
return album.GetPhoto(ctx, in)
|
||||
}
|
||||
|
||||
// 更新照片
|
||||
func (s *AlbumServer) UpdatePhoto(ctx context.Context, in *pb.CloudPhotoItem) (*pb.StatusReply, error) {
|
||||
return album.UpdatePhoto(ctx, in)
|
||||
}
|
||||
|
||||
// 删除照片
|
||||
func (s *AlbumServer) DeletePhoto(ctx context.Context, in *pb.IdentRequest) (*pb.StatusReply, error) {
|
||||
return album.DeletePhoto(ctx, in)
|
||||
}
|
||||
|
||||
// 获取照片列表
|
||||
func (s *AlbumServer) ListPhotos(ctx context.Context, in *pb.FetchRequest) (*pb.ListPhotosResponse, error) {
|
||||
return album.ListPhotos(ctx, in)
|
||||
}
|
||||
|
||||
// 移动照片到其他相册
|
||||
func (s *AlbumServer) MovePhoto(ctx context.Context, in *pb.MovePhotoRequest) (*pb.StatusReply, error) {
|
||||
return album.MovePhoto(ctx, in)
|
||||
}
|
||||
46
module/base/cloud/internal/server/bookmark_server.go
Normal file
46
module/base/cloud/internal/server/bookmark_server.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// Code generated by protoc-gen-slc. DO NOT EDIT.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bsm/full/module/base/cloud/internal/logic/bookmark"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
)
|
||||
|
||||
type BookmarkServer struct {
|
||||
pb.UnimplementedBookmarkServer
|
||||
}
|
||||
|
||||
func NewBookmarkServer() *BookmarkServer {
|
||||
return &BookmarkServer{}
|
||||
}
|
||||
|
||||
// 创建书签
|
||||
func (s *BookmarkServer) CreateBookmark(ctx context.Context, in *pb.CreateBookmarkRequest) (*pb.StatusReply, error) {
|
||||
return bookmark.CreateBookmark(ctx, in)
|
||||
}
|
||||
|
||||
// 获取书签详情
|
||||
func (s *BookmarkServer) GetBookmark(ctx context.Context, in *pb.IDRequest) (*pb.CloudBookmarkItem, error) {
|
||||
return bookmark.GetBookmark(ctx, in)
|
||||
}
|
||||
|
||||
// 更新书签
|
||||
func (s *BookmarkServer) UpdateBookmark(ctx context.Context, in *pb.CloudBookmarkItem) (*pb.StatusReply, error) {
|
||||
return bookmark.UpdateBookmark(ctx, in)
|
||||
}
|
||||
|
||||
// 删除书签
|
||||
func (s *BookmarkServer) DeleteBookmark(ctx context.Context, in *pb.IDRequest) (*pb.StatusReply, error) {
|
||||
return bookmark.DeleteBookmark(ctx, in)
|
||||
}
|
||||
|
||||
// 获取书签列表
|
||||
func (s *BookmarkServer) ListBookmarks(ctx context.Context, in *pb.FetchRequest) (*pb.ListBookmarksResponse, error) {
|
||||
return bookmark.ListBookmarks(ctx, in)
|
||||
}
|
||||
|
||||
// 导入书签
|
||||
func (s *BookmarkServer) ImportBookmarks(ctx context.Context, in *pb.ImportBookmarksRequest) (*pb.StatusReply, error) {
|
||||
return bookmark.ImportBookmarks(ctx, in)
|
||||
}
|
||||
91
module/base/cloud/internal/server/disk_server.go
Normal file
91
module/base/cloud/internal/server/disk_server.go
Normal file
@@ -0,0 +1,91 @@
|
||||
// Code generated by protoc-gen-slc. DO NOT EDIT.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bsm/full/module/base/cloud/internal/logic/disk"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
)
|
||||
|
||||
type DiskServer struct {
|
||||
pb.UnimplementedDiskServer
|
||||
}
|
||||
|
||||
func NewDiskServer() *DiskServer {
|
||||
return &DiskServer{}
|
||||
}
|
||||
|
||||
// 创建目录
|
||||
func (s *DiskServer) CreateDir(ctx context.Context, in *pb.CreateDirRequest) (*pb.StatusReply, error) {
|
||||
return disk.CreateDir(ctx, in)
|
||||
}
|
||||
|
||||
// 获取目录详情
|
||||
func (s *DiskServer) GetDir(ctx context.Context, in *pb.IdentRequest) (*pb.CloudDiskDirItem, error) {
|
||||
return disk.GetDir(ctx, in)
|
||||
}
|
||||
|
||||
// 更新目录
|
||||
func (s *DiskServer) UpdateDir(ctx context.Context, in *pb.CloudDiskDirItem) (*pb.StatusReply, error) {
|
||||
return disk.UpdateDir(ctx, in)
|
||||
}
|
||||
|
||||
// 删除目录
|
||||
func (s *DiskServer) DeleteDir(ctx context.Context, in *pb.IdentRequest) (*pb.StatusReply, error) {
|
||||
return disk.DeleteDir(ctx, in)
|
||||
}
|
||||
|
||||
// 获取目录列表
|
||||
func (s *DiskServer) ListDirs(ctx context.Context, in *pb.FetchRequest) (*pb.ListDirsResponse, error) {
|
||||
return disk.ListDirs(ctx, in)
|
||||
}
|
||||
|
||||
// 获取目录树
|
||||
func (s *DiskServer) GetDirTree(ctx context.Context, in *pb.IdentRequest) (*pb.CloudDiskDirItem, error) {
|
||||
return disk.GetDirTree(ctx, in)
|
||||
}
|
||||
|
||||
// 移动目录
|
||||
func (s *DiskServer) MoveDir(ctx context.Context, in *pb.MoveDirRequest) (*pb.StatusReply, error) {
|
||||
return disk.MoveDir(ctx, in)
|
||||
}
|
||||
|
||||
// 上传文件
|
||||
func (s *DiskServer) UploadFile(ctx context.Context, in *pb.CloudDiskFileRequest) (*pb.StatusReply, error) {
|
||||
return disk.UploadFile(ctx, in)
|
||||
}
|
||||
|
||||
// 获取文件详情
|
||||
func (s *DiskServer) GetFile(ctx context.Context, in *pb.IdentRequest) (*pb.CloudDiskFileItem, error) {
|
||||
return disk.GetFile(ctx, in)
|
||||
}
|
||||
|
||||
// 更新文件
|
||||
func (s *DiskServer) UpdateFile(ctx context.Context, in *pb.CloudDiskFileItem) (*pb.StatusReply, error) {
|
||||
return disk.UpdateFile(ctx, in)
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
func (s *DiskServer) DeleteFile(ctx context.Context, in *pb.IdentRequest) (*pb.StatusReply, error) {
|
||||
return disk.DeleteFile(ctx, in)
|
||||
}
|
||||
|
||||
// 获取文件列表
|
||||
func (s *DiskServer) ListFiles(ctx context.Context, in *pb.FetchRequest) (*pb.ListFilesResponse, error) {
|
||||
return disk.ListFiles(ctx, in)
|
||||
}
|
||||
|
||||
// 移动文件
|
||||
func (s *DiskServer) MoveFile(ctx context.Context, in *pb.MoveFileRequest) (*pb.StatusReply, error) {
|
||||
return disk.MoveFile(ctx, in)
|
||||
}
|
||||
|
||||
// 复制文件
|
||||
func (s *DiskServer) CopyFile(ctx context.Context, in *pb.CopyFileRequest) (*pb.StatusReply, error) {
|
||||
return disk.CopyFile(ctx, in)
|
||||
}
|
||||
|
||||
// 搜索文件
|
||||
func (s *DiskServer) SearchFiles(ctx context.Context, in *pb.FetchRequest) (*pb.ListFilesResponse, error) {
|
||||
return disk.SearchFiles(ctx, in)
|
||||
}
|
||||
121
module/base/cloud/internal/server/new.go
Normal file
121
module/base/cloud/internal/server/new.go
Normal file
@@ -0,0 +1,121 @@
|
||||
// Code generated by protoc-gen-slc. DO NOT EDIT.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
"git.apinb.com/bsm-sdk/core/vars"
|
||||
gwRuntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/reflection"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Grpc *grpc.Server
|
||||
Ctx context.Context
|
||||
Mux *gwRuntime.ServeMux
|
||||
grpcConns map[string]*grpc.ClientConn // 连接池
|
||||
}
|
||||
|
||||
func New(addr string) *Server {
|
||||
srv := &Server{
|
||||
Ctx: context.Background(),
|
||||
Grpc: grpc.NewServer(),
|
||||
Mux: gwRuntime.NewServeMux(gwRuntime.WithForwardResponseRewriter(responseEnvelope)),
|
||||
grpcConns: make(map[string]*grpc.ClientConn),
|
||||
}
|
||||
|
||||
// register service to grpc.Server
|
||||
pb.RegisterAlbumServer(srv.Grpc, NewAlbumServer())
|
||||
pb.RegisterBookmarkServer(srv.Grpc, NewBookmarkServer())
|
||||
pb.RegisterDiskServer(srv.Grpc, NewDiskServer())
|
||||
pb.RegisterNoteServer(srv.Grpc, NewNoteServer())
|
||||
pb.RegisterPrivateServer(srv.Grpc, NewPrivateServer())
|
||||
pb.RegisterShareServer(srv.Grpc, NewShareServer())
|
||||
pb.RegisterSpaceServer(srv.Grpc, NewSpaceServer())
|
||||
|
||||
reflection.Register(srv.Grpc)
|
||||
|
||||
// 连接池: 只创建一次连接并复用
|
||||
conn, ok := srv.grpcConns[addr]
|
||||
if !ok {
|
||||
var err error
|
||||
conn, err = grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
panic("failed to dial grpc server: " + err.Error())
|
||||
}
|
||||
srv.grpcConns[addr] = conn
|
||||
}
|
||||
|
||||
// 将服务注册到Gateway
|
||||
|
||||
if err := pb.RegisterAlbumHandler(srv.Ctx, srv.Mux, conn); err != nil {
|
||||
panic("Failed to register Album handler: " + err.Error())
|
||||
}
|
||||
|
||||
if err := pb.RegisterBookmarkHandler(srv.Ctx, srv.Mux, conn); err != nil {
|
||||
panic("Failed to register Bookmark handler: " + err.Error())
|
||||
}
|
||||
|
||||
if err := pb.RegisterDiskHandler(srv.Ctx, srv.Mux, conn); err != nil {
|
||||
panic("Failed to register Disk handler: " + err.Error())
|
||||
}
|
||||
|
||||
if err := pb.RegisterNoteHandler(srv.Ctx, srv.Mux, conn); err != nil {
|
||||
panic("Failed to register Note handler: " + err.Error())
|
||||
}
|
||||
|
||||
if err := pb.RegisterPrivateHandler(srv.Ctx, srv.Mux, conn); err != nil {
|
||||
panic("Failed to register Private handler: " + err.Error())
|
||||
}
|
||||
|
||||
if err := pb.RegisterShareHandler(srv.Ctx, srv.Mux, conn); err != nil {
|
||||
panic("Failed to register Share handler: " + err.Error())
|
||||
}
|
||||
|
||||
if err := pb.RegisterSpaceHandler(srv.Ctx, srv.Mux, conn); err != nil {
|
||||
panic("Failed to register Space handler: " + err.Error())
|
||||
}
|
||||
|
||||
// Register services swagger
|
||||
srv.RegisterSwagger()
|
||||
|
||||
return srv
|
||||
}
|
||||
|
||||
// RegisterSwagger 注册swagger
|
||||
func (s *Server) RegisterSwagger() {
|
||||
srvKey := strings.ToLower(vars.ServiceKey)
|
||||
s.Mux.HandlePath("GET", "/"+srvKey+".swagger.json", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
bytes, err := os.ReadFile("./swagger/" + srvKey + ".swagger.json")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write(bytes)
|
||||
return
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// response envelope
|
||||
func responseEnvelope(_ context.Context, response proto.Message) (interface{}, error) {
|
||||
name := string(response.ProtoReflect().Descriptor().Name())
|
||||
if name == "Status" || name == "Error" || name == "StatusReply" {
|
||||
return response, nil
|
||||
}
|
||||
return map[string]any{
|
||||
"code": 0,
|
||||
"message": vars.OK,
|
||||
"details": response,
|
||||
"timeseq": time.Now().Unix(),
|
||||
}, nil
|
||||
}
|
||||
66
module/base/cloud/internal/server/note_server.go
Normal file
66
module/base/cloud/internal/server/note_server.go
Normal file
@@ -0,0 +1,66 @@
|
||||
// Code generated by protoc-gen-slc. DO NOT EDIT.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bsm/full/module/base/cloud/internal/logic/note"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
)
|
||||
|
||||
type NoteServer struct {
|
||||
pb.UnimplementedNoteServer
|
||||
}
|
||||
|
||||
func NewNoteServer() *NoteServer {
|
||||
return &NoteServer{}
|
||||
}
|
||||
|
||||
// 创建笔记
|
||||
func (s *NoteServer) CreateNote(ctx context.Context, in *pb.CreateNoteRequest) (*pb.StatusReply, error) {
|
||||
return note.CreateNote(ctx, in)
|
||||
}
|
||||
|
||||
// 获取笔记详情
|
||||
func (s *NoteServer) GetNote(ctx context.Context, in *pb.IdentRequest) (*pb.CloudNoteItem, error) {
|
||||
return note.GetNote(ctx, in)
|
||||
}
|
||||
|
||||
// 更新笔记
|
||||
func (s *NoteServer) UpdateNote(ctx context.Context, in *pb.CloudNoteItem) (*pb.StatusReply, error) {
|
||||
return note.UpdateNote(ctx, in)
|
||||
}
|
||||
|
||||
// 删除笔记
|
||||
func (s *NoteServer) DeleteNote(ctx context.Context, in *pb.IdentRequest) (*pb.StatusReply, error) {
|
||||
return note.DeleteNote(ctx, in)
|
||||
}
|
||||
|
||||
// 获取笔记列表
|
||||
func (s *NoteServer) ListNotes(ctx context.Context, in *pb.FetchRequest) (*pb.ListNotesResponse, error) {
|
||||
return note.ListNotes(ctx, in)
|
||||
}
|
||||
|
||||
// 置顶/取消置顶笔记
|
||||
func (s *NoteServer) TogglePin(ctx context.Context, in *pb.TogglePinRequest) (*pb.StatusReply, error) {
|
||||
return note.TogglePin(ctx, in)
|
||||
}
|
||||
|
||||
// 增加浏览次数
|
||||
func (s *NoteServer) IncrementViews(ctx context.Context, in *pb.IdentRequest) (*pb.StatusReply, error) {
|
||||
return note.IncrementViews(ctx, in)
|
||||
}
|
||||
|
||||
// 搜索笔记
|
||||
func (s *NoteServer) SearchNotes(ctx context.Context, in *pb.FetchRequest) (*pb.ListNotesResponse, error) {
|
||||
return note.SearchNotes(ctx, in)
|
||||
}
|
||||
|
||||
// 上传附件
|
||||
func (s *NoteServer) InsertAttachment(ctx context.Context, in *pb.NoteAttachmentItem) (*pb.StatusReply, error) {
|
||||
return note.InsertAttachment(ctx, in)
|
||||
}
|
||||
|
||||
// 删除附件
|
||||
func (s *NoteServer) DeleteAttachment(ctx context.Context, in *pb.IdentRequest) (*pb.StatusReply, error) {
|
||||
return note.DeleteAttachment(ctx, in)
|
||||
}
|
||||
61
module/base/cloud/internal/server/private_server.go
Normal file
61
module/base/cloud/internal/server/private_server.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Code generated by protoc-gen-slc. DO NOT EDIT.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bsm/full/module/base/cloud/internal/logic/private"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
)
|
||||
|
||||
type PrivateServer struct {
|
||||
pb.UnimplementedPrivateServer
|
||||
}
|
||||
|
||||
func NewPrivateServer() *PrivateServer {
|
||||
return &PrivateServer{}
|
||||
}
|
||||
|
||||
// 创建隐私数据
|
||||
func (s *PrivateServer) CreatePrivateData(ctx context.Context, in *pb.CreatePrivateDataRequest) (*pb.StatusReply, error) {
|
||||
return private.CreatePrivateData(ctx, in)
|
||||
}
|
||||
|
||||
// 获取隐私数据详情
|
||||
func (s *PrivateServer) GetPrivateData(ctx context.Context, in *pb.IdentRequest) (*pb.CloudPrivateItem, error) {
|
||||
return private.GetPrivateData(ctx, in)
|
||||
}
|
||||
|
||||
// 更新隐私数据
|
||||
func (s *PrivateServer) UpdatePrivateData(ctx context.Context, in *pb.CloudPrivateItem) (*pb.StatusReply, error) {
|
||||
return private.UpdatePrivateData(ctx, in)
|
||||
}
|
||||
|
||||
// 删除隐私数据
|
||||
func (s *PrivateServer) DeletePrivateData(ctx context.Context, in *pb.IdentRequest) (*pb.StatusReply, error) {
|
||||
return private.DeletePrivateData(ctx, in)
|
||||
}
|
||||
|
||||
// 获取隐私数据列表
|
||||
func (s *PrivateServer) ListPrivateData(ctx context.Context, in *pb.FetchRequest) (*pb.ListPrivateDataResponse, error) {
|
||||
return private.ListPrivateData(ctx, in)
|
||||
}
|
||||
|
||||
// 按类型获取隐私数据
|
||||
func (s *PrivateServer) GetPrivateDataByType(ctx context.Context, in *pb.FetchRequest) (*pb.ListPrivateDataResponse, error) {
|
||||
return private.GetPrivateDataByType(ctx, in)
|
||||
}
|
||||
|
||||
// 搜索隐私数据
|
||||
func (s *PrivateServer) SearchPrivateData(ctx context.Context, in *pb.FetchRequest) (*pb.ListPrivateDataResponse, error) {
|
||||
return private.SearchPrivateData(ctx, in)
|
||||
}
|
||||
|
||||
// 加密数据
|
||||
func (s *PrivateServer) EncryptData(ctx context.Context, in *pb.DataRequest) (*pb.StatusReply, error) {
|
||||
return private.EncryptData(ctx, in)
|
||||
}
|
||||
|
||||
// 解密数据
|
||||
func (s *PrivateServer) DecryptData(ctx context.Context, in *pb.DataRequest) (*pb.StatusReply, error) {
|
||||
return private.DecryptData(ctx, in)
|
||||
}
|
||||
41
module/base/cloud/internal/server/share_server.go
Normal file
41
module/base/cloud/internal/server/share_server.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Code generated by protoc-gen-slc. DO NOT EDIT.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bsm/full/module/base/cloud/internal/logic/share"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
)
|
||||
|
||||
type ShareServer struct {
|
||||
pb.UnimplementedShareServer
|
||||
}
|
||||
|
||||
func NewShareServer() *ShareServer {
|
||||
return &ShareServer{}
|
||||
}
|
||||
|
||||
// 创建分享
|
||||
func (s *ShareServer) CreateShare(ctx context.Context, in *pb.CreateShareRequest) (*pb.StatusReply, error) {
|
||||
return share.CreateShare(ctx, in)
|
||||
}
|
||||
|
||||
// 获取分享详情
|
||||
func (s *ShareServer) GetShare(ctx context.Context, in *pb.IdentRequest) (*pb.CloudShareItem, error) {
|
||||
return share.GetShare(ctx, in)
|
||||
}
|
||||
|
||||
// 删除分享
|
||||
func (s *ShareServer) DeleteShare(ctx context.Context, in *pb.IdentRequest) (*pb.StatusReply, error) {
|
||||
return share.DeleteShare(ctx, in)
|
||||
}
|
||||
|
||||
// 获取分享列表
|
||||
func (s *ShareServer) ListShares(ctx context.Context, in *pb.FetchRequest) (*pb.ListSharesResponse, error) {
|
||||
return share.ListShares(ctx, in)
|
||||
}
|
||||
|
||||
// 验证分享密码
|
||||
func (s *ShareServer) ValidateSharePassword(ctx context.Context, in *pb.ValidateSharePasswordRequest) (*pb.StatusReply, error) {
|
||||
return share.ValidateSharePassword(ctx, in)
|
||||
}
|
||||
26
module/base/cloud/internal/server/space_server.go
Normal file
26
module/base/cloud/internal/server/space_server.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// Code generated by protoc-gen-slc. DO NOT EDIT.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bsm/full/module/base/cloud/internal/logic/space"
|
||||
pb "bsm/full/module/base/cloud/pb"
|
||||
)
|
||||
|
||||
type SpaceServer struct {
|
||||
pb.UnimplementedSpaceServer
|
||||
}
|
||||
|
||||
func NewSpaceServer() *SpaceServer {
|
||||
return &SpaceServer{}
|
||||
}
|
||||
|
||||
// 获取空间数据
|
||||
func (s *SpaceServer) Get(ctx context.Context, in *pb.Empty) (*pb.CloudSpace, error) {
|
||||
return space.Get(ctx, in)
|
||||
}
|
||||
|
||||
// 获取空间数据
|
||||
func (s *SpaceServer) GetByKeyIdentifier(ctx context.Context, in *pb.IdentRequest) (*pb.CloudSpace, error) {
|
||||
return space.GetByKeyIdentifier(ctx, in)
|
||||
}
|
||||
Reference in New Issue
Block a user