chore: rename controllers to handles

This commit is contained in:
Noah Hsu
2022-07-11 17:12:50 +08:00
parent 8971a924f1
commit dc38f21294
12 changed files with 61 additions and 61 deletions

70
server/handles/account.go Normal file
View File

@ -0,0 +1,70 @@
package handles
import (
"strconv"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/operations"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
func ListStorages(c *gin.Context) {
var req common.PageReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
log.Debugf("%+v", req)
storages, total, err := db.GetStorages(req.PageIndex, req.PageSize)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
common.SuccessResp(c, common.PageResp{
Content: storages,
Total: total,
})
}
func CreateStorage(c *gin.Context) {
var req model.Storage
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
if err := operations.CreateStorage(c, req); err != nil {
common.ErrorResp(c, err, 500, true)
} else {
common.SuccessResp(c)
}
}
func UpdateStorage(c *gin.Context) {
var req model.Storage
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
if err := operations.UpdateStorage(c, req); err != nil {
common.ErrorResp(c, err, 500, true)
} else {
common.SuccessResp(c)
}
}
func DeleteStorage(c *gin.Context) {
idStr := c.Query("id")
id, err := strconv.Atoi(idStr)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
if err := operations.DeleteStorageById(c, uint(id)); err != nil {
common.ErrorResp(c, err, 500, true)
return
}
common.SuccessResp(c)
}

69
server/handles/aria2.go Normal file
View File

@ -0,0 +1,69 @@
package handles
import (
"github.com/alist-org/alist/v3/internal/aria2"
"github.com/alist-org/alist/v3/internal/conf"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
stdpath "path"
)
type SetAria2Req struct {
Uri string `json:"uri" form:"uri"`
Secret string `json:"secret" form:"secret"`
}
func SetAria2(c *gin.Context) {
var req SetAria2Req
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
items := []model.SettingItem{
{Key: conf.Aria2Uri, Value: req.Uri, Type: conf.TypeString, Group: model.ARIA2, Flag: model.PRIVATE},
{Key: conf.Aria2Secret, Value: req.Secret, Type: conf.TypeString, Group: model.ARIA2, Flag: model.PRIVATE},
}
if err := db.SaveSettingItems(items); err != nil {
common.ErrorResp(c, err, 500)
return
}
err := aria2.InitClient(2)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
common.SuccessResp(c)
}
type AddAria2Req struct {
Urls []string `json:"urls"`
Path string `json:"path"`
}
func AddAria2(c *gin.Context) {
user := c.MustGet("user").(*model.User)
if !user.CanAddAria2Tasks() {
common.ErrorStrResp(c, "permission denied", 403)
return
}
if !aria2.IsAria2Ready() {
common.ErrorStrResp(c, "aria2 not ready", 500)
return
}
var req AddAria2Req
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
req.Path = stdpath.Join(user.BasePath, req.Path)
for _, url := range req.Urls {
err := aria2.AddURI(c, url, req.Path)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
}
common.SuccessResp(c)
}

68
server/handles/auth.go Normal file
View File

@ -0,0 +1,68 @@
package handles
import (
"time"
"github.com/Xhofe/go-cache"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
)
var loginCache = cache.NewMemCache[int]()
var (
defaultDuration = time.Minute * 5
defaultTimes = 5
)
type LoginReq struct {
Username string `json:"username"`
Password string `json:"password"`
}
func Login(c *gin.Context) {
// check count of login
ip := c.ClientIP()
count, ok := loginCache.Get(ip)
if ok && count >= defaultTimes {
common.ErrorStrResp(c, "Too many unsuccessful sign-in attempts have been made using an incorrect username or password, Try again later.", 403)
loginCache.Expire(ip, defaultDuration)
return
}
// check username
var req LoginReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
user, err := db.GetUserByName(req.Username)
if err != nil {
common.ErrorResp(c, err, 400)
loginCache.Set(ip, count+1)
return
}
// validate password
if err := user.ValidatePassword(req.Password); err != nil {
common.ErrorResp(c, err, 400)
loginCache.Set(ip, count+1)
return
}
// generate token
token, err := common.GenerateToken(user.Username)
if err != nil {
common.ErrorResp(c, err, 400, true)
return
}
common.SuccessResp(c, gin.H{"token": token})
loginCache.Del(ip)
}
// CurrentUser get current user by token
// if token is empty, return guest user
func CurrentUser(c *gin.Context) {
user := c.MustGet("user").(*model.User)
userResp := *user
userResp.Password = ""
common.SuccessResp(c, userResp)
}

115
server/handles/down.go Normal file
View File

@ -0,0 +1,115 @@
package handles
import (
"fmt"
"github.com/alist-org/alist/v3/internal/conf"
"github.com/alist-org/alist/v3/internal/sign"
stdpath "path"
"strings"
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/fs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/setting"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
)
func Down(c *gin.Context) {
rawPath := c.MustGet("path").(string)
filename := stdpath.Base(rawPath)
storage, err := fs.GetStorage(rawPath)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if shouldProxy(storage, filename) {
Proxy(c)
return
} else {
link, _, err := fs.Link(c, rawPath, model.LinkArgs{
IP: c.ClientIP(),
Header: c.Request.Header,
})
if err != nil {
common.ErrorResp(c, err, 500)
return
}
c.Redirect(302, link.URL)
}
}
func Proxy(c *gin.Context) {
rawPath := c.MustGet("path").(string)
filename := stdpath.Base(rawPath)
storage, err := fs.GetStorage(rawPath)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if canProxy(storage, filename) {
downProxyUrl := storage.GetStorage().DownProxyUrl
if downProxyUrl != "" {
_, ok := c.GetQuery("d")
if ok {
URL := fmt.Sprintf("%s%s?sign=%s", strings.Split(downProxyUrl, "\n")[0], rawPath, sign.Sign(filename))
c.Redirect(302, URL)
return
}
}
link, file, err := fs.Link(c, rawPath, model.LinkArgs{
Header: c.Request.Header,
})
if err != nil {
common.ErrorResp(c, err, 500)
return
}
err = common.Proxy(c.Writer, c.Request, link, file)
if err != nil {
common.ErrorResp(c, err, 500, true)
return
}
} else {
common.ErrorStrResp(c, "proxy not allowed", 403)
return
}
}
// TODO need optimize
// when should be proxy?
// 1. config.MustProxy()
// 2. storage.WebProxy
// 3. proxy_types
func shouldProxy(storage driver.Driver, filename string) bool {
if storage.Config().MustProxy() || storage.GetStorage().WebProxy {
return true
}
proxyTypes := setting.GetByKey(conf.ProxyTypes)
if strings.Contains(proxyTypes, utils.Ext(filename)) {
return true
}
return false
}
// TODO need optimize
// when can be proxy?
// 1. text file
// 2. config.MustProxy()
// 3. storage.WebProxy
// 4. proxy_types
// solution: text_file + shouldProxy()
func canProxy(storage driver.Driver, filename string) bool {
if storage.Config().MustProxy() || storage.GetStorage().WebProxy {
return true
}
proxyTypes := setting.GetByKey(conf.ProxyTypes)
if strings.Contains(proxyTypes, utils.Ext(filename)) {
return true
}
textTypes := setting.GetByKey(conf.TextTypes)
if strings.Contains(textTypes, utils.Ext(filename)) {
return true
}
return false
}

27
server/handles/driver.go Normal file
View File

@ -0,0 +1,27 @@
package handles
import (
"fmt"
"github.com/alist-org/alist/v3/internal/operations"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
)
func ListDriverItems(c *gin.Context) {
common.SuccessResp(c, operations.GetDriverItemsMap())
}
func ListDriverNames(c *gin.Context) {
common.SuccessResp(c, operations.GetDriverNames())
}
func GetDriverItems(c *gin.Context) {
driverName := c.Query("driver")
itemsMap := operations.GetDriverItemsMap()
items, ok := itemsMap[driverName]
if !ok {
common.ErrorStrResp(c, fmt.Sprintf("driver [%s] not found", driverName), 404)
return
}
common.SuccessResp(c, items)
}

258
server/handles/fsmanage.go Normal file
View File

@ -0,0 +1,258 @@
package handles
import (
"fmt"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/fs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/sign"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
stdpath "path"
"strconv"
"time"
)
type MkdirOrLinkReq struct {
Path string `json:"path" form:"path"`
}
func FsMkdir(c *gin.Context) {
var req MkdirOrLinkReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
user := c.MustGet("user").(*model.User)
req.Path = stdpath.Join(user.BasePath, req.Path)
if !user.CanWrite() {
meta, err := db.GetNearestMeta(req.Path)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if !canWrite(meta, req.Path) {
common.ErrorResp(c, errs.PermissionDenied, 403)
return
}
}
if err := fs.MakeDir(c, req.Path); err != nil {
common.ErrorResp(c, err, 500)
return
}
fs.ClearCache(stdpath.Dir(req.Path))
common.SuccessResp(c)
}
func canWrite(meta *model.Meta, path string) bool {
if meta == nil || !meta.Write {
return false
}
return meta.WSub || meta.Path == path
}
type MoveCopyReq struct {
SrcDir string `json:"src_dir"`
DstDir string `json:"dst_dir"`
Names []string `json:"names"`
}
func FsMove(c *gin.Context) {
var req MoveCopyReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
if len(req.Names) == 0 {
common.ErrorStrResp(c, "Empty file names", 400)
return
}
user := c.MustGet("user").(*model.User)
if !user.CanMove() {
common.ErrorResp(c, errs.PermissionDenied, 403)
return
}
req.SrcDir = stdpath.Join(user.BasePath, req.SrcDir)
req.DstDir = stdpath.Join(user.BasePath, req.DstDir)
for _, name := range req.Names {
err := fs.Move(c, stdpath.Join(req.SrcDir, name), req.DstDir)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
}
fs.ClearCache(req.SrcDir)
fs.ClearCache(req.DstDir)
common.SuccessResp(c)
}
func FsCopy(c *gin.Context) {
var req MoveCopyReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
if len(req.Names) == 0 {
common.ErrorStrResp(c, "Empty file names", 400)
return
}
user := c.MustGet("user").(*model.User)
if !user.CanCopy() {
common.ErrorResp(c, errs.PermissionDenied, 403)
return
}
req.SrcDir = stdpath.Join(user.BasePath, req.SrcDir)
req.DstDir = stdpath.Join(user.BasePath, req.DstDir)
var addedTask []string
for _, name := range req.Names {
ok, err := fs.Copy(c, stdpath.Join(req.SrcDir, name), req.DstDir)
if ok {
addedTask = append(addedTask, name)
}
if err != nil {
common.ErrorResp(c, err, 500)
return
}
}
if len(req.Names) != len(addedTask) {
fs.ClearCache(req.DstDir)
}
if len(addedTask) > 0 {
common.SuccessResp(c, fmt.Sprintf("Added %d tasks", len(addedTask)))
} else {
common.SuccessResp(c)
}
}
type RenameReq struct {
Path string `json:"path"`
Name string `json:"name"`
}
func FsRename(c *gin.Context) {
var req RenameReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
user := c.MustGet("user").(*model.User)
if !user.CanRename() {
common.ErrorResp(c, errs.PermissionDenied, 403)
return
}
req.Path = stdpath.Join(user.BasePath, req.Path)
if err := fs.Rename(c, req.Path, req.Name); err != nil {
common.ErrorResp(c, err, 500)
return
}
fs.ClearCache(stdpath.Dir(req.Path))
common.SuccessResp(c)
}
type RemoveReq struct {
Dir string `json:"dir"`
Names []string `json:"names"`
}
func FsRemove(c *gin.Context) {
var req RemoveReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
if len(req.Names) == 0 {
common.ErrorStrResp(c, "Empty file names", 400)
return
}
user := c.MustGet("user").(*model.User)
if !user.CanRemove() {
common.ErrorResp(c, errs.PermissionDenied, 403)
return
}
req.Dir = stdpath.Join(user.BasePath, req.Dir)
for _, name := range req.Names {
err := fs.Remove(c, stdpath.Join(req.Dir, name))
if err != nil {
common.ErrorResp(c, err, 500)
return
}
}
fs.ClearCache(req.Dir)
common.SuccessResp(c)
}
func FsPut(c *gin.Context) {
path := c.GetHeader("File-Path")
asTask := c.GetHeader("As-Task") == "true"
user := c.MustGet("user").(*model.User)
path = stdpath.Join(user.BasePath, path)
if !user.CanWrite() {
meta, err := db.GetNearestMeta(path)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if !canWrite(meta, path) {
common.ErrorResp(c, errs.PermissionDenied, 403)
return
}
}
dir, name := stdpath.Split(path)
sizeStr := c.GetHeader("Content-Length")
size, err := strconv.ParseInt(sizeStr, 10, 64)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
stream := &model.FileStream{
Obj: model.Object{
Name: name,
Size: size,
Modified: time.Now(),
},
ReadCloser: c.Request.Body,
Mimetype: c.GetHeader("Content-Type"),
WebPutAsTask: asTask,
}
if asTask {
err = fs.PutAsTask(dir, stream)
} else {
err = fs.PutDirectly(c, dir, stream)
}
if err != nil {
common.ErrorResp(c, err, 500)
return
}
common.SuccessResp(c)
}
// Link return real link, just for proxy program, it may contain cookie
func Link(c *gin.Context) {
var req FsGetOrLinkReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
user := c.MustGet("user").(*model.User)
rawPath := stdpath.Join(user.BasePath, req.Path)
storage, err := fs.GetStorage(rawPath)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if storage.Config().OnlyLocal {
common.SuccessResp(c, model.Link{
URL: fmt.Sprintf("%s/p%s?d&sign=%s", common.GetBaseUrl(c.Request), req.Path, sign.Sign(stdpath.Base(rawPath))),
})
return
}
link, _, err := fs.Link(c, rawPath, model.LinkArgs{IP: c.ClientIP()})
if err != nil {
common.ErrorResp(c, err, 500)
return
}
common.SuccessResp(c, link)
return
}

249
server/handles/fsread.go Normal file
View File

@ -0,0 +1,249 @@
package handles
import (
"fmt"
"github.com/alist-org/alist/v3/internal/sign"
stdpath "path"
"strings"
"time"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/fs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
)
type ListReq struct {
common.PageReq
Path string `json:"path" form:"path"`
Password string `json:"password" form:"password"`
}
type DirReq struct {
Path string `json:"path" form:"path"`
Password string `json:"password" form:"password"`
}
type ObjResp struct {
Name string `json:"name"`
Size int64 `json:"size"`
IsDir bool `json:"is_dir"`
Modified time.Time `json:"modified"`
Sign string `json:"sign"`
}
type FsListResp struct {
Content []ObjResp `json:"content"`
Total int64 `json:"total"`
Readme string `json:"readme"`
Write bool `json:"write"`
}
func FsList(c *gin.Context) {
var req ListReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
req.Validate()
user := c.MustGet("user").(*model.User)
req.Path = stdpath.Join(user.BasePath, req.Path)
meta, err := db.GetNearestMeta(req.Path)
if err != nil {
if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
common.ErrorResp(c, err, 500, true)
return
}
}
c.Set("meta", meta)
if !canAccess(user, meta, req.Path, req.Password) {
common.ErrorStrResp(c, "password is incorrect", 403)
return
}
objs, err := fs.List(c, req.Path)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
total, objs := pagination(objs, &req.PageReq)
common.SuccessResp(c, FsListResp{
Content: toObjResp(objs),
Total: int64(total),
Readme: getReadme(meta, req.Path),
Write: user.CanWrite() || canWrite(meta, req.Path),
})
}
func FsDirs(c *gin.Context) {
var req DirReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
user := c.MustGet("user").(*model.User)
req.Path = stdpath.Join(user.BasePath, req.Path)
meta, err := db.GetNearestMeta(req.Path)
if err != nil {
if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
common.ErrorResp(c, err, 500, true)
return
}
}
c.Set("meta", meta)
if !canAccess(user, meta, req.Path, req.Password) {
common.ErrorStrResp(c, "password is incorrect", 403)
return
}
objs, err := fs.List(c, req.Path)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
dirs := filterDirs(objs)
common.SuccessResp(c, dirs)
}
type DirResp struct {
Name string `json:"name"`
Modified time.Time `json:"modified"`
}
func filterDirs(objs []model.Obj) []DirResp {
var dirs []DirResp
for _, obj := range objs {
if obj.IsDir() {
dirs = append(dirs, DirResp{
Name: obj.GetName(),
Modified: obj.ModTime(),
})
}
}
return dirs
}
func getReadme(meta *model.Meta, path string) string {
if meta != nil && (utils.PathEqual(meta.Path, path) || meta.RSub) {
return meta.Readme
}
return ""
}
func canAccess(user *model.User, meta *model.Meta, path string, password string) bool {
// if is not guest, can access
if user.CanAccessWithoutPassword() {
return true
}
// if meta is nil or password is empty, can access
if meta == nil || meta.Password == "" {
return true
}
// if meta doesn't apply to sub_folder, can access
if !utils.PathEqual(meta.Path, path) && !meta.PSub {
return true
}
// validate password
return meta.Password == password
}
func pagination(objs []model.Obj, req *common.PageReq) (int, []model.Obj) {
pageIndex, pageSize := req.PageIndex, req.PageSize
total := len(objs)
start := (pageIndex - 1) * pageSize
if start > total {
return total, []model.Obj{}
}
end := start + pageSize
if end > total {
end = total
}
return total, objs[start:end]
}
func toObjResp(objs []model.Obj) []ObjResp {
var resp []ObjResp
for _, obj := range objs {
resp = append(resp, ObjResp{
Name: obj.GetName(),
Size: obj.GetSize(),
IsDir: obj.IsDir(),
Modified: obj.ModTime(),
Sign: common.Sign(obj),
})
}
return resp
}
type FsGetOrLinkReq struct {
Path string `json:"path" form:"path"`
Password string `json:"password" form:"password"`
}
type FsGetResp struct {
ObjResp
RawURL string `json:"raw_url"`
}
func FsGet(c *gin.Context) {
var req FsGetOrLinkReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
user := c.MustGet("user").(*model.User)
req.Path = stdpath.Join(user.BasePath, req.Path)
meta, err := db.GetNearestMeta(req.Path)
if err != nil {
if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
common.ErrorResp(c, err, 500)
return
}
}
c.Set("meta", meta)
if !canAccess(user, meta, req.Path, req.Password) {
common.ErrorStrResp(c, "password is incorrect", 403)
return
}
obj, err := fs.Get(c, req.Path)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
var rawURL string
// file have raw url
if !obj.IsDir() {
if u, ok := obj.(model.URL); ok {
rawURL = u.URL()
} else {
storage, _ := fs.GetStorage(req.Path)
if storage.Config().MustProxy() || storage.GetStorage().WebProxy {
if storage.GetStorage().DownProxyUrl != "" {
rawURL = fmt.Sprintf("%s%s?sign=%s", strings.Split(storage.GetStorage().DownProxyUrl, "\n")[0], req.Path, sign.Sign(obj.GetName()))
} else {
rawURL = fmt.Sprintf("%s/p%s?sign=%s", common.GetBaseUrl(c.Request), req.Path, sign.Sign(obj.GetName()))
}
} else {
// if storage is not proxy, use raw url by fs.Link
link, _, err := fs.Link(c, req.Path, model.LinkArgs{IP: c.ClientIP()})
if err != nil {
common.ErrorResp(c, err, 500)
return
}
rawURL = link.URL
}
}
}
common.SuccessResp(c, FsGetResp{
ObjResp: ObjResp{
Name: obj.GetName(),
Size: obj.GetSize(),
IsDir: obj.IsDir(),
Modified: obj.ModTime(),
Sign: common.Sign(obj),
},
RawURL: rawURL,
})
}

