- PostgreSQL metadata overlay layer on top of existing S3 storage - 3 new tables: folders, files, share_links - Folder CRUD: create, get with children, tree, rename, delete (cascade) - File operations: upload to folder, move between folders - Share links: create with optional password/expiry/download limit, public access - S3 compensation on PG write failure - Existing 14 endpoints untouched
85 lines
1.9 KiB
Go
85 lines
1.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"time"
|
|
|
|
"rag/file-system/internal/domain/model"
|
|
"rag/file-system/internal/domain/repository"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type CreateShareCommand struct {
|
|
ResourceType string
|
|
ResourceID string
|
|
Password *string
|
|
ExpiresAt *time.Time
|
|
MaxDownloads *int
|
|
CreatedBy string
|
|
}
|
|
|
|
type DeleteShareCommand struct {
|
|
ShareID string
|
|
CreatedBy string
|
|
}
|
|
|
|
type CreateShareHandler struct {
|
|
ShareRepo repository.ShareRepository
|
|
}
|
|
|
|
func NewCreateShareHandler(shareRepo repository.ShareRepository) *CreateShareHandler {
|
|
return &CreateShareHandler{ShareRepo: shareRepo}
|
|
}
|
|
|
|
func (h *CreateShareHandler) Handle(ctx context.Context, cmd CreateShareCommand) (*model.ShareLink, error) {
|
|
token, err := generateShareToken()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to generate token: %w", err)
|
|
}
|
|
|
|
share := &model.ShareLink{
|
|
ID: uuid.New().String(),
|
|
ResourceType: cmd.ResourceType,
|
|
ResourceID: cmd.ResourceID,
|
|
Token: token,
|
|
Password: cmd.Password,
|
|
ExpiresAt: cmd.ExpiresAt,
|
|
DownloadCount: 0,
|
|
MaxDownloads: cmd.MaxDownloads,
|
|
CreatedBy: cmd.CreatedBy,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
|
|
if err := h.ShareRepo.Create(ctx, share); err != nil {
|
|
return nil, err
|
|
}
|
|
return share, nil
|
|
}
|
|
|
|
type DeleteShareHandler struct {
|
|
ShareRepo repository.ShareRepository
|
|
}
|
|
|
|
func NewDeleteShareHandler(shareRepo repository.ShareRepository) *DeleteShareHandler {
|
|
return &DeleteShareHandler{ShareRepo: shareRepo}
|
|
}
|
|
|
|
func (h *DeleteShareHandler) Handle(ctx context.Context, cmd DeleteShareCommand) (string, error) {
|
|
if err := h.ShareRepo.Delete(ctx, cmd.ShareID, cmd.CreatedBy); err != nil {
|
|
return "", err
|
|
}
|
|
return "分享已取消", nil
|
|
}
|
|
|
|
func generateShareToken() (string, error) {
|
|
b := make([]byte, 16)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(b), nil
|
|
}
|