feat: add biz layer with usecases for file, bucket, folder, share
Defines repo interfaces in biz (dependency inversion) implemented by data layer. Removes old domain layer replaced by data layer in previous commit.
This commit is contained in:
parent
bcd637387a
commit
4927de90cc
10
internal/biz/biz.go
Normal file
10
internal/biz/biz.go
Normal file
@ -0,0 +1,10 @@
|
||||
package biz
|
||||
|
||||
import "github.com/google/wire"
|
||||
|
||||
var ProviderSet = wire.NewSet(
|
||||
NewFileUsecase,
|
||||
NewBucketUsecase,
|
||||
NewFolderUsecase,
|
||||
NewShareUsecase,
|
||||
)
|
||||
36
internal/biz/bucket.go
Normal file
36
internal/biz/bucket.go
Normal file
@ -0,0 +1,36 @@
|
||||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
)
|
||||
|
||||
// BucketUsecase wraps FileRepo bucket operations.
|
||||
type BucketUsecase struct {
|
||||
repo FileRepo
|
||||
log *log.Helper
|
||||
}
|
||||
|
||||
// NewBucketUsecase creates a new BucketUsecase.
|
||||
func NewBucketUsecase(repo FileRepo, logger log.Logger) *BucketUsecase {
|
||||
return &BucketUsecase{
|
||||
repo: repo,
|
||||
log: log.NewHelper(logger),
|
||||
}
|
||||
}
|
||||
|
||||
// ListBuckets returns all bucket names.
|
||||
func (uc *BucketUsecase) ListBuckets(ctx context.Context) ([]string, error) {
|
||||
return uc.repo.ListBuckets(ctx)
|
||||
}
|
||||
|
||||
// CreateBucket creates a new S3 bucket.
|
||||
func (uc *BucketUsecase) CreateBucket(ctx context.Context, name string) error {
|
||||
return uc.repo.CreateBucket(ctx, name)
|
||||
}
|
||||
|
||||
// DeleteBucket deletes an S3 bucket.
|
||||
func (uc *BucketUsecase) DeleteBucket(ctx context.Context, name string) error {
|
||||
return uc.repo.DeleteBucket(ctx, name)
|
||||
}
|
||||
97
internal/biz/file.go
Normal file
97
internal/biz/file.go
Normal file
@ -0,0 +1,97 @@
|
||||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"rag/file-system/internal/data"
|
||||
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
)
|
||||
|
||||
// FileRepo defines the interface for S3 storage operations.
|
||||
type FileRepo interface {
|
||||
UploadFile(ctx context.Context, bucket, key string, fileData io.Reader) error
|
||||
DownloadFile(ctx context.Context, bucket, key string) (io.ReadCloser, error)
|
||||
ListBuckets(ctx context.Context) ([]string, error)
|
||||
CreateBucket(ctx context.Context, name string) error
|
||||
DeleteBucket(ctx context.Context, name string) error
|
||||
ListObjectsV2(ctx context.Context, bucket, prefix string, maxKeys int32, token *string) (*data.ListFilesResult, error)
|
||||
GeneratePresignedURL(ctx context.Context, bucket, key string, expiry time.Duration) (string, error)
|
||||
GetFileContent(ctx context.Context, bucket, key string) (string, error)
|
||||
DeleteFile(ctx context.Context, bucket, key string) error
|
||||
CreateMultipartUpload(ctx context.Context, bucket, key string) (string, error)
|
||||
UploadPart(ctx context.Context, bucket, key, uploadID string, partNumber int32, fileData io.Reader) (string, error)
|
||||
CompleteMultipartUpload(ctx context.Context, bucket, key, uploadID string, parts []data.Part) (string, error)
|
||||
AbortMultipartUpload(ctx context.Context, bucket, key, uploadID string) error
|
||||
}
|
||||
|
||||
// FileUsecase wraps FileRepo and provides file-level business operations.
|
||||
type FileUsecase struct {
|
||||
repo FileRepo
|
||||
log *log.Helper
|
||||
}
|
||||
|
||||
// NewFileUsecase creates a new FileUsecase.
|
||||
func NewFileUsecase(repo FileRepo, logger log.Logger) *FileUsecase {
|
||||
return &FileUsecase{
|
||||
repo: repo,
|
||||
log: log.NewHelper(logger),
|
||||
}
|
||||
}
|
||||
|
||||
// UploadFile uploads data to the specified bucket and key.
|
||||
func (uc *FileUsecase) UploadFile(ctx context.Context, bucket, key string, fileData io.Reader) error {
|
||||
return uc.repo.UploadFile(ctx, bucket, key, fileData)
|
||||
}
|
||||
|
||||
// DownloadFile downloads an object from S3.
|
||||
func (uc *FileUsecase) DownloadFile(ctx context.Context, bucket, key string) (io.ReadCloser, error) {
|
||||
return uc.repo.DownloadFile(ctx, bucket, key)
|
||||
}
|
||||
|
||||
// GetFileContent retrieves text content for preview.
|
||||
func (uc *FileUsecase) GetFileContent(ctx context.Context, bucket, key string) (string, error) {
|
||||
return uc.repo.GetFileContent(ctx, bucket, key)
|
||||
}
|
||||
|
||||
// DeleteFile removes a file from S3.
|
||||
func (uc *FileUsecase) DeleteFile(ctx context.Context, bucket, key string) error {
|
||||
return uc.repo.DeleteFile(ctx, bucket, key)
|
||||
}
|
||||
|
||||
// ListObjectsV2 lists files with pagination support.
|
||||
func (uc *FileUsecase) ListObjectsV2(ctx context.Context, bucket, prefix string, maxKeys int32, token *string) (*data.ListFilesResult, error) {
|
||||
return uc.repo.ListObjectsV2(ctx, bucket, prefix, maxKeys, token)
|
||||
}
|
||||
|
||||
// GeneratePresignedURL generates a presigned URL with custom expiry.
|
||||
func (uc *FileUsecase) GeneratePresignedURL(ctx context.Context, bucket, key string, expiry time.Duration) (string, error) {
|
||||
return uc.repo.GeneratePresignedURL(ctx, bucket, key, expiry)
|
||||
}
|
||||
|
||||
// GetPreviewURL generates a presigned URL with 24h expiry for file preview.
|
||||
func (uc *FileUsecase) GetPreviewURL(ctx context.Context, bucket, key string) (string, error) {
|
||||
return uc.repo.GeneratePresignedURL(ctx, bucket, key, 24*time.Hour)
|
||||
}
|
||||
|
||||
// CreateMultipartUpload initializes a multipart upload session.
|
||||
func (uc *FileUsecase) CreateMultipartUpload(ctx context.Context, bucket, key string) (string, error) {
|
||||
return uc.repo.CreateMultipartUpload(ctx, bucket, key)
|
||||
}
|
||||
|
||||
// UploadPart uploads a single part of a multipart upload.
|
||||
func (uc *FileUsecase) UploadPart(ctx context.Context, bucket, key, uploadID string, partNumber int32, fileData io.Reader) (string, error) {
|
||||
return uc.repo.UploadPart(ctx, bucket, key, uploadID, partNumber, fileData)
|
||||
}
|
||||
|
||||
// CompleteMultipartUpload assembles all parts to complete the upload.
|
||||
func (uc *FileUsecase) CompleteMultipartUpload(ctx context.Context, bucket, key, uploadID string, parts []data.Part) (string, error) {
|
||||
return uc.repo.CompleteMultipartUpload(ctx, bucket, key, uploadID, parts)
|
||||
}
|
||||
|
||||
// AbortMultipartUpload cancels an in-progress multipart upload.
|
||||
func (uc *FileUsecase) AbortMultipartUpload(ctx context.Context, bucket, key, uploadID string) error {
|
||||
return uc.repo.AbortMultipartUpload(ctx, bucket, key, uploadID)
|
||||
}
|
||||
155
internal/biz/folder.go
Normal file
155
internal/biz/folder.go
Normal file
@ -0,0 +1,155 @@
|
||||
package biz
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"rag/file-system/internal/data"
|
||||
"rag/file-system/internal/pkg/sanitize"
|
||||
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// FolderRepo defines the interface for folder persistence operations.
|
||||
type FolderRepo interface {
|
||||
Create(ctx context.Context, folder *data.FolderPO) error
|
||||
GetByID(ctx context.Context, id string) (*data.FolderPO, error)
|
||||
GetWithChildren(ctx context.Context, id, ownerID string) (*data.FolderWithChildren, error)
|
||||
GetTree(ctx context.Context, ownerID string) ([]data.FolderPO, error)
|
||||
Update(ctx context.Context, folder *data.FolderPO) error
|
||||
Delete(ctx context.Context, id, ownerID string) error
|
||||
GetDescendantFileS3Keys(ctx context.Context, id, ownerID string) ([]data.FileMetaPO, error)
|
||||
}
|
||||
|
||||
// FileMetaRepo defines the interface for file metadata persistence operations.
|
||||
type FileMetaRepo interface {
|
||||
Create(ctx context.Context, file *data.FileMetaPO) error
|
||||
GetByID(ctx context.Context, id string) (*data.FileMetaPO, error)
|
||||
GetByFolder(ctx context.Context, folderID string) ([]data.FileMetaPO, error)
|
||||
Move(ctx context.Context, fileID, targetFolderID, ownerID string) error
|
||||
Delete(ctx context.Context, id, ownerID string) error
|
||||
}
|
||||
|
||||
// FolderUsecase handles folder and file metadata business logic.
|
||||
type FolderUsecase struct {
|
||||
folderRepo FolderRepo
|
||||
fileRepo FileMetaRepo
|
||||
s3Repo FileRepo
|
||||
log *log.Helper
|
||||
}
|
||||
|
||||
// NewFolderUsecase creates a new FolderUsecase.
|
||||
func NewFolderUsecase(folderRepo FolderRepo, fileRepo FileMetaRepo, s3Repo FileRepo, logger log.Logger) *FolderUsecase {
|
||||
return &FolderUsecase{
|
||||
folderRepo: folderRepo,
|
||||
fileRepo: fileRepo,
|
||||
s3Repo: s3Repo,
|
||||
log: log.NewHelper(logger),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateFolder creates a new folder under the given parent.
|
||||
func (uc *FolderUsecase) CreateFolder(ctx context.Context, parentID *string, name, ownerID string) (*data.FolderPO, error) {
|
||||
folder := &data.FolderPO{
|
||||
ParentID: parentID,
|
||||
Name: sanitize.Filename(name),
|
||||
OwnerID: ownerID,
|
||||
}
|
||||
if err := uc.folderRepo.Create(ctx, folder); err != nil {
|
||||
return nil, fmt.Errorf("failed to create folder: %w", err)
|
||||
}
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
// GetFolder retrieves a folder with its children (sub-folders and files).
|
||||
func (uc *FolderUsecase) GetFolder(ctx context.Context, id, ownerID string) (*data.FolderPO, []data.FolderPO, []data.FileMetaPO, error) {
|
||||
result, err := uc.folderRepo.GetWithChildren(ctx, id, ownerID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to get folder: %w", err)
|
||||
}
|
||||
if result == nil {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
return &result.Folder, result.SubFolders, result.Files, nil
|
||||
}
|
||||
|
||||
// GetFolderTree retrieves all folders owned by the given owner.
|
||||
func (uc *FolderUsecase) GetFolderTree(ctx context.Context, ownerID string) ([]data.FolderPO, error) {
|
||||
return uc.folderRepo.GetTree(ctx, ownerID)
|
||||
}
|
||||
|
||||
// RenameFolder updates a folder's name.
|
||||
func (uc *FolderUsecase) RenameFolder(ctx context.Context, id, name, ownerID string) (*data.FolderPO, error) {
|
||||
folder, err := uc.folderRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get folder: %w", err)
|
||||
}
|
||||
if folder == nil || folder.OwnerID != ownerID {
|
||||
return nil, fmt.Errorf("folder not found or not owned by user")
|
||||
}
|
||||
folder.Name = sanitize.Filename(name)
|
||||
folder.UpdatedAt = time.Now().UTC()
|
||||
if err := uc.folderRepo.Update(ctx, folder); err != nil {
|
||||
return nil, fmt.Errorf("failed to rename folder: %w", err)
|
||||
}
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
// DeleteFolder deletes a folder and all descendant files from both S3 and the database.
|
||||
func (uc *FolderUsecase) DeleteFolder(ctx context.Context, id, ownerID string) error {
|
||||
// First, get all descendant file S3 keys so we can delete from S3.
|
||||
files, err := uc.folderRepo.GetDescendantFileS3Keys(ctx, id, ownerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get descendant files: %w", err)
|
||||
}
|
||||
|
||||
// Delete each file from S3.
|
||||
for _, f := range files {
|
||||
if delErr := uc.s3Repo.DeleteFile(ctx, f.S3Bucket, f.S3Key); delErr != nil {
|
||||
uc.log.Errorf("failed to delete S3 object %s/%s: %v", f.S3Bucket, f.S3Key, delErr)
|
||||
// Continue deleting other files even if one fails.
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the folder record (cascade should handle child files in DB).
|
||||
if err := uc.folderRepo.Delete(ctx, id, ownerID); err != nil {
|
||||
return fmt.Errorf("failed to delete folder: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UploadToFolder uploads a file to a folder: generates a UUID S3 key, uploads to S3, saves metadata.
|
||||
func (uc *FolderUsecase) UploadToFolder(ctx context.Context, folderID, fileName string, fileData []byte, contentType, ownerID string) (*data.FileMetaPO, error) {
|
||||
s3Key := uuid.New().String()
|
||||
safeName := sanitize.Filename(fileName)
|
||||
bucket := "files" // Default bucket for folder-based uploads.
|
||||
|
||||
if err := uc.s3Repo.UploadFile(ctx, bucket, s3Key, bytes.NewReader(fileData)); err != nil {
|
||||
return nil, fmt.Errorf("failed to upload file to S3: %w", err)
|
||||
}
|
||||
|
||||
meta := &data.FileMetaPO{
|
||||
FolderID: folderID,
|
||||
Name: safeName,
|
||||
S3Key: s3Key,
|
||||
S3Bucket: bucket,
|
||||
Size: int64(len(fileData)),
|
||||
ContentType: contentType,
|
||||
OwnerID: ownerID,
|
||||
}
|
||||
if err := uc.fileRepo.Create(ctx, meta); err != nil {
|
||||
// Attempt to clean up the S3 object on metadata save failure.
|
||||
_ = uc.s3Repo.DeleteFile(ctx, bucket, s3Key)
|
||||
return nil, fmt.Errorf("failed to save file metadata: %w", err)
|
||||
}
|
||||
return meta, nil
|
||||
}
|
||||
|
||||
// MoveFile moves a file from one folder to another.
|
||||
func (uc *FolderUsecase) MoveFile(ctx context.Context, fileID, targetFolderID, ownerID string) error {
|
||||
return uc.fileRepo.Move(ctx, fileID, targetFolderID, ownerID)
|
||||
}
|
||||
|
||||
146
internal/biz/share.go
Normal file
146
internal/biz/share.go
Normal file
@ -0,0 +1,146 @@
|
||||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"rag/file-system/internal/data"
|
||||
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
)
|
||||
|
||||
// ShareRepo defines the interface for share link persistence operations.
|
||||
type ShareRepo interface {
|
||||
Create(ctx context.Context, share *data.ShareLinkPO) error
|
||||
GetByToken(ctx context.Context, token string) (*data.ShareLinkPO, error)
|
||||
GetByID(ctx context.Context, id string) (*data.ShareLinkPO, error)
|
||||
Delete(ctx context.Context, id, createdBy string) error
|
||||
IncrementDownloadCount(ctx context.Context, token string) error
|
||||
ListByResource(ctx context.Context, resourceType, resourceID string) ([]data.ShareLinkPO, error)
|
||||
}
|
||||
|
||||
// FileMetaRepoForShare is a minimal interface for share usecase to look up file metadata.
|
||||
type FileMetaRepoForShare interface {
|
||||
GetByID(ctx context.Context, id string) (*data.FileMetaPO, error)
|
||||
}
|
||||
|
||||
// ShareUsecase handles share link business logic.
|
||||
type ShareUsecase struct {
|
||||
shareRepo ShareRepo
|
||||
fileRepo FileMetaRepoForShare
|
||||
s3Repo FileRepo
|
||||
log *log.Helper
|
||||
}
|
||||
|
||||
// NewShareUsecase creates a new ShareUsecase.
|
||||
func NewShareUsecase(shareRepo ShareRepo, fileRepo FileMetaRepoForShare, s3Repo FileRepo, logger log.Logger) *ShareUsecase {
|
||||
return &ShareUsecase{
|
||||
shareRepo: shareRepo,
|
||||
fileRepo: fileRepo,
|
||||
s3Repo: s3Repo,
|
||||
log: log.NewHelper(logger),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateShare creates a new share link with a random token.
|
||||
func (uc *ShareUsecase) CreateShare(ctx context.Context, resourceType, resourceID, password string, expiresAt *time.Time, maxDownloads *int, createdBy string) (*data.ShareLinkPO, error) {
|
||||
token, err := generateToken(16)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate share token: %w", err)
|
||||
}
|
||||
|
||||
share := &data.ShareLinkPO{
|
||||
ResourceType: resourceType,
|
||||
ResourceID: resourceID,
|
||||
Token: token,
|
||||
ExpiresAt: expiresAt,
|
||||
MaxDownloads: maxDownloads,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
if password != "" {
|
||||
pwd := password
|
||||
share.Password = &pwd
|
||||
}
|
||||
|
||||
if err := uc.shareRepo.Create(ctx, share); err != nil {
|
||||
return nil, fmt.Errorf("failed to create share link: %w", err)
|
||||
}
|
||||
return share, nil
|
||||
}
|
||||
|
||||
// DeleteShare removes a share link by ID and creator.
|
||||
func (uc *ShareUsecase) DeleteShare(ctx context.Context, id, createdBy string) error {
|
||||
return uc.shareRepo.Delete(ctx, id, createdBy)
|
||||
}
|
||||
|
||||
// GetShareInfo retrieves share details and the associated file metadata.
|
||||
func (uc *ShareUsecase) GetShareInfo(ctx context.Context, token string) (*data.ShareLinkPO, *data.FileMetaPO, error) {
|
||||
share, err := uc.shareRepo.GetByToken(ctx, token)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get share link: %w", err)
|
||||
}
|
||||
if share == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
fileMeta, err := uc.fileRepo.GetByID(ctx, share.ResourceID)
|
||||
if err != nil {
|
||||
return share, nil, fmt.Errorf("failed to get file metadata: %w", err)
|
||||
}
|
||||
return share, fileMeta, nil
|
||||
}
|
||||
|
||||
// DownloadShare validates the share link, increments download count, and returns a presigned URL + filename.
|
||||
func (uc *ShareUsecase) DownloadShare(ctx context.Context, token string) (string, string, error) {
|
||||
share, err := uc.shareRepo.GetByToken(ctx, token)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get share link: %w", err)
|
||||
}
|
||||
if share == nil {
|
||||
return "", "", fmt.Errorf("share link not found")
|
||||
}
|
||||
|
||||
// Check expiry.
|
||||
if share.ExpiresAt != nil && share.ExpiresAt.Before(time.Now().UTC()) {
|
||||
return "", "", fmt.Errorf("share link has expired")
|
||||
}
|
||||
|
||||
// Check max downloads.
|
||||
if share.MaxDownloads != nil && share.DownloadCount >= *share.MaxDownloads {
|
||||
return "", "", fmt.Errorf("download limit reached")
|
||||
}
|
||||
|
||||
// Get file metadata for bucket/key info.
|
||||
fileMeta, err := uc.fileRepo.GetByID(ctx, share.ResourceID)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get file metadata: %w", err)
|
||||
}
|
||||
if fileMeta == nil {
|
||||
return "", "", fmt.Errorf("file not found")
|
||||
}
|
||||
|
||||
// Generate presigned URL.
|
||||
url, err := uc.s3Repo.GeneratePresignedURL(ctx, fileMeta.S3Bucket, fileMeta.S3Key, 15*time.Minute)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to generate download URL: %w", err)
|
||||
}
|
||||
|
||||
// Increment download count.
|
||||
if err := uc.shareRepo.IncrementDownloadCount(ctx, token); err != nil {
|
||||
uc.log.Errorf("failed to increment download count for token %s: %v", token, err)
|
||||
}
|
||||
|
||||
return url, fileMeta.Name, nil
|
||||
}
|
||||
|
||||
// generateToken creates a cryptographically secure random hex token.
|
||||
func generateToken(byteLen int) (string, error) {
|
||||
b := make([]byte, byteLen)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(b), nil
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type FileMeta struct {
|
||||
ID string
|
||||
FolderID string
|
||||
Name string
|
||||
S3Key string
|
||||
S3Bucket string
|
||||
Size int64
|
||||
ContentType string
|
||||
OwnerID string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Folder struct {
|
||||
ID string
|
||||
ParentID *string
|
||||
Name string
|
||||
OwnerID string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type FolderWithChildren struct {
|
||||
Folder Folder
|
||||
SubFolders []Folder
|
||||
Files []FileMeta
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type ShareLink struct {
|
||||
ID string
|
||||
ResourceType string
|
||||
ResourceID string
|
||||
Token string
|
||||
Password *string
|
||||
ExpiresAt *time.Time
|
||||
DownloadCount int
|
||||
MaxDownloads *int
|
||||
CreatedBy string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type ShareInfo struct {
|
||||
Token string
|
||||
ResourceType string
|
||||
FileName string
|
||||
FileSize int64
|
||||
HasPassword bool
|
||||
ExpiresAt *time.Time
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"rag/file-system/internal/domain/model"
|
||||
)
|
||||
|
||||
type FileMetaRepository interface {
|
||||
Create(ctx context.Context, file *model.FileMeta) error
|
||||
GetByID(ctx context.Context, id string) (*model.FileMeta, error)
|
||||
GetByFolder(ctx context.Context, folderID string) ([]model.FileMeta, error)
|
||||
Move(ctx context.Context, fileID string, targetFolderID string, ownerID string) error
|
||||
Delete(ctx context.Context, id string, ownerID string) error
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"rag/file-system/internal/common"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FileInfo struct {
|
||||
Key string
|
||||
Size int64
|
||||
LastModified time.Time
|
||||
ETag string
|
||||
}
|
||||
|
||||
type ListFilesResult struct {
|
||||
Files []FileInfo
|
||||
NextContinuationToken *string
|
||||
}
|
||||
|
||||
type FileRepository interface {
|
||||
UploadFile(ctx context.Context, bucketName string, objectKey string, data io.Reader) error
|
||||
DownloadFile(ctx context.Context, bucketName string, objectKey string) (io.ReadCloser, error)
|
||||
ListBuckets(ctx context.Context) ([]string, error)
|
||||
CreateBucket(ctx context.Context, bucketName string) error
|
||||
DeleteBucket(ctx context.Context, bucketName string) error
|
||||
|
||||
// File listing with pagination
|
||||
ListObjectsV2(ctx context.Context, bucketName string, prefix string, maxKeys int32, continuationToken *string) (*ListFilesResult, error)
|
||||
GeneratePresignedURL(ctx context.Context, bucketName string, objectKey string, expiry time.Duration) (string, error)
|
||||
|
||||
// File content retrieval for text preview
|
||||
GetFileContent(ctx context.Context, bucketName string, objectKey string) (string, error)
|
||||
|
||||
// File deletion
|
||||
DeleteFile(ctx context.Context, bucketName string, objectKey string) error
|
||||
|
||||
// Multipart upload
|
||||
CreateMultipartUpload(ctx context.Context, bucketName string, objectKey string) (string, error)
|
||||
UploadPart(ctx context.Context, bucketName string, objectKey string, uploadId string, partNumber int32, data io.Reader) (string, error)
|
||||
CompleteMultipartUpload(ctx context.Context, bucketName string, objectKey string, uploadId string, parts []common.Part) (string, error)
|
||||
AbortMultipartUpload(ctx context.Context, bucketName string, objectKey string, uploadId string) error
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"rag/file-system/internal/domain/model"
|
||||
)
|
||||
|
||||
type FolderRepository interface {
|
||||
Create(ctx context.Context, folder *model.Folder) error
|
||||
GetByID(ctx context.Context, id string) (*model.Folder, error)
|
||||
GetWithChildren(ctx context.Context, id string, ownerID string) (*model.FolderWithChildren, error)
|
||||
GetTree(ctx context.Context, ownerID string) ([]model.Folder, error)
|
||||
Update(ctx context.Context, folder *model.Folder) error
|
||||
Delete(ctx context.Context, id string, ownerID string) error
|
||||
GetDescendantFileS3Keys(ctx context.Context, id string, ownerID string) ([]model.FileMeta, error)
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"rag/file-system/internal/domain/model"
|
||||
)
|
||||
|
||||
type ShareRepository interface {
|
||||
Create(ctx context.Context, share *model.ShareLink) error
|
||||
GetByToken(ctx context.Context, token string) (*model.ShareLink, error)
|
||||
GetByID(ctx context.Context, id string) (*model.ShareLink, error)
|
||||
Delete(ctx context.Context, id string, createdBy string) error
|
||||
IncrementDownloadCount(ctx context.Context, token string) error
|
||||
ListByResource(ctx context.Context, resourceType string, resourceID string) ([]model.ShareLink, error)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user