96
server/handles/meta.go Normal file
View File

@ -0,0 +1,96 @@
package handles
import (
"fmt"
"regexp"
"strconv"
"strings"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
func ListMetas(c *gin.Context) {
var req common.PageReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
log.Debugf("%+v", req)
metas, total, err := db.GetMetas(req.PageIndex, req.PageSize)
if err != nil {
common.ErrorResp(c, err, 500, true)
return
}
common.SuccessResp(c, common.PageResp{
Content: metas,
Total: total,
})
}
func CreateMeta(c *gin.Context) {
var req model.Meta
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
r, err := validHide(req.Hide)
if err != nil {
common.ErrorStrResp(c, fmt.Sprintf("%s is illegal: %s", r, err.Error()), 400)
return
}
req.Path = utils.StandardizePath(req.Path)
if err := db.CreateMeta(&req); err != nil {
common.ErrorResp(c, err, 500, true)
} else {
common.SuccessResp(c)
}
}
func UpdateMeta(c *gin.Context) {
var req model.Meta
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
r, err := validHide(req.Hide)
if err != nil {
common.ErrorStrResp(c, fmt.Sprintf("%s is illegal: %s", r, err.Error()), 400)
return
}
req.Path = utils.StandardizePath(req.Path)
if err := db.UpdateMeta(&req); err != nil {
common.ErrorResp(c, err, 500, true)
} else {
common.SuccessResp(c)
}
}
func validHide(hide string) (string, error) {
rs := strings.Split(hide, "\n")
for _, r := range rs {
_, err := regexp.Compile(r)
if err != nil {
return r, err
}
}
return "", nil
}
func DeleteMeta(c *gin.Context) {
idStr := c.Query("id")
id, err := strconv.Atoi(idStr)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
if err := db.DeleteMetaById(uint(id)); err != nil {
common.ErrorResp(c, err, 500, true)
return
}
common.SuccessResp(c)
}

78
server/handles/setting.go Normal file
View File

@ -0,0 +1,78 @@
package handles
import (
"github.com/alist-org/alist/v3/internal/conf"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/sign"
"github.com/alist-org/alist/v3/pkg/utils/random"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
"strconv"
)
func ResetToken(c *gin.Context) {
token := random.Token()
item := model.SettingItem{Key: "token", Value: token, Type: conf.TypeString, Group: model.SINGLE, Flag: model.PRIVATE}
if err := db.SaveSettingItem(item); err != nil {
common.ErrorResp(c, err, 500)
return
}
sign.Instance()
common.SuccessResp(c, token)
}
func GetSetting(c *gin.Context) {
key := c.Query("key")
item, err := db.GetSettingItemByKey(key)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
common.SuccessResp(c, item)
}
func SaveSettings(c *gin.Context) {
var req []model.SettingItem
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
if err := db.SaveSettingItems(req); err != nil {
common.ErrorResp(c, err, 500)
} else {
common.SuccessResp(c)
}
}
func ListSettings(c *gin.Context) {
groupStr := c.Query("group")
var settings []model.SettingItem
var err error
if groupStr == "" {
settings, err = db.GetSettingItems()
} else {
group, err := strconv.Atoi(groupStr)
if err == nil {
settings, err = db.GetSettingItemsByGroup(group)
}
}
if err != nil {
common.ErrorResp(c, err, 400)
return
}
common.SuccessResp(c, settings)
}
func DeleteSetting(c *gin.Context) {
key := c.Query("key")
if err := db.DeleteSettingItemByKey(key); err != nil {
common.ErrorResp(c, err, 500)
return
}
common.SuccessResp(c)
}
func PublicSettings(c *gin.Context) {
common.SuccessResp(c, db.GetPublicSettingsMap())
}

140
server/handles/task.go Normal file
View File

@ -0,0 +1,140 @@
package handles
import (
"github.com/alist-org/alist/v3/internal/aria2"
"github.com/alist-org/alist/v3/internal/fs"
"github.com/alist-org/alist/v3/pkg/task"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
"strconv"
)
type TaskInfo struct {
ID string `json:"id"`
Name string `json:"name"`
State string `json:"state"`
Status string `json:"status"`
Progress int `json:"progress"`
Error string `json:"error"`
}
func getTaskInfoUint(task *task.Task[uint64]) TaskInfo {
return TaskInfo{
ID: strconv.FormatUint(task.ID, 10),
Name: task.Name,
State: task.GetState(),
Status: task.GetStatus(),
Progress: task.GetProgress(),
Error: task.Error.Error(),
}
}
func getTaskInfoStr(task *task.Task[string]) TaskInfo {
return TaskInfo{
ID: task.ID,
Name: task.Name,
State: task.GetState(),
Status: task.GetStatus(),
Progress: task.GetProgress(),
Error: task.GetErrMsg(),
}
}
func getTaskInfosUint(tasks []*task.Task[uint64]) []TaskInfo {
var infos []TaskInfo
for _, t := range tasks {
infos = append(infos, getTaskInfoUint(t))
}
return infos
}
func getTaskInfosStr(tasks []*task.Task[string]) []TaskInfo {
var infos []TaskInfo
for _, t := range tasks {
infos = append(infos, getTaskInfoStr(t))
}
return infos
}
func UndoneDownTask(c *gin.Context) {
common.SuccessResp(c, getTaskInfosStr(aria2.DownTaskManager.ListUndone()))
}
func DoneDownTask(c *gin.Context) {
common.SuccessResp(c, getTaskInfosStr(aria2.DownTaskManager.ListDone()))
}
func CancelDownTask(c *gin.Context) {
tid := c.Query("tid")
if err := aria2.DownTaskManager.Cancel(tid); err != nil {
common.ErrorResp(c, err, 500)
} else {
common.SuccessResp(c)
}
}
func UndoneTransferTask(c *gin.Context) {
common.SuccessResp(c, getTaskInfosUint(aria2.TransferTaskManager.ListUndone()))
}
func DoneTransferTask(c *gin.Context) {
common.SuccessResp(c, getTaskInfosUint(aria2.TransferTaskManager.ListDone()))
}
func CancelTransferTask(c *gin.Context) {
id := c.Query("tid")
tid, err := strconv.ParseUint(id, 10, 64)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
if err := aria2.TransferTaskManager.Cancel(tid); err != nil {
common.ErrorResp(c, err, 500)
} else {
common.SuccessResp(c)
}
}
func UndoneUploadTask(c *gin.Context) {
common.SuccessResp(c, getTaskInfosUint(fs.UploadTaskManager.ListUndone()))
}
func DoneUploadTask(c *gin.Context) {
common.SuccessResp(c, getTaskInfosUint(fs.UploadTaskManager.ListDone()))
}
func CancelUploadTask(c *gin.Context) {
id := c.Query("tid")
tid, err := strconv.ParseUint(id, 10, 64)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
if err := fs.UploadTaskManager.Cancel(tid); err != nil {
common.ErrorResp(c, err, 500)
} else {
common.SuccessResp(c)
}
}
func UndoneCopyTask(c *gin.Context) {
common.SuccessResp(c, getTaskInfosUint(fs.CopyTaskManager.ListUndone()))
}
func DoneCopyTask(c *gin.Context) {
common.SuccessResp(c, getTaskInfosUint(fs.CopyTaskManager.ListDone()))
}
func CancelCopyTask(c *gin.Context) {
id := c.Query("tid")
tid, err := strconv.ParseUint(id, 10, 64)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
if err := fs.CopyTaskManager.Cancel(tid); err != nil {
common.ErrorResp(c, err, 500)
} else {
common.SuccessResp(c)
}
}

82
server/handles/user.go Normal file
View File

@ -0,0 +1,82 @@
package handles
import (
"strconv"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
func ListUsers(c *gin.Context) {
var req common.PageReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
log.Debugf("%+v", req)
users, total, err := db.GetUsers(req.PageIndex, req.PageSize)
if err != nil {
common.ErrorResp(c, err, 500, true)
return
}
common.SuccessResp(c, common.PageResp{
Content: users,
Total: total,
})
}
func CreateUser(c *gin.Context) {
var req model.User
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
if req.IsAdmin() || req.IsGuest() {
common.ErrorStrResp(c, "admin or guest user can not be created", 400, true)
return
}
if err := db.CreateUser(&req); err != nil {
common.ErrorResp(c, err, 500, true)
} else {
common.SuccessResp(c)
}
}
func UpdateUser(c *gin.Context) {
var req model.User
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
user, err := db.GetUserById(req.ID)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if user.Role != req.Role {
common.ErrorStrResp(c, "role can not be changed", 400)
return
}
if err := db.UpdateUser(&req); err != nil {
common.ErrorResp(c, err, 500)
} else {
common.SuccessResp(c)
}
}
func DeleteUser(c *gin.Context) {
idStr := c.Query("id")
id, err := strconv.Atoi(idStr)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
if err := db.DeleteUserById(uint(id)); err != nil {
common.ErrorResp(c, err, 500)
return
}
common.SuccessResp(c)
}