init
This commit is contained in:
596
routers/controllers/admin.go
Normal file
596
routers/controllers/admin.go
Normal file
@ -0,0 +1,596 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
// "io"
|
||||
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/aria2"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/cluster"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/email"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/mq"
|
||||
|
||||
// "github.com/cloudreve/Cloudreve/v3/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/wopi"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/admin"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AdminSummary 获取管理站点概况
|
||||
func AdminSummary(c *gin.Context) {
|
||||
var service admin.NoParamService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Summary()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminNews 获取社区新闻
|
||||
// func AdminNews(c *gin.Context) {
|
||||
// tag := "announcements"
|
||||
// if c.Query("tag") != "" {
|
||||
// tag = c.Query("tag")
|
||||
// }
|
||||
// r := request.NewClient()
|
||||
// res := r.Request("GET", "https://forum.cloudreve.org/api/discussions?include=startUser%2ClastUser%2CstartPost%2Ctags&filter%5Bq%5D=%20tag%3A"+tag+"&sort=-startTime&page%5Blimit%5D=10", nil)
|
||||
// if res.Err == nil {
|
||||
// io.Copy(c.Writer, res.Response.Body)
|
||||
// }
|
||||
// }
|
||||
|
||||
// AdminChangeSetting 获取站点设定项
|
||||
func AdminChangeSetting(c *gin.Context) {
|
||||
var service admin.BatchSettingChangeService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Change()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminGetSetting 获取站点设置
|
||||
func AdminGetSetting(c *gin.Context) {
|
||||
var service admin.BatchSettingGet
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Get()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminGetGroups 获取用户组列表
|
||||
func AdminGetGroups(c *gin.Context) {
|
||||
var service admin.NoParamService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.GroupList()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminReloadService 重新加载子服务
|
||||
func AdminReloadService(c *gin.Context) {
|
||||
service := c.Param("service")
|
||||
switch service {
|
||||
case "email":
|
||||
email.Init()
|
||||
case "aria2":
|
||||
aria2.Init(true, cluster.Default, mq.GlobalMQ)
|
||||
case "wopi":
|
||||
wopi.Init()
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// AdminSendTestMail 发送测试邮件
|
||||
func AdminSendTestMail(c *gin.Context) {
|
||||
var service admin.MailTestService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Send()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminTestThumbGenerator Tests thumb generator
|
||||
func AdminTestThumbGenerator(c *gin.Context) {
|
||||
var service admin.ThumbGeneratorTestService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Test(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListRedeems 列出激活码
|
||||
func AdminListRedeems(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Redeems()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminGenerateRedeems 生成激活码
|
||||
func AdminGenerateRedeems(c *gin.Context) {
|
||||
var service admin.GenerateRedeemsService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Generate()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteRedeem 删除激活码
|
||||
func AdminDeleteRedeem(c *gin.Context) {
|
||||
var service admin.SingleIDService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.DeleteRedeem()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminTestAria2 测试aria2连接
|
||||
func AdminTestAria2(c *gin.Context) {
|
||||
var service admin.Aria2TestService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
var res serializer.Response
|
||||
if service.Type == model.MasterNodeType {
|
||||
res = service.TestMaster()
|
||||
} else {
|
||||
res = service.TestSlave()
|
||||
}
|
||||
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListPolicy 列出存储策略
|
||||
func AdminListPolicy(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Policies()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminTestPath 测试本地路径可用性
|
||||
func AdminTestPath(c *gin.Context) {
|
||||
var service admin.PathTestService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Test()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminTestSlave 测试从机可用性
|
||||
func AdminTestSlave(c *gin.Context) {
|
||||
var service admin.SlaveTestService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Test()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminAddPolicy 新建存储策略
|
||||
func AdminAddPolicy(c *gin.Context) {
|
||||
var service admin.AddPolicyService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Add()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminAddCORS 创建跨域策略
|
||||
func AdminAddCORS(c *gin.Context) {
|
||||
var service admin.PolicyService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.AddCORS()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminAddSCF 创建回调函数
|
||||
func AdminAddSCF(c *gin.Context) {
|
||||
var service admin.PolicyService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.AddSCF()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminOAuthURL 获取 OneDrive OAuth URL
|
||||
func AdminOAuthURL(policyType string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var service admin.PolicyService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.GetOAuth(c, policyType)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AdminGetPolicy 获取存储策略详情
|
||||
func AdminGetPolicy(c *gin.Context) {
|
||||
var service admin.PolicyService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Get()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeletePolicy 删除存储策略
|
||||
func AdminDeletePolicy(c *gin.Context) {
|
||||
var service admin.PolicyService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Delete()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListGroup 列出用户组
|
||||
func AdminListGroup(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Groups()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminAddGroup 新建用户组
|
||||
func AdminAddGroup(c *gin.Context) {
|
||||
var service admin.AddGroupService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Add()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteGroup 删除用户组
|
||||
func AdminDeleteGroup(c *gin.Context) {
|
||||
var service admin.GroupService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Delete()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminGetGroup 获取用户组详情
|
||||
func AdminGetGroup(c *gin.Context) {
|
||||
var service admin.GroupService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Get()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListUser 列出用户
|
||||
func AdminListUser(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Users()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminAddUser 新建用户组
|
||||
func AdminAddUser(c *gin.Context) {
|
||||
var service admin.AddUserService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Add()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminGetUser 获取用户详情
|
||||
func AdminGetUser(c *gin.Context) {
|
||||
var service admin.UserService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Get()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteUser 批量删除用户
|
||||
func AdminDeleteUser(c *gin.Context) {
|
||||
var service admin.UserBatchService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Delete()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminBanUser 封禁/解封用户
|
||||
func AdminBanUser(c *gin.Context) {
|
||||
var service admin.UserService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Ban()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListFile 列出文件
|
||||
func AdminListFile(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Files()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminGetFile 获取文件
|
||||
func AdminGetFile(c *gin.Context) {
|
||||
var service admin.FileService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Get(c)
|
||||
// 是否需要重定向
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteFile 批量删除文件
|
||||
func AdminDeleteFile(c *gin.Context) {
|
||||
var service admin.FileBatchService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Delete(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListShare 列出分享
|
||||
func AdminListShare(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Shares()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteShare 批量删除分享
|
||||
func AdminDeleteShare(c *gin.Context) {
|
||||
var service admin.ShareBatchService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Delete(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListOrder 列出订单
|
||||
func AdminListOrder(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Orders()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteOrder 批量删除订单
|
||||
func AdminDeleteOrder(c *gin.Context) {
|
||||
var service admin.OrderBatchService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Delete(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListDownload 列出离线下载任务
|
||||
func AdminListDownload(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Downloads()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteDownload 批量删除任务
|
||||
func AdminDeleteDownload(c *gin.Context) {
|
||||
var service admin.TaskBatchService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Delete(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListTask 列出任务
|
||||
func AdminListTask(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Tasks()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteTask 批量删除任务
|
||||
func AdminDeleteTask(c *gin.Context) {
|
||||
var service admin.TaskBatchService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.DeleteGeneral(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminCreateImportTask 新建文件导入任务
|
||||
func AdminCreateImportTask(c *gin.Context) {
|
||||
var service admin.ImportTaskService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Create(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListFolders 列出用户或外部文件系统目录
|
||||
func AdminListFolders(c *gin.Context) {
|
||||
var service admin.ListFolderService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.List(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListReport 列出未处理举报
|
||||
func AdminListReport(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Reports()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteTask 批量删除举报
|
||||
func AdminDeleteReport(c *gin.Context) {
|
||||
var service admin.ReportBatchService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Delete()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListNodes 列出从机节点
|
||||
func AdminListNodes(c *gin.Context) {
|
||||
var service admin.AdminListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Nodes()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminAddNode 新建节点
|
||||
func AdminAddNode(c *gin.Context) {
|
||||
var service admin.AddNodeService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Add()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminToggleNode 启用/暂停节点
|
||||
func AdminToggleNode(c *gin.Context) {
|
||||
var service admin.ToggleNodeService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Toggle()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminDeleteGroup 删除用户组
|
||||
func AdminDeleteNode(c *gin.Context) {
|
||||
var service admin.NodeService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Delete()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminGetNode 获取节点详情
|
||||
func AdminGetNode(c *gin.Context) {
|
||||
var service admin.NodeService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Get()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminSyncVol 同步VOL授权
|
||||
func AdminSyncVol(c *gin.Context) {
|
||||
var service admin.VolService
|
||||
res := service.Sync()
|
||||
c.JSON(200, res)
|
||||
}
|
97
routers/controllers/aria2.go
Normal file
97
routers/controllers/aria2.go
Normal file
@ -0,0 +1,97 @@
|
||||
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))
|
||||
}
|
||||
}
|
140
routers/controllers/callback.go
Normal file
140
routers/controllers/callback.go
Normal file
@ -0,0 +1,140 @@
|
||||
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"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 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,
|
||||
)
|
||||
return
|
||||
}
|
||||
res := callback.ProcessCallback(callbackBody, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
28
routers/controllers/directory.go
Normal file
28
routers/controllers/directory.go
Normal file
@ -0,0 +1,28 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/cloudreve/Cloudreve/v3/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))
|
||||
}
|
||||
}
|
387
routers/controllers/file.go
Normal file
387
routers/controllers/file.go
Normal file
@ -0,0 +1,387 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/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))
|
||||
}
|
||||
}
|
||||
|
||||
func Archive(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate 创建文件转移任务
|
||||
func Relocate(c *gin.Context) {
|
||||
var service explorer.ItemRelocateService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.CreateRelocateTask(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// Thumb 获取文件缩略图
|
||||
func Thumb(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fs, err := filesystem.NewFileSystemFromContext(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))
|
||||
return
|
||||
}
|
||||
|
||||
// 获取缩略图
|
||||
resp, err := fs.GetThumb(ctx, fileID.(uint))
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeNotSet, "Failed to get thumbnail", err))
|
||||
return
|
||||
}
|
||||
|
||||
if resp.Redirect {
|
||||
c.Header("Cache-Control", fmt.Sprintf("max-age=%d", resp.MaxAge))
|
||||
c.Redirect(http.StatusMovedPermanently, resp.URL)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
request.BlackHole(c.Request.Body)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.ShouldBindQuery(&service); err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
res := service.Search(c)
|
||||
c.JSON(200, res)
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
69
routers/controllers/main.go
Normal file
69
routers/controllers/main.go
Normal file
@ -0,0 +1,69 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
// ParamErrorMsg 根据Validator返回的错误信息给出错误提示
|
||||
func ParamErrorMsg(filed string, tag string) string {
|
||||
// 未通过验证的表单域与中文对应
|
||||
fieldMap := map[string]string{
|
||||
"UserName": "Email",
|
||||
"Password": "Password",
|
||||
"Path": "Path",
|
||||
"SourceID": "Source resource",
|
||||
"URL": "URL",
|
||||
"Nick": "Nickname",
|
||||
}
|
||||
// 未通过的规则与中文对应
|
||||
tagMap := map[string]string{
|
||||
"required": "cannot be empty",
|
||||
"min": "too short",
|
||||
"max": "too long",
|
||||
"email": "format error",
|
||||
}
|
||||
fieldVal, findField := fieldMap[filed]
|
||||
if !findField {
|
||||
fieldVal = filed
|
||||
}
|
||||
tagVal, findTag := tagMap[tag]
|
||||
if findTag {
|
||||
// 返回拼接出来的错误信息
|
||||
return fieldVal + " " + tagVal
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ErrorResponse 返回错误消息
|
||||
func ErrorResponse(err error) serializer.Response {
|
||||
// 处理 Validator 产生的错误
|
||||
if ve, ok := err.(validator.ValidationErrors); ok {
|
||||
for _, e := range ve {
|
||||
return serializer.ParamErr(
|
||||
ParamErrorMsg(e.Field(), e.Tag()),
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := err.(*json.UnmarshalTypeError); ok {
|
||||
return serializer.ParamErr("JSON marshall error", err)
|
||||
}
|
||||
|
||||
return serializer.ParamErr("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
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
84
routers/controllers/objects.go
Normal file
84
routers/controllers/objects.go
Normal file
@ -0,0 +1,84 @@
|
||||
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))
|
||||
}
|
||||
}
|
259
routers/controllers/share.go
Normal file
259
routers/controllers/share.go
Normal file
@ -0,0 +1,259 @@
|
||||
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/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// SaveShare 转存他人分享
|
||||
func SaveShare(c *gin.Context) {
|
||||
var service share.Service
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.SaveToMyFile(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))
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.ShouldBindQuery(&service); err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
res := service.Search(c)
|
||||
c.JSON(200, res)
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// ReportShare 举报分享
|
||||
func ReportShare(c *gin.Context) {
|
||||
var service share.ShareReportService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Report(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
167
routers/controllers/site.go
Normal file
167
routers/controllers/site.go
Normal file
@ -0,0 +1,167 @@
|
||||
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/gin-gonic/gin"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
// SiteConfig 获取站点全局配置
|
||||
func SiteConfig(c *gin.Context) {
|
||||
siteConfig := model.GetSettingByNames(
|
||||
"siteName",
|
||||
"siteNotice",
|
||||
"login_captcha",
|
||||
"qq_login",
|
||||
"reg_captcha",
|
||||
"email_active",
|
||||
"forget_captcha",
|
||||
// "email_active",
|
||||
"themes",
|
||||
"defaultTheme",
|
||||
"score_enabled",
|
||||
"share_score_rate",
|
||||
"home_view_method",
|
||||
"share_view_method",
|
||||
"authn_enabled",
|
||||
"captcha_ReCaptchaKey",
|
||||
"captcha_type",
|
||||
"captcha_TCaptcha_CaptchaAppId",
|
||||
"register_enabled",
|
||||
"report_enabled",
|
||||
"show_app_promotion",
|
||||
"app_forum_link",
|
||||
"app_feedback_link",
|
||||
)
|
||||
|
||||
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))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.BuildSiteConfig(siteConfig, nil, wopiExts))
|
||||
}
|
||||
|
||||
// Ping 状态检查页面
|
||||
func Ping(c *gin.Context) {
|
||||
version := conf.BackendVersion
|
||||
if conf.IsPlus == "true" {
|
||||
version += "-plus"
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Code: 0,
|
||||
Data: version,
|
||||
})
|
||||
}
|
||||
|
||||
// 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,
|
||||
})
|
||||
}
|
||||
|
||||
// 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",
|
||||
)
|
||||
|
||||
c.JSON(200, map[string]interface{}{
|
||||
"short_name": options["siteName"],
|
||||
"name": options["siteTitle"],
|
||||
"icons": []map[string]string{
|
||||
{
|
||||
"src": options["pwa_small_icon"],
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon",
|
||||
},
|
||||
{
|
||||
"src": options["pwa_medium_icon"],
|
||||
"type": "image/png",
|
||||
"sizes": "192x192",
|
||||
},
|
||||
{
|
||||
"src": options["pwa_large_icon"],
|
||||
"type": "image/png",
|
||||
"sizes": "512x512",
|
||||
},
|
||||
},
|
||||
"start_url": ".",
|
||||
"display": options["pwa_display"],
|
||||
"theme_color": options["pwa_theme_color"],
|
||||
"background_color": options["pwa_background_color"],
|
||||
})
|
||||
}
|
||||
|
||||
// GetVolSecret 获取 VOL 密钥
|
||||
func GetVolSecret(c *gin.Context) {
|
||||
vol := model.GetSettingByNames("vol_content", "vol_signature")
|
||||
if vol["vol_signature"] == "" {
|
||||
c.JSON(200, serializer.Response{
|
||||
Code: serializer.CodeNotFound,
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: serializer.VolResponse{
|
||||
Signature: vol["vol_signature"],
|
||||
Content: vol["vol_content"],
|
||||
},
|
||||
})
|
||||
}
|
246
routers/controllers/slave.go
Normal file
246
routers/controllers/slave.go
Normal file
@ -0,0 +1,246 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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/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)
|
||||
request.BlackHole(c.Request.Body)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// SlaveDeleteUploadSession 从机删除上传会话
|
||||
func SlaveDeleteUploadSession(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// SlaveList 从机列出文件
|
||||
func SlaveList(c *gin.Context) {
|
||||
var service explorer.SlaveListService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.List(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
39
routers/controllers/tag.go
Normal file
39
routers/controllers/tag.go
Normal file
@ -0,0 +1,39 @@
|
||||
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))
|
||||
}
|
||||
}
|
445
routers/controllers/user.go
Normal file
445
routers/controllers/user.go
Normal file
@ -0,0 +1,445 @@
|
||||
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/qq"
|
||||
"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/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// StartLoginAuthn 开始注册WebAuthn登录
|
||||
func StartLoginAuthn(c *gin.Context) {
|
||||
userName := c.Param("username")
|
||||
expectedUser, err := model.GetActiveUserByEmail(userName)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeUserNotFound, "", 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})
|
||||
}
|
||||
|
||||
// FinishLoginAuthn 完成注册WebAuthn登录
|
||||
func FinishLoginAuthn(c *gin.Context) {
|
||||
userName := c.Param("username")
|
||||
expectedUser, err := model.GetActiveUserByEmail(userName)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeUserNotFound, "", err))
|
||||
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))
|
||||
}
|
||||
|
||||
// StartRegAuthn 开始注册WebAuthn信息
|
||||
func StartRegAuthn(c *gin.Context) {
|
||||
currUser := CurrentUser(c)
|
||||
|
||||
instance, err := authn.NewAuthnInstance()
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeInitializeAuthn, "Cannot initialize authn", 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})
|
||||
}
|
||||
|
||||
// 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()
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeInitializeAuthn, "Cannot initialize authn", err))
|
||||
return
|
||||
}
|
||||
|
||||
credential, err := instance.FinishRegistration(currUser, sessionData, c.Request)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = currUser.RegisterAuthn(credential)
|
||||
if err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Code: 0,
|
||||
Data: map[string]interface{}{
|
||||
"id": credential.ID,
|
||||
"fingerprint": fmt.Sprintf("% X", credential.Authenticator.AAGUID),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// UserQQLogin 初始化QQ登录
|
||||
func UserQQLogin(c *gin.Context) {
|
||||
// 新建绑定
|
||||
res, err := qq.NewLoginRequest()
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeNotSet, "无法使用QQ登录", err))
|
||||
return
|
||||
}
|
||||
|
||||
// 设定QQ登录会话Secret
|
||||
util.SetSession(c, map[string]interface{}{"qq_login_secret": res.SecretKey})
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Data: res.URL,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// UserSignOut 用户退出登录
|
||||
func UserSignOut(c *gin.Context) {
|
||||
util.DeleteSession(c, "user_id")
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// UserMe 获取当前登录的用户
|
||||
func UserMe(c *gin.Context) {
|
||||
currUser := CurrentUser(c)
|
||||
res := serializer.BuildUserResponse(*currUser)
|
||||
c.JSON(200, res)
|
||||
}
|
||||
|
||||
// UserStorage 获取用户的存储信息
|
||||
func UserStorage(c *gin.Context) {
|
||||
currUser := CurrentUser(c)
|
||||
res := serializer.BuildUserStorageResponse(*currUser)
|
||||
c.JSON(200, res)
|
||||
}
|
||||
|
||||
// UserAvailablePolicies 用户存储策略设置
|
||||
func UserAvailablePolicies(c *gin.Context) {
|
||||
var service user.SettingService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Policy(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// UserAvailableNodes 用户可选节点
|
||||
func UserAvailableNodes(c *gin.Context) {
|
||||
var service user.SettingService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Nodes(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
return
|
||||
}
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// 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))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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 "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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
214
routers/controllers/vas.go
Normal file
214
routers/controllers/vas.go
Normal file
@ -0,0 +1,214 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/payment"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/vas"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iGoogle-ink/gopay"
|
||||
"github.com/iGoogle-ink/gopay/wechat/v3"
|
||||
"github.com/qingwg/payjs/notify"
|
||||
"github.com/smartwalle/alipay/v3"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// GetQuota 获取容量配额信息
|
||||
func GetQuota(c *gin.Context) {
|
||||
var service vas.GeneralVASService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Quota(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// GetProduct 获取商品信息
|
||||
func GetProduct(c *gin.Context) {
|
||||
var service vas.GeneralVASService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Products(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// NewOrder 新建支付订单
|
||||
func NewOrder(c *gin.Context) {
|
||||
var service vas.CreateOrderService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Create(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// OrderStatus 查询订单状态
|
||||
func OrderStatus(c *gin.Context) {
|
||||
var service vas.OrderService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Status(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// GetRedeemInfo 获取兑换码信息
|
||||
func GetRedeemInfo(c *gin.Context) {
|
||||
var service vas.RedeemService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Query(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// DoRedeem 获取兑换码信息
|
||||
func DoRedeem(c *gin.Context) {
|
||||
var service vas.RedeemService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Redeem(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AlipayCallback 支付宝回调
|
||||
func AlipayCallback(c *gin.Context) {
|
||||
pay, err := payment.NewPaymentInstance("alipay")
|
||||
if err != nil {
|
||||
util.Log().Debug("[Alipay callback] Failed to create alipay client, %s", err)
|
||||
c.Status(400)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := pay.(*payment.Alipay).Client.GetTradeNotification(c.Request)
|
||||
if err != nil {
|
||||
util.Log().Debug("[Alipay callback] Failed to validate callback request, %s", err)
|
||||
c.Status(403)
|
||||
return
|
||||
}
|
||||
|
||||
if res != nil && res.TradeStatus == "TRADE_SUCCESS" {
|
||||
// 支付成功
|
||||
if err := payment.OrderPaid(res.OutTradeNo); err != nil {
|
||||
util.Log().Debug("[Alipay callback] Failed to process payment, %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 确认收到通知消息
|
||||
alipay.AckNotification(c.Writer)
|
||||
}
|
||||
|
||||
// WechatCallback 微信扫码支付回调
|
||||
func WechatCallback(c *gin.Context) {
|
||||
pay, err := payment.NewPaymentInstance("wechat")
|
||||
if err != nil {
|
||||
util.Log().Debug("[Wechat pay callback] Failed to create alipay client, %s", err)
|
||||
c.JSON(500, &wechat.V3NotifyRsp{Code: gopay.FAIL, Message: "Failed to create alipay client"})
|
||||
return
|
||||
}
|
||||
|
||||
notifyReq, err := wechat.V3ParseNotify(c.Request)
|
||||
if err != nil {
|
||||
util.Log().Debug("[Wechat pay callback] Failed to parse callback content, %s", err)
|
||||
c.JSON(500, &wechat.V3NotifyRsp{Code: gopay.FAIL, Message: "Failed to parse callback content"})
|
||||
return
|
||||
}
|
||||
|
||||
err = notifyReq.VerifySign(pay.(*payment.Wechat).GetPlatformCert())
|
||||
if err != nil {
|
||||
util.Log().Debug("[Wechat pay callback] Failed to verify callback signature, %s", err)
|
||||
c.JSON(403, &wechat.V3NotifyRsp{Code: gopay.FAIL, Message: "Failed to verify callback signature"})
|
||||
return
|
||||
}
|
||||
|
||||
// 解密回调正文
|
||||
result, err := notifyReq.DecryptCipherText(pay.(*payment.Wechat).ApiV3Key)
|
||||
if result != nil && result.TradeState == "SUCCESS" {
|
||||
// 支付成功
|
||||
if err := payment.OrderPaid(result.OutTradeNo); err != nil {
|
||||
util.Log().Debug("[Wechat pay callback] Failed to process payment, %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 确认收到通知消息
|
||||
c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "Success"})
|
||||
}
|
||||
|
||||
// PayJSCallback PayJS回调
|
||||
func PayJSCallback(c *gin.Context) {
|
||||
pay, err := payment.NewPaymentInstance("payjs")
|
||||
if err != nil {
|
||||
util.Log().Debug("[PayJS callback] Failed to initialize payment client, %s", err)
|
||||
c.Status(400)
|
||||
return
|
||||
}
|
||||
|
||||
payNotify := pay.(*payment.PayJSClient).Client.GetNotify(c.Request, c.Writer)
|
||||
|
||||
//设置接收消息的处理方法
|
||||
payNotify.SetMessageHandler(func(msg notify.Message) {
|
||||
if err := payment.OrderPaid(msg.OutTradeNo); err != nil {
|
||||
util.Log().Debug("[PayJS callback] Failed to process payment, %s", err)
|
||||
}
|
||||
})
|
||||
|
||||
//处理消息接收以及回复
|
||||
err = payNotify.Serve()
|
||||
if err != nil {
|
||||
util.Log().Debug("[PayJS callback] Failed to process payment, %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
//发送回复的消息
|
||||
payNotify.SendResponseMsg()
|
||||
|
||||
}
|
||||
|
||||
// QQCallback QQ互联回调
|
||||
func QQCallback(c *gin.Context) {
|
||||
var service vas.QQCallbackService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Callback(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// CustomCallback PayJS回调
|
||||
func CustomCallback(c *gin.Context) {
|
||||
orderNo := c.Param("orderno")
|
||||
sessionID := c.Param("id")
|
||||
sessionRaw, exist := cache.Get(payment.CallbackSessionPrefix + sessionID)
|
||||
if !exist {
|
||||
util.Log().Debug("[Custom callback] Failed to process payment, session not found")
|
||||
c.JSON(200, serializer.Err(serializer.CodeNotFound, "session not found", nil))
|
||||
return
|
||||
}
|
||||
|
||||
expectedID := sessionRaw.(string)
|
||||
if expectedID != orderNo {
|
||||
util.Log().Debug("[Custom callback] Failed to process payment, session mismatch")
|
||||
c.JSON(200, serializer.Err(serializer.CodeInternalSetting, "session mismatch", nil))
|
||||
return
|
||||
}
|
||||
|
||||
cache.Deletes([]string{sessionID}, payment.CallbackSessionPrefix)
|
||||
|
||||
if err := payment.OrderPaid(orderNo); err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeInternalSetting, "failed to fulfill payment", err))
|
||||
util.Log().Debug("[Custom callback] Failed to process payment, %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{})
|
||||
}
|
138
routers/controllers/webdav.go
Normal file
138
routers/controllers/webdav.go
Normal file
@ -0,0 +1,138 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
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/gin-gonic/gin"
|
||||
)
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
util.Log().Warning("Failed to initialize filesystem for WebDAV,%s", err)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateWebDAVAccountsReadonly 更改WebDAV账户只读性
|
||||
func UpdateWebDAVAccountsReadonly(c *gin.Context) {
|
||||
var service setting.WebDAVAccountUpdateReadonlyService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Update(c, CurrentUser(c))
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
77
routers/controllers/wopi.go
Normal file
77
routers/controllers/wopi.go
Normal file
@ -0,0 +1,77 @@
|
||||
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/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// CheckFileInfo Get file info
|
||||
func CheckFileInfo(c *gin.Context) {
|
||||
var service explorer.WopiService
|
||||
res, err := service.FileInfo(c)
|
||||
if err != nil {
|
||||
c.Status(http.StatusInternalServerError)
|
||||
c.Header(wopi.ServerErrorHeader, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, res)
|
||||
}
|
||||
|
||||
// GetFile Get file content
|
||||
func GetFile(c *gin.Context) {
|
||||
var service explorer.WopiService
|
||||
err := service.GetFile(c)
|
||||
if err != nil {
|
||||
c.Status(http.StatusInternalServerError)
|
||||
c.Header(wopi.ServerErrorHeader, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 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:
|
||||
c.Status(http.StatusInternalServerError)
|
||||
c.Header(wopi.ServerErrorHeader, res.Error)
|
||||
}
|
||||
}
|
||||
|
||||
// ModifyFile Modify file properties
|
||||
func ModifyFile(c *gin.Context) {
|
||||
action := c.GetHeader(wopi.OverwriteHeader)
|
||||
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())
|
||||
return
|
||||
}
|
||||
default:
|
||||
c.Status(http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
}
|
864
routers/router.go
Normal file
864
routers/router.go
Normal file
@ -0,0 +1,864 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
// "github.com/abslant/gzip"
|
||||
"github.com/cloudreve/Cloudreve/v3/bootstrap"
|
||||
"github.com/cloudreve/Cloudreve/v3/middleware"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/auth"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/cluster"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/conf"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/hashid"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||
wopi2 "github.com/cloudreve/Cloudreve/v3/pkg/wopi"
|
||||
"github.com/cloudreve/Cloudreve/v3/routers/controllers"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-contrib/gzip"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// InitRouter 初始化路由
|
||||
func InitRouter() *gin.Engine {
|
||||
if conf.SystemConfig.Mode == "master" {
|
||||
util.Log().Info("Current running mode: Master.")
|
||||
return InitMasterRouter()
|
||||
}
|
||||
util.Log().Info("Current running mode: Slave.")
|
||||
return InitSlaveRouter()
|
||||
|
||||
}
|
||||
|
||||
// InitSlaveRouter 初始化从机模式路由
|
||||
func InitSlaveRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
// 跨域相关
|
||||
InitCORS(r)
|
||||
v3 := r.Group("/api/v3/slave")
|
||||
// 鉴权中间件
|
||||
v3.Use(middleware.SignRequired(auth.General))
|
||||
// 主机信息解析
|
||||
v3.Use(middleware.MasterMetadata())
|
||||
// 禁止缓存
|
||||
v3.Use(middleware.CacheControl())
|
||||
|
||||
/*
|
||||
路由
|
||||
*/
|
||||
{
|
||||
// Ping
|
||||
v3.POST("ping", controllers.SlavePing)
|
||||
// 测试 Aria2 RPC 连接
|
||||
v3.POST("ping/aria2", controllers.AdminTestAria2)
|
||||
// 接收主机心跳包
|
||||
v3.POST("heartbeat", controllers.SlaveHeartbeat)
|
||||
// 上传
|
||||
upload := v3.Group("upload")
|
||||
{
|
||||
// 上传分片
|
||||
upload.POST(":sessionId", controllers.SlaveUpload)
|
||||
// 创建上传会话上传
|
||||
upload.PUT("", controllers.SlaveGetUploadSession)
|
||||
// 删除上传会话
|
||||
upload.DELETE(":sessionId", controllers.SlaveDeleteUploadSession)
|
||||
}
|
||||
// 下载
|
||||
v3.GET("download/:speed/:path/:name", controllers.SlaveDownload)
|
||||
// 预览 / 外链
|
||||
v3.GET("source/:speed/:path/:name", controllers.SlavePreview)
|
||||
// 缩略图
|
||||
v3.GET("thumb/:path/:ext", controllers.SlaveThumb)
|
||||
// 删除文件
|
||||
v3.POST("delete", controllers.SlaveDelete)
|
||||
// 列出文件
|
||||
v3.POST("list", controllers.SlaveList)
|
||||
|
||||
// 离线下载
|
||||
aria2 := v3.Group("aria2")
|
||||
aria2.Use(middleware.UseSlaveAria2Instance(cluster.DefaultController))
|
||||
{
|
||||
// 创建离线下载任务
|
||||
aria2.POST("task", controllers.SlaveAria2Create)
|
||||
// 获取任务状态
|
||||
aria2.POST("status", controllers.SlaveAria2Status)
|
||||
// 取消离线下载任务
|
||||
aria2.POST("cancel", controllers.SlaveCancelAria2Task)
|
||||
// 选取任务文件
|
||||
aria2.POST("select", controllers.SlaveSelectTask)
|
||||
// 删除任务临时文件
|
||||
aria2.POST("delete", controllers.SlaveDeleteTempFile)
|
||||
}
|
||||
|
||||
// 异步任务
|
||||
task := v3.Group("task")
|
||||
{
|
||||
task.PUT("transfer", controllers.SlaveCreateTransferTask)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// InitCORS 初始化跨域配置
|
||||
func InitCORS(router *gin.Engine) {
|
||||
if conf.CORSConfig.AllowOrigins[0] != "UNSET" {
|
||||
router.Use(cors.New(cors.Config{
|
||||
AllowOrigins: conf.CORSConfig.AllowOrigins,
|
||||
AllowMethods: conf.CORSConfig.AllowMethods,
|
||||
AllowHeaders: conf.CORSConfig.AllowHeaders,
|
||||
AllowCredentials: conf.CORSConfig.AllowCredentials,
|
||||
ExposeHeaders: conf.CORSConfig.ExposeHeaders,
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
// slave模式下未启动跨域的警告
|
||||
if conf.SystemConfig.Mode == "slave" {
|
||||
util.Log().Warning("You are running Cloudreve as slave node, if you are using slave storage policy, please enable CORS feature in config file, otherwise file cannot be uploaded from Master site.")
|
||||
}
|
||||
}
|
||||
|
||||
// InitMasterRouter 初始化主机模式路由
|
||||
func InitMasterRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
bootstrap.InitCustomRoute(r.Group("/api/v3"))
|
||||
// bootstrap.InitCustomRoute(r.Group("/custom"))
|
||||
|
||||
/*
|
||||
静态资源
|
||||
*/
|
||||
r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{"/api/"})))
|
||||
// r.Use(gzip.GzipHandler())
|
||||
r.Use(middleware.FrontendFileHandler())
|
||||
r.GET("manifest.json", controllers.Manifest)
|
||||
|
||||
v3 := r.Group("/api/v3")
|
||||
|
||||
/*
|
||||
中间件
|
||||
*/
|
||||
v3.Use(middleware.Session(conf.SystemConfig.SessionSecret))
|
||||
// 跨域相关
|
||||
InitCORS(r)
|
||||
// 测试模式加入Mock助手中间件
|
||||
if gin.Mode() == gin.TestMode {
|
||||
v3.Use(middleware.MockHelper())
|
||||
}
|
||||
// 用户会话
|
||||
v3.Use(middleware.CurrentUser())
|
||||
|
||||
// 禁止缓存
|
||||
v3.Use(middleware.CacheControl())
|
||||
|
||||
/*
|
||||
路由
|
||||
*/
|
||||
{
|
||||
// Redirect file source link
|
||||
source := r.Group("f")
|
||||
{
|
||||
source.GET(":id/:name",
|
||||
middleware.HashID(hashid.SourceLinkID),
|
||||
middleware.ValidateSourceLink(),
|
||||
controllers.AnonymousPermLink)
|
||||
}
|
||||
|
||||
// 全局设置相关
|
||||
site := v3.Group("site")
|
||||
{
|
||||
// 测试用路由
|
||||
site.GET("ping", controllers.Ping)
|
||||
// 验证码
|
||||
site.GET("captcha", controllers.Captcha)
|
||||
// 站点全局配置
|
||||
site.GET("config", middleware.CSRFInit(), controllers.SiteConfig)
|
||||
// VOL 密钥
|
||||
site.GET("vol", controllers.GetVolSecret)
|
||||
}
|
||||
|
||||
// 用户相关路由
|
||||
user := v3.Group("user")
|
||||
{
|
||||
// 用户登录
|
||||
user.POST("session", middleware.CaptchaRequired("login_captcha"), controllers.UserLogin)
|
||||
// 用户注册
|
||||
user.POST("",
|
||||
middleware.IsFunctionEnabled("register_enabled"),
|
||||
middleware.CaptchaRequired("reg_captcha"),
|
||||
controllers.UserRegister,
|
||||
)
|
||||
// 用二步验证户登录
|
||||
user.POST("2fa", controllers.User2FALogin)
|
||||
// 发送密码重设邮件
|
||||
user.POST("reset", middleware.CaptchaRequired("forget_captcha"), controllers.UserSendReset)
|
||||
// 通过邮件里的链接重设密码
|
||||
user.PATCH("reset", controllers.UserReset)
|
||||
// 邮件激活
|
||||
user.GET("activate/:id",
|
||||
middleware.SignRequired(auth.General),
|
||||
middleware.HashID(hashid.UserID),
|
||||
controllers.UserActivate,
|
||||
)
|
||||
// 初始化QQ登录
|
||||
user.POST("qq", controllers.UserQQLogin)
|
||||
// WebAuthn登陆初始化
|
||||
user.GET("authn/:username",
|
||||
middleware.IsFunctionEnabled("authn_enabled"),
|
||||
controllers.StartLoginAuthn,
|
||||
)
|
||||
// WebAuthn登陆
|
||||
user.POST("authn/finish/:username",
|
||||
middleware.IsFunctionEnabled("authn_enabled"),
|
||||
controllers.FinishLoginAuthn,
|
||||
)
|
||||
// 获取用户主页展示用分享
|
||||
user.GET("profile/:id",
|
||||
middleware.HashID(hashid.UserID),
|
||||
controllers.GetUserShare,
|
||||
)
|
||||
// 获取用户头像
|
||||
user.GET("avatar/:id/:size",
|
||||
middleware.HashID(hashid.UserID),
|
||||
middleware.StaticResourceCache(),
|
||||
controllers.GetUserAvatar,
|
||||
)
|
||||
}
|
||||
|
||||
// 需要携带签名验证的
|
||||
sign := v3.Group("")
|
||||
sign.Use(middleware.SignRequired(auth.General))
|
||||
{
|
||||
file := sign.Group("file")
|
||||
{
|
||||
// 文件外链(直接输出文件数据)
|
||||
file.GET("get/:id/:name",
|
||||
middleware.Sandbox(),
|
||||
middleware.StaticResourceCache(),
|
||||
controllers.AnonymousGetContent,
|
||||
)
|
||||
// 文件外链(301跳转)
|
||||
file.GET("source/:id/:name", controllers.AnonymousPermLinkDeprecated)
|
||||
// 下载文件
|
||||
file.GET("download/:id",
|
||||
middleware.StaticResourceCache(),
|
||||
controllers.Download,
|
||||
)
|
||||
// 打包并下载文件
|
||||
file.GET("archive/:sessionID/archive.zip", controllers.DownloadArchive)
|
||||
}
|
||||
|
||||
// Copy user session
|
||||
sign.GET(
|
||||
"user/session/copy/:id",
|
||||
middleware.MobileRequestOnly(),
|
||||
controllers.UserPerformCopySession,
|
||||
)
|
||||
}
|
||||
|
||||
// 从机的 RPC 通信
|
||||
slave := v3.Group("slave")
|
||||
slave.Use(middleware.SlaveRPCSignRequired(cluster.Default))
|
||||
{
|
||||
// 事件通知
|
||||
slave.PUT("notification/:subject", controllers.SlaveNotificationPush)
|
||||
// 上传
|
||||
upload := slave.Group("upload")
|
||||
{
|
||||
// 上传分片
|
||||
upload.POST(":sessionId", controllers.SlaveUpload)
|
||||
// 创建上传会话上传
|
||||
upload.PUT("", controllers.SlaveGetUploadSession)
|
||||
// 删除上传会话
|
||||
upload.DELETE(":sessionId", controllers.SlaveDeleteUploadSession)
|
||||
}
|
||||
// Oauth 存储策略凭证
|
||||
slave.GET("credential/:id", controllers.SlaveGetOauthCredential)
|
||||
}
|
||||
|
||||
// 回调接口
|
||||
callback := v3.Group("callback")
|
||||
{
|
||||
// QQ互联回调
|
||||
callback.POST(
|
||||
"qq",
|
||||
controllers.QQCallback,
|
||||
)
|
||||
// PAYJS回调
|
||||
callback.POST(
|
||||
"payjs",
|
||||
controllers.PayJSCallback,
|
||||
)
|
||||
// 支付宝回调
|
||||
callback.POST(
|
||||
"alipay",
|
||||
controllers.AlipayCallback,
|
||||
)
|
||||
// 微信扫码支付回调
|
||||
callback.POST(
|
||||
"wechat",
|
||||
controllers.WechatCallback,
|
||||
)
|
||||
// Custom payment callback
|
||||
callback.GET(
|
||||
"custom/:orderno/:id",
|
||||
middleware.SignRequired(auth.General),
|
||||
controllers.CustomCallback,
|
||||
)
|
||||
// 远程策略上传回调
|
||||
callback.POST(
|
||||
"remote/:sessionID/:key",
|
||||
middleware.UseUploadSession("remote"),
|
||||
middleware.RemoteCallbackAuth(),
|
||||
controllers.RemoteCallback,
|
||||
)
|
||||
// 七牛策略上传回调
|
||||
callback.POST(
|
||||
"qiniu/:sessionID",
|
||||
middleware.UseUploadSession("qiniu"),
|
||||
middleware.QiniuCallbackAuth(),
|
||||
controllers.QiniuCallback,
|
||||
)
|
||||
// 阿里云OSS策略上传回调
|
||||
callback.POST(
|
||||
"oss/:sessionID",
|
||||
middleware.UseUploadSession("oss"),
|
||||
middleware.OSSCallbackAuth(),
|
||||
controllers.OSSCallback,
|
||||
)
|
||||
// 又拍云策略上传回调
|
||||
callback.POST(
|
||||
"upyun/:sessionID",
|
||||
middleware.UseUploadSession("upyun"),
|
||||
middleware.UpyunCallbackAuth(),
|
||||
controllers.UpyunCallback,
|
||||
)
|
||||
onedrive := callback.Group("onedrive")
|
||||
{
|
||||
// 文件上传完成
|
||||
onedrive.POST(
|
||||
"finish/:sessionID",
|
||||
middleware.UseUploadSession("onedrive"),
|
||||
middleware.OneDriveCallbackAuth(),
|
||||
controllers.OneDriveCallback,
|
||||
)
|
||||
// OAuth 完成
|
||||
onedrive.GET(
|
||||
"auth",
|
||||
controllers.OneDriveOAuth,
|
||||
)
|
||||
}
|
||||
// Google Drive related
|
||||
gdrive := callback.Group("googledrive")
|
||||
{
|
||||
// OAuth 完成
|
||||
gdrive.GET(
|
||||
"auth",
|
||||
controllers.GoogleDriveOAuth,
|
||||
)
|
||||
}
|
||||
// 腾讯云COS策略上传回调
|
||||
callback.GET(
|
||||
"cos/:sessionID",
|
||||
middleware.UseUploadSession("cos"),
|
||||
controllers.COSCallback,
|
||||
)
|
||||
// AWS S3策略上传回调
|
||||
callback.GET(
|
||||
"s3/:sessionID",
|
||||
middleware.UseUploadSession("s3"),
|
||||
controllers.S3Callback,
|
||||
)
|
||||
}
|
||||
|
||||
// 分享相关
|
||||
share := v3.Group("share", middleware.ShareAvailable())
|
||||
{
|
||||
// 获取分享
|
||||
share.GET("info/:id", controllers.GetShare)
|
||||
// 创建文件下载会话
|
||||
share.PUT("download/:id",
|
||||
middleware.CheckShareUnlocked(),
|
||||
middleware.BeforeShareDownload(),
|
||||
controllers.GetShareDownload,
|
||||
)
|
||||
// 预览分享文件
|
||||
share.GET("preview/:id",
|
||||
middleware.CSRFCheck(),
|
||||
middleware.CheckShareUnlocked(),
|
||||
middleware.ShareCanPreview(),
|
||||
middleware.BeforeShareDownload(),
|
||||
controllers.PreviewShare,
|
||||
)
|
||||
// 取得Office文档预览地址
|
||||
share.GET("doc/:id",
|
||||
middleware.CheckShareUnlocked(),
|
||||
middleware.ShareCanPreview(),
|
||||
middleware.BeforeShareDownload(),
|
||||
controllers.GetShareDocPreview,
|
||||
)
|
||||
// 获取文本文件内容
|
||||
share.GET("content/:id",
|
||||
middleware.CheckShareUnlocked(),
|
||||
middleware.BeforeShareDownload(),
|
||||
controllers.PreviewShareText,
|
||||
)
|
||||
// 分享目录列文件
|
||||
share.GET("list/:id/*path",
|
||||
middleware.CheckShareUnlocked(),
|
||||
controllers.ListSharedFolder,
|
||||
)
|
||||
// 分享目录搜索
|
||||
share.GET("search/:id/:type/:keywords",
|
||||
middleware.CheckShareUnlocked(),
|
||||
controllers.SearchSharedFolder,
|
||||
)
|
||||
// 归档打包下载
|
||||
share.POST("archive/:id",
|
||||
middleware.CheckShareUnlocked(),
|
||||
middleware.BeforeShareDownload(),
|
||||
controllers.ArchiveShare,
|
||||
)
|
||||
// 获取README文本文件内容
|
||||
share.GET("readme/:id",
|
||||
middleware.CheckShareUnlocked(),
|
||||
controllers.PreviewShareReadme,
|
||||
)
|
||||
// 获取缩略图
|
||||
share.GET("thumb/:id/:file",
|
||||
middleware.CheckShareUnlocked(),
|
||||
middleware.ShareCanPreview(),
|
||||
controllers.ShareThumb,
|
||||
)
|
||||
// 举报分享
|
||||
share.POST("report/:id",
|
||||
middleware.IsFunctionEnabled("report_enabled"),
|
||||
middleware.CheckShareUnlocked(),
|
||||
controllers.ReportShare,
|
||||
)
|
||||
// 搜索公共分享
|
||||
v3.Group("share").GET("search", middleware.AuthRequired(), controllers.SearchShare)
|
||||
}
|
||||
|
||||
wopi := v3.Group(
|
||||
"wopi",
|
||||
middleware.HashID(hashid.FileID),
|
||||
middleware.WopiAccessValidation(wopi2.Default, cache.Store),
|
||||
)
|
||||
{
|
||||
// 获取文件信息
|
||||
wopi.GET("files/:id", controllers.CheckFileInfo)
|
||||
// 获取文件内容
|
||||
wopi.GET("files/:id/contents", controllers.GetFile)
|
||||
// 更新文件内容
|
||||
wopi.POST("files/:id/contents", middleware.WopiWriteAccess(), controllers.PutFile)
|
||||
// 通用文件操作
|
||||
wopi.POST("files/:id", middleware.WopiWriteAccess(), controllers.ModifyFile)
|
||||
}
|
||||
|
||||
// 需要登录保护的
|
||||
auth := v3.Group("")
|
||||
auth.Use(middleware.AuthRequired())
|
||||
{
|
||||
// 管理
|
||||
admin := auth.Group("admin", middleware.IsAdmin())
|
||||
{
|
||||
// 获取站点概况
|
||||
admin.GET("summary", controllers.AdminSummary)
|
||||
// 获取社区新闻
|
||||
// admin.GET("news", controllers.AdminNews)
|
||||
// 更改设置
|
||||
admin.PATCH("setting", controllers.AdminChangeSetting)
|
||||
// 获取设置
|
||||
admin.POST("setting", controllers.AdminGetSetting)
|
||||
// 获取用户组列表
|
||||
admin.GET("groups", controllers.AdminGetGroups)
|
||||
// 重新加载子服务
|
||||
admin.GET("reload/:service", controllers.AdminReloadService)
|
||||
// 测试设置
|
||||
test := admin.Group("test")
|
||||
{
|
||||
// 测试邮件设置
|
||||
test.POST("mail", controllers.AdminSendTestMail)
|
||||
// 测试缩略图生成器调用
|
||||
test.POST("thumb", controllers.AdminTestThumbGenerator)
|
||||
}
|
||||
|
||||
// 离线下载相关
|
||||
aria2 := admin.Group("aria2")
|
||||
{
|
||||
// 测试连接配置
|
||||
aria2.POST("test", controllers.AdminTestAria2)
|
||||
}
|
||||
|
||||
vol := admin.Group("vol")
|
||||
{
|
||||
vol.GET("sync", controllers.AdminSyncVol)
|
||||
}
|
||||
|
||||
// 兑换码相关
|
||||
redeem := admin.Group("redeem")
|
||||
{
|
||||
// 列出激活码
|
||||
redeem.POST("list", controllers.AdminListRedeems)
|
||||
// 生成激活码
|
||||
redeem.POST("", controllers.AdminGenerateRedeems)
|
||||
// 删除激活码
|
||||
redeem.DELETE(":id", controllers.AdminDeleteRedeem)
|
||||
}
|
||||
|
||||
// 存储策略管理
|
||||
policy := admin.Group("policy")
|
||||
{
|
||||
// 列出存储策略
|
||||
policy.POST("list", controllers.AdminListPolicy)
|
||||
// 测试本地路径可用性
|
||||
policy.POST("test/path", controllers.AdminTestPath)
|
||||
// 测试从机通信
|
||||
policy.POST("test/slave", controllers.AdminTestSlave)
|
||||
// 创建存储策略
|
||||
policy.POST("", controllers.AdminAddPolicy)
|
||||
// 创建跨域策略
|
||||
policy.POST("cors", controllers.AdminAddCORS)
|
||||
// 创建COS回调函数
|
||||
policy.POST("scf", controllers.AdminAddSCF)
|
||||
// 获取 OneDrive OAuth URL
|
||||
oauth := policy.Group(":id/oauth")
|
||||
{
|
||||
// 获取 OneDrive OAuth URL
|
||||
oauth.GET("onedrive", controllers.AdminOAuthURL("onedrive"))
|
||||
// 获取 Google Drive OAuth URL
|
||||
oauth.GET("googledrive", controllers.AdminOAuthURL("googledrive"))
|
||||
}
|
||||
|
||||
// 获取 存储策略
|
||||
policy.GET(":id", controllers.AdminGetPolicy)
|
||||
// 删除 存储策略
|
||||
policy.DELETE(":id", controllers.AdminDeletePolicy)
|
||||
}
|
||||
|
||||
// 用户组管理
|
||||
group := admin.Group("group")
|
||||
{
|
||||
// 列出用户组
|
||||
group.POST("list", controllers.AdminListGroup)
|
||||
// 获取用户组
|
||||
group.GET(":id", controllers.AdminGetGroup)
|
||||
// 创建/保存用户组
|
||||
group.POST("", controllers.AdminAddGroup)
|
||||
// 删除
|
||||
group.DELETE(":id", controllers.AdminDeleteGroup)
|
||||
}
|
||||
|
||||
user := admin.Group("user")
|
||||
{
|
||||
// 列出用户
|
||||
user.POST("list", controllers.AdminListUser)
|
||||
// 获取用户
|
||||
user.GET(":id", controllers.AdminGetUser)
|
||||
// 创建/保存用户
|
||||
user.POST("", controllers.AdminAddUser)
|
||||
// 删除
|
||||
user.POST("delete", controllers.AdminDeleteUser)
|
||||
// 封禁/解封用户
|
||||
user.PATCH("ban/:id", controllers.AdminBanUser)
|
||||
}
|
||||
|
||||
file := admin.Group("file")
|
||||
{
|
||||
// 列出文件
|
||||
file.POST("list", controllers.AdminListFile)
|
||||
// 预览文件
|
||||
file.GET("preview/:id", middleware.Sandbox(), controllers.AdminGetFile)
|
||||
// 删除
|
||||
file.POST("delete", controllers.AdminDeleteFile)
|
||||
// 列出用户或外部文件系统目录
|
||||
file.GET("folders/:type/:id/*path",
|
||||
controllers.AdminListFolders)
|
||||
}
|
||||
|
||||
share := admin.Group("share")
|
||||
{
|
||||
// 列出分享
|
||||
share.POST("list", controllers.AdminListShare)
|
||||
// 删除
|
||||
share.POST("delete", controllers.AdminDeleteShare)
|
||||
}
|
||||
|
||||
order := admin.Group("order")
|
||||
{
|
||||
// 列出订单
|
||||
order.POST("list", controllers.AdminListOrder)
|
||||
// 删除
|
||||
order.POST("delete", controllers.AdminDeleteOrder)
|
||||
}
|
||||
|
||||
download := admin.Group("download")
|
||||
{
|
||||
// 列出任务
|
||||
download.POST("list", controllers.AdminListDownload)
|
||||
// 删除
|
||||
download.POST("delete", controllers.AdminDeleteDownload)
|
||||
}
|
||||
|
||||
task := admin.Group("task")
|
||||
{
|
||||
// 列出任务
|
||||
task.POST("list", controllers.AdminListTask)
|
||||
// 删除
|
||||
task.POST("delete", controllers.AdminDeleteTask)
|
||||
// 新建文件导入任务
|
||||
task.POST("import", controllers.AdminCreateImportTask)
|
||||
}
|
||||
|
||||
report := admin.Group("report")
|
||||
{
|
||||
// 列出未处理举报
|
||||
report.POST("list", controllers.AdminListReport)
|
||||
// 删除
|
||||
report.POST("delete", controllers.AdminDeleteReport)
|
||||
}
|
||||
|
||||
node := admin.Group("node")
|
||||
{
|
||||
// 列出从机节点
|
||||
node.POST("list", controllers.AdminListNodes)
|
||||
// 列出从机节点
|
||||
node.POST("aria2/test", controllers.AdminTestAria2)
|
||||
// 创建/保存节点
|
||||
node.POST("", controllers.AdminAddNode)
|
||||
// 启用/暂停节点
|
||||
node.PATCH("enable/:id/:desired", controllers.AdminToggleNode)
|
||||
// 删除节点
|
||||
node.DELETE(":id", controllers.AdminDeleteNode)
|
||||
// 获取节点
|
||||
node.GET(":id", controllers.AdminGetNode)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 用户
|
||||
user := auth.Group("user")
|
||||
{
|
||||
// 当前登录用户信息
|
||||
user.GET("me", controllers.UserMe)
|
||||
// 存储信息
|
||||
user.GET("storage", controllers.UserStorage)
|
||||
// 退出登录
|
||||
user.DELETE("session", controllers.UserSignOut)
|
||||
// Generate temp URL for copying client-side session, used in adding accounts
|
||||
// for mobile App.
|
||||
user.GET("session", controllers.UserPrepareCopySession)
|
||||
|
||||
// WebAuthn 注册相关
|
||||
authn := user.Group("authn",
|
||||
middleware.IsFunctionEnabled("authn_enabled"))
|
||||
{
|
||||
authn.PUT("", controllers.StartRegAuthn)
|
||||
authn.PUT("finish", controllers.FinishRegAuthn)
|
||||
}
|
||||
|
||||
// 用户设置
|
||||
setting := user.Group("setting")
|
||||
{
|
||||
// 获取用户可选存储策略
|
||||
setting.GET("policies", controllers.UserAvailablePolicies)
|
||||
// 获取用户可选节点
|
||||
setting.GET("nodes", controllers.UserAvailableNodes)
|
||||
// 任务队列
|
||||
setting.GET("tasks", controllers.UserTasks)
|
||||
// 获取当前用户设定
|
||||
setting.GET("", controllers.UserSetting)
|
||||
// 从文件上传头像
|
||||
setting.POST("avatar", controllers.UploadAvatar)
|
||||
// 设定为Gravatar头像
|
||||
setting.PUT("avatar", controllers.UseGravatar)
|
||||
// 更改用户设定
|
||||
setting.PATCH(":option", controllers.UpdateOption)
|
||||
// 获得二步验证初始化信息
|
||||
setting.GET("2fa", controllers.UserInit2FA)
|
||||
}
|
||||
}
|
||||
|
||||
// 文件
|
||||
file := auth.Group("file", middleware.PhoneRequired(), middleware.HashID(hashid.FileID))
|
||||
{
|
||||
// 上传
|
||||
upload := file.Group("upload")
|
||||
{
|
||||
// 文件上传
|
||||
upload.POST(":sessionId/:index", controllers.FileUpload)
|
||||
// 创建上传会话
|
||||
upload.PUT("", controllers.GetUploadSession)
|
||||
// 删除给定上传会话
|
||||
upload.DELETE(":sessionId", controllers.DeleteUploadSession)
|
||||
// 删除全部上传会话
|
||||
upload.DELETE("", controllers.DeleteAllUploadSession)
|
||||
}
|
||||
// 更新文件
|
||||
file.PUT("update/:id", controllers.PutContent)
|
||||
// 创建空白文件
|
||||
file.POST("create", controllers.CreateFile)
|
||||
// 创建文件下载会话
|
||||
file.PUT("download/:id", controllers.CreateDownloadSession)
|
||||
// 预览文件
|
||||
file.GET("preview/:id", middleware.Sandbox(), controllers.Preview)
|
||||
// 获取文本文件内容
|
||||
file.GET("content/:id", middleware.Sandbox(), controllers.PreviewText)
|
||||
// 取得Office文档预览地址
|
||||
file.GET("doc/:id", controllers.GetDocPreview)
|
||||
// 获取缩略图
|
||||
file.GET("thumb/:id", controllers.Thumb)
|
||||
// 取得文件外链
|
||||
file.POST("source", controllers.GetSource)
|
||||
// 打包要下载的文件
|
||||
file.POST("archive", controllers.Archive)
|
||||
// 创建文件压缩任务
|
||||
file.POST("compress", controllers.Compress)
|
||||
// 创建文件解压缩任务
|
||||
file.POST("decompress", controllers.Decompress)
|
||||
// 创建文件转移任务
|
||||
file.POST("relocate", controllers.Relocate)
|
||||
// 搜索文件
|
||||
file.GET("search/:type/:keywords", controllers.SearchFile)
|
||||
}
|
||||
|
||||
// 离线下载任务
|
||||
aria2 := auth.Group("aria2", middleware.PhoneRequired())
|
||||
{
|
||||
// 创建URL下载任务
|
||||
aria2.POST("url", controllers.AddAria2URL)
|
||||
// 创建种子下载任务
|
||||
aria2.POST("torrent/:id", middleware.HashID(hashid.FileID), controllers.AddAria2Torrent)
|
||||
// 重新选择要下载的文件
|
||||
aria2.PUT("select/:gid", controllers.SelectAria2File)
|
||||
// 取消或删除下载任务
|
||||
aria2.DELETE("task/:gid", controllers.CancelAria2Download)
|
||||
// 获取正在下载中的任务
|
||||
aria2.GET("downloading", controllers.ListDownloading)
|
||||
// 获取已完成的任务
|
||||
aria2.GET("finished", controllers.ListFinished)
|
||||
}
|
||||
|
||||
// 目录
|
||||
directory := auth.Group("directory", middleware.PhoneRequired())
|
||||
{
|
||||
// 创建目录
|
||||
directory.PUT("", controllers.CreateDirectory)
|
||||
// 列出目录下内容
|
||||
directory.GET("*path", controllers.ListDirectory)
|
||||
}
|
||||
|
||||
// 对象,文件和目录的抽象
|
||||
object := auth.Group("object", middleware.PhoneRequired())
|
||||
{
|
||||
// 删除对象
|
||||
object.DELETE("", controllers.Delete)
|
||||
// 移动对象
|
||||
object.PATCH("", controllers.Move)
|
||||
// 复制对象
|
||||
object.POST("copy", controllers.Copy)
|
||||
// 重命名对象
|
||||
object.POST("rename", controllers.Rename)
|
||||
// 获取对象属性
|
||||
object.GET("property/:id", controllers.GetProperty)
|
||||
}
|
||||
|
||||
// 分享
|
||||
share := auth.Group("share", middleware.PhoneRequired())
|
||||
{
|
||||
// 创建新分享
|
||||
share.POST("", controllers.CreateShare)
|
||||
// 列出我的分享
|
||||
share.GET("", controllers.ListShare)
|
||||
// 转存他人分享
|
||||
share.POST("save/:id",
|
||||
middleware.ShareAvailable(),
|
||||
middleware.CheckShareUnlocked(),
|
||||
middleware.BeforeShareDownload(),
|
||||
controllers.SaveShare,
|
||||
)
|
||||
// 更新分享属性
|
||||
share.PATCH(":id",
|
||||
middleware.ShareAvailable(),
|
||||
middleware.ShareOwner(),
|
||||
controllers.UpdateShare,
|
||||
)
|
||||
// 删除分享
|
||||
share.DELETE(":id",
|
||||
controllers.DeleteShare,
|
||||
)
|
||||
}
|
||||
|
||||
// 用户标签
|
||||
tag := auth.Group("tag")
|
||||
{
|
||||
// 创建文件分类标签
|
||||
tag.POST("filter", controllers.CreateFilterTag)
|
||||
// 创建目录快捷方式标签
|
||||
tag.POST("link", controllers.CreateLinkTag)
|
||||
// 删除标签
|
||||
tag.DELETE(":id", middleware.HashID(hashid.TagID), controllers.DeleteTag)
|
||||
}
|
||||
|
||||
// 增值服务相关
|
||||
vas := auth.Group("vas", middleware.PhoneRequired())
|
||||
{
|
||||
// 获取容量包及配额信息
|
||||
vas.GET("pack", controllers.GetQuota)
|
||||
// 获取商品信息,同时返回支付信息
|
||||
vas.GET("product", controllers.GetProduct)
|
||||
// 新建支付订单
|
||||
vas.POST("order", controllers.NewOrder)
|
||||
// 查询订单状态
|
||||
vas.GET("order/:id", controllers.OrderStatus)
|
||||
// 获取兑换码信息
|
||||
vas.GET("redeem/:code", controllers.GetRedeemInfo)
|
||||
// 执行兑换
|
||||
vas.POST("redeem/:code", controllers.DoRedeem)
|
||||
}
|
||||
|
||||
// WebDAV管理相关
|
||||
webdav := auth.Group("webdav", middleware.PhoneRequired())
|
||||
{
|
||||
// 获取账号信息
|
||||
webdav.GET("accounts", controllers.GetWebDAVAccounts)
|
||||
// 新建账号
|
||||
webdav.POST("accounts", controllers.CreateWebDAVAccounts)
|
||||
// 删除账号
|
||||
webdav.DELETE("accounts/:id", controllers.DeleteWebDAVAccounts)
|
||||
// 删除目录挂载
|
||||
webdav.DELETE("mount/:id",
|
||||
middleware.HashID(hashid.FolderID),
|
||||
controllers.DeleteWebDAVMounts,
|
||||
)
|
||||
// 创建目录挂载
|
||||
webdav.POST("mount", controllers.CreateWebDAVMounts)
|
||||
// 更新账号可读性和是否使用代理服务
|
||||
webdav.PATCH("accounts", controllers.UpdateWebDAVAccounts)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 初始化WebDAV相关路由
|
||||
initWebDAV(r.Group("dav"))
|
||||
return r
|
||||
}
|
||||
|
||||
// initWebDAV 初始化WebDAV相关路由
|
||||
func initWebDAV(group *gin.RouterGroup) {
|
||||
{
|
||||
group.Use(middleware.WebDAVAuth())
|
||||
|
||||
group.Any("/*path", controllers.ServeWebDAV)
|
||||
group.Any("", controllers.ServeWebDAV)
|
||||
group.Handle("PROPFIND", "/*path", controllers.ServeWebDAV)
|
||||
group.Handle("PROPFIND", "", controllers.ServeWebDAV)
|
||||
group.Handle("MKCOL", "/*path", controllers.ServeWebDAV)
|
||||
group.Handle("LOCK", "/*path", controllers.ServeWebDAV)
|
||||
group.Handle("UNLOCK", "/*path", controllers.ServeWebDAV)
|
||||
group.Handle("PROPPATCH", "/*path", controllers.ServeWebDAV)
|
||||
group.Handle("COPY", "/*path", controllers.ServeWebDAV)
|
||||
group.Handle("MOVE", "/*path", controllers.ServeWebDAV)
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user