Cloudreve/routers/router.go

1192 lines
37 KiB
Go

package routers
import (
"net/http"
"github.com/abslant/gzip"
"github.com/cloudreve/Cloudreve/v4/application/constants"
"github.com/cloudreve/Cloudreve/v4/application/dependency"
"github.com/cloudreve/Cloudreve/v4/inventory/types"
"github.com/cloudreve/Cloudreve/v4/middleware"
"github.com/cloudreve/Cloudreve/v4/pkg/cluster"
"github.com/cloudreve/Cloudreve/v4/pkg/conf"
"github.com/cloudreve/Cloudreve/v4/pkg/downloader/slave"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs"
"github.com/cloudreve/Cloudreve/v4/pkg/hashid"
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
"github.com/cloudreve/Cloudreve/v4/pkg/webdav"
"github.com/cloudreve/Cloudreve/v4/routers/controllers"
adminsvc "github.com/cloudreve/Cloudreve/v4/service/admin"
"github.com/cloudreve/Cloudreve/v4/service/basic"
"github.com/cloudreve/Cloudreve/v4/service/explorer"
"github.com/cloudreve/Cloudreve/v4/service/node"
"github.com/cloudreve/Cloudreve/v4/service/setting"
sharesvc "github.com/cloudreve/Cloudreve/v4/service/share"
usersvc "github.com/cloudreve/Cloudreve/v4/service/user"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
// InitRouter 初始化路由
func InitRouter(dep dependency.Dep) *gin.Engine {
l := dep.Logger()
if dep.ConfigProvider().System().Mode == conf.MasterMode {
l.Info("Current running mode: Master.")
return initMasterRouter(dep)
}
l.Info("Current running mode: Slave.")
return initSlaveRouter(dep)
}
func newGinEngine(dep dependency.Dep) *gin.Engine {
r := gin.New()
r.ContextWithFallback = true
r.Use(gin.Recovery())
r.Use(middleware.InitializeHandling(dep))
if dep.ConfigProvider().System().Mode == conf.SlaveMode {
r.Use(middleware.InitializeHandlingSlave())
}
r.Use(middleware.Logging())
return r
}
func initSlaveFileRouter(v4 *gin.RouterGroup) {
// Upload related, no signature required under this router group
upload := v4.Group("upload")
{
// 上传分片
upload.POST(":sessionId",
controllers.FromUri[explorer.UploadService](explorer.UploadParameterCtx{}),
controllers.SlaveUpload,
)
// 创建上传会话上传
upload.PUT("",
controllers.FromJSON[explorer.SlaveCreateUploadSessionService](explorer.SlaveCreateUploadSessionParamCtx{}),
controllers.SlaveGetUploadSession,
)
// 删除上传会话
upload.DELETE(":sessionId",
controllers.FromUri[explorer.SlaveDeleteUploadSessionService](explorer.SlaveDeleteUploadSessionParamCtx{}),
controllers.SlaveDeleteUploadSession)
}
file := v4.Group("file")
{
// Get entity content for preview/download
file.GET("content/:nodeId/:src/:speed/:name",
middleware.Sandbox(),
controllers.FromUri[explorer.EntityDownloadService](explorer.EntityDownloadParameterCtx{}),
controllers.SlaveServeEntity,
)
file.HEAD("content/:nodeId/:src/:speed/:name",
controllers.FromUri[explorer.EntityDownloadService](explorer.EntityDownloadParameterCtx{}),
controllers.SlaveServeEntity,
)
// Get media metadata
file.GET("meta/:src/:ext",
controllers.FromUri[explorer.SlaveMetaService](explorer.SlaveMetaParamCtx{}),
controllers.SlaveMeta,
)
// Get thumbnail
file.GET("thumb/:src/:ext",
controllers.FromUri[explorer.SlaveThumbService](explorer.SlaveThumbParamCtx{}),
controllers.SlaveThumb,
)
// 删除文件
file.DELETE("",
controllers.FromJSON[explorer.SlaveDeleteFileService](explorer.SlaveDeleteFileParamCtx{}),
controllers.SlaveDelete)
// 列出文件
file.GET("list",
controllers.FromQuery[explorer.SlaveListService](explorer.SlaveListParamCtx{}),
controllers.SlaveList,
)
}
}
// initSlaveRouter 初始化从机模式路由
func initSlaveRouter(dep dependency.Dep) *gin.Engine {
r := newGinEngine(dep)
// 跨域相关
initCORS(dep.Logger(), dep.ConfigProvider(), r)
v4 := r.Group(constants.APIPrefix + "/slave")
// 鉴权中间件
v4.Use(middleware.SignRequired(dep.GeneralAuth()))
// 禁止缓存
v4.Use(middleware.CacheControl())
/*
路由
*/
{
// Ping
v4.POST("ping",
controllers.FromJSON[adminsvc.SlavePingService](adminsvc.SlavePingParameterCtx{}),
controllers.SlavePing,
)
// // 测试 Aria2 RPC 连接
// v4.POST("ping/aria2", controllers.AdminTestAria2)
initSlaveFileRouter(v4)
// 离线下载
download := v4.Group("download")
{
// 创建离线下载任务
download.POST("task",
controllers.FromJSON[slave.CreateSlaveDownload](node.CreateSlaveDownloadTaskParamCtx{}),
middleware.PrepareSlaveDownloader(dep, node.CreateSlaveDownloadTaskParamCtx{}),
controllers.SlaveDownloadTaskCreate)
// 获取任务状态
download.POST("status",
controllers.FromJSON[slave.GetSlaveDownload](node.GetSlaveDownloadTaskParamCtx{}),
middleware.PrepareSlaveDownloader(dep, node.GetSlaveDownloadTaskParamCtx{}),
controllers.SlaveDownloadTaskStatus)
// 取消离线下载任务
download.POST("cancel",
controllers.FromJSON[slave.CancelSlaveDownload](node.CancelSlaveDownloadTaskParamCtx{}),
middleware.PrepareSlaveDownloader(dep, node.CancelSlaveDownloadTaskParamCtx{}),
controllers.SlaveCancelDownloadTask)
// 选取任务文件
download.POST("select",
controllers.FromJSON[slave.SetSlaveFilesToDownload](node.SelectSlaveDownloadFilesParamCtx{}),
middleware.PrepareSlaveDownloader(dep, node.SelectSlaveDownloadFilesParamCtx{}),
controllers.SlaveSelectFilesToDownload)
// 测试下载器连接
download.POST("test",
controllers.FromJSON[slave.TestSlaveDownload](node.TestSlaveDownloadParamCtx{}),
middleware.PrepareSlaveDownloader(dep, node.TestSlaveDownloadParamCtx{}),
controllers.SlaveTestDownloader,
)
}
// 异步任务
task := v4.Group("task")
{
task.PUT("",
controllers.FromJSON[cluster.CreateSlaveTask](node.CreateSlaveTaskParamCtx{}),
controllers.SlaveCreateTask)
task.GET(":id",
controllers.FromUri[node.GetSlaveTaskService](node.GetSlaveTaskParamCtx{}),
controllers.SlaveGetTask)
task.POST("cleanup",
controllers.FromJSON[cluster.FolderCleanup](node.FolderCleanupParamCtx{}),
controllers.SlaveCleanupFolder)
}
}
return r
}
// initCORS 初始化跨域配置
func initCORS(l logging.Logger, config conf.ConfigProvider, router *gin.Engine) {
c := config.Cors()
if c.AllowOrigins[0] != "UNSET" {
router.Use(cors.New(cors.Config{
AllowOrigins: c.AllowOrigins,
AllowMethods: c.AllowMethods,
AllowHeaders: c.AllowHeaders,
AllowCredentials: c.AllowCredentials,
ExposeHeaders: c.ExposeHeaders,
}))
return
}
// slave模式下未启动跨域的警告
if config.System().Mode == conf.SlaveMode {
l.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 basic.")
}
}
// initMasterRouter 初始化主机模式路由
func initMasterRouter(dep dependency.Dep) *gin.Engine {
r := newGinEngine(dep)
// 跨域相关
initCORS(dep.Logger(), dep.ConfigProvider(), r) // Done
/*
静态资源
*/
r.Use(gzip.GzipHandler()) // Done
r.Use(middleware.FrontendFileHandler(dep)) // Done
r.GET("manifest.json", controllers.Manifest) // Done
noAuth := r.Group(constants.APIPrefix)
wopi := noAuth.Group("file/wopi", middleware.HashID(hashid.FileID), middleware.ViewerSessionValidation())
{
// 获取文件信息
wopi.GET(":id", controllers.CheckFileInfo)
// 获取文件内容
wopi.GET(":id/contents", controllers.GetFile)
// 更新文件内容
wopi.POST(":id/contents", controllers.PutFile)
// 通用文件操作
wopi.POST(":id", controllers.ModifyFile)
}
v4 := r.Group(constants.APIPrefix)
/*
中间件
*/
v4.Use(middleware.Session(dep)) // Done
// 用户会话
v4.Use(middleware.CurrentUser())
// 禁止缓存
v4.Use(middleware.CacheControl()) // Done
/*
路由
*/
{
// Redirect file source link
source := r.Group("f")
{
source.GET(":id/:name",
middleware.HashID(hashid.SourceLinkID),
controllers.AnonymousPermLink(false))
source.GET("d/:id/:name",
middleware.HashID(hashid.SourceLinkID),
controllers.AnonymousPermLink(true))
}
shareShort := r.Group("s")
{
shareShort.GET(":id",
controllers.FromUri[sharesvc.ShortLinkRedirectService](sharesvc.ShortLinkRedirectParamCtx{}),
controllers.ShareRedirect,
)
shareShort.GET(":id/:password",
controllers.FromUri[sharesvc.ShortLinkRedirectService](sharesvc.ShortLinkRedirectParamCtx{}),
controllers.ShareRedirect,
)
}
// 全局设置相关
site := v4.Group("site")
{
// 测试用路由
site.GET("ping", controllers.Ping)
// 验证码
site.GET("captcha", controllers.Captcha)
// 站点全局配置
site.GET("config/:section",
controllers.FromUri[basic.GetSettingService](basic.GetSettingParamCtx{}),
controllers.SiteConfig,
)
}
// User authentication
session := v4.Group("session")
{
token := session.Group("token")
// Token based authentication
{
// 用户登录
token.POST("",
middleware.CaptchaRequired(func(c *gin.Context) bool {
return dep.SettingProvider().LoginCaptchaEnabled(c)
}),
controllers.FromJSON[usersvc.UserLoginService](usersvc.LoginParameterCtx{}),
controllers.UserLoginValidation,
controllers.UserIssueToken,
)
// 2-factor authentication
token.POST("2fa",
controllers.FromJSON[usersvc.OtpValidationService](usersvc.OtpValidationParameterCtx{}),
controllers.UserLogin2FAValidation,
controllers.UserIssueToken,
)
token.POST("refresh",
controllers.FromJSON[usersvc.RefreshTokenService](usersvc.RefreshTokenParameterCtx{}),
controllers.UserRefreshToken,
)
token.DELETE("",
controllers.FromJSON[usersvc.RefreshTokenService](usersvc.RefreshTokenParameterCtx{}),
controllers.UserSignOut,
)
}
// Prepare login
session.GET("prepare",
controllers.FromQuery[usersvc.PrepareLoginService](usersvc.PrepareLoginParameterCtx{}),
controllers.UserPrepareLogin,
)
authn := session.Group("authn")
{
// WebAuthn login prepare
authn.PUT("",
middleware.IsFunctionEnabled(func(c *gin.Context) bool {
return dep.SettingProvider().AuthnEnabled(c)
}),
controllers.StartLoginAuthn,
)
// WebAuthn finish login
authn.POST("",
middleware.IsFunctionEnabled(func(c *gin.Context) bool {
return dep.SettingProvider().AuthnEnabled(c)
}),
controllers.FromJSON[usersvc.FinishPasskeyLoginService](usersvc.FinishPasskeyLoginParameterCtx{}),
controllers.FinishLoginAuthn,
controllers.UserIssueToken,
)
}
}
// 用户相关路由
user := v4.Group("user")
{
// 用户注册 Done
user.POST("",
middleware.IsFunctionEnabled(func(c *gin.Context) bool {
return dep.SettingProvider().RegisterEnabled(c)
}),
middleware.CaptchaRequired(func(c *gin.Context) bool {
return dep.SettingProvider().RegCaptchaEnabled(c)
}),
controllers.FromJSON[usersvc.UserRegisterService](usersvc.RegisterParameterCtx{}),
controllers.UserRegister,
)
// 通过邮件里的链接重设密码
user.PATCH("reset/:id",
middleware.HashID(hashid.UserID),
controllers.FromJSON[usersvc.UserResetService](usersvc.UserResetParameterCtx{}),
controllers.UserReset,
)
// 发送密码重设邮件
user.POST("reset",
middleware.CaptchaRequired(func(c *gin.Context) bool {
return dep.SettingProvider().ForgotPasswordCaptchaEnabled(c)
}),
controllers.FromJSON[usersvc.UserResetEmailService](usersvc.UserResetEmailParameterCtx{}),
controllers.UserSendReset,
)
// 邮件激活 Done
user.GET("activate/:id",
middleware.SignRequired(dep.GeneralAuth()),
middleware.HashID(hashid.UserID),
controllers.UserActivate,
)
// 获取用户头像
user.GET("avatar/:id",
middleware.HashID(hashid.UserID),
controllers.FromQuery[usersvc.GetAvatarService](usersvc.GetAvatarServiceParamsCtx{}),
controllers.GetUserAvatar,
)
// User info
user.GET("info/:id", middleware.HashID(hashid.UserID), controllers.UserGet)
// List user shares
user.GET("shares/:id",
middleware.HashID(hashid.UserID),
controllers.FromQuery[sharesvc.ListShareService](sharesvc.ListShareParamCtx{}),
controllers.ListPublicShare,
)
}
// 需要携带签名验证的
sign := v4.Group("")
sign.Use(middleware.SignRequired(dep.GeneralAuth()))
{
file := sign.Group("file")
{
file.GET("archive/:sessionID/archive.zip",
controllers.FromUri[explorer.ArchiveService](explorer.ArchiveParamCtx{}),
controllers.DownloadArchive,
)
}
// Copy user session
sign.GET(
"user/session/copy/:id",
middleware.MobileRequestOnly(),
controllers.UserPerformCopySession,
)
}
// Receive calls from slave node
slave := v4.Group("slave")
slave.Use(
middleware.SlaveRPCSignRequired(),
)
{
initSlaveFileRouter(slave)
// Get credential
slave.GET("credential/:id",
controllers.FromUri[node.OauthCredentialService](node.OauthCredentialParamCtx{}),
controllers.SlaveGetCredential)
statelessUpload := slave.Group("statelessUpload")
{
// Prepare upload
statelessUpload.PUT("prepare",
controllers.FromJSON[fs.StatelessPrepareUploadService](node.StatelessPrepareUploadParamCtx{}),
controllers.StatelessPrepareUpload)
// Complete upload
statelessUpload.POST("complete",
controllers.FromJSON[fs.StatelessCompleteUploadService](node.StatelessCompleteUploadParamCtx{}),
controllers.StatelessCompleteUpload)
// On upload failed
statelessUpload.POST("failed",
controllers.FromJSON[fs.StatelessOnUploadFailedService](node.StatelessOnUploadFailedParamCtx{}),
controllers.StatelessOnUploadFailed)
// Create file
statelessUpload.POST("create",
controllers.FromJSON[fs.StatelessCreateFileService](node.StatelessCreateFileParamCtx{}),
controllers.StatelessCreateFile)
}
}
// 回调接口
callback := v4.Group("callback")
{
// 远程策略上传回调
callback.POST(
"remote/:sessionID/:key",
middleware.UseUploadSession(types.PolicyTypeRemote),
middleware.RemoteCallbackAuth(),
controllers.ProcessCallback(http.StatusOK, false),
)
// OSS callback
callback.POST(
"oss/:sessionID/:key",
middleware.UseUploadSession(types.PolicyTypeOss),
middleware.OSSCallbackAuth(),
controllers.OSSCallbackValidate,
controllers.ProcessCallback(http.StatusBadRequest, false),
)
// 又拍云策略上传回调
callback.POST(
"upyun/:sessionID/:key",
middleware.UseUploadSession(types.PolicyTypeUpyun),
controllers.UpyunCallbackAuth,
controllers.ProcessCallback(http.StatusBadRequest, false),
)
onedrive := callback.Group("onedrive")
{
// 文件上传完成
onedrive.POST(
":sessionID/:key",
middleware.UseUploadSession(types.PolicyTypeOd),
controllers.ProcessCallback(http.StatusOK, false),
)
}
// Google Drive related
gdrive := callback.Group("googledrive")
{
// OAuth 完成
gdrive.GET(
"auth",
controllers.GoogleDriveOAuth,
)
}
// 腾讯云COS策略上传回调
callback.GET(
"cos/:sessionID/:key",
middleware.UseUploadSession(types.PolicyTypeCos),
controllers.ProcessCallback(http.StatusBadRequest, false),
)
// AWS S3策略上传回调
callback.GET(
"s3/:sessionID/:key",
middleware.UseUploadSession(types.PolicyTypeS3),
controllers.ProcessCallback(http.StatusBadRequest, false),
)
// 金山 ks3策略上传回调
callback.GET(
"ks3/:sessionID/:key",
middleware.UseUploadSession(types.PolicyTypeKs3),
controllers.ProcessCallback(http.StatusBadRequest, false),
)
// Huawei OBS upload callback
callback.POST(
"obs/:sessionID/:key",
middleware.UseUploadSession(types.PolicyTypeObs),
controllers.ProcessCallback(http.StatusBadRequest, false),
)
// Qiniu callback
callback.POST(
"qiniu/:sessionID/:key",
middleware.UseUploadSession(types.PolicyTypeQiniu),
controllers.QiniuCallbackValidate,
controllers.ProcessCallback(http.StatusBadRequest, true),
)
}
// Workflows
wf := v4.Group("workflow")
wf.Use(middleware.LoginRequired())
{
// List
wf.GET("",
controllers.FromQuery[explorer.ListTaskService](explorer.ListTaskParamCtx{}),
controllers.ListTasks,
)
// GetTaskProgress
wf.GET("progress/:id",
middleware.HashID(hashid.TaskID),
controllers.GetTaskPhaseProgress,
)
// Create task to create an archive file
wf.POST("archive",
controllers.FromJSON[explorer.ArchiveWorkflowService](explorer.CreateArchiveParamCtx{}),
controllers.CreateArchive,
)
// Create task to extract an archive file
wf.POST("extract",
controllers.FromJSON[explorer.ArchiveWorkflowService](explorer.CreateArchiveParamCtx{}),
controllers.ExtractArchive,
)
remoteDownload := wf.Group("download")
{
// Create task to download a file
remoteDownload.POST("",
controllers.FromJSON[explorer.DownloadWorkflowService](explorer.CreateDownloadParamCtx{}),
controllers.CreateRemoteDownload,
)
// Set download target
remoteDownload.PATCH(":id",
middleware.HashID(hashid.TaskID),
controllers.FromJSON[explorer.SetDownloadFilesService](explorer.SetDownloadFilesParamCtx{}),
controllers.SetDownloadTaskTarget,
)
remoteDownload.DELETE(":id",
middleware.HashID(hashid.TaskID),
controllers.CancelDownloadTask,
)
}
}
// 文件
file := v4.Group("file")
{
// List files
file.GET("",
controllers.FromQuery[explorer.ListFileService](explorer.ListFileParameterCtx{}),
controllers.ListDirectory,
)
// Create file
file.POST("create",
controllers.FromJSON[explorer.CreateFileService](explorer.CreateFileParameterCtx{}),
controllers.CreateFile,
)
// Rename file
file.POST("rename",
controllers.FromJSON[explorer.RenameFileService](explorer.RenameFileParameterCtx{}),
controllers.RenameFile,
)
// Move or copy files
file.POST("move",
controllers.FromJSON[explorer.MoveFileService](explorer.MoveFileParameterCtx{}),
middleware.ValidateBatchFileCount(dep, explorer.MoveFileParameterCtx{}),
controllers.MoveFile)
// Get URL of the file for preview/download
file.POST("url",
middleware.ContextHint(),
controllers.FromJSON[explorer.FileURLService](explorer.FileURLParameterCtx{}),
middleware.ValidateBatchFileCount(dep, explorer.FileURLParameterCtx{}),
controllers.FileURL,
)
// Update file content
file.PUT("content",
controllers.FromQuery[explorer.FileUpdateService](explorer.FileUpdateParameterCtx{}),
controllers.PutContent)
// Get entity content for preview/download
content := file.Group("content")
contentCors := cors.New(cors.Config{
AllowOrigins: []string{"*"},
})
content.Use(contentCors)
{
content.OPTIONS("*option", contentCors)
content.GET(":id/:speed/:name",
middleware.SignRequired(dep.GeneralAuth()),
middleware.HashID(hashid.EntityID),
middleware.Sandbox(),
controllers.FromUri[explorer.EntityDownloadService](explorer.EntityDownloadParameterCtx{}),
controllers.ServeEntity,
)
content.HEAD(":id/:speed/:name",
middleware.SignRequired(dep.GeneralAuth()),
middleware.HashID(hashid.EntityID),
controllers.FromUri[explorer.EntityDownloadService](explorer.EntityDownloadParameterCtx{}),
controllers.ServeEntity,
)
}
// 获取缩略图
file.GET("thumb",
middleware.ContextHint(),
controllers.FromQuery[explorer.FileThumbService](explorer.FileThumbParameterCtx{}),
controllers.Thumb,
)
// Delete files
file.DELETE("",
controllers.FromJSON[explorer.DeleteFileService](explorer.DeleteFileParameterCtx{}),
middleware.ValidateBatchFileCount(dep, explorer.DeleteFileParameterCtx{}),
controllers.Delete,
)
// Force unlock
file.DELETE("lock",
controllers.FromJSON[explorer.UnlockFileService](explorer.UnlockFileParameterCtx{}),
controllers.Unlock,
)
// Restore files
file.POST("restore",
controllers.FromJSON[explorer.DeleteFileService](explorer.DeleteFileParameterCtx{}),
middleware.ValidateBatchFileCount(dep, explorer.DeleteFileParameterCtx{}),
controllers.Restore,
)
// Patch metadata
file.PATCH("metadata",
controllers.FromJSON[explorer.PatchMetadataService](explorer.PatchMetadataParameterCtx{}),
middleware.ValidateBatchFileCount(dep, explorer.PatchMetadataParameterCtx{}),
controllers.PatchMetadata,
)
// Upload related
upload := file.Group("upload")
{
// Create upload session
upload.PUT("",
controllers.FromJSON[explorer.CreateUploadSessionService](explorer.CreateUploadSessionParameterCtx{}),
controllers.CreateUploadSession,
)
// Upload file data
upload.POST(":sessionId/:index",
controllers.FromUri[explorer.UploadService](explorer.UploadParameterCtx{}),
controllers.FileUpload,
)
upload.DELETE("",
controllers.FromJSON[explorer.DeleteUploadSessionService](explorer.DeleteUploadSessionParameterCtx{}),
controllers.DeleteUploadSession,
)
}
// Pin file
pin := file.Group("pin")
{
// Pin file
pin.PUT("",
controllers.FromJSON[explorer.PinFileService](explorer.PinFileParameterCtx{}),
controllers.Pin,
)
// Unpin file
pin.DELETE("",
controllers.FromJSON[explorer.PinFileService](explorer.PinFileParameterCtx{}),
controllers.Unpin,
)
}
// Get file info
file.GET("info",
controllers.FromQuery[explorer.GetFileInfoService](explorer.GetFileInfoParameterCtx{}),
controllers.GetFileInfo,
)
// Version management
version := file.Group("version")
{
// Set current version
version.POST("current",
controllers.FromJSON[explorer.SetCurrentVersionService](explorer.SetCurrentVersionParamCtx{}),
controllers.SetCurrentVersion,
)
// Delete a version from a file
version.DELETE("",
controllers.FromJSON[explorer.DeleteVersionService](explorer.DeleteVersionParamCtx{}),
controllers.DeleteVersion,
)
}
file.PUT("viewerSession",
controllers.FromJSON[explorer.CreateViewerSessionService](explorer.CreateViewerSessionParamCtx{}),
controllers.CreateViewerSession,
)
// Create task to import files
wf.POST("import",
middleware.IsAdmin(),
controllers.FromJSON[explorer.ImportWorkflowService](explorer.CreateImportParamCtx{}),
controllers.ImportFiles,
)
// 取得文件外链
source := file.Group("source")
{
source.PUT("",
controllers.FromJSON[explorer.GetDirectLinkService](explorer.GetDirectLinkParamCtx{}),
middleware.ValidateBatchFileCount(dep, explorer.GetDirectLinkParamCtx{}),
controllers.GetSource,
)
source.DELETE(":id",
middleware.HashID(hashid.SourceLinkID),
controllers.DeleteDirectLink,
)
}
// Patch view
file.PATCH("view",
controllers.FromJSON[explorer.PatchViewService](explorer.PatchViewParameterCtx{}),
controllers.PatchView,
)
}
// 分享相关
share := v4.Group("share")
{
// Create share link
share.PUT("",
middleware.LoginRequired(),
controllers.FromJSON[sharesvc.ShareCreateService](sharesvc.ShareCreateParamCtx{}),
controllers.CreateShare,
)
// Edit existing share link
share.POST(":id",
middleware.LoginRequired(),
middleware.HashID(hashid.ShareID),
controllers.FromJSON[sharesvc.ShareCreateService](sharesvc.ShareCreateParamCtx{}),
controllers.EditShare,
)
// Get share link info
share.GET("info/:id",
middleware.HashID(hashid.ShareID),
controllers.FromQuery[sharesvc.ShareInfoService](sharesvc.ShareInfoParamCtx{}),
controllers.GetShare,
)
// List my shares
share.GET("",
middleware.LoginRequired(),
controllers.FromQuery[sharesvc.ListShareService](sharesvc.ListShareParamCtx{}),
controllers.ListShare,
)
// 删除分享
share.DELETE(":id",
middleware.LoginRequired(),
middleware.HashID(hashid.ShareID),
controllers.DeleteShare,
)
//// 获取README文本文件内容
//share.GET("readme/:id",
// middleware.CheckShareUnlocked(),
// controllers.PreviewShareReadme,
//)
//// 举报分享
//share.POST("report/:id",
// middleware.CheckShareUnlocked(),
// controllers.ReportShare,
//)
}
// 需要登录保护的
auth := v4.Group("")
auth.Use(middleware.LoginRequired())
{
// 管理
admin := auth.Group("admin", middleware.IsAdmin())
{
admin.GET("summary",
controllers.FromQuery[adminsvc.SummaryService](adminsvc.SummaryParamCtx{}),
controllers.AdminSummary,
)
settings := admin.Group("settings")
{
// Get settings
settings.POST("",
controllers.FromJSON[adminsvc.GetSettingService](adminsvc.GetSettingParamCtx{}),
controllers.AdminGetSettings,
)
// Patch settings
settings.PATCH("",
controllers.FromJSON[adminsvc.SetSettingService](adminsvc.SetSettingParamCtx{}),
controllers.AdminSetSettings,
)
}
// 用户组管理
group := admin.Group("group")
{
// 列出用户组
group.POST("",
controllers.FromJSON[adminsvc.AdminListService](adminsvc.AdminListServiceParamsCtx{}),
controllers.AdminListGroups,
)
// 获取用户组
group.GET(":id",
controllers.FromUri[adminsvc.SingleGroupService](adminsvc.SingleGroupParamCtx{}),
controllers.AdminGetGroup,
)
// 创建用户组
group.PUT("",
controllers.FromJSON[adminsvc.UpsertGroupService](adminsvc.UpsertGroupParamCtx{}),
controllers.AdminCreateGroup,
)
// 更新用户组
group.PUT(":id",
controllers.FromJSON[adminsvc.UpsertGroupService](adminsvc.UpsertGroupParamCtx{}),
controllers.AdminUpdateGroup,
)
// 删除用户组
group.DELETE(":id",
controllers.FromUri[adminsvc.SingleGroupService](adminsvc.SingleGroupParamCtx{}),
controllers.AdminDeleteGroup,
)
}
tool := admin.Group("tool")
{
tool.GET("wopi",
controllers.FromQuery[adminsvc.FetchWOPIDiscoveryService](adminsvc.FetchWOPIDiscoveryParamCtx{}),
controllers.AdminFetchWopi,
)
tool.POST("thumbExecutable",
controllers.FromJSON[adminsvc.ThumbGeneratorTestService](adminsvc.ThumbGeneratorTestParamCtx{}),
controllers.AdminTestThumbGenerator)
tool.POST("mail",
controllers.FromJSON[adminsvc.TestSMTPService](adminsvc.TestSMTPParamCtx{}),
controllers.AdminSendTestMail,
)
tool.DELETE("entityUrlCache",
controllers.AdminClearEntityUrlCache,
)
}
queue := admin.Group("queue")
{
queue.GET("metrics", controllers.AdminGetQueueMetrics)
// List tasks
queue.POST("",
controllers.FromJSON[adminsvc.AdminListService](adminsvc.AdminListServiceParamsCtx{}),
controllers.AdminListTasks,
)
// Get task
queue.GET(":id",
controllers.FromUri[adminsvc.SingleTaskService](adminsvc.SingleTaskParamCtx{}),
controllers.AdminGetTask,
)
// Batch delete task
queue.POST("batch/delete",
controllers.FromJSON[adminsvc.BatchTaskService](adminsvc.BatchTaskParamCtx{}),
controllers.AdminBatchDeleteTask,
)
// Cleanup tasks
queue.POST("cleanup",
controllers.FromJSON[adminsvc.CleanupTaskService](adminsvc.CleanupTaskParameterCtx{}),
controllers.AdminCleanupTask,
)
// // 列出任务
// queue.POST("list", controllers.AdminListTask)
// // 新建文件导入任务
// queue.POST("import", controllers.AdminCreateImportTask)
}
// 存储策略管理
policy := admin.Group("policy")
{
// 列出存储策略
policy.POST("",
controllers.FromJSON[adminsvc.AdminListService](adminsvc.AdminListServiceParamsCtx{}),
controllers.AdminListPolicies,
)
// 获取存储策略详情
policy.GET(":id",
controllers.FromUri[adminsvc.SingleStoragePolicyService](adminsvc.GetStoragePolicyParamCtx{}),
controllers.AdminGetPolicy,
)
// 创建存储策略
policy.PUT("",
controllers.FromJSON[adminsvc.CreateStoragePolicyService](adminsvc.CreateStoragePolicyParamCtx{}),
controllers.AdminCreatePolicy,
)
// 更新存储策略
policy.PUT(":id",
controllers.FromJSON[adminsvc.UpdateStoragePolicyService](adminsvc.UpdateStoragePolicyParamCtx{}),
controllers.AdminUpdatePolicy,
)
// 创建跨域策略
policy.POST("cors",
controllers.FromJSON[adminsvc.CreateStoragePolicyCorsService](adminsvc.CreateStoragePolicyCorsParamCtx{}),
controllers.AdminCreateStoragePolicyCors,
)
// // 获取 OneDrive OAuth URL
oauth := policy.Group("oauth")
{
// 获取 OneDrive OAuth URL
oauth.POST("signin",
controllers.FromJSON[adminsvc.GetOauthRedirectService](adminsvc.GetOauthRedirectParamCtx{}),
controllers.AdminOdOAuthURL,
)
// 获取 OAuth 回调 URL
oauth.GET("redirect", controllers.AdminGetPolicyOAuthCallbackURL)
oauth.GET("status/:id",
controllers.FromUri[adminsvc.SingleStoragePolicyService](adminsvc.GetStoragePolicyParamCtx{}),
controllers.AdminGetPolicyOAuthStatus,
)
oauth.POST("callback",
controllers.FromJSON[adminsvc.FinishOauthCallbackService](adminsvc.FinishOauthCallbackParamCtx{}),
controllers.AdminFinishOauthCallback,
)
oauth.GET("root/:id",
controllers.FromUri[adminsvc.SingleStoragePolicyService](adminsvc.GetStoragePolicyParamCtx{}),
controllers.AdminGetSharePointDriverRoot,
)
}
// // 获取 存储策略
// policy.GET(":id", controllers.AdminGetPolicy)
// 删除 存储策略
policy.DELETE(":id",
controllers.FromUri[adminsvc.SingleStoragePolicyService](adminsvc.GetStoragePolicyParamCtx{}),
controllers.AdminDeletePolicy,
)
}
node := admin.Group("node")
{
node.POST("",
controllers.FromJSON[adminsvc.AdminListService](adminsvc.AdminListServiceParamsCtx{}),
controllers.AdminListNodes,
)
node.GET(":id",
controllers.FromUri[adminsvc.SingleNodeService](adminsvc.SingleNodeParamCtx{}),
controllers.AdminGetNode,
)
node.POST("test",
controllers.FromJSON[adminsvc.TestNodeService](adminsvc.TestNodeParamCtx{}),
controllers.AdminTestSlave,
)
node.POST("test/downloader",
controllers.FromJSON[adminsvc.TestNodeDownloaderService](adminsvc.TestNodeDownloaderParamCtx{}),
controllers.AdminTestDownloader,
)
node.PUT("",
controllers.FromJSON[adminsvc.UpsertNodeService](adminsvc.UpsertNodeParamCtx{}),
controllers.AdminCreateNode,
)
node.PUT(":id",
controllers.FromJSON[adminsvc.UpsertNodeService](adminsvc.UpsertNodeParamCtx{}),
controllers.AdminUpdateNode,
)
node.DELETE(":id",
controllers.FromUri[adminsvc.SingleNodeService](adminsvc.SingleNodeParamCtx{}),
controllers.AdminDeleteNode,
)
}
user := admin.Group("user")
{
// 列出用户
user.POST("",
controllers.FromJSON[adminsvc.AdminListService](adminsvc.AdminListServiceParamsCtx{}),
controllers.AdminListUsers,
)
// 获取用户
user.GET(":id",
controllers.FromUri[adminsvc.SingleUserService](adminsvc.SingleUserParamCtx{}),
controllers.AdminGetUser,
)
// 更新用户
user.PUT(":id",
controllers.FromJSON[adminsvc.UpsertUserService](adminsvc.UpsertUserParamCtx{}),
controllers.AdminUpdateUser,
)
// 创建用户
user.PUT("",
controllers.FromJSON[adminsvc.UpsertUserService](adminsvc.UpsertUserParamCtx{}),
controllers.AdminCreateUser,
)
batch := user.Group("batch")
{
// 批量删除用户
batch.POST("delete",
controllers.FromJSON[adminsvc.BatchUserService](adminsvc.BatchUserParamCtx{}),
controllers.AdminDeleteUser,
)
}
user.POST(":id/calibrate",
controllers.FromUri[adminsvc.SingleUserService](adminsvc.SingleUserParamCtx{}),
controllers.AdminCalibrateStorage,
)
}
file := admin.Group("file")
{
// 列出文件
file.POST("",
controllers.FromJSON[adminsvc.AdminListService](adminsvc.AdminListServiceParamsCtx{}),
controllers.AdminListFiles,
)
// 获取文件
file.GET(":id",
controllers.FromUri[adminsvc.SingleFileService](adminsvc.SingleFileParamCtx{}),
controllers.AdminGetFile,
)
// 更新文件
file.PUT(":id",
controllers.FromJSON[adminsvc.UpsertFileService](adminsvc.UpsertFileParamCtx{}),
controllers.AdminUpdateFile,
)
// 获取文件 URL
file.GET("url/:id",
controllers.FromUri[adminsvc.SingleFileService](adminsvc.SingleFileParamCtx{}),
controllers.AdminGetFileUrl,
)
// 批量删除文件
file.POST("batch/delete",
controllers.FromJSON[adminsvc.BatchFileService](adminsvc.BatchFileParamCtx{}),
controllers.AdminBatchDeleteFile,
)
}
entity := admin.Group("entity")
{
// List blobs
entity.POST("",
controllers.FromJSON[adminsvc.AdminListService](adminsvc.AdminListServiceParamsCtx{}),
controllers.AdminListEntities,
)
// Get entity
entity.GET(":id",
controllers.FromUri[adminsvc.SingleEntityService](adminsvc.SingleEntityParamCtx{}),
controllers.AdminGetEntity,
)
// Batch delete entity
entity.POST("batch/delete",
controllers.FromJSON[adminsvc.BatchEntityService](adminsvc.BatchEntityParamCtx{}),
controllers.AdminBatchDeleteEntity,
)
// Get entity url
entity.GET("url/:id",
controllers.FromUri[adminsvc.SingleEntityService](adminsvc.SingleEntityParamCtx{}),
controllers.AdminGetEntityUrl,
)
}
share := admin.Group("share")
{
// List shares
share.POST("",
controllers.FromJSON[adminsvc.AdminListService](adminsvc.AdminListServiceParamsCtx{}),
controllers.AdminListShares,
)
// Get share
share.GET(":id",
controllers.FromUri[adminsvc.SingleShareService](adminsvc.SingleShareParamCtx{}),
controllers.AdminGetShare,
)
// Batch delete shares
share.POST("batch/delete",
controllers.FromJSON[adminsvc.BatchShareService](adminsvc.BatchShareParamCtx{}),
controllers.AdminBatchDeleteShare,
)
}
}
// 用户
user := auth.Group("user")
{
// 当前登录用户信息
user.GET("me", controllers.UserMe)
// 存储信息
user.GET("capacity", controllers.UserStorage)
// Search user by keywords
user.GET("search",
controllers.FromQuery[usersvc.SearchUserService](usersvc.SearchUserParamCtx{}),
controllers.UserSearch,
)
// WebAuthn 注册相关
authn := user.Group("authn",
middleware.IsFunctionEnabled(func(c *gin.Context) bool {
return dep.SettingProvider().AuthnEnabled(c)
}))
{
authn.PUT("", controllers.StartRegAuthn)
authn.POST("",
controllers.FromJSON[usersvc.FinishPasskeyRegisterService](usersvc.FinishPasskeyRegisterParameterCtx{}),
controllers.FinishRegAuthn,
)
authn.DELETE("",
controllers.FromQuery[usersvc.DeletePasskeyService](usersvc.DeletePasskeyParameterCtx{}),
controllers.UserDeletePasskey,
)
}
// 用户设置
setting := user.Group("setting")
{
// 获取当前用户设定
setting.GET("", controllers.UserSetting)
// 从文件上传头像
setting.PUT("avatar", controllers.UploadAvatar)
// 更改用户设定
setting.PATCH("",
controllers.FromJSON[usersvc.PatchUserSetting](usersvc.PatchUserSettingParamsCtx{}),
controllers.UpdateOption,
)
// 获得二步验证初始化信息
setting.GET("2fa", controllers.UserInit2FA)
}
}
// WebDAV and devices
devices := auth.Group("devices")
{
dav := devices.Group("dav")
{
// List WebDAV accounts
dav.GET("",
controllers.FromQuery[setting.ListDavAccountsService](setting.ListDavAccountParamCtx{}),
controllers.ListDavAccounts,
)
// Create WebDAV account
dav.PUT("",
controllers.FromJSON[setting.CreateDavAccountService](setting.CreateDavAccountParamCtx{}),
controllers.CreateDAVAccounts,
)
// Create WebDAV account
dav.PATCH(":id",
middleware.HashID(hashid.DavAccountID),
controllers.FromJSON[setting.CreateDavAccountService](setting.CreateDavAccountParamCtx{}),
controllers.UpdateDAVAccounts,
)
// Delete WebDAV account
dav.DELETE(":id",
middleware.HashID(hashid.DavAccountID),
controllers.DeleteDAVAccounts,
)
}
//// 获取账号信息
//devices.GET("dav", controllers.GetWebDAVAccounts)
//// 删除目录挂载
//devices.DELETE("mount/:id",
// middleware.HashID(hashid.FolderID),
// controllers.DeleteWebDAVMounts,
//)
//// 创建目录挂载
//devices.POST("mount", controllers.CreateWebDAVMounts)
//// 更新账号可读性
//devices.PATCH("accounts", controllers.UpdateWebDAVAccountsReadonly)
}
}
}
// 初始化WebDAV相关路由
initWebDAV(r.Group("dav"))
return r
}
// initWebDAV 初始化WebDAV相关路由
func initWebDAV(group *gin.RouterGroup) {
{
group.Use(middleware.CacheControl(), middleware.WebDAVAuth())
group.Any("/*path", webdav.ServeHTTP)
group.Any("", webdav.ServeHTTP)
group.Handle("PROPFIND", "/*path", webdav.ServeHTTP)
group.Handle("PROPFIND", "", webdav.ServeHTTP)
group.Handle("MKCOL", "/*path", webdav.ServeHTTP)
group.Handle("LOCK", "/*path", webdav.ServeHTTP)
group.Handle("UNLOCK", "/*path", webdav.ServeHTTP)
group.Handle("PROPPATCH", "/*path", webdav.ServeHTTP)
group.Handle("COPY", "/*path", webdav.ServeHTTP)
group.Handle("MOVE", "/*path", webdav.ServeHTTP)
}
}