更新前后端代码
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"filestoragesystem/internal/middleware"
|
||||
"filestoragesystem/internal/repository"
|
||||
"filestoragesystem/internal/utils"
|
||||
)
|
||||
|
||||
// FileController 文件控制器
|
||||
type FileController struct {
|
||||
*Base
|
||||
}
|
||||
|
||||
// NewFileController 创建文件控制器
|
||||
func NewFileController(b *Base) *FileController { return &FileController{Base: b} }
|
||||
|
||||
// Upload 上传文件
|
||||
func (ctl *FileController) Upload(c *gin.Context) {
|
||||
fh, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
utils.FailMsg(c, "缺少上传文件字段file")
|
||||
return
|
||||
}
|
||||
userID := middleware.CurrentUserID(c)
|
||||
f, err := ctl.svc.File.Upload(c, userID, fh)
|
||||
if err != nil {
|
||||
ctl.svc.RecordOpLog(ctl.opCtx(c), "upload", "file", 0, fh.Filename, false, err.Error())
|
||||
utils.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
ctl.svc.RecordOpLog(ctl.opCtx(c), "upload", "file", f.ID, f.Filename, true, "")
|
||||
utils.OK(c, f)
|
||||
}
|
||||
|
||||
// List 文件列表(支持project_id/filename/prefix/trash过滤)
|
||||
func (ctl *FileController) List(c *gin.Context) {
|
||||
userID := middleware.CurrentUserID(c)
|
||||
page, pageSize := utils.ParsePage(c)
|
||||
filter := repository.FileListFilter{
|
||||
ProjectID: parseUintQuery(c, "project_id"),
|
||||
Filename: c.Query("filename"),
|
||||
Prefix: utils.SanitizePath(c.Query("prefix")),
|
||||
Trashed: c.Query("trash") == "true",
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
}
|
||||
if v := parseUintQuery(c, "visibility"); v > 0 {
|
||||
filter.Visibility = int8(v)
|
||||
}
|
||||
files, total, err := ctl.svc.File.List(userID, middleware.IsAdmin(c), filter)
|
||||
if err != nil {
|
||||
utils.ServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
utils.OKPage(c, files, total, page, pageSize)
|
||||
}
|
||||
|
||||
// GetInfo 获取文件信息
|
||||
func (ctl *FileController) GetInfo(c *gin.Context) {
|
||||
id, ok := paramID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
userID := middleware.CurrentUserID(c)
|
||||
f, err := ctl.svc.File.GetInfo(userID, id, middleware.IsAdmin(c))
|
||||
if err != nil {
|
||||
utils.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
utils.OK(c, f)
|
||||
}
|
||||
|
||||
// Download 下载文件
|
||||
func (ctl *FileController) Download(c *gin.Context) {
|
||||
id, ok := paramID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
userID := middleware.CurrentUserID(c)
|
||||
f, fp, err := ctl.svc.File.Open(c, userID, id, middleware.IsAdmin(c))
|
||||
if err != nil {
|
||||
utils.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
ctl.svc.File.RecordDownload(c, f)
|
||||
ctl.svc.RecordOpLog(ctl.opCtx(c), "download", "file", f.ID, f.Filename, true, "")
|
||||
|
||||
c.Header("Content-Disposition",
|
||||
fmt.Sprintf(`attachment; filename*=UTF-8''%s`, url.PathEscape(filepath.Base(f.Filename))))
|
||||
c.Header("Content-Type", f.MimeType)
|
||||
http.ServeContent(c.Writer, c.Request, filepath.Base(f.Filename), f.UpdatedAt, fp)
|
||||
}
|
||||
|
||||
// Delete 删除文件(permanent=true硬删除,否则进入回收站)
|
||||
func (ctl *FileController) Delete(c *gin.Context) {
|
||||
id, ok := paramID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
userID := middleware.CurrentUserID(c)
|
||||
permanent := c.Query("permanent") == "true"
|
||||
f, _ := ctl.svc.File.GetInfo(userID, id, middleware.IsAdmin(c))
|
||||
if err := ctl.svc.File.Delete(userID, id, middleware.IsAdmin(c), permanent); err != nil {
|
||||
utils.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
name := ""
|
||||
if f != nil {
|
||||
name = f.Filename
|
||||
}
|
||||
ctl.svc.RecordOpLog(ctl.opCtx(c), "delete", "file", id, name, true, "")
|
||||
if permanent {
|
||||
utils.OKMsg(c, "文件已彻底删除")
|
||||
} else {
|
||||
utils.OKMsg(c, "文件已移入回收站")
|
||||
}
|
||||
}
|
||||
|
||||
// Restore 恢复回收站文件
|
||||
func (ctl *FileController) Restore(c *gin.Context) {
|
||||
id, ok := paramID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
userID := middleware.CurrentUserID(c)
|
||||
if err := ctl.svc.File.Restore(userID, id, middleware.IsAdmin(c)); err != nil {
|
||||
utils.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
ctl.svc.RecordOpLog(ctl.opCtx(c), "update", "file", id, "restore", true, "")
|
||||
utils.OKMsg(c, "文件已恢复")
|
||||
}
|
||||
|
||||
type tempLinkReq struct {
|
||||
Password string `json:"password"`
|
||||
MaxCount int `json:"max_count"`
|
||||
ExpiresIn int64 `json:"expires_in"` // 秒,0使用默认
|
||||
}
|
||||
|
||||
// CreateTempLink 生成临时访问链接
|
||||
func (ctl *FileController) CreateTempLink(c *gin.Context) {
|
||||
id, ok := paramID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var req tempLinkReq
|
||||
if !bindJSON(c, &req) {
|
||||
return
|
||||
}
|
||||
userID := middleware.CurrentUserID(c)
|
||||
link, err := ctl.svc.File.CreateTempLink(userID, id, middleware.IsAdmin(c), req.Password, req.MaxCount, req.ExpiresIn)
|
||||
if err != nil {
|
||||
utils.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
ctl.svc.RecordOpLog(ctl.opCtx(c), "create", "file", id, "temp_link", true, "")
|
||||
utils.OK(c, gin.H{
|
||||
"token": link.Token,
|
||||
"url": "/api/v1/files/temp/" + link.Token,
|
||||
"expires_at": link.ExpiresAt,
|
||||
"has_password": link.HasPwd,
|
||||
"max_count": link.MaxCount,
|
||||
})
|
||||
}
|
||||
|
||||
// TempAccess 通过临时链接访问文件(公开接口,支持password参数)
|
||||
func (ctl *FileController) TempAccess(c *gin.Context) {
|
||||
token := c.Param("token")
|
||||
password := c.Query("password")
|
||||
if password == "" {
|
||||
password = c.GetHeader("X-Link-Password")
|
||||
}
|
||||
f, fp, err := ctl.svc.File.ResolveTempLink(token, password)
|
||||
if err != nil {
|
||||
utils.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
ctl.svc.File.RecordDownload(c, f)
|
||||
c.Header("Content-Disposition",
|
||||
fmt.Sprintf(`inline; filename*=UTF-8''%s`, url.PathEscape(filepath.Base(f.Filename))))
|
||||
c.Header("Content-Type", f.MimeType)
|
||||
http.ServeContent(c.Writer, c.Request, filepath.Base(f.Filename), f.UpdatedAt, fp)
|
||||
}
|
||||
Reference in New Issue
Block a user