初始化
This commit is contained in:
356
server/controller/file_controller.go
Normal file
356
server/controller/file_controller.go
Normal file
@@ -0,0 +1,356 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"seeyon-filesystem/dto"
|
||||
"seeyon-filesystem/middleware"
|
||||
"seeyon-filesystem/service"
|
||||
"seeyon-filesystem/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// FileController 文件控制器
|
||||
type FileController struct {
|
||||
fileService *service.FileService
|
||||
}
|
||||
|
||||
// NewFileController 创建文件控制器实例
|
||||
func NewFileController() *FileController {
|
||||
return &FileController{
|
||||
fileService: service.NewFileService(),
|
||||
}
|
||||
}
|
||||
|
||||
// Upload 上传文件
|
||||
// POST /api/file/upload?folder_id=1&storage_policy_id=1
|
||||
func (c *FileController) Upload(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
// 获取文件
|
||||
fileHeader, err := ctx.FormFile("file")
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "请选择要上传的文件")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取目标文件夹ID
|
||||
folderIDStr := ctx.DefaultQuery("folder_id", "0")
|
||||
folderID, _ := strconv.ParseUint(folderIDStr, 10, 64)
|
||||
|
||||
// 获取存储策略ID(可选, 0=使用默认策略)
|
||||
policyIDStr := ctx.DefaultQuery("storage_policy_id", "0")
|
||||
storagePolicyID, _ := strconv.ParseUint(policyIDStr, 10, 64)
|
||||
|
||||
// 调用服务层
|
||||
result, err := c.fileService.Upload(fileHeader, folderID, ownerID, storagePolicyID)
|
||||
if err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(ctx, result)
|
||||
}
|
||||
|
||||
// GetByID 获取文件信息
|
||||
// GET /api/file/:id
|
||||
func (c *FileController) GetByID(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := c.fileService.GetByID(id, ownerID)
|
||||
if err != nil {
|
||||
utils.NotFound(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(ctx, result)
|
||||
}
|
||||
|
||||
// Download 下载文件
|
||||
// GET /api/file/:id/download
|
||||
func (c *FileController) Download(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
reader, file, err := c.fileService.Download(id, ownerID)
|
||||
if err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
// 设置下载响应头
|
||||
ctx.Header("Content-Disposition", "attachment; filename=\""+file.Name+"\"")
|
||||
ctx.Header("Content-Type", file.MimeType)
|
||||
ctx.DataFromReader(http.StatusOK, file.Size, file.MimeType, reader, nil)
|
||||
}
|
||||
|
||||
// GetDownloadURL 获取文件下载链接
|
||||
// GET /api/file/:id/download-url
|
||||
func (c *FileController) GetDownloadURL(ctx *gin.Context) {
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
downloadURL, err := c.fileService.GetDownloadURL(id)
|
||||
if err != nil {
|
||||
utils.NotFound(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(ctx, gin.H{"download_url": downloadURL})
|
||||
}
|
||||
|
||||
// GetPreviewURL 获取文件预览链接
|
||||
// GET /api/file/:id/preview-url
|
||||
func (c *FileController) GetPreviewURL(ctx *gin.Context) {
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
previewURL, err := c.fileService.GetPreviewURL(id)
|
||||
if err != nil {
|
||||
utils.NotFound(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(ctx, gin.H{"preview_url": previewURL})
|
||||
}
|
||||
|
||||
// Preview 文件预览(直接返回文件流, 浏览器内联展示)
|
||||
// GET /api/file/:id/preview
|
||||
func (c *FileController) Preview(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
reader, file, err := c.fileService.Download(id, ownerID)
|
||||
if err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
// 内联展示而非下载
|
||||
ctx.Header("Content-Disposition", "inline; filename=\""+file.Name+"\"")
|
||||
ctx.Header("Content-Type", file.MimeType)
|
||||
ctx.DataFromReader(http.StatusOK, file.Size, file.MimeType, reader, nil)
|
||||
}
|
||||
|
||||
// GetByKey 根据fileKey查询文件信息
|
||||
// GET /api/file/info?key=xxx
|
||||
func (c *FileController) GetByKey(ctx *gin.Context) {
|
||||
key := ctx.Query("key")
|
||||
if key == "" {
|
||||
utils.BadRequest(ctx, "请提供fileKey参数")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := c.fileService.GetByKey(key)
|
||||
if err != nil {
|
||||
utils.NotFound(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(ctx, result)
|
||||
}
|
||||
|
||||
// Rename 重命名文件
|
||||
// PUT /api/file/:id/rename
|
||||
func (c *FileController) Rename(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
NewName string `json:"new_name" binding:"required"`
|
||||
Version int `json:"version"` // 乐观锁版本号
|
||||
}
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.fileService.Rename(id, req.NewName, ownerID, req.Version); err != nil {
|
||||
if strings.Contains(err.Error(), "已被其他人修改") {
|
||||
utils.Error(ctx, 409, 409, err.Error())
|
||||
return
|
||||
}
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithMessage(ctx, "重命名成功", nil)
|
||||
}
|
||||
|
||||
// Move 移动文件
|
||||
// POST /api/file/:id/move
|
||||
func (c *FileController) Move(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
TargetFolderID uint64 `json:"target_folder_id" binding:"required"`
|
||||
}
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.fileService.Move(id, req.TargetFolderID, ownerID); err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithMessage(ctx, "移动成功", nil)
|
||||
}
|
||||
|
||||
// SoftDelete 移入回收站
|
||||
// DELETE /api/file/:id
|
||||
func (c *FileController) SoftDelete(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.fileService.SoftDelete(id, ownerID); err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithMessage(ctx, "已移入回收站", nil)
|
||||
}
|
||||
|
||||
// Restore 从回收站恢复
|
||||
// POST /api/file/:id/restore
|
||||
func (c *FileController) Restore(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.fileService.Restore(id, ownerID); err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithMessage(ctx, "已恢复", nil)
|
||||
}
|
||||
|
||||
// HardDelete 永久删除
|
||||
// DELETE /api/file/:id/permanent
|
||||
func (c *FileController) HardDelete(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
utils.BadRequest(ctx, "无效的文件ID")
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.fileService.HardDelete(id, ownerID); err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithMessage(ctx, "已永久删除", nil)
|
||||
}
|
||||
|
||||
// Search 搜索文件
|
||||
// GET /api/file/search?keyword=xxx
|
||||
func (c *FileController) Search(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
keyword := ctx.Query("keyword")
|
||||
typeFilter := ctx.Query("type") // 可选: image/video/document/audio/archive/code
|
||||
|
||||
if keyword == "" && typeFilter == "" {
|
||||
utils.BadRequest(ctx, "请输入搜索关键词或指定类型")
|
||||
return
|
||||
}
|
||||
|
||||
var results []dto.FileVO
|
||||
var err error
|
||||
|
||||
if typeFilter != "" {
|
||||
// 按类型搜索
|
||||
exts := getExtensionsByType(typeFilter)
|
||||
results, err = c.fileService.SearchByType(ownerID, exts)
|
||||
} else {
|
||||
// 按关键词搜索(支持|分隔多关键词)
|
||||
results, err = c.fileService.Search(ownerID, keyword)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(ctx, results)
|
||||
}
|
||||
|
||||
// getExtensionsByType 根据类型获取扩展名列表
|
||||
func getExtensionsByType(fileType string) []string {
|
||||
typeMap := map[string][]string{
|
||||
"image": {"jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "ico"},
|
||||
"video": {"mp4", "avi", "mov", "wmv", "flv", "mkv", "webm"},
|
||||
"audio": {"mp3", "wav", "ogg", "aac", "flac", "wma"},
|
||||
"document": {"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "md", "csv"},
|
||||
"archive": {"zip", "rar", "7z", "tar", "gz", "bz2"},
|
||||
"code": {"js", "ts", "py", "go", "java", "c", "cpp", "h", "css", "html", "sql", "json", "xml", "yaml", "yml"},
|
||||
}
|
||||
if exts, ok := typeMap[fileType]; ok {
|
||||
return exts
|
||||
}
|
||||
return []string{fileType}
|
||||
}
|
||||
|
||||
// ListTrashed 查询回收站
|
||||
// GET /api/file/trash
|
||||
func (c *FileController) ListTrashed(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
|
||||
results, err := c.fileService.ListTrashed(ownerID)
|
||||
if err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(ctx, results)
|
||||
}
|
||||
Reference in New Issue
Block a user