Files
2026-07-16 22:16:45 +07:00

243 lines
9.2 KiB
Go

package filemanager
import (
"context"
"errors"
"io"
"time"
)
const (
SystemRootFolderName = "__system_root_files__"
)
var (
ErrDuplicateName = errors.New("duplicate name in target folder")
ErrInvalidMove = errors.New("invalid folder move")
ErrFolderNotFound = errors.New("folder not found")
ErrFileNotFound = errors.New("file not found")
ErrFileAlreadyFinalized = errors.New("file already finalized")
ErrFileNotEligibleForFinalize = errors.New("file is not eligible for finalize")
ErrInvalidFileStatusTransition = errors.New("invalid file status transition")
ErrFileStatusConflict = errors.New("file status conflict")
ErrStorageUnavailable = errors.New("storage unavailable")
ErrFolderNotEmpty = errors.New("folder is not empty")
ErrFolderNotInTrash = errors.New("folder is not in trash")
ErrFileNotInTrash = errors.New("file is not in trash")
ErrInvalidName = errors.New("invalid name")
ErrReservedName = errors.New("reserved name")
ErrFileTooLarge = errors.New("file too large")
ErrFileMimeTypeNotAllowed = errors.New("file mime type is not allowed")
ErrFileExtensionNotAllowed = errors.New("file extension is not allowed")
ErrEmptyFileNotAllowed = errors.New("empty file is not allowed")
ErrFileNameTooLong = errors.New("file name exceeds maximum length")
ErrFileProcessingQueueDisabled = errors.New("file processing queue is not configured")
ErrUploadIntentRepositoryDisabled = errors.New("file upload intent repository is not configured")
ErrUploadIntentNotFound = errors.New("upload intent not found")
ErrUploadIntentExpired = errors.New("upload intent is expired")
ErrUploadIntentAlreadyComplete = errors.New("upload intent already completed")
ErrUploadIntentStatusConflict = errors.New("upload intent status conflict")
ErrUploadObjectNotFound = errors.New("uploaded object not found in storage")
ErrUploadObjectMismatch = errors.New("uploaded object does not match upload intent")
ErrAttachmentRepositoryDisabled = errors.New("attachment repository is not configured")
ErrAttachmentNotFound = errors.New("attachment not found")
ErrAttachmentAlreadyExists = errors.New("attachment already exists for this reference")
ErrAttachmentRefRequired = errors.New("attachment ref_type and ref_id are required")
ErrFileNotReadyForAttachment = errors.New("file is not ready for attachment")
)
type FileUploadPolicy struct {
MaxFileSizeBytes int64
AllowedMimeTypes []string
AllowedExtensions []string
AllowEmptyFile bool
MaxFilenameLength int
}
type FileProcessingJob struct {
JobID string
FileUUID string
Bucket string
ObjectKey string
UploadedBy string
MimeType string
SizeBytes int64
TraceID string
RequestID string
}
type FileProcessingQueue interface {
Enqueue(ctx context.Context, job FileProcessingJob) error
}
type CreateFolderParams struct {
Name string
ParentID []byte
ActorID []byte
}
type MoveFolderParams struct {
Name *string
ParentID []byte
ParentProvided bool
ActorID []byte
}
type UploadFileParams struct {
Name string
ContentType string
SizeBytes int64
Body io.Reader
ActorID []byte
IsTemplate bool
}
type RequestFileUploadIntentParams struct {
Name string
ContentType string
SizeBytes int64
ActorID []byte
}
type FileUploadIntentGrant struct {
UploadIntentID []byte
Bucket string
ObjectKey string
Name string
MimeType string
SizeBytes int64
Method string
UploadURL string
Headers map[string]string
ExpiresAt time.Time
}
type CompleteFileUploadIntentParams struct {
UploadIntentID []byte
ActorID []byte
}
type CancelFileUploadIntentParams struct {
UploadIntentID []byte
ActorID []byte
}
type CreateFileFromUploadParams struct {
UploadFileID []byte
FolderID []byte
FolderProvided bool
Name *string
ActorID []byte
IsTemplate bool
}
type CreateFileFromUploadIntentParams struct {
UploadIntentID []byte
FolderID []byte
FolderProvided bool
Name string
ActorID []byte
IsTemplate bool
}
type BulkFileNodeResult struct {
Index int
File *File
Err error
}
type MoveFileParams struct {
Name *string
FolderID []byte
FolderProvided bool
ActorID []byte
}
type CreateAttachmentParams struct {
FileID []byte
RefType string
RefID string
Category *string
SortOrder int
IsPrimary bool
ActorID []byte
}
type ListAttachmentsParams struct {
RefType string
RefID string
Category *string
Sort string
Limit int
Offset int
}
type FileCleanupStats struct {
Scanned int
Deleted int
Skipped int
Failed int
DryRun bool
}
// LifecycleManager is an optional extension implemented by concrete services
// to expose file lifecycle transitions without widening the base Service
// interface used by existing handlers/tests.
type LifecycleManager interface {
MarkFileActive(ctx context.Context, fileID []byte, actorID []byte) error
ReconcileFileLifecycle(ctx context.Context, fileID []byte, actorID []byte) error
CleanupOrphanPendingFiles(ctx context.Context, now time.Time, gracePeriod time.Duration, limit int, dryRun bool) (FileCleanupStats, error)
}
type Service interface {
SetObjectStorage(storage ObjectStorage)
SetUploadPolicy(policy FileUploadPolicy)
SetFileProcessingQueue(fileQueue FileProcessingQueue)
SetFileUploadIntentRepository(repo FileUploadIntentRepository)
RequestFileUploadIntent(ctx context.Context, params RequestFileUploadIntentParams) (*FileUploadIntentGrant, error)
CompleteFileUploadIntent(ctx context.Context, params CompleteFileUploadIntentParams) (*File, error)
CancelFileUploadIntent(ctx context.Context, params CancelFileUploadIntentParams) error
CreateFileNodeFromUploadIntent(ctx context.Context, params CreateFileFromUploadIntentParams) (*File, error)
GetOrCreateSystemRootFolder(ctx context.Context) (*Folder, error)
CreateFolderNode(ctx context.Context, params CreateFolderParams) (*Folder, error)
MoveFolderNode(ctx context.Context, id []byte, params MoveFolderParams) (*Folder, error)
UploadFileNode(ctx context.Context, params UploadFileParams) (*File, error)
CreateFileNodeFromUpload(ctx context.Context, params CreateFileFromUploadParams) (*File, error)
UploadFileNodesBulk(ctx context.Context, params []UploadFileParams) []BulkFileNodeResult
CreateFileNodesFromUploadBulk(ctx context.Context, params []CreateFileFromUploadParams) []BulkFileNodeResult
MoveFileNode(ctx context.Context, id []byte, params MoveFileParams) (*File, error)
PurgeFolderNode(ctx context.Context, id []byte) error
PurgeFileNode(ctx context.Context, id []byte) error
ListNodesByParent(ctx context.Context, parentID []byte) ([]Folder, []File, error)
SearchNodes(ctx context.Context, query string) ([]Folder, []File, error)
ListTrashNodes(ctx context.Context) ([]Folder, []File, error)
CreateFolder(ctx context.Context, row *Folder) error
UpdateFolder(ctx context.Context, row *Folder) error
DeleteFolder(ctx context.Context, id []byte, deletedBy []byte, purgeAt *time.Time) error
RestoreFolder(ctx context.Context, id []byte, targetParentID []byte, targetProvided bool, restoredBy []byte) error
PurgeFolder(ctx context.Context, id []byte) error
GetFolderByID(ctx context.Context, id []byte) (*Folder, error)
GetFolderByIDAny(ctx context.Context, id []byte) (*Folder, error)
GetFolderByParentAndName(ctx context.Context, parentID []byte, nameNormalized string) (*Folder, error)
ListFoldersByParent(ctx context.Context, parentID []byte, sort string, limit, offset int) ([]Folder, int64, error)
ListTrashFoldersByParent(ctx context.Context, parentID []byte, sort string, limit, offset int) ([]Folder, int64, error)
CreateFile(ctx context.Context, row *File) error
UpdateFile(ctx context.Context, row *File) error
DeleteFile(ctx context.Context, id []byte, deletedBy []byte, purgeAt *time.Time) error
RestoreFile(ctx context.Context, id []byte, targetFolderID []byte, targetProvided bool, restoredBy []byte) error
PurgeFile(ctx context.Context, id []byte) error
GetFileByID(ctx context.Context, id []byte) (*File, error)
GetFileByIDAny(ctx context.Context, id []byte) (*File, error)
GetFileByObjectKey(ctx context.Context, objectKey string) (*File, error)
GetFileByFolderAndName(ctx context.Context, folderID []byte, nameNormalized string) (*File, error)
ListFilesByFolder(ctx context.Context, folderID []byte, sort string, limit, offset int) ([]File, int64, error)
ListTrashFilesByFolder(ctx context.Context, folderID []byte, sort string, limit, offset int) ([]File, int64, error)
CreateAttachment(ctx context.Context, params CreateAttachmentParams) (*Attachment, error)
GetAttachmentByID(ctx context.Context, id []byte) (*Attachment, error)
ListAttachmentsByReference(ctx context.Context, params ListAttachmentsParams) ([]Attachment, int64, error)
DeleteAttachment(ctx context.Context, id []byte) error
ListEditedWBFilesByTakeoverID(ctx context.Context, takeoverID []byte) ([]File, error)
}