mirror of https://github.com/Xhofe/alist
* feat: support general users view and cancel own tasks Add a creator attribute to the upload, copy and offline download tasks, so that a GENERAL task creator can view and cancel them. BREAKING CHANGE: 1. A new internal package `task` including the struct `TaskWithCreator` which embeds `tache.Base` is created, and the past dependence on `tache.Task` will all be transferred to dependence on this package. 2. The API `/admin/task` can now also be accessed via `/task`, and the old endpoint is retained to ensure compatibility with legacy automation scripts. Closes #7398 * fix(deps): update github.com/xhofe/tache to v0.1.3pull/7453/head
parent
10c7ebb1c0
commit
64ceb5afb6
2
go.mod
2
go.mod
|
@ -56,7 +56,7 @@ require (
|
|||
github.com/u2takey/ffmpeg-go v0.5.0
|
||||
github.com/upyun/go-sdk/v3 v3.0.4
|
||||
github.com/winfsp/cgofuse v1.5.1-0.20230130140708-f87f5db493b5
|
||||
github.com/xhofe/tache v0.1.2
|
||||
github.com/xhofe/tache v0.1.3
|
||||
github.com/xhofe/wopan-sdk-go v0.1.3
|
||||
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22
|
||||
golang.org/x/crypto v0.27.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -514,6 +514,8 @@ github.com/xhofe/gsync v0.0.0-20230917091818-2111ceb38a25 h1:eDfebW/yfq9DtG9RO3K
|
|||
github.com/xhofe/gsync v0.0.0-20230917091818-2111ceb38a25/go.mod h1:fH4oNm5F9NfI5dLi0oIMtsLNKQOirUDbEMCIBb/7SU0=
|
||||
github.com/xhofe/tache v0.1.2 h1:pHrXlrWcbTb4G7hVUDW7Rc+YTUnLJvnLBrdktVE1Fqg=
|
||||
github.com/xhofe/tache v0.1.2/go.mod h1:iKumPFvywf30FRpAHHCt64G0JHLMzT0K+wyGedHsmTQ=
|
||||
github.com/xhofe/tache v0.1.3 h1:MipxzlljYX29E1YI/SLC7hVomVF+51iP1OUzlsuq1wE=
|
||||
github.com/xhofe/tache v0.1.3/go.mod h1:iKumPFvywf30FRpAHHCt64G0JHLMzT0K+wyGedHsmTQ=
|
||||
github.com/xhofe/wopan-sdk-go v0.1.3 h1:J58X6v+n25ewBZjb05pKOr7AWGohb+Rdll4CThGh6+A=
|
||||
github.com/xhofe/wopan-sdk-go v0.1.3/go.mod h1:dcY9yA28fnaoZPnXZiVTFSkcd7GnIPTpTIIlfSI5z5Q=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
|
|
@ -11,13 +11,14 @@ import (
|
|||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/internal/op"
|
||||
"github.com/alist-org/alist/v3/internal/stream"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
"github.com/alist-org/alist/v3/pkg/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xhofe/tache"
|
||||
)
|
||||
|
||||
type CopyTask struct {
|
||||
tache.Base
|
||||
task.TaskWithCreator
|
||||
Status string `json:"-"` //don't save status to save space
|
||||
SrcObjPath string `json:"src_path"`
|
||||
DstDirPath string `json:"dst_path"`
|
||||
|
@ -53,7 +54,7 @@ var CopyTaskManager *tache.Manager[*CopyTask]
|
|||
|
||||
// Copy if in the same storage, call move method
|
||||
// if not, add copy task
|
||||
func _copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (tache.TaskWithInfo, error) {
|
||||
func _copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (task.TaskInfoWithCreator, error) {
|
||||
srcStorage, srcObjActualPath, err := op.GetStorageAndActualPath(srcObjPath)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, "failed get src storage")
|
||||
|
@ -92,7 +93,11 @@ func _copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool
|
|||
}
|
||||
}
|
||||
// not in the same storage
|
||||
taskCreator, _ := ctx.Value("user").(*model.User) // taskCreator is nil when convert failed
|
||||
t := &CopyTask{
|
||||
TaskWithCreator: task.TaskWithCreator{
|
||||
Creator: taskCreator,
|
||||
},
|
||||
srcStorage: srcStorage,
|
||||
dstStorage: dstStorage,
|
||||
SrcObjPath: srcObjActualPath,
|
||||
|
@ -123,6 +128,9 @@ func copyBetween2Storages(t *CopyTask, srcStorage, dstStorage driver.Driver, src
|
|||
srcObjPath := stdpath.Join(srcObjPath, obj.GetName())
|
||||
dstObjPath := stdpath.Join(dstDirPath, srcObj.GetName())
|
||||
CopyTaskManager.Add(&CopyTask{
|
||||
TaskWithCreator: task.TaskWithCreator{
|
||||
Creator: t.Creator,
|
||||
},
|
||||
srcStorage: srcStorage,
|
||||
dstStorage: dstStorage,
|
||||
SrcObjPath: srcObjPath,
|
||||
|
|
|
@ -5,8 +5,8 @@ import (
|
|||
"github.com/alist-org/alist/v3/internal/driver"
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/internal/op"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/xhofe/tache"
|
||||
)
|
||||
|
||||
// the param named path of functions in this package is a mount path
|
||||
|
@ -69,7 +69,7 @@ func Move(ctx context.Context, srcPath, dstDirPath string, lazyCache ...bool) er
|
|||
return err
|
||||
}
|
||||
|
||||
func Copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (tache.TaskWithInfo, error) {
|
||||
func Copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (task.TaskInfoWithCreator, error) {
|
||||
res, err := _copy(ctx, srcObjPath, dstDirPath, lazyCache...)
|
||||
if err != nil {
|
||||
log.Errorf("failed copy %s to %s: %+v", srcObjPath, dstDirPath, err)
|
||||
|
@ -101,8 +101,8 @@ func PutDirectly(ctx context.Context, dstDirPath string, file model.FileStreamer
|
|||
return err
|
||||
}
|
||||
|
||||
func PutAsTask(dstDirPath string, file model.FileStreamer) (tache.TaskWithInfo, error) {
|
||||
t, err := putAsTask(dstDirPath, file)
|
||||
func PutAsTask(ctx context.Context, dstDirPath string, file model.FileStreamer) (task.TaskInfoWithCreator, error) {
|
||||
t, err := putAsTask(ctx, dstDirPath, file)
|
||||
if err != nil {
|
||||
log.Errorf("failed put %s: %+v", dstDirPath, err)
|
||||
}
|
||||
|
|
|
@ -7,12 +7,13 @@ import (
|
|||
"github.com/alist-org/alist/v3/internal/errs"
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/internal/op"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xhofe/tache"
|
||||
)
|
||||
|
||||
type UploadTask struct {
|
||||
tache.Base
|
||||
task.TaskWithCreator
|
||||
storage driver.Driver
|
||||
dstDirActualPath string
|
||||
file model.FileStreamer
|
||||
|
@ -33,7 +34,7 @@ func (t *UploadTask) Run() error {
|
|||
var UploadTaskManager *tache.Manager[*UploadTask]
|
||||
|
||||
// putAsTask add as a put task and return immediately
|
||||
func putAsTask(dstDirPath string, file model.FileStreamer) (tache.TaskWithInfo, error) {
|
||||
func putAsTask(ctx context.Context, dstDirPath string, file model.FileStreamer) (task.TaskInfoWithCreator, error) {
|
||||
storage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, "failed get storage")
|
||||
|
@ -49,7 +50,11 @@ func putAsTask(dstDirPath string, file model.FileStreamer) (tache.TaskWithInfo,
|
|||
//file.SetReader(tempFile)
|
||||
//file.SetTmpFile(tempFile)
|
||||
}
|
||||
taskCreator, _ := ctx.Value("user").(*model.User) // taskCreator is nil when convert failed
|
||||
t := &UploadTask{
|
||||
TaskWithCreator: task.TaskWithCreator{
|
||||
Creator: taskCreator,
|
||||
},
|
||||
storage: storage,
|
||||
dstDirActualPath: dstDirActualPath,
|
||||
file: file,
|
||||
|
|
|
@ -2,6 +2,8 @@ package tool
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/alist-org/alist/v3/internal/conf"
|
||||
|
@ -9,7 +11,6 @@ import (
|
|||
"github.com/alist-org/alist/v3/internal/op"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xhofe/tache"
|
||||
)
|
||||
|
||||
type DeletePolicy string
|
||||
|
@ -28,7 +29,7 @@ type AddURLArgs struct {
|
|||
DeletePolicy DeletePolicy
|
||||
}
|
||||
|
||||
func AddURL(ctx context.Context, args *AddURLArgs) (tache.TaskWithInfo, error) {
|
||||
func AddURL(ctx context.Context, args *AddURLArgs) (task.TaskInfoWithCreator, error) {
|
||||
// get tool
|
||||
tool, err := Tools.Get(args.Tool)
|
||||
if err != nil {
|
||||
|
@ -78,7 +79,11 @@ func AddURL(ctx context.Context, args *AddURLArgs) (tache.TaskWithInfo, error) {
|
|||
deletePolicy = DeleteNever
|
||||
}
|
||||
|
||||
taskCreator, _ := ctx.Value("user").(*model.User) // taskCreator is nil when convert failed
|
||||
t := &DownloadTask{
|
||||
TaskWithCreator: task.TaskWithCreator{
|
||||
Creator: taskCreator,
|
||||
},
|
||||
Url: args.URL,
|
||||
DstDirPath: args.DstDirPath,
|
||||
TempDir: tempDir,
|
||||
|
|
|
@ -7,13 +7,14 @@ import (
|
|||
"github.com/alist-org/alist/v3/internal/conf"
|
||||
"github.com/alist-org/alist/v3/internal/errs"
|
||||
"github.com/alist-org/alist/v3/internal/setting"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/xhofe/tache"
|
||||
)
|
||||
|
||||
type DownloadTask struct {
|
||||
tache.Base
|
||||
task.TaskWithCreator
|
||||
Url string `json:"url"`
|
||||
DstDirPath string `json:"dst_dir_path"`
|
||||
TempDir string `json:"temp_dir"`
|
||||
|
@ -171,6 +172,9 @@ func (t *DownloadTask) Complete() error {
|
|||
for i := range files {
|
||||
file := files[i]
|
||||
TransferTaskManager.Add(&TransferTask{
|
||||
TaskWithCreator: task.TaskWithCreator{
|
||||
Creator: t.Creator,
|
||||
},
|
||||
file: file,
|
||||
DstDirPath: t.DstDirPath,
|
||||
TempDir: t.TempDir,
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/internal/op"
|
||||
"github.com/alist-org/alist/v3/internal/stream"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
"github.com/alist-org/alist/v3/pkg/utils"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
@ -15,7 +16,7 @@ import (
|
|||
)
|
||||
|
||||
type TransferTask struct {
|
||||
tache.Base
|
||||
task.TaskWithCreator
|
||||
FileDir string `json:"file_dir"`
|
||||
DstDirPath string `json:"dst_dir_path"`
|
||||
TempDir string `json:"temp_dir"`
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package task
|
||||
|
||||
import (
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/xhofe/tache"
|
||||
)
|
||||
|
||||
type TaskWithCreator struct {
|
||||
tache.Base
|
||||
Creator *model.User
|
||||
}
|
||||
|
||||
func (t *TaskWithCreator) SetCreator(creator *model.User) {
|
||||
t.Creator = creator
|
||||
t.Persist()
|
||||
}
|
||||
|
||||
func (t *TaskWithCreator) GetCreator() *model.User {
|
||||
return t.Creator
|
||||
}
|
||||
|
||||
type TaskInfoWithCreator interface {
|
||||
tache.TaskWithInfo
|
||||
SetCreator(creator *model.User)
|
||||
GetCreator() *model.User
|
||||
}
|
|
@ -2,7 +2,7 @@ package handles
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/xhofe/tache"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
"io"
|
||||
stdpath "path"
|
||||
|
||||
|
@ -121,7 +121,7 @@ func FsCopy(c *gin.Context) {
|
|||
common.ErrorResp(c, err, 403)
|
||||
return
|
||||
}
|
||||
var addedTasks []tache.TaskWithInfo
|
||||
var addedTasks []task.TaskInfoWithCreator
|
||||
for i, name := range req.Names {
|
||||
t, err := fs.Copy(c, stdpath.Join(srcDir, name), dstDir, len(req.Names) > i+1)
|
||||
if t != nil {
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
package handles
|
||||
|
||||
import (
|
||||
"github.com/xhofe/tache"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
"io"
|
||||
"net/url"
|
||||
stdpath "path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/alist-org/alist/v3/internal/stream"
|
||||
|
||||
"github.com/alist-org/alist/v3/internal/fs"
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/internal/stream"
|
||||
"github.com/alist-org/alist/v3/server/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
@ -58,9 +57,9 @@ func FsStream(c *gin.Context) {
|
|||
Mimetype: c.GetHeader("Content-Type"),
|
||||
WebPutAsTask: asTask,
|
||||
}
|
||||
var t tache.TaskWithInfo
|
||||
var t task.TaskInfoWithCreator
|
||||
if asTask {
|
||||
t, err = fs.PutAsTask(dir, s)
|
||||
t, err = fs.PutAsTask(c, dir, s)
|
||||
} else {
|
||||
err = fs.PutDirectly(c, dir, s, true)
|
||||
}
|
||||
|
@ -123,12 +122,12 @@ func FsForm(c *gin.Context) {
|
|||
Mimetype: file.Header.Get("Content-Type"),
|
||||
WebPutAsTask: asTask,
|
||||
}
|
||||
var t tache.TaskWithInfo
|
||||
var t task.TaskInfoWithCreator
|
||||
if asTask {
|
||||
s.Reader = struct {
|
||||
io.Reader
|
||||
}{f}
|
||||
t, err = fs.PutAsTask(dir, &s)
|
||||
t, err = fs.PutAsTask(c, dir, &s)
|
||||
} else {
|
||||
ss, err := stream.NewSeekableStream(s, nil)
|
||||
if err != nil {
|
||||
|
|
|
@ -5,9 +5,9 @@ import (
|
|||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/internal/offline_download/tool"
|
||||
"github.com/alist-org/alist/v3/internal/op"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
"github.com/alist-org/alist/v3/server/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xhofe/tache"
|
||||
)
|
||||
|
||||
type SetAria2Req struct {
|
||||
|
@ -133,7 +133,7 @@ func AddOfflineDownload(c *gin.Context) {
|
|||
common.ErrorResp(c, err, 403)
|
||||
return
|
||||
}
|
||||
var tasks []tache.TaskWithInfo
|
||||
var tasks []task.TaskInfoWithCreator
|
||||
for _, url := range req.Urls {
|
||||
t, err := tool.AddURL(c, &tool.AddURLArgs{
|
||||
URL: url,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package handles
|
||||
|
||||
import (
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/internal/task"
|
||||
"math"
|
||||
|
||||
"github.com/alist-org/alist/v3/internal/fs"
|
||||
|
@ -14,13 +16,15 @@ import (
|
|||
type TaskInfo struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Creator string `json:"creator"`
|
||||
CreatorRole int `json:"creator_role"`
|
||||
State tache.State `json:"state"`
|
||||
Status string `json:"status"`
|
||||
Progress float64 `json:"progress"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func getTaskInfo[T tache.TaskWithInfo](task T) TaskInfo {
|
||||
func getTaskInfo[T task.TaskInfoWithCreator](task T) TaskInfo {
|
||||
errMsg := ""
|
||||
if task.GetErr() != nil {
|
||||
errMsg = task.GetErr().Error()
|
||||
|
@ -30,9 +34,17 @@ func getTaskInfo[T tache.TaskWithInfo](task T) TaskInfo {
|
|||
if math.IsNaN(progress) {
|
||||
progress = 100
|
||||
}
|
||||
creatorName := ""
|
||||
creatorRole := -1
|
||||
if task.GetCreator() != nil {
|
||||
creatorName = task.GetCreator().Username
|
||||
creatorRole = task.GetCreator().Role
|
||||
}
|
||||
return TaskInfo{
|
||||
ID: task.GetID(),
|
||||
Name: task.GetName(),
|
||||
Creator: creatorName,
|
||||
CreatorRole: creatorRole,
|
||||
State: task.GetState(),
|
||||
Status: task.GetStatus(),
|
||||
Progress: progress,
|
||||
|
@ -40,52 +52,124 @@ func getTaskInfo[T tache.TaskWithInfo](task T) TaskInfo {
|
|||
}
|
||||
}
|
||||
|
||||
func getTaskInfos[T tache.TaskWithInfo](tasks []T) []TaskInfo {
|
||||
func getTaskInfos[T task.TaskInfoWithCreator](tasks []T) []TaskInfo {
|
||||
return utils.MustSliceConvert(tasks, getTaskInfo[T])
|
||||
}
|
||||
|
||||
func taskRoute[T tache.TaskWithInfo](g *gin.RouterGroup, manager *tache.Manager[T]) {
|
||||
g.GET("/undone", func(c *gin.Context) {
|
||||
common.SuccessResp(c, getTaskInfos(manager.GetByState(tache.StatePending, tache.StateRunning,
|
||||
tache.StateCanceling, tache.StateErrored, tache.StateFailing, tache.StateWaitingRetry, tache.StateBeforeRetry)))
|
||||
})
|
||||
g.GET("/done", func(c *gin.Context) {
|
||||
common.SuccessResp(c, getTaskInfos(manager.GetByState(tache.StateCanceled, tache.StateFailed, tache.StateSucceeded)))
|
||||
})
|
||||
g.POST("/info", func(c *gin.Context) {
|
||||
tid := c.Query("tid")
|
||||
task, ok := manager.GetByID(tid)
|
||||
func argsContains[T comparable](v T, slice ...T) bool {
|
||||
return utils.SliceContains(slice, v)
|
||||
}
|
||||
|
||||
func getUserInfo(c *gin.Context) (bool, uint, bool) {
|
||||
if user, ok := c.Value("user").(*model.User); ok {
|
||||
return user.IsAdmin(), user.ID, true
|
||||
} else {
|
||||
return false, 0, false
|
||||
}
|
||||
}
|
||||
|
||||
func getTargetedHandler[T task.TaskInfoWithCreator](manager *tache.Manager[T], callback func(c *gin.Context, task T)) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
isAdmin, uid, ok := getUserInfo(c)
|
||||
if !ok {
|
||||
// if there is no bug, here is unreachable
|
||||
common.ErrorStrResp(c, "user invalid", 401)
|
||||
return
|
||||
}
|
||||
t, ok := manager.GetByID(c.Query("tid"))
|
||||
if !ok {
|
||||
common.ErrorStrResp(c, "task not found", 404)
|
||||
return
|
||||
}
|
||||
if !isAdmin && uid != t.GetCreator().ID {
|
||||
// to avoid an attacker using error messages to guess valid TID, return a 404 rather than a 403
|
||||
common.ErrorStrResp(c, "task not found", 404)
|
||||
return
|
||||
}
|
||||
callback(c, t)
|
||||
}
|
||||
}
|
||||
|
||||
func taskRoute[T task.TaskInfoWithCreator](g *gin.RouterGroup, manager *tache.Manager[T]) {
|
||||
g.GET("/undone", func(c *gin.Context) {
|
||||
isAdmin, uid, ok := getUserInfo(c)
|
||||
if !ok {
|
||||
// if there is no bug, here is unreachable
|
||||
common.ErrorStrResp(c, "user invalid", 401)
|
||||
return
|
||||
}
|
||||
common.SuccessResp(c, getTaskInfos(manager.GetByCondition(func(task T) bool {
|
||||
// avoid directly passing the user object into the function to reduce closure size
|
||||
return (isAdmin || uid == task.GetCreator().ID) &&
|
||||
argsContains(task.GetState(), tache.StatePending, tache.StateRunning, tache.StateCanceling,
|
||||
tache.StateErrored, tache.StateFailing, tache.StateWaitingRetry, tache.StateBeforeRetry)
|
||||
})))
|
||||
})
|
||||
g.GET("/done", func(c *gin.Context) {
|
||||
isAdmin, uid, ok := getUserInfo(c)
|
||||
if !ok {
|
||||
// if there is no bug, here is unreachable
|
||||
common.ErrorStrResp(c, "user invalid", 401)
|
||||
return
|
||||
}
|
||||
common.SuccessResp(c, getTaskInfos(manager.GetByCondition(func(task T) bool {
|
||||
return (isAdmin || uid == task.GetCreator().ID) &&
|
||||
argsContains(task.GetState(), tache.StateCanceled, tache.StateFailed, tache.StateSucceeded)
|
||||
})))
|
||||
})
|
||||
g.POST("/info", getTargetedHandler(manager, func(c *gin.Context, task T) {
|
||||
common.SuccessResp(c, getTaskInfo(task))
|
||||
})
|
||||
g.POST("/cancel", func(c *gin.Context) {
|
||||
tid := c.Query("tid")
|
||||
manager.Cancel(tid)
|
||||
}))
|
||||
g.POST("/cancel", getTargetedHandler(manager, func(c *gin.Context, task T) {
|
||||
manager.Cancel(task.GetID())
|
||||
common.SuccessResp(c)
|
||||
})
|
||||
g.POST("/delete", func(c *gin.Context) {
|
||||
tid := c.Query("tid")
|
||||
manager.Remove(tid)
|
||||
}))
|
||||
g.POST("/delete", getTargetedHandler(manager, func(c *gin.Context, task T) {
|
||||
manager.Remove(task.GetID())
|
||||
common.SuccessResp(c)
|
||||
})
|
||||
g.POST("/retry", func(c *gin.Context) {
|
||||
tid := c.Query("tid")
|
||||
manager.Retry(tid)
|
||||
}))
|
||||
g.POST("/retry", getTargetedHandler(manager, func(c *gin.Context, task T) {
|
||||
manager.Retry(task.GetID())
|
||||
common.SuccessResp(c)
|
||||
})
|
||||
}))
|
||||
g.POST("/clear_done", func(c *gin.Context) {
|
||||
manager.RemoveByState(tache.StateCanceled, tache.StateFailed, tache.StateSucceeded)
|
||||
isAdmin, uid, ok := getUserInfo(c)
|
||||
if !ok {
|
||||
// if there is no bug, here is unreachable
|
||||
common.ErrorStrResp(c, "user invalid", 401)
|
||||
return
|
||||
}
|
||||
manager.RemoveByCondition(func(task T) bool {
|
||||
return (isAdmin || uid == task.GetCreator().ID) &&
|
||||
argsContains(task.GetState(), tache.StateCanceled, tache.StateFailed, tache.StateSucceeded)
|
||||
})
|
||||
common.SuccessResp(c)
|
||||
})
|
||||
g.POST("/clear_succeeded", func(c *gin.Context) {
|
||||
manager.RemoveByState(tache.StateSucceeded)
|
||||
isAdmin, uid, ok := getUserInfo(c)
|
||||
if !ok {
|
||||
// if there is no bug, here is unreachable
|
||||
common.ErrorStrResp(c, "user invalid", 401)
|
||||
return
|
||||
}
|
||||
manager.RemoveByCondition(func(task T) bool {
|
||||
return (isAdmin || uid == task.GetCreator().ID) && task.GetState() == tache.StateSucceeded
|
||||
})
|
||||
common.SuccessResp(c)
|
||||
})
|
||||
g.POST("/retry_failed", func(c *gin.Context) {
|
||||
manager.RetryAllFailed()
|
||||
isAdmin, uid, ok := getUserInfo(c)
|
||||
if !ok {
|
||||
// if there is no bug, here is unreachable
|
||||
common.ErrorStrResp(c, "user invalid", 401)
|
||||
return
|
||||
}
|
||||
tasks := manager.GetByCondition(func(task T) bool {
|
||||
return (isAdmin || uid == task.GetCreator().ID) && task.GetState() == tache.StateFailed
|
||||
})
|
||||
for _, t := range tasks {
|
||||
manager.Retry(t.GetID())
|
||||
}
|
||||
common.SuccessResp(c)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -127,6 +127,16 @@ func Authn(c *gin.Context) {
|
|||
c.Next()
|
||||
}
|
||||
|
||||
func AuthNotGuest(c *gin.Context) {
|
||||
user := c.MustGet("user").(*model.User)
|
||||
if user.IsGuest() {
|
||||
common.ErrorStrResp(c, "You are a guest", 403)
|
||||
c.Abort()
|
||||
} else {
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func AuthAdmin(c *gin.Context) {
|
||||
user := c.MustGet("user").(*model.User)
|
||||
if !user.IsAdmin() {
|
||||
|
|
|
@ -76,6 +76,7 @@ func Init(e *gin.Engine) {
|
|||
public.Any("/offline_download_tools", handles.OfflineDownloadTools)
|
||||
|
||||
_fs(auth.Group("/fs"))
|
||||
_task(auth.Group("/task", middlewares.AuthNotGuest))
|
||||
admin(auth.Group("/admin", middlewares.AuthAdmin))
|
||||
if flags.Debug || flags.Dev {
|
||||
debug(g.Group("/debug"))
|
||||
|
@ -127,8 +128,8 @@ func admin(g *gin.RouterGroup) {
|
|||
setting.POST("/set_qbit", handles.SetQbittorrent)
|
||||
setting.POST("/set_transmission", handles.SetTransmission)
|
||||
|
||||
task := g.Group("/task")
|
||||
handles.SetupTaskRoute(task)
|
||||
// retain /admin/task API to ensure compatibility with legacy automation scripts
|
||||
_task(g.Group("/task"))
|
||||
|
||||
ms := g.Group("/message")
|
||||
ms.POST("/get", message.HttpInstance.GetHandle)
|
||||
|
@ -166,6 +167,10 @@ func _fs(g *gin.RouterGroup) {
|
|||
g.POST("/add_offline_download", handles.AddOfflineDownload)
|
||||
}
|
||||
|
||||
func _task(g *gin.RouterGroup) {
|
||||
handles.SetupTaskRoute(g)
|
||||
}
|
||||
|
||||
func Cors(r *gin.Engine) {
|
||||
config := cors.DefaultConfig()
|
||||
// config.AllowAllOrigins = true
|
||||
|
|
Loading…
Reference in New Issue