Init V4 community edition (#2265)
* Init V4 community edition * Init V4 community edition
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,97 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/aria2/common"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/aria2"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/explorer"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AddAria2URL 添加离线下载URL
|
||||
func AddAria2URL(c *gin.Context) {
|
||||
var addService aria2.BatchAddURLService
|
||||
if err := c.ShouldBindJSON(&addService); err == nil {
|
||||
res := addService.Add(c, common.URLTask)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// SelectAria2File 选择多文件离线下载中要下载的文件
|
||||
func SelectAria2File(c *gin.Context) {
|
||||
var selectService aria2.SelectFileService
|
||||
if err := c.ShouldBindJSON(&selectService); err == nil {
|
||||
res := selectService.Select(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AddAria2Torrent 添加离线下载种子
|
||||
func AddAria2Torrent(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.FileIDService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
// 获取种子内容的下载地址
|
||||
res := service.CreateDownloadSession(ctx, c)
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建下载任务
|
||||
var addService aria2.AddURLService
|
||||
addService.URL = res.Data.(string)
|
||||
|
||||
if err := c.ShouldBindJSON(&addService); err == nil {
|
||||
addService.URL = res.Data.(string)
|
||||
res := addService.Add(c, nil, common.URLTask)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// CancelAria2Download 取消或删除aria2离线下载任务
|
||||
func CancelAria2Download(c *gin.Context) {
|
||||
var selectService aria2.DownloadTaskService
|
||||
if err := c.ShouldBindUri(&selectService); err == nil {
|
||||
res := selectService.Delete(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// ListDownloading 获取正在下载中的任务
|
||||
func ListDownloading(c *gin.Context) {
|
||||
var service aria2.DownloadListService
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.Downloading(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// ListFinished 获取已完成的任务
|
||||
func ListFinished(c *gin.Context) {
|
||||
var service aria2.DownloadListService
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.Finished(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
@@ -1,140 +1,126 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/callback"
|
||||
"fmt"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/driver/upyun"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/manager"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/util"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/callback"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/qiniu/go-sdk/v7/auth/qbox"
|
||||
)
|
||||
|
||||
// RemoteCallback 远程上传回调
|
||||
func RemoteCallback(c *gin.Context) {
|
||||
var callbackBody callback.RemoteUploadCallbackService
|
||||
if err := c.ShouldBindJSON(&callbackBody); err == nil {
|
||||
res := callback.ProcessCallback(callbackBody, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// QiniuCallback 七牛上传回调
|
||||
func QiniuCallback(c *gin.Context) {
|
||||
var callbackBody callback.UploadCallbackService
|
||||
if err := c.ShouldBindJSON(&callbackBody); err == nil {
|
||||
res := callback.ProcessCallback(callbackBody, c)
|
||||
if res.Code != 0 {
|
||||
c.JSON(401, serializer.GeneralUploadCallbackFailed{Error: res.Msg})
|
||||
} else {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(401, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// OSSCallback 阿里云OSS上传回调
|
||||
func OSSCallback(c *gin.Context) {
|
||||
var callbackBody callback.UploadCallbackService
|
||||
if err := c.ShouldBindJSON(&callbackBody); err == nil {
|
||||
if callbackBody.PicInfo == "," {
|
||||
callbackBody.PicInfo = ""
|
||||
}
|
||||
res := callback.ProcessCallback(callbackBody, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// UpyunCallback 又拍云上传回调
|
||||
func UpyunCallback(c *gin.Context) {
|
||||
var callbackBody callback.UpyunCallbackService
|
||||
if err := c.ShouldBind(&callbackBody); err == nil {
|
||||
if callbackBody.Code != 200 {
|
||||
util.Log().Debug(
|
||||
"Upload callback returned error code:%d, message: %s",
|
||||
callbackBody.Code,
|
||||
callbackBody.Message,
|
||||
)
|
||||
// RemoteCallback process callback request to complete upload
|
||||
func ProcessCallback(failedStatusCode int, generalResp bool) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
err := callback.ProcessCallback(c)
|
||||
if err != nil {
|
||||
if generalResp {
|
||||
c.JSON(failedStatusCode, serializer.GeneralUploadCallbackFailed{Error: err.Error()})
|
||||
} else {
|
||||
c.JSON(failedStatusCode, serializer.Err(c, err))
|
||||
}
|
||||
return
|
||||
}
|
||||
res := callback.ProcessCallback(callbackBody, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
}
|
||||
|
||||
// OneDriveCallback OneDrive上传完成客户端回调
|
||||
func OneDriveCallback(c *gin.Context) {
|
||||
var callbackBody callback.OneDriveCallback
|
||||
if err := c.ShouldBindJSON(&callbackBody); err == nil {
|
||||
res := callbackBody.PreProcess(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// QiniuCallbackAuth 七牛回调签名验证
|
||||
func QiniuCallbackValidate(c *gin.Context) {
|
||||
session := c.MustGet(manager.UploadSessionCtx).(*fs.UploadSession)
|
||||
|
||||
// 验证回调是否来自qiniu
|
||||
mac := qbox.NewMac(session.Policy.AccessKey, session.Policy.SecretKey)
|
||||
ok, err := mac.VerifyCallback(c.Request)
|
||||
if err != nil {
|
||||
util.Log().Debug("Failed to verify callback request: %s", err)
|
||||
c.JSON(401, serializer.GeneralUploadCallbackFailed{Error: "Failed to verify callback request."})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if !ok {
|
||||
c.JSON(401, serializer.GeneralUploadCallbackFailed{Error: "Invalid signature."})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// OSSCallbackValidate 阿里云OSS上传回调
|
||||
func OSSCallbackValidate(c *gin.Context) {
|
||||
var callbackBody callback.UploadCallbackService
|
||||
if err := c.ShouldBindJSON(&callbackBody); err == nil {
|
||||
uploadSession := c.MustGet(manager.UploadSessionCtx).(*fs.UploadSession)
|
||||
if uploadSession.Props.Size != callbackBody.Size {
|
||||
l := logging.FromContext(c)
|
||||
l.Error("Callback validate failed: size mismatch, expected: %d, actual:%d", uploadSession.Props.Size, callbackBody.Size)
|
||||
c.JSON(401,
|
||||
serializer.GeneralUploadCallbackFailed{
|
||||
Error: fmt.Sprintf("size mismatch"),
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
} else {
|
||||
c.JSON(401, ErrorResponse(err))
|
||||
c.Abort()
|
||||
}
|
||||
}
|
||||
|
||||
// UpyunCallbackAuth 又拍云回调签名验证
|
||||
func UpyunCallbackAuth(c *gin.Context) {
|
||||
uploadSession := c.MustGet(manager.UploadSessionCtx).(*fs.UploadSession)
|
||||
l := logging.FromContext(c)
|
||||
if err := upyun.ValidateCallback(c, uploadSession); err != nil {
|
||||
l.Error("Failed to verify callback request: %s", err)
|
||||
|
||||
c.JSON(401, serializer.GeneralUploadCallbackFailed{Error: "Failed to verify callback request."})
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// OneDriveOAuth OneDrive 授权回调
|
||||
func OneDriveOAuth(c *gin.Context) {
|
||||
var callbackBody callback.OauthService
|
||||
if err := c.ShouldBindQuery(&callbackBody); err == nil {
|
||||
res := callbackBody.OdAuth(c)
|
||||
redirect := model.GetSiteURL()
|
||||
redirect.Path = path.Join(redirect.Path, "/admin/policy")
|
||||
queries := redirect.Query()
|
||||
queries.Add("code", strconv.Itoa(res.Code))
|
||||
queries.Add("msg", res.Msg)
|
||||
queries.Add("err", res.Error)
|
||||
redirect.RawQuery = queries.Encode()
|
||||
c.Redirect(303, redirect.String())
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
//var callbackBody callback.OauthService
|
||||
//if err := c.ShouldBindQuery(&callbackBody); err == nil {
|
||||
// res := callbackBody.OdAuth(c)
|
||||
// redirect := model.GetSiteURL()
|
||||
// redirect.Path = path.Join(redirect.Path, "/admin/policy")
|
||||
// queries := redirect.Query()
|
||||
// queries.Add("code", strconv.Itoa(res.Code))
|
||||
// queries.Add("msg", res.Msg)
|
||||
// queries.Add("err", res.Error)
|
||||
// redirect.RawQuery = queries.Encode()
|
||||
// c.Redirect(303, redirect.String())
|
||||
//} else {
|
||||
// c.JSON(200, ErrorResponse(err))
|
||||
//}
|
||||
}
|
||||
|
||||
// GoogleDriveOAuth Google Drive 授权回调
|
||||
func GoogleDriveOAuth(c *gin.Context) {
|
||||
var callbackBody callback.OauthService
|
||||
if err := c.ShouldBindQuery(&callbackBody); err == nil {
|
||||
res := callbackBody.GDriveAuth(c)
|
||||
redirect := model.GetSiteURL()
|
||||
redirect.Path = path.Join(redirect.Path, "/admin/policy")
|
||||
queries := redirect.Query()
|
||||
queries.Add("code", strconv.Itoa(res.Code))
|
||||
queries.Add("msg", res.Msg)
|
||||
queries.Add("err", res.Error)
|
||||
redirect.RawQuery = queries.Encode()
|
||||
c.Redirect(303, redirect.String())
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// COSCallback COS上传完成客户端回调
|
||||
func COSCallback(c *gin.Context) {
|
||||
var callbackBody callback.COSCallback
|
||||
if err := c.ShouldBindQuery(&callbackBody); err == nil {
|
||||
res := callbackBody.PreProcess(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// S3Callback S3上传完成客户端回调
|
||||
func S3Callback(c *gin.Context) {
|
||||
var callbackBody callback.S3Callback
|
||||
if err := c.ShouldBindQuery(&callbackBody); err == nil {
|
||||
res := callbackBody.PreProcess(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
//var callbackBody callback.OauthService
|
||||
//if err := c.ShouldBindQuery(&callbackBody); err == nil {
|
||||
// res := callbackBody.GDriveAuth(c)
|
||||
// redirect := model.GetSiteURL()
|
||||
// redirect.Path = path.Join(redirect.Path, "/admin/policy")
|
||||
// queries := redirect.Query()
|
||||
// queries.Add("code", strconv.Itoa(res.Code))
|
||||
// queries.Add("msg", res.Msg)
|
||||
// queries.Add("err", res.Error)
|
||||
// redirect.RawQuery = queries.Encode()
|
||||
// c.Redirect(303, redirect.String())
|
||||
//} else {
|
||||
// c.JSON(200, ErrorResponse(err))
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/cloudreve/Cloudreve/v3/service/explorer"
|
||||
"errors"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/explorer"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CreateDirectory 创建目录
|
||||
func CreateDirectory(c *gin.Context) {
|
||||
var service explorer.DirectoryService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.CreateDirectory(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// ListDirectory 列出目录下内容
|
||||
func ListDirectory(c *gin.Context) {
|
||||
var service explorer.DirectoryService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.ListDirectory(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*explorer.ListFileService](c, explorer.ListFileParameterCtx{})
|
||||
resp, err := service.List(c)
|
||||
if err != nil {
|
||||
if errors.Is(err, explorer.ErrSSETakeOver) {
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,421 +1,373 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
|
||||
"net/http"
|
||||
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/explorer"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/explorer"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func DownloadArchive(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.ArchiveService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
service.DownloadArchived(ctx, c)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*explorer.ArchiveService](c, explorer.ArchiveParamCtx{})
|
||||
err := service.DownloadArchived(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func Archive(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
// CreateArchive 创建文件压缩任务
|
||||
func CreateArchive(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.ArchiveWorkflowService](c, explorer.CreateArchiveParamCtx{})
|
||||
resp, err := service.CreateCompressTask(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
var service explorer.ItemIDService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Archive(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Compress 创建文件压缩任务
|
||||
func Compress(c *gin.Context) {
|
||||
var service explorer.ItemCompressService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.CreateCompressTask(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// CreateRemoteDownload creates remote download task
|
||||
func CreateRemoteDownload(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.DownloadWorkflowService](c, explorer.CreateDownloadParamCtx{})
|
||||
resp, err := service.CreateDownloadTask(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Decompress 创建文件解压缩任务
|
||||
func Decompress(c *gin.Context) {
|
||||
var service explorer.ItemDecompressService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.CreateDecompressTask(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// ExtractArchive creates extract archive task
|
||||
func ExtractArchive(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.ArchiveWorkflowService](c, explorer.CreateArchiveParamCtx{})
|
||||
resp, err := service.CreateExtractTask(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// AnonymousGetContent 匿名获取文件资源
|
||||
func AnonymousGetContent(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.FileAnonymousGetService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Download(ctx, c)
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AnonymousPermLink Deprecated 文件签名后的永久链接
|
||||
func AnonymousPermLinkDeprecated(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.FileAnonymousGetService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Source(ctx, c)
|
||||
// 是否需要重定向
|
||||
if res.Code == -302 {
|
||||
c.Redirect(302, res.Data.(string))
|
||||
return
|
||||
}
|
||||
// 是否有错误发生
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// AnonymousPermLink 文件中转后的永久直链接
|
||||
func AnonymousPermLink(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
sourceLinkRaw, ok := c.Get("source_link")
|
||||
if !ok {
|
||||
c.JSON(200, serializer.Err(serializer.CodeFileNotFound, "", nil))
|
||||
name := c.Param("name")
|
||||
if err := explorer.RedirectDirectLink(c, name); err != nil {
|
||||
c.JSON(404, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
sourceLink := sourceLinkRaw.(*model.SourceLink)
|
||||
|
||||
service := &explorer.FileAnonymousGetService{
|
||||
ID: sourceLink.FileID,
|
||||
Name: sourceLink.File.Name,
|
||||
}
|
||||
|
||||
res := service.Source(ctx, c)
|
||||
// 是否需要重定向
|
||||
if res.Code == -302 {
|
||||
c.Redirect(302, res.Data.(string))
|
||||
return
|
||||
}
|
||||
|
||||
// 是否有错误发生
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// GetSource 获取文件的外链地址
|
||||
func GetSource(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.ItemIDService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Sources(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*explorer.GetDirectLinkService](c, explorer.GetDirectLinkParamCtx{})
|
||||
res, err := service.Get(c)
|
||||
if err != nil && len(res) == 0 {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// Not fully completed
|
||||
errResp := serializer.Err(c, err)
|
||||
errResp.Data = res
|
||||
c.JSON(200, errResp)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{Data: res})
|
||||
}
|
||||
|
||||
// Thumb 获取文件缩略图
|
||||
func Thumb(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fs, err := filesystem.NewFileSystemFromContext(c)
|
||||
service := ParametersFromContext[*explorer.FileThumbService](c, explorer.FileThumbParameterCtx{})
|
||||
res, err := service.Get(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err))
|
||||
return
|
||||
}
|
||||
defer fs.Recycle()
|
||||
|
||||
// 获取文件ID
|
||||
fileID, ok := c.Get("object_id")
|
||||
if !ok {
|
||||
c.JSON(200, serializer.Err(serializer.CodeFileNotFound, "", err))
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 获取缩略图
|
||||
resp, err := fs.GetThumb(ctx, fileID.(uint))
|
||||
c.JSON(200, serializer.Response{Data: res})
|
||||
}
|
||||
|
||||
// FileURL get temporary file url for preview or download
|
||||
func FileURL(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.FileURLService](c, explorer.FileURLParameterCtx{})
|
||||
resp, err := service.Get(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeNotSet, "Failed to get thumbnail", err))
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if resp.Redirect {
|
||||
c.Header("Cache-Control", fmt.Sprintf("max-age=%d", resp.MaxAge))
|
||||
c.Redirect(http.StatusMovedPermanently, resp.URL)
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ServeEntity download entity content
|
||||
func ServeEntity(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.EntityDownloadService](c, explorer.EntityDownloadParameterCtx{})
|
||||
err := service.Serve(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// CreateViewerSession creates a viewer session
|
||||
func CreateViewerSession(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.CreateViewerSessionService](c, explorer.CreateViewerSessionParamCtx{})
|
||||
resp, err := service.Create(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Content.Close()
|
||||
http.ServeContent(c.Writer, c.Request, "thumb."+model.GetSettingByNameWithDefault("thumb_encode_method", "jpg"), fs.FileTarget[0].UpdatedAt, resp.Content)
|
||||
|
||||
}
|
||||
|
||||
// Preview 预览文件
|
||||
func Preview(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.FileIDService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.PreviewContent(ctx, c, false)
|
||||
// 是否需要重定向
|
||||
if res.Code == -301 {
|
||||
c.Redirect(302, res.Data.(string))
|
||||
return
|
||||
}
|
||||
// 是否有错误发生
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// PreviewText 预览文本文件
|
||||
func PreviewText(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.FileIDService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.PreviewContent(ctx, c, true)
|
||||
// 是否有错误发生
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// GetDocPreview 获取DOC文件预览地址
|
||||
func GetDocPreview(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.FileIDService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.CreateDocPreviewSession(ctx, c, true)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// CreateDownloadSession 创建文件下载会话
|
||||
func CreateDownloadSession(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.FileIDService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.CreateDownloadSession(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// Download 文件下载
|
||||
func Download(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.DownloadService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Download(ctx, c)
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// PutContent 更新文件内容
|
||||
func PutContent(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.FileIDService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.PutContent(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*explorer.FileUpdateService](c, explorer.FileUpdateParameterCtx{})
|
||||
res, err := service.PutContent(c, nil)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
request.BlackHole(c.Request.Body)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{Data: res})
|
||||
}
|
||||
|
||||
// FileUpload 本地策略文件上传
|
||||
func FileUpload(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.UploadService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.LocalUpload(ctx, c)
|
||||
c.JSON(200, res)
|
||||
service := ParametersFromContext[*explorer.UploadService](c, explorer.UploadParameterCtx{})
|
||||
err := service.LocalUpload(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
request.BlackHole(c.Request.Body)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
//fileData := fsctx.FileStream{
|
||||
// MIMEType: c.Request.Header.Get("Content-Type"),
|
||||
// File: c.Request.Body,
|
||||
// Size: fileSize,
|
||||
// Name: fileName,
|
||||
// VirtualPath: filePath,
|
||||
// Mode: fsctx.Create,
|
||||
//}
|
||||
//
|
||||
//// 创建文件系统
|
||||
//fs, err := filesystem.NewFileSystemFromContext(c)
|
||||
//if err != nil {
|
||||
// c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err))
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// 非可用策略时拒绝上传
|
||||
//if !fs.Policy.IsTransitUpload(fileSize) {
|
||||
// request.BlackHole(c.Request.Body)
|
||||
// c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, "当前存储策略无法使用", nil))
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// 给文件系统分配钩子
|
||||
//fs.Use("BeforeUpload", filesystem.HookValidateFile)
|
||||
//fs.Use("BeforeUpload", filesystem.HookValidateCapacity)
|
||||
//fs.Use("AfterUploadCanceled", filesystem.HookDeleteTempFile)
|
||||
//fs.Use("AfterUploadCanceled", filesystem.HookGiveBackCapacity)
|
||||
//fs.Use("AfterUpload", filesystem.GenericAfterUpload)
|
||||
//fs.Use("AfterValidateFailed", filesystem.HookDeleteTempFile)
|
||||
//fs.Use("AfterValidateFailed", filesystem.HookGiveBackCapacity)
|
||||
//fs.Use("AfterUploadFailed", filesystem.HookGiveBackCapacity)
|
||||
//
|
||||
//// 执行上传
|
||||
//ctx = context.WithValue(ctx, fsctx.ValidateCapacityOnceCtx, &sync.Once{})
|
||||
//uploadCtx := context.WithValue(ctx, fsctx.GinCtx, c)
|
||||
//err = fs.Upload(uploadCtx, &fileData)
|
||||
//if err != nil {
|
||||
// c.JSON(200, serializer.Err(serializer.CodeUploadFailed, err.Error(), err))
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//c.JSON(200, serializer.Response{
|
||||
// Code: 0,
|
||||
//})
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// DeleteUploadSession 删除上传会话
|
||||
func DeleteUploadSession(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.UploadSessionService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Delete(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteAllUploadSession 删除全部上传会话
|
||||
func DeleteAllUploadSession(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
res := explorer.DeleteAllUploadSession(ctx, c)
|
||||
c.JSON(200, res)
|
||||
}
|
||||
|
||||
// GetUploadSession 创建上传会话
|
||||
func GetUploadSession(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.CreateUploadSessionService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Create(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// SearchFile 搜索文件
|
||||
func SearchFile(c *gin.Context) {
|
||||
var service explorer.ItemSearchService
|
||||
if err := c.ShouldBindUri(&service); err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*explorer.DeleteUploadSessionService](c, explorer.DeleteUploadSessionParameterCtx{})
|
||||
err := service.Delete(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.ShouldBindQuery(&service); err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// CreateUploadSession 创建上传会话
|
||||
func CreateUploadSession(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.CreateUploadSessionService](c, explorer.CreateUploadSessionParameterCtx{})
|
||||
resp, err := service.Create(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
res := service.Search(c)
|
||||
c.JSON(200, res)
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateFile 创建空白文件
|
||||
func CreateFile(c *gin.Context) {
|
||||
var service explorer.SingleFileService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Create(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*explorer.CreateFileService](c, explorer.CreateFileParameterCtx{})
|
||||
resp, err := service.Create(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// RenameFile Renames a file.
|
||||
func RenameFile(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.RenameFileService](c, explorer.RenameFileParameterCtx{})
|
||||
resp, err := service.Rename(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// MoveFile Moves or Copy files.
|
||||
func MoveFile(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.MoveFileService](c, explorer.MoveFileParameterCtx{})
|
||||
if err := service.Move(c); err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// Delete 删除文件或目录
|
||||
func Delete(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.DeleteFileService](c, explorer.DeleteFileParameterCtx{})
|
||||
err := service.Delete(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// Restore restore file or directory
|
||||
func Restore(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.DeleteFileService](c, explorer.DeleteFileParameterCtx{})
|
||||
err := service.Restore(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// Unlock unlocks files by given tokens
|
||||
func Unlock(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.UnlockFileService](c, explorer.UnlockFileParameterCtx{})
|
||||
err := service.Unlock(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// Pin pins files by given uri
|
||||
func Pin(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.PinFileService](c, explorer.PinFileParameterCtx{})
|
||||
err := service.PinFile(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// Unpin unpins files by given uri
|
||||
func Unpin(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.PinFileService](c, explorer.PinFileParameterCtx{})
|
||||
err := service.UnpinFile(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// PatchMetadata patch metadata
|
||||
func PatchMetadata(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.PatchMetadataService](c, explorer.PatchMetadataParameterCtx{})
|
||||
err := service.Patch(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// GetFileInfo gets file info
|
||||
func GetFileInfo(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.GetFileInfoService](c, explorer.GetFileInfoParameterCtx{})
|
||||
resp, err := service.Get(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// SetCurrentVersion sets current version
|
||||
func SetCurrentVersion(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.SetCurrentVersionService](c, explorer.SetCurrentVersionParamCtx{})
|
||||
err := service.Set(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// DeleteVersion deletes a version
|
||||
func DeleteVersion(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.DeleteVersionService](c, explorer.DeleteVersionParamCtx{})
|
||||
err := service.Delete(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
@@ -44,7 +43,7 @@ func ErrorResponse(err error) serializer.Response {
|
||||
// 处理 Validator 产生的错误
|
||||
if ve, ok := err.(validator.ValidationErrors); ok {
|
||||
for _, e := range ve {
|
||||
return serializer.ParamErr(
|
||||
return serializer.ParamErrDeprecated(
|
||||
ParamErrorMsg(e.Field(), e.Tag()),
|
||||
err,
|
||||
)
|
||||
@@ -52,18 +51,55 @@ func ErrorResponse(err error) serializer.Response {
|
||||
}
|
||||
|
||||
if _, ok := err.(*json.UnmarshalTypeError); ok {
|
||||
return serializer.ParamErr("JSON marshall error", err)
|
||||
return serializer.ParamErrDeprecated("JSON marshall error", err)
|
||||
}
|
||||
|
||||
return serializer.ParamErr("Parameter error", err)
|
||||
return serializer.ParamErrDeprecated("Parameter error", err)
|
||||
}
|
||||
|
||||
// CurrentUser 获取当前用户
|
||||
func CurrentUser(c *gin.Context) *model.User {
|
||||
if user, _ := c.Get("user"); user != nil {
|
||||
if u, ok := user.(*model.User); ok {
|
||||
return u
|
||||
// FromJSON Parse and validate JSON from request body
|
||||
func FromJSON[T any](ctxKey any) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var service T
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), ctxKey, &service))
|
||||
c.Next()
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.Abort()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FromQuery Parse and validate form from request query
|
||||
func FromQuery[T any](ctxKey any) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var service T
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), ctxKey, &service))
|
||||
c.Next()
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.Abort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FromUri Parse and validate form from request uri
|
||||
func FromUri[T any](ctxKey any) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var service T
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), ctxKey, &service))
|
||||
c.Next()
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.Abort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ParametersFromContext retrieves request parameters from context
|
||||
func ParametersFromContext[T any](c *gin.Context, ctxKey any) T {
|
||||
return c.Request.Context().Value(ctxKey).(T)
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v3/service/explorer"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Delete 删除文件或目录
|
||||
func Delete(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.ItemIDService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Delete(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// Move 移动文件或目录
|
||||
func Move(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.ItemMoveService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Move(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// Copy 复制文件或目录
|
||||
func Copy(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.ItemMoveService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Copy(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// Rename 重命名文件或目录
|
||||
func Rename(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.ItemRenameService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Rename(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// Rename 重命名文件或目录
|
||||
func GetProperty(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.ItemPropertyService
|
||||
service.ID = c.Param("id")
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.GetProperty(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
@@ -1,237 +1,78 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/share"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/hashid"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/share"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// CreateShare 创建分享
|
||||
func CreateShare(c *gin.Context) {
|
||||
var service share.ShareCreateService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Create(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*share.ShareCreateService](c, share.ShareCreateParamCtx{})
|
||||
uri, err := service.Upsert(c, 0)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{Data: uri})
|
||||
}
|
||||
|
||||
// EditShare 编辑分享
|
||||
func EditShare(c *gin.Context) {
|
||||
service := ParametersFromContext[*share.ShareCreateService](c, share.ShareCreateParamCtx{})
|
||||
uri, err := service.Upsert(c, hashid.FromContext(c))
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{Data: uri})
|
||||
}
|
||||
|
||||
// GetShare 查看分享
|
||||
func GetShare(c *gin.Context) {
|
||||
var service share.ShareGetService
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.Get(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*share.ShareInfoService](c, share.ShareInfoParamCtx{})
|
||||
info, err := service.Get(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{Data: info})
|
||||
}
|
||||
|
||||
// ListShare 列出分享
|
||||
func ListShare(c *gin.Context) {
|
||||
var service share.ShareListService
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.List(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*share.ListShareService](c, share.ListShareParamCtx{})
|
||||
resp, err := service.List(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// SearchShare 搜索分享
|
||||
func SearchShare(c *gin.Context) {
|
||||
var service share.ShareListService
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.Search(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateShare 更新分享属性
|
||||
func UpdateShare(c *gin.Context) {
|
||||
var service share.ShareUpdateService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Update(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteShare 删除分享
|
||||
func DeleteShare(c *gin.Context) {
|
||||
var service share.Service
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Delete(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// GetShareDownload 创建分享下载会话
|
||||
func GetShareDownload(c *gin.Context) {
|
||||
var service share.Service
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.CreateDownloadSession(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// PreviewShare 预览分享文件内容
|
||||
func PreviewShare(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service share.Service
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.PreviewContent(ctx, c, false)
|
||||
// 是否需要重定向
|
||||
if res.Code == -301 {
|
||||
c.Redirect(302, res.Data.(string))
|
||||
return
|
||||
}
|
||||
// 是否有错误发生
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// PreviewShareText 预览文本文件
|
||||
func PreviewShareText(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service share.Service
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.PreviewContent(ctx, c, true)
|
||||
// 是否有错误发生
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// PreviewShareReadme 预览文本自述文件
|
||||
func PreviewShareReadme(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service share.Service
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
// 自述文件名限制
|
||||
allowFileName := []string{"readme.txt", "readme.md"}
|
||||
fileName := strings.ToLower(path.Base(service.Path))
|
||||
if !util.ContainsString(allowFileName, fileName) {
|
||||
c.JSON(200, serializer.ParamErr("Not a README file", nil))
|
||||
}
|
||||
|
||||
// 必须是目录分享
|
||||
if shareCtx, ok := c.Get("share"); ok {
|
||||
if !shareCtx.(*model.Share).IsDir {
|
||||
c.JSON(200, serializer.ParamErr("This share has no README file", nil))
|
||||
}
|
||||
}
|
||||
|
||||
res := service.PreviewContent(ctx, c, true)
|
||||
// 是否有错误发生
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// GetShareDocPreview 创建分享Office文档预览地址
|
||||
func GetShareDocPreview(c *gin.Context) {
|
||||
var service share.Service
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.CreateDocPreviewSession(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// ListSharedFolder 列出分享的目录下的对象
|
||||
func ListSharedFolder(c *gin.Context) {
|
||||
var service share.Service
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.List(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// SearchSharedFolder 搜索分享的目录下的对象
|
||||
func SearchSharedFolder(c *gin.Context) {
|
||||
var service share.SearchService
|
||||
if err := c.ShouldBindUri(&service); err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
err := share.DeleteShare(c, hashid.FromContext(c))
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.ShouldBindQuery(&service); err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
res := service.Search(c)
|
||||
c.JSON(200, res)
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// ArchiveShare 打包要下载的分享
|
||||
func ArchiveShare(c *gin.Context) {
|
||||
var service share.ArchiveService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Archive(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// ShareThumb 获取分享目录下文件的缩略图
|
||||
func ShareThumb(c *gin.Context) {
|
||||
var service share.Service
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.Thumb(c)
|
||||
if res.Code >= 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserShare 查看给定用户的分享
|
||||
func GetUserShare(c *gin.Context) {
|
||||
var service share.ShareUserGetService
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.Get(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
func ShareRedirect(c *gin.Context) {
|
||||
service := ParametersFromContext[*share.ShortLinkRedirectService](c, share.ShortLinkRedirectParamCtx{})
|
||||
c.Redirect(http.StatusFound, service.RedirectTo(c))
|
||||
}
|
||||
|
||||
@@ -1,55 +1,33 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/conf"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/wopi"
|
||||
"github.com/cloudreve/Cloudreve/v4/application/constants"
|
||||
"github.com/cloudreve/Cloudreve/v4/application/dependency"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/basic"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
// SiteConfig 获取站点全局配置
|
||||
func SiteConfig(c *gin.Context) {
|
||||
siteConfig := model.GetSettingByNames(
|
||||
"siteName",
|
||||
"login_captcha",
|
||||
"reg_captcha",
|
||||
"email_active",
|
||||
"forget_captcha",
|
||||
"email_active",
|
||||
"themes",
|
||||
"defaultTheme",
|
||||
"home_view_method",
|
||||
"share_view_method",
|
||||
"authn_enabled",
|
||||
"captcha_ReCaptchaKey",
|
||||
"captcha_type",
|
||||
"captcha_TCaptcha_CaptchaAppId",
|
||||
"register_enabled",
|
||||
"show_app_promotion",
|
||||
)
|
||||
service := ParametersFromContext[*basic.GetSettingService](c, basic.GetSettingParamCtx{})
|
||||
|
||||
var wopiExts []string
|
||||
if wopi.Default != nil {
|
||||
wopiExts = wopi.Default.AvailableExts()
|
||||
}
|
||||
|
||||
// 如果已登录,则同时返回用户信息和标签
|
||||
user, _ := c.Get("user")
|
||||
if user, ok := user.(*model.User); ok {
|
||||
c.JSON(200, serializer.BuildSiteConfig(siteConfig, user, wopiExts))
|
||||
resp, err := service.GetSiteConfig(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.BuildSiteConfig(siteConfig, nil, wopiExts))
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// Ping 状态检查页面
|
||||
func Ping(c *gin.Context) {
|
||||
version := conf.BackendVersion
|
||||
if conf.IsPro == "true" {
|
||||
version := constants.BackendVersion
|
||||
if constants.IsProBool {
|
||||
version += "-pro"
|
||||
}
|
||||
|
||||
@@ -61,81 +39,41 @@ func Ping(c *gin.Context) {
|
||||
|
||||
// Captcha 获取验证码
|
||||
func Captcha(c *gin.Context) {
|
||||
options := model.GetSettingByNames(
|
||||
"captcha_IsShowHollowLine",
|
||||
"captcha_IsShowNoiseDot",
|
||||
"captcha_IsShowNoiseText",
|
||||
"captcha_IsShowSlimeLine",
|
||||
"captcha_IsShowSineLine",
|
||||
)
|
||||
// 验证码配置
|
||||
var configD = base64Captcha.ConfigCharacter{
|
||||
Height: model.GetIntSetting("captcha_height", 60),
|
||||
Width: model.GetIntSetting("captcha_width", 240),
|
||||
//const CaptchaModeNumber:数字,CaptchaModeAlphabet:字母,CaptchaModeArithmetic:算术,CaptchaModeNumberAlphabet:数字字母混合.
|
||||
Mode: model.GetIntSetting("captcha_mode", 3),
|
||||
ComplexOfNoiseText: model.GetIntSetting("captcha_ComplexOfNoiseText", 0),
|
||||
ComplexOfNoiseDot: model.GetIntSetting("captcha_ComplexOfNoiseDot", 0),
|
||||
IsShowHollowLine: model.IsTrueVal(options["captcha_IsShowHollowLine"]),
|
||||
IsShowNoiseDot: model.IsTrueVal(options["captcha_IsShowNoiseDot"]),
|
||||
IsShowNoiseText: model.IsTrueVal(options["captcha_IsShowNoiseText"]),
|
||||
IsShowSlimeLine: model.IsTrueVal(options["captcha_IsShowSlimeLine"]),
|
||||
IsShowSineLine: model.IsTrueVal(options["captcha_IsShowSineLine"]),
|
||||
CaptchaLen: model.GetIntSetting("captcha_CaptchaLen", 6),
|
||||
}
|
||||
|
||||
// 生成验证码
|
||||
idKeyD, capD := base64Captcha.GenerateCaptcha("", configD)
|
||||
// 将验证码UID存入Session以便后续验证
|
||||
util.SetSession(c, map[string]interface{}{
|
||||
"captchaID": idKeyD,
|
||||
})
|
||||
|
||||
// 将验证码图像编码为Base64
|
||||
base64stringD := base64Captcha.CaptchaWriteToBase64Encoding(capD)
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Code: 0,
|
||||
Data: base64stringD,
|
||||
Data: basic.GetCaptchaImage(c),
|
||||
})
|
||||
}
|
||||
|
||||
// Manifest 获取manifest.json
|
||||
func Manifest(c *gin.Context) {
|
||||
options := model.GetSettingByNames(
|
||||
"siteName",
|
||||
"siteTitle",
|
||||
"pwa_small_icon",
|
||||
"pwa_medium_icon",
|
||||
"pwa_large_icon",
|
||||
"pwa_display",
|
||||
"pwa_theme_color",
|
||||
"pwa_background_color",
|
||||
)
|
||||
|
||||
settingClient := dependency.FromContext(c).SettingProvider()
|
||||
siteOpts := settingClient.SiteBasic(c)
|
||||
pwaOpts := settingClient.PWA(c)
|
||||
c.Header("Cache-Control", "public, no-cache")
|
||||
c.JSON(200, map[string]interface{}{
|
||||
"short_name": options["siteName"],
|
||||
"name": options["siteTitle"],
|
||||
"short_name": siteOpts.Name,
|
||||
"name": siteOpts.Name,
|
||||
"icons": []map[string]string{
|
||||
{
|
||||
"src": options["pwa_small_icon"],
|
||||
"src": pwaOpts.SmallIcon,
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon",
|
||||
},
|
||||
{
|
||||
"src": options["pwa_medium_icon"],
|
||||
"src": pwaOpts.MediumIcon,
|
||||
"type": "image/png",
|
||||
"sizes": "192x192",
|
||||
},
|
||||
{
|
||||
"src": options["pwa_large_icon"],
|
||||
"src": pwaOpts.LargeIcon,
|
||||
"type": "image/png",
|
||||
"sizes": "512x512",
|
||||
},
|
||||
},
|
||||
"start_url": ".",
|
||||
"display": options["pwa_display"],
|
||||
"theme_color": options["pwa_theme_color"],
|
||||
"background_color": options["pwa_background_color"],
|
||||
"display": pwaOpts.Display,
|
||||
"theme_color": pwaOpts.ThemeColor,
|
||||
"background_color": pwaOpts.BackgroundColor,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,138 +1,118 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/admin"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/aria2"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/explorer"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/node"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/cluster"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/downloader"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/downloader/slave"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/admin"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/explorer"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/node"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// SlaveUpload 从机文件上传
|
||||
func SlaveUpload(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.UploadService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.SlaveUpload(ctx, c)
|
||||
c.JSON(200, res)
|
||||
service := ParametersFromContext[*explorer.UploadService](c, explorer.UploadParameterCtx{})
|
||||
err := service.SlaveUpload(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
request.BlackHole(c.Request.Body)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// SlaveGetUploadSession 从机创建上传会话
|
||||
func SlaveGetUploadSession(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.SlaveCreateUploadSessionService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Create(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*explorer.SlaveCreateUploadSessionService](c, explorer.SlaveCreateUploadSessionParamCtx{})
|
||||
if err := service.Create(c); err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// SlaveDeleteUploadSession 从机删除上传会话
|
||||
func SlaveDeleteUploadSession(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
service := ParametersFromContext[*explorer.SlaveDeleteUploadSessionService](c, explorer.SlaveDeleteUploadSessionParamCtx{})
|
||||
if err := service.Delete(c); err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
var service explorer.UploadSessionService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.SlaveDelete(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// SlaveServeEntity download entity content
|
||||
func SlaveServeEntity(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.EntityDownloadService](c, explorer.EntityDownloadParameterCtx{})
|
||||
err := service.SlaveServe(c)
|
||||
if err != nil {
|
||||
c.JSON(400, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// SlaveDownload 从机文件下载,此请求返回的HTTP状态码不全为200
|
||||
func SlaveDownload(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.SlaveDownloadService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.ServeFile(ctx, c, true)
|
||||
if res.Code != 0 {
|
||||
c.JSON(400, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(400, ErrorResponse(err))
|
||||
// SlaveMeta retrieve media metadata
|
||||
func SlaveMeta(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.SlaveMetaService](c, explorer.SlaveMetaParamCtx{})
|
||||
res, err := service.MediaMeta(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// SlavePreview 从机文件预览
|
||||
func SlavePreview(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.SlaveDownloadService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.ServeFile(ctx, c, false)
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
c.JSON(200, serializer.NewResponseWithGobData(c, res))
|
||||
}
|
||||
|
||||
// SlaveThumb 从机文件缩略图
|
||||
func SlaveThumb(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.SlaveFileService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Thumb(ctx, c)
|
||||
if res.Code != 0 {
|
||||
c.JSON(200, res)
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*explorer.SlaveThumbService](c, explorer.SlaveThumbParamCtx{})
|
||||
err := service.Thumb(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// SlaveDelete 从机删除
|
||||
func SlaveDelete(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var service explorer.SlaveFilesService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Delete(ctx, c)
|
||||
c.JSON(200, res)
|
||||
service := ParametersFromContext[*explorer.SlaveDeleteFileService](c, explorer.SlaveDeleteFileParamCtx{})
|
||||
if failed, err := service.Delete(c); err != nil {
|
||||
c.JSON(200, serializer.NewResponseWithGobData(c, serializer.Response{
|
||||
Code: serializer.CodeNotFullySuccess,
|
||||
Data: failed,
|
||||
Msg: fmt.Sprintf("Failed to delete %d files(s)", len(failed)),
|
||||
Error: err.Error(),
|
||||
}))
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.JSON(200, serializer.Response{Data: ""})
|
||||
}
|
||||
}
|
||||
|
||||
// SlavePing 从机测试
|
||||
func SlavePing(c *gin.Context) {
|
||||
var service admin.SlavePingService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Test()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*admin.SlavePingService](c, admin.SlavePingParameterCtx{})
|
||||
if err := service.Test(c); err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// SlaveList 从机列出文件
|
||||
@@ -146,101 +126,167 @@ func SlaveList(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// SlaveHeartbeat 接受主机心跳包
|
||||
func SlaveHeartbeat(c *gin.Context) {
|
||||
var service serializer.NodePingReq
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := node.HandleMasterHeartbeat(&service)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// SlaveDownloadTaskCreate creates a download task on slave
|
||||
func SlaveDownloadTaskCreate(c *gin.Context) {
|
||||
service := ParametersFromContext[*slave.CreateSlaveDownload](c, node.CreateSlaveDownloadTaskParamCtx{})
|
||||
d := c.MustGet(downloader.DownloaderCtxKey).(downloader.Downloader)
|
||||
handle, err := d.CreateTask(c, service.Url, service.Options)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.NewResponseWithGobData(c, handle))
|
||||
}
|
||||
|
||||
// SlaveAria2Create 创建 Aria2 任务
|
||||
func SlaveAria2Create(c *gin.Context) {
|
||||
var service serializer.SlaveAria2Call
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := aria2.Add(c, &service)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// SlaveDownloadTaskStatus 查询从机 Aria2 任务状态
|
||||
func SlaveDownloadTaskStatus(c *gin.Context) {
|
||||
service := ParametersFromContext[*slave.GetSlaveDownload](c, node.GetSlaveDownloadTaskParamCtx{})
|
||||
d := c.MustGet(downloader.DownloaderCtxKey).(downloader.Downloader)
|
||||
info, err := d.Info(c, service.Handle)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.NewResponseWithGobData(c, info))
|
||||
}
|
||||
|
||||
// SlaveAria2Status 查询从机 Aria2 任务状态
|
||||
func SlaveAria2Status(c *gin.Context) {
|
||||
var service serializer.SlaveAria2Call
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := aria2.SlaveStatus(c, &service)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// SlaveCancelDownloadTask 取消从机离线下载任务
|
||||
func SlaveCancelDownloadTask(c *gin.Context) {
|
||||
service := ParametersFromContext[*slave.CancelSlaveDownload](c, node.CancelSlaveDownloadTaskParamCtx{})
|
||||
d := c.MustGet(downloader.DownloaderCtxKey).(downloader.Downloader)
|
||||
err := d.Cancel(c, service.Handle)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// SlaveCancelAria2Task 取消从机离线下载任务
|
||||
func SlaveCancelAria2Task(c *gin.Context) {
|
||||
var service serializer.SlaveAria2Call
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := aria2.SlaveCancel(c, &service)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// SlaveSelectFilesToDownload 从机选取离线下载文件
|
||||
func SlaveSelectFilesToDownload(c *gin.Context) {
|
||||
service := ParametersFromContext[*slave.SetSlaveFilesToDownload](c, node.SelectSlaveDownloadFilesParamCtx{})
|
||||
d := c.MustGet(downloader.DownloaderCtxKey).(downloader.Downloader)
|
||||
err := d.SetFilesToDownload(c, service.Handle, service.Args...)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// SlaveSelectTask 从机选取离线下载文件
|
||||
func SlaveSelectTask(c *gin.Context) {
|
||||
var service serializer.SlaveAria2Call
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := aria2.SlaveSelect(c, &service)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// SlaveTestDownloader 从机测试下载器连接
|
||||
func SlaveTestDownloader(c *gin.Context) {
|
||||
d := c.MustGet(downloader.DownloaderCtxKey).(downloader.Downloader)
|
||||
res, err := d.Test(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// SlaveCreateTransferTask 从机创建中转任务
|
||||
func SlaveCreateTransferTask(c *gin.Context) {
|
||||
var service serializer.SlaveTransferReq
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := explorer.CreateTransferTask(c, &service)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// SlaveNotificationPush 处理从机发送的消息推送
|
||||
func SlaveNotificationPush(c *gin.Context) {
|
||||
var service node.SlaveNotificationService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.HandleSlaveNotificationPush(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
c.JSON(200, serializer.Response{Data: res})
|
||||
}
|
||||
|
||||
// SlaveGetOauthCredential 从机获取主机的OneDrive存储策略凭证
|
||||
func SlaveGetOauthCredential(c *gin.Context) {
|
||||
var service node.OauthCredentialService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Get(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
func SlaveGetCredential(c *gin.Context) {
|
||||
service := ParametersFromContext[*node.OauthCredentialService](c, node.OauthCredentialParamCtx{})
|
||||
cred, err := service.Get(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.NewResponseWithGobData(c, cred))
|
||||
}
|
||||
|
||||
// SlaveSelectTask 从机删除离线下载临时文件
|
||||
func SlaveDeleteTempFile(c *gin.Context) {
|
||||
var service serializer.SlaveAria2Call
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := aria2.SlaveDeleteTemp(c, &service)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// SlaveCreateTask creates tasks and register it in registry
|
||||
func SlaveCreateTask(c *gin.Context) {
|
||||
service := ParametersFromContext[*cluster.CreateSlaveTask](c, node.CreateSlaveTaskParamCtx{})
|
||||
taskId, err := node.CreateTaskInSlave(service, c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.NewResponseWithGobData(c, taskId))
|
||||
}
|
||||
|
||||
// SlaveCreateTask creates tasks and register it in registry
|
||||
func SlaveGetTask(c *gin.Context) {
|
||||
service := ParametersFromContext[*node.GetSlaveTaskService](c, node.GetSlaveTaskParamCtx{})
|
||||
task, err := service.Get(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.NewResponseWithGobData(c, task))
|
||||
}
|
||||
|
||||
func SlaveCleanupFolder(c *gin.Context) {
|
||||
service := ParametersFromContext[*cluster.FolderCleanup](c, node.FolderCleanupParamCtx{})
|
||||
if err := node.Cleanup(service, c); err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
func StatelessPrepareUpload(c *gin.Context) {
|
||||
service := ParametersFromContext[*fs.StatelessPrepareUploadService](c, node.StatelessPrepareUploadParamCtx{})
|
||||
uploadSession, err := node.StatelessPrepareUpload(service, c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.NewResponseWithGobData(c, uploadSession))
|
||||
}
|
||||
|
||||
func StatelessCompleteUpload(c *gin.Context) {
|
||||
service := ParametersFromContext[*fs.StatelessCompleteUploadService](c, node.StatelessCompleteUploadParamCtx{})
|
||||
_, err := node.StatelessCompleteUpload(service, c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
func StatelessOnUploadFailed(c *gin.Context) {
|
||||
service := ParametersFromContext[*fs.StatelessOnUploadFailedService](c, node.StatelessOnUploadFailedParamCtx{})
|
||||
if err := node.StatelessOnUploadFailed(service, c); err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
func StatelessCreateFile(c *gin.Context) {
|
||||
service := ParametersFromContext[*fs.StatelessCreateFileService](c, node.StatelessCreateFileParamCtx{})
|
||||
if err := node.StatelessCreateFile(service, c); err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/cloudreve/Cloudreve/v3/service/explorer"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CreateFilterTag 创建文件分类标签
|
||||
func CreateFilterTag(c *gin.Context) {
|
||||
var service explorer.FilterTagCreateService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Create(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// CreateLinkTag 创建目录快捷方式标签
|
||||
func CreateLinkTag(c *gin.Context) {
|
||||
var service explorer.LinkTagCreateService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Create(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteTag 删除标签
|
||||
func DeleteTag(c *gin.Context) {
|
||||
var service explorer.TagService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Delete(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
@@ -1,216 +1,173 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/authn"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/thumb"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/user"
|
||||
"github.com/duo-labs/webauthn/webauthn"
|
||||
"github.com/cloudreve/Cloudreve/v4/application/dependency"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent"
|
||||
"github.com/cloudreve/Cloudreve/v4/inventory"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/hashid"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/util"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/share"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/user"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
// StartLoginAuthn 开始注册WebAuthn登录
|
||||
func StartLoginAuthn(c *gin.Context) {
|
||||
userName := c.Param("username")
|
||||
expectedUser, err := model.GetActiveUserByEmail(userName)
|
||||
res, err := user.PreparePasskeyLogin(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeUserNotFound, "", err))
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
instance, err := authn.NewAuthnInstance()
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeInitializeAuthn, "Cannot initialize authn", err))
|
||||
return
|
||||
}
|
||||
|
||||
options, sessionData, err := instance.BeginLogin(expectedUser)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
val, err := json.Marshal(sessionData)
|
||||
if err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
util.SetSession(c, map[string]interface{}{
|
||||
"registration-session": val,
|
||||
})
|
||||
c.JSON(200, serializer.Response{Code: 0, Data: options})
|
||||
c.JSON(200, serializer.Response{Data: res})
|
||||
}
|
||||
|
||||
// FinishLoginAuthn 完成注册WebAuthn登录
|
||||
func FinishLoginAuthn(c *gin.Context) {
|
||||
userName := c.Param("username")
|
||||
expectedUser, err := model.GetActiveUserByEmail(userName)
|
||||
service := ParametersFromContext[*user.FinishPasskeyLoginService](c, user.FinishPasskeyLoginParameterCtx{})
|
||||
u, err := service.FinishPasskeyLogin(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeUserNotFound, "", err))
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
sessionDataJSON := util.GetSession(c, "registration-session").([]byte)
|
||||
|
||||
var sessionData webauthn.SessionData
|
||||
err = json.Unmarshal(sessionDataJSON, &sessionData)
|
||||
|
||||
instance, err := authn.NewAuthnInstance()
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeInitializeAuthn, "Cannot initialize authn", err))
|
||||
return
|
||||
}
|
||||
|
||||
_, err = instance.FinishLogin(expectedUser, sessionData, c.Request)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeWebAuthnCredentialError, "Verification failed", err))
|
||||
return
|
||||
}
|
||||
|
||||
util.SetSession(c, map[string]interface{}{
|
||||
"user_id": expectedUser.ID,
|
||||
})
|
||||
c.JSON(200, serializer.BuildUserResponse(expectedUser))
|
||||
util.WithValue(c, inventory.UserCtx{}, u)
|
||||
}
|
||||
|
||||
// StartRegAuthn 开始注册WebAuthn信息
|
||||
func StartRegAuthn(c *gin.Context) {
|
||||
currUser := CurrentUser(c)
|
||||
|
||||
instance, err := authn.NewAuthnInstance()
|
||||
res, err := user.PreparePasskeyRegister(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeInitializeAuthn, "Cannot initialize authn", err))
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
options, sessionData, err := instance.BeginRegistration(currUser)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
val, err := json.Marshal(sessionData)
|
||||
if err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
util.SetSession(c, map[string]interface{}{
|
||||
"registration-session": val,
|
||||
})
|
||||
c.JSON(200, serializer.Response{Code: 0, Data: options})
|
||||
c.JSON(200, serializer.Response{Data: res})
|
||||
}
|
||||
|
||||
// FinishRegAuthn 完成注册WebAuthn信息
|
||||
func FinishRegAuthn(c *gin.Context) {
|
||||
currUser := CurrentUser(c)
|
||||
sessionDataJSON := util.GetSession(c, "registration-session").([]byte)
|
||||
|
||||
var sessionData webauthn.SessionData
|
||||
err := json.Unmarshal(sessionDataJSON, &sessionData)
|
||||
|
||||
instance, err := authn.NewAuthnInstance()
|
||||
service := ParametersFromContext[*user.FinishPasskeyRegisterService](c, user.FinishPasskeyRegisterParameterCtx{})
|
||||
res, err := service.FinishPasskeyRegister(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeInitializeAuthn, "Cannot initialize authn", err))
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
credential, err := instance.FinishRegistration(currUser, sessionData, c.Request)
|
||||
c.JSON(200, serializer.Response{Data: res})
|
||||
}
|
||||
|
||||
// UserDeletePasskey deletes user passkey
|
||||
func UserDeletePasskey(c *gin.Context) {
|
||||
service := ParametersFromContext[*user.DeletePasskeyService](c, user.DeletePasskeyParameterCtx{})
|
||||
err := service.DeletePasskey(c)
|
||||
if err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
err = currUser.RegisterAuthn(credential)
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// UserLoginValidation validates user login request
|
||||
func UserLoginValidation(c *gin.Context) {
|
||||
service := ParametersFromContext[*user.UserLoginService](c, user.LoginParameterCtx{})
|
||||
expectedUser, twoFaSession, err := service.Login(c)
|
||||
if err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if twoFaSession == "" {
|
||||
// No 2FA required, proceed
|
||||
util.WithValue(c, inventory.UserCtx{}, expectedUser)
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{Code: serializer.CodeNotFullySuccess, Data: twoFaSession})
|
||||
c.Abort()
|
||||
}
|
||||
|
||||
// UserLogin2FAValidation validates user OTP code
|
||||
func UserLogin2FAValidation(c *gin.Context) {
|
||||
service := ParametersFromContext[*user.OtpValidationService](c, user.OtpValidationParameterCtx{})
|
||||
expectedUser, err := service.Verify2FA(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
util.WithValue(c, inventory.UserCtx{}, expectedUser)
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// UserIssueToken generates new token pair for user
|
||||
func UserIssueToken(c *gin.Context) {
|
||||
resp, err := user.IssueToken(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Code: 0,
|
||||
Data: map[string]interface{}{
|
||||
"id": credential.ID,
|
||||
"fingerprint": fmt.Sprintf("% X", credential.Authenticator.AAGUID),
|
||||
},
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// UserLogin 用户登录
|
||||
func UserLogin(c *gin.Context) {
|
||||
var service user.UserLoginService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Login(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// UserRefreshToken refreshes token pair for user
|
||||
func UserRefreshToken(c *gin.Context) {
|
||||
service := ParametersFromContext[*user.RefreshTokenService](c, user.RefreshTokenParameterCtx{})
|
||||
resp, err := service.Refresh(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// UserRegister 用户注册
|
||||
func UserRegister(c *gin.Context) {
|
||||
var service user.UserRegisterService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Register(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// User2FALogin 用户二步验证登录
|
||||
func User2FALogin(c *gin.Context) {
|
||||
var service user.Enable2FA
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Login(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
service := ParametersFromContext[*user.UserRegisterService](c, user.RegisterParameterCtx{})
|
||||
c.JSON(200, service.Register(c))
|
||||
}
|
||||
|
||||
// UserSendReset 发送密码重设邮件
|
||||
func UserSendReset(c *gin.Context) {
|
||||
var service user.UserResetEmailService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Reset(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*user.UserResetEmailService](c, user.UserResetEmailParameterCtx{})
|
||||
if err := service.Reset(c); err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// UserReset 重设密码
|
||||
func UserReset(c *gin.Context) {
|
||||
var service user.UserResetService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Reset(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*user.UserResetService](c, user.UserResetParameterCtx{})
|
||||
res, err := service.Reset(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.JSON(200, serializer.Response{Data: res})
|
||||
}
|
||||
|
||||
// UserActivate 用户激活
|
||||
func UserActivate(c *gin.Context) {
|
||||
var service user.SettingService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Activate(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
c.JSON(200, user.ActivateUser(c))
|
||||
}
|
||||
|
||||
// UserSignOut 用户退出登录
|
||||
@@ -221,92 +178,63 @@ func UserSignOut(c *gin.Context) {
|
||||
|
||||
// UserMe 获取当前登录的用户
|
||||
func UserMe(c *gin.Context) {
|
||||
currUser := CurrentUser(c)
|
||||
res := serializer.BuildUserResponse(*currUser)
|
||||
c.JSON(200, res)
|
||||
dep := dependency.FromContext(c)
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: user.BuildUser(inventory.UserFromContext(c), dep.HashIDEncoder()),
|
||||
})
|
||||
}
|
||||
|
||||
// UserGet 获取用户信息
|
||||
func UserGet(c *gin.Context) {
|
||||
u, err := user.GetUser(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
isAnonymous := inventory.IsAnonymousUser(inventory.UserFromContext(c))
|
||||
redactLevel := user.RedactLevelUser
|
||||
if isAnonymous {
|
||||
redactLevel = user.RedactLevelAnonymous
|
||||
}
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: user.BuildUserRedacted(u, redactLevel, dependency.FromContext(c).HashIDEncoder()),
|
||||
})
|
||||
}
|
||||
|
||||
// UserStorage 获取用户的存储信息
|
||||
func UserStorage(c *gin.Context) {
|
||||
currUser := CurrentUser(c)
|
||||
res := serializer.BuildUserStorageResponse(*currUser)
|
||||
c.JSON(200, res)
|
||||
}
|
||||
|
||||
// UserTasks 获取任务队列
|
||||
func UserTasks(c *gin.Context) {
|
||||
var service user.SettingListService
|
||||
if err := c.ShouldBindQuery(&service); err == nil {
|
||||
res := service.ListTasks(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
res, err := user.GetUserCapacity(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: res,
|
||||
})
|
||||
}
|
||||
|
||||
// UserSetting 获取用户设定
|
||||
func UserSetting(c *gin.Context) {
|
||||
var service user.SettingService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Settings(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// UseGravatar 设定头像使用全球通用
|
||||
func UseGravatar(c *gin.Context) {
|
||||
u := CurrentUser(c)
|
||||
if err := u.Update(map[string]interface{}{"avatar": "gravatar"}); err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeDBError, "无法更新头像", err))
|
||||
res, err := user.GetUserSettings(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.JSON(200, serializer.Response{})
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: res,
|
||||
})
|
||||
}
|
||||
|
||||
// UploadAvatar 从文件上传头像
|
||||
func UploadAvatar(c *gin.Context) {
|
||||
// 取得头像上传大小限制
|
||||
maxSize := model.GetIntSetting("avatar_size", 2097152)
|
||||
if c.Request.ContentLength == -1 || c.Request.ContentLength > int64(maxSize) {
|
||||
request.BlackHole(c.Request.Body)
|
||||
c.JSON(200, serializer.Err(serializer.CodeFileTooLarge, "", nil))
|
||||
return
|
||||
}
|
||||
|
||||
// 取得上传的文件
|
||||
file, err := c.FormFile("avatar")
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.ParamErr("Failed to read avatar file data", err))
|
||||
return
|
||||
}
|
||||
|
||||
// 初始化头像
|
||||
r, err := file.Open()
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.ParamErr("Failed to read avatar file data", err))
|
||||
return
|
||||
}
|
||||
avatar, err := thumb.NewThumbFromFile(r, file.Filename)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.ParamErr("Invalid image", err))
|
||||
return
|
||||
}
|
||||
|
||||
// 创建头像
|
||||
u := CurrentUser(c)
|
||||
err = avatar.CreateAvatar(u.ID)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeIOFailed, "Failed to create avatar file", err))
|
||||
return
|
||||
}
|
||||
|
||||
// 保存头像标记
|
||||
if err := u.Update(map[string]interface{}{
|
||||
"avatar": "file",
|
||||
}); err != nil {
|
||||
c.JSON(200, serializer.DBErr("Failed to update avatar attribute", err))
|
||||
if err := user.UpdateUserAvatar(c); err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -315,84 +243,158 @@ func UploadAvatar(c *gin.Context) {
|
||||
|
||||
// GetUserAvatar 获取用户头像
|
||||
func GetUserAvatar(c *gin.Context) {
|
||||
var service user.AvatarService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Get(c)
|
||||
if res.Code == -301 {
|
||||
// 重定向到gravatar
|
||||
c.Redirect(301, res.Data.(string))
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*user.GetAvatarService](c, user.GetAvatarServiceParamsCtx{})
|
||||
err := service.Get(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateOption 更改用户设定
|
||||
func UpdateOption(c *gin.Context) {
|
||||
var service user.SettingUpdateService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
var (
|
||||
subService user.OptionsChangeHandler
|
||||
subErr error
|
||||
)
|
||||
|
||||
switch service.Option {
|
||||
case "nick":
|
||||
subService = &user.ChangerNick{}
|
||||
case "homepage":
|
||||
subService = &user.HomePage{}
|
||||
case "password":
|
||||
subService = &user.PasswordChange{}
|
||||
case "2fa":
|
||||
subService = &user.Enable2FA{}
|
||||
case "authn":
|
||||
subService = &user.DeleteWebAuthn{}
|
||||
case "theme":
|
||||
subService = &user.ThemeChose{}
|
||||
default:
|
||||
subService = &user.ChangerNick{}
|
||||
}
|
||||
|
||||
subErr = c.ShouldBindJSON(subService)
|
||||
if subErr != nil {
|
||||
c.JSON(200, ErrorResponse(subErr))
|
||||
return
|
||||
}
|
||||
|
||||
res := subService.Update(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
service := ParametersFromContext[*user.PatchUserSetting](c, user.PatchUserSettingParamsCtx{})
|
||||
err := service.Patch(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
|
||||
//var service user.SettingUpdateService
|
||||
//if err := c.ShouldBindUri(&service); err == nil {
|
||||
// var (
|
||||
// subService user.OptionsChangeHandler
|
||||
// subErr error
|
||||
// )
|
||||
//
|
||||
// switch service.Option {
|
||||
// case "nick":
|
||||
// subService = &user.ChangerNick{}
|
||||
// case "vip":
|
||||
// subService = &user.VIPUnsubscribe{}
|
||||
// case "qq":
|
||||
// subService = &user.QQBind{}
|
||||
// case "policy":
|
||||
// subService = &user.PolicyChange{}
|
||||
// case "homepage":
|
||||
// subService = &user.HomePage{}
|
||||
// case "password":
|
||||
// subService = &user.PasswordChange{}
|
||||
// case "2fa":
|
||||
// subService = &user.Enable2FA{}
|
||||
// case "authn":
|
||||
// subService = &user.DeleteWebAuthn{}
|
||||
// case "theme":
|
||||
// subService = &user.ThemeChose{}
|
||||
// default:
|
||||
// subService = &user.ChangerNick{}
|
||||
// }
|
||||
//
|
||||
// subErr = c.ShouldBindJSON(subService)
|
||||
// if subErr != nil {
|
||||
// c.JSON(200, ErrorResponse(subErr))
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// res := subService.Update(c, CurrentUser(c))
|
||||
// c.JSON(200, res)
|
||||
//
|
||||
//} else {
|
||||
// c.JSON(200, ErrorResponse(err))
|
||||
//}
|
||||
}
|
||||
|
||||
// UserInit2FA 初始化二步验证
|
||||
func UserInit2FA(c *gin.Context) {
|
||||
var service user.SettingService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Init2FA(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
secret, err := user.Init2FA(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// UserPrepareCopySession generates URL for copy session
|
||||
func UserPrepareCopySession(c *gin.Context) {
|
||||
var service user.CopySessionService
|
||||
res := service.Prepare(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: secret,
|
||||
})
|
||||
}
|
||||
|
||||
// UserPerformCopySession copy to create new session or refresh current session
|
||||
func UserPerformCopySession(c *gin.Context) {
|
||||
var service user.CopySessionService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Copy(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
//var service user.CopySessionService
|
||||
//if err := c.ShouldBindUri(&service); err == nil {
|
||||
// res := service.Copy(c)
|
||||
// c.JSON(200, res)
|
||||
//} else {
|
||||
// c.JSON(200, ErrorResponse(err))
|
||||
//}
|
||||
}
|
||||
|
||||
// UserPrepareLogin validates precondition for login
|
||||
func UserPrepareLogin(c *gin.Context) {
|
||||
service := ParametersFromContext[*user.PrepareLoginService](c, user.PrepareLoginParameterCtx{})
|
||||
res, err := service.Prepare(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{Data: res})
|
||||
}
|
||||
|
||||
// UserSearch Search user by keyword
|
||||
func UserSearch(c *gin.Context) {
|
||||
service := ParametersFromContext[*user.SearchUserService](c, user.SearchUserParamCtx{})
|
||||
u, err := service.Search(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
hasher := dependency.FromContext(c).HashIDEncoder()
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: lo.Map(u, func(item *ent.User, index int) user.User {
|
||||
return user.BuildUserRedacted(item, user.RedactLevelUser, hasher)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
// GetGroupList list all groups for options
|
||||
func GetGroupList(c *gin.Context) {
|
||||
u, err := user.ListAllGroups(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
hasher := dependency.FromContext(c).HashIDEncoder()
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: lo.Map(u, func(item *ent.Group, index int) *user.Group {
|
||||
g := user.BuildGroup(item, hasher)
|
||||
return user.RedactedGroup(g)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
// ListPublicShare lists all public shares for given user
|
||||
func ListPublicShare(c *gin.Context) {
|
||||
service := ParametersFromContext[*share.ListShareService](c, share.ListShareParamCtx{})
|
||||
resp, err := service.ListInUserProfile(c, hashid.FromContext(c))
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,104 +1,101 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/webdav"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/setting"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/setting"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var handler *webdav.Handler
|
||||
|
||||
func init() {
|
||||
handler = &webdav.Handler{
|
||||
Prefix: "/dav",
|
||||
LockSystem: make(map[uint]webdav.LockSystem),
|
||||
Mutex: &sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
// ServeWebDAV 处理WebDAV相关请求
|
||||
func ServeWebDAV(c *gin.Context) {
|
||||
fs, err := filesystem.NewFileSystemFromContext(c)
|
||||
// ListDavAccounts lists all WebDAV accounts.
|
||||
func ListDavAccounts(c *gin.Context) {
|
||||
service := ParametersFromContext[*setting.ListDavAccountsService](c, setting.ListDavAccountParamCtx{})
|
||||
resp, err := service.List(c)
|
||||
if err != nil {
|
||||
util.Log().Warning("Failed to initialize filesystem for WebDAV,%s", err)
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if webdavCtx, ok := c.Get("webdav"); ok {
|
||||
application := webdavCtx.(*model.Webdav)
|
||||
|
||||
// 重定根目录
|
||||
if application.Root != "/" {
|
||||
if exist, root := fs.IsPathExist(application.Root); exist {
|
||||
root.Position = ""
|
||||
root.Name = "/"
|
||||
fs.Root = root
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否只读
|
||||
if application.Readonly {
|
||||
switch c.Request.Method {
|
||||
case "DELETE", "PUT", "MKCOL", "COPY", "MOVE":
|
||||
c.Status(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 更新Context
|
||||
c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), fsctx.WebDAVCtx, application))
|
||||
}
|
||||
|
||||
handler.ServeHTTP(c.Writer, c.Request, fs)
|
||||
}
|
||||
|
||||
// GetWebDAVAccounts 获取webdav账号列表
|
||||
func GetWebDAVAccounts(c *gin.Context) {
|
||||
var service setting.WebDAVListService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Accounts(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteWebDAVAccounts 删除WebDAV账户
|
||||
func DeleteWebDAVAccounts(c *gin.Context) {
|
||||
var service setting.WebDAVAccountService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Delete(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// CreateDAVAccounts 创建WebDAV账户
|
||||
func CreateDAVAccounts(c *gin.Context) {
|
||||
service := ParametersFromContext[*setting.CreateDavAccountService](c, setting.CreateDavAccountParamCtx{})
|
||||
resp, err := service.Create(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateWebDAVAccounts 更改WebDAV账户只读性和是否使用代理服务
|
||||
func UpdateWebDAVAccounts(c *gin.Context) {
|
||||
var service setting.WebDAVAccountUpdateService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Update(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// UpdateDAVAccounts updates WebDAV accounts.
|
||||
func UpdateDAVAccounts(c *gin.Context) {
|
||||
service := ParametersFromContext[*setting.CreateDavAccountService](c, setting.CreateDavAccountParamCtx{})
|
||||
resp, err := service.Update(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateWebDAVAccounts 创建WebDAV账户
|
||||
func CreateWebDAVAccounts(c *gin.Context) {
|
||||
var service setting.WebDAVAccountCreateService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Create(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
// DeleteDAVAccounts deletes WebDAV accounts.
|
||||
func DeleteDAVAccounts(c *gin.Context) {
|
||||
err := setting.DeleteDavAccount(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
//
|
||||
//// DeleteWebDAVAccounts 删除WebDAV账户
|
||||
//func DeleteWebDAVAccounts(c *gin.Context) {
|
||||
// var service setting.WebDAVAccountService
|
||||
// if err := c.ShouldBindUri(&service); err == nil {
|
||||
// res := service.Delete(c, CurrentUser(c))
|
||||
// c.JSON(200, res)
|
||||
// } else {
|
||||
// c.JSON(200, ErrorResponse(err))
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// DeleteWebDAVMounts 删除WebDAV挂载
|
||||
//func DeleteWebDAVMounts(c *gin.Context) {
|
||||
// var service setting.WebDAVListService
|
||||
// if err := c.ShouldBindUri(&service); err == nil {
|
||||
// res := service.Unmount(c, CurrentUser(c))
|
||||
// c.JSON(200, res)
|
||||
// } else {
|
||||
// c.JSON(200, ErrorResponse(err))
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//// CreateWebDAVMounts 创建WebDAV目录挂载
|
||||
//func CreateWebDAVMounts(c *gin.Context) {
|
||||
// var service setting.WebDAVMountCreateService
|
||||
// if err := c.ShouldBindJSON(&service); err == nil {
|
||||
// res := service.Create(c, CurrentUser(c))
|
||||
// c.JSON(200, res)
|
||||
// } else {
|
||||
// c.JSON(200, ErrorResponse(err))
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/wopi"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/explorer"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/wopi"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/explorer"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
@@ -35,43 +33,46 @@ func GetFile(c *gin.Context) {
|
||||
|
||||
// PutFile Puts file content
|
||||
func PutFile(c *gin.Context) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
service := &explorer.FileIDService{}
|
||||
res := service.PutContent(ctx, c)
|
||||
switch res.Code {
|
||||
case serializer.CodeFileTooLarge:
|
||||
c.Status(http.StatusRequestEntityTooLarge)
|
||||
c.Header(wopi.ServerErrorHeader, res.Error)
|
||||
case serializer.CodeNotFound:
|
||||
c.Status(http.StatusNotFound)
|
||||
c.Header(wopi.ServerErrorHeader, res.Error)
|
||||
case 0:
|
||||
c.Status(http.StatusOK)
|
||||
default:
|
||||
service := &explorer.WopiService{}
|
||||
err := service.PutContent(c)
|
||||
if err != nil {
|
||||
c.Status(http.StatusInternalServerError)
|
||||
c.Header(wopi.ServerErrorHeader, res.Error)
|
||||
c.Header(wopi.ServerErrorHeader, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// ModifyFile Modify file properties
|
||||
func ModifyFile(c *gin.Context) {
|
||||
action := c.GetHeader(wopi.OverwriteHeader)
|
||||
var (
|
||||
service explorer.WopiService
|
||||
err error
|
||||
)
|
||||
|
||||
switch action {
|
||||
case wopi.MethodLock, wopi.MethodRefreshLock, wopi.MethodUnlock:
|
||||
c.Status(http.StatusOK)
|
||||
return
|
||||
case wopi.MethodRename:
|
||||
var service explorer.WopiService
|
||||
err := service.Rename(c)
|
||||
if err != nil {
|
||||
c.Status(http.StatusInternalServerError)
|
||||
c.Header(wopi.ServerErrorHeader, err.Error())
|
||||
case wopi.MethodLock:
|
||||
err = service.Lock(c)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
case wopi.MethodRefreshLock:
|
||||
err = service.RefreshLock(c)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
case wopi.MethodUnlock:
|
||||
err = service.Unlock(c)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
default:
|
||||
c.Status(http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.Status(http.StatusInternalServerError)
|
||||
c.Header(wopi.ServerErrorHeader, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
68
routers/controllers/workflow.go
Normal file
68
routers/controllers/workflow.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/hashid"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/queue"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v4/service/explorer"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func ListTasks(c *gin.Context) {
|
||||
service := ParametersFromContext[*explorer.ListTaskService](c, explorer.ListTaskParamCtx{})
|
||||
resp, err := service.ListTasks(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func GetTaskPhaseProgress(c *gin.Context) {
|
||||
taskId := hashid.FromContext(c)
|
||||
resp, err := explorer.TaskPhaseProgress(c, taskId)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if resp != nil {
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: resp,
|
||||
})
|
||||
} else {
|
||||
c.JSON(200, serializer.Response{Data: queue.Progresses{}})
|
||||
}
|
||||
}
|
||||
|
||||
func SetDownloadTaskTarget(c *gin.Context) {
|
||||
taskId := hashid.FromContext(c)
|
||||
service := ParametersFromContext[*explorer.SetDownloadFilesService](c, explorer.SetDownloadFilesParamCtx{})
|
||||
err := service.SetDownloadFiles(c, taskId)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
func CancelDownloadTask(c *gin.Context) {
|
||||
taskId := hashid.FromContext(c)
|
||||
err := explorer.CancelDownloadTask(c, taskId)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(c, err))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
Reference in New Issue
Block a user