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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user