refactor: reorganize modules and add Linux build tooling

This commit is contained in:
2026-08-09 12:41:08 +08:00
parent 86024fa81d
commit 5cc5fd92ed
1461 changed files with 4054 additions and 4724 deletions

View 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)
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View File

@@ -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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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(&note).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(&note).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
}

View 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(&note).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
}

View 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(&note).Error; err != nil {
printer.Error("Note not found: %v", err)
return nil, errcode.ErrInvalidArgument
}
// 增加浏览次数
note.Views++
if err := impl.DBService.Save(&note).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
}

View 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(&note).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
}

View 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(&notes).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
}

View 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(&notes).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
}

View 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(&note).Error; err != nil {
printer.Error("Note not found: %v", err)
return nil, errcode.ErrInvalidArgument
}
// 更新置顶状态
note.IsPinned = in.IsPinned
if err := impl.DBService.Save(&note).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
}

View 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(&note).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(&note).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
}

View File

@@ -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
}

View 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
}

View File

@@ -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
}

View 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
}

View 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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View 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
}

View 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
}

View 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
}

View 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
}

View File

@@ -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
}

View 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(&noteCount)
// 统计书签数量
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
}

View 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(&noteCount)
// 统计书签数量
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
}

View 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{})
}

View 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{})
}

View 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{})
}

View 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{})
}

View 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{})
}

View 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{})
}

View 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{})
}

View 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{})
}

View 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{})
}

View 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{})
}

View 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
}

View 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)
}

View 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)
}

View 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)
}

View 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
}

View 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)
}

View 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)
}

View 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)
}

View 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)
}