mirror of
https://github.com/AlistGo/alist.git
synced 2025-11-25 03:15:10 +08:00
* 标签管理 * pr检查优化 * feat(role): Implement role management functionality - Add role management routes in `server/router.go` for listing, getting, creating, updating, and deleting roles - Introduce `initRoles()` in `internal/bootstrap/data/data.go` for initializing roles during bootstrap - Create `internal/op/role.go` to handle role operations including caching and singleflight - Implement role handler functions in `server/handles/role.go` for API responses - Define database operations for roles in `internal/db/role.go` - Extend `internal/db/db.go` for role model auto-migration - Design `internal/model/role.go` to represent role structure with ID, name, description, base path, and permissions - Initialize default roles (`admin` and `guest`) in `internal/bootstrap/data/role.go` during startup * refactor(user roles): Support multiple roles for users - Change the `Role` field type from `int` to `[]int` in `drivers/alist_v3/types.go` and `drivers/quqi/types.go`. - Update the `Role` field in `internal/model/user.go` to use a new `Roles` type with JSON and database support. - Modify `IsGuest` and `IsAdmin` methods to check for roles using `Contains` method. - Update `GetUserByRole` method in `internal/db/user.go` to handle multiple roles. - Add `roles.go` to define a new `Roles` type with JSON marshalling and scanning capabilities. - Adjust code in `server/handles/user.go` to compare roles with `utils.SliceEqual`. - Change role initialization for users in `internal/bootstrap/data/dev.go` and `internal/bootstrap/data/user.go`. - Update `Role` handling in `server/handles/task.go`, `server/handles/ssologin.go`, and `server/handles/ldap_login.go`. * feat(user/role): Add path limit check for user and role permissions - Add new permission bit for checking path limits in `user.go` - Implement `CheckPathLimit` method in `User` struct to validate path access - Modify `JoinPath` method in `User` to enforce path limit checks - Update `role.go` to include path limit logic in `Role` struct - Document new permission bit in `Role` and `User` comments for clarity * feat(permission): Add role-based permission handling - Introduce `role_perm.go` for managing user permissions based on roles. - Implement `HasPermission` and `MergeRolePermissions` functions. - Update `webdav.go` to utilize role-based permissions instead of direct user checks. - Modify `fsup.go` to integrate `CanAccessWithRoles` function. - Refactor `fsread.go` to use `common.HasPermission` for permission validation. - Adjust `fsmanage.go` for role-based access control checks. - Enhance `ftp.go` and `sftp.go` to manage FTP access via roles. - Update `fsbatch.go` to employ `MergeRolePermissions` for batch operations. - Replace direct user permission checks with role-based permission handling across various modules. * refactor(user): Replace integer role values with role IDs - Change `GetAdmin()` and `GetGuest()` functions to retrieve role by name and use role ID. - Add patch for version `v3.45.2` to convert legacy integer roles to role IDs. - Update `dev.go` and `user.go` to use role IDs instead of integer values for roles. - Remove redundant code in `role.go` related to guest role creation. - Modify `ssologin.go` and `ldap_login.go` to set user roles to nil instead of using integer roles. - Introduce `convert_roles.go` to handle conversion of legacy roles and ensure role existence in the database. * feat(role_perm): implement support for multiple base paths for roles - Modify role permission checks to support multiple base paths - Update role creation and update functions to handle multiple base paths - Add migration script to convert old base_path to base_paths - Define new Paths type for handling multiple paths in the model - Adjust role model to replace BasePath with BasePaths - Update existing patches to handle roles with multiple base paths - Update bootstrap data to reflect the new base_paths field * feat(role): Restrict modifications to default roles (admin and guest) - Add validation to prevent changes to "admin" and "guest" roles in `UpdateRole` and `DeleteRole` functions. - Introduce `ErrChangeDefaultRole` error in `internal/errs/role.go` to standardize error messaging. - Update role-related API handlers in `server/handles/role.go` to enforce the new restriction. - Enhance comments in `internal/bootstrap/data/role.go` to clarify the significance of default roles. - Ensure consistent error responses for unauthorized role modifications across the application. * 🔄 **refactor(role): Enhance role permission handling** - Replaced `BasePaths` with `PermissionPaths` in `Role` struct for better permission granularity. - Introduced JSON serialization for `PermissionPaths` using `RawPermission` field in `Role` struct. - Implemented `BeforeSave` and `AfterFind` GORM hooks for handling `PermissionPaths` serialization. - Refactored permission calculation logic in `role_perm.go` to work with `PermissionPaths`. - Updated role creation logic to initialize `PermissionPaths` for `admin` and `guest` roles. - Removed deprecated `CheckPathLimit` method from `Role` struct. * fix(model/user/role): update permission settings for admin and role - Change `RawPermission` field in `role.go` to hide JSON representation - Update `Permission` field in `user.go` to `0xFFFF` for full access - Modify `PermissionScopes` in `role.go` to `0xFFFF` for enhanced permissions * 🔒 feat(role-permissions): Enhance role-based access control - Introduce `canReadPathByRole` function in `role_perm.go` to verify path access based on user roles - Modify `CanAccessWithRoles` to include role-based path read check - Add `RoleNames` and `Permissions` to `UserResp` struct in `auth.go` for enhanced user role and permission details - Implement role details aggregation in `auth.go` to populate `RoleNames` and `Permissions` - Update `User` struct in `user.go` to include `RolesDetail` for more detailed role information - Enhance middleware in `auth.go` to load and verify detailed role information for users - Move `guest` user initialization logic in `user.go` to improve code organization and avoid repetition * 🔒 fix(permissions): Add permission checks for archive operations - Add `MergeRolePermissions` and `HasPermission` checks to validate user access for reading archives - Ensure users have `PermReadArchives` before proceeding with `GetNearestMeta` in specific archive paths - Implement permission checks for decompress operations, requiring `PermDecompress` for source paths - Return `PermissionDenied` errors with 403 status if user lacks necessary permissions * 🔒 fix(server): Add permission check for offline download - Add permission merging logic for user roles - Check user has permission for offline download addition - Return error response with "permission denied" if check fails * ✨ feat(role-permission): Implement path-based role permission checks - Add `CheckPathLimitWithRoles` function to validate access based on `PermPathLimit` permission. - Integrate `CheckPathLimitWithRoles` in `offline_download` to enforce path-based access control. - Apply `CheckPathLimitWithRoles` across file system management operations (e.g., creation, movement, deletion). - Ensure `CheckPathLimitWithRoles` is invoked for batch operations and archive-related actions. - Update error handling to return `PermissionDenied` if the path validation fails. - Import `errs` package in `offline_download` for consistent error responses. * ✨ feat(role-permission): Implement path-based role permission checks - Add `CheckPathLimitWithRoles` function to validate access based on `PermPathLimit` permission. - Integrate `CheckPathLimitWithRoles` in `offline_download` to enforce path-based access control. - Apply `CheckPathLimitWithRoles` across file system management operations (e.g., creation, movement, deletion). - Ensure `CheckPathLimitWithRoles` is invoked for batch operations and archive-related actions. - Update error handling to return `PermissionDenied` if the path validation fails. - Import `errs` package in `offline_download` for consistent error responses. * ♻️ refactor(access-control): Update access control logic to use role-based checks - Remove deprecated logic from `CanAccess` function in `check.go`, replacing it with `CanAccessWithRoles` for improved role-based access control. - Modify calls in `search.go` to use `CanAccessWithRoles` for more precise handling of permissions. - Update `fsread.go` to utilize `CanAccessWithRoles`, ensuring accurate access validation based on user roles. - Simplify import statements in `check.go` by removing unused packages to clean up the codebase. * ✨ feat(fs): Improve visibility logic for hidden files - Import `server/common` package to handle permissions more robustly - Update `whetherHide` function to use `MergeRolePermissions` for user-specific path permissions - Replace direct user checks with `HasPermission` for `PermSeeHides` - Enhance logic to ensure `nil` user cases are handled explicitly * 标签管理 * feat(db/auth/user): Enhance role handling and clean permission paths - Comment out role modification checks in `server/handles/user.go` to allow flexible role changes. - Improve permission path handling in `server/handles/auth.go` by normalizing and deduplicating paths. - Introduce `addedPaths` map in `CurrentUser` to prevent duplicate permissions. * feat(storage/db): Implement role permissions path prefix update - Add `UpdateRolePermissionsPathPrefix` function in `role.go` to update role permissions paths. - Modify `storage.go` to call the new function when the mount path is renamed. - Introduce path cleaning and prefix matching logic for accurate path updates. - Ensure roles are updated only if their permission scopes are modified. - Handle potential errors with informative messages during database operations. * feat(role-migration): Implement role conversion and introduce NEWGENERAL role - Add `NEWGENERAL` to the roles enumeration in `user.go` - Create new file `convert_role.go` for migrating legacy roles to new model - Implement `ConvertLegacyRoles` function to handle role conversion with permission scopes - Add `convert_role.go` patch to `all.go` under version `v3.46.0` * feat(role/auth): Add role retrieval by user ID and update path prefixes - Add `GetRolesByUserID` function for efficient role retrieval by user ID - Implement `UpdateUserBasePathPrefix` to update user base paths - Modify `UpdateRolePermissionsPathPrefix` to return modified role IDs - Update `auth.go` middleware to use the new role retrieval function - Refresh role and user caches upon path prefix updates to maintain consistency --------- Co-authored-by: Leslie-Xy <540049476@qq.com>
427 lines
11 KiB
Go
427 lines
11 KiB
Go
package handles
|
|
|
|
import (
|
|
"fmt"
|
|
stdpath "path"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/alist-org/alist/v3/internal/conf"
|
|
"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/op"
|
|
"github.com/alist-org/alist/v3/internal/setting"
|
|
"github.com/alist-org/alist/v3/internal/sign"
|
|
"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 {
|
|
model.PageReq
|
|
Path string `json:"path" form:"path"`
|
|
Password string `json:"password" form:"password"`
|
|
Refresh bool `json:"refresh"`
|
|
}
|
|
|
|
type DirReq struct {
|
|
Path string `json:"path" form:"path"`
|
|
Password string `json:"password" form:"password"`
|
|
ForceRoot bool `json:"force_root" form:"force_root"`
|
|
}
|
|
|
|
type ObjResp struct {
|
|
Id string `json:"id"`
|
|
Path string `json:"path"`
|
|
Name string `json:"name"`
|
|
Size int64 `json:"size"`
|
|
IsDir bool `json:"is_dir"`
|
|
Modified time.Time `json:"modified"`
|
|
Created time.Time `json:"created"`
|
|
Sign string `json:"sign"`
|
|
Thumb string `json:"thumb"`
|
|
Type int `json:"type"`
|
|
HashInfoStr string `json:"hashinfo"`
|
|
HashInfo map[*utils.HashType]string `json:"hash_info"`
|
|
}
|
|
|
|
type FsListResp struct {
|
|
Content []ObjLabelResp `json:"content"`
|
|
Total int64 `json:"total"`
|
|
Readme string `json:"readme"`
|
|
Header string `json:"header"`
|
|
Write bool `json:"write"`
|
|
Provider string `json:"provider"`
|
|
}
|
|
|
|
type ObjLabelResp struct {
|
|
Id string `json:"id"`
|
|
Path string `json:"path"`
|
|
Name string `json:"name"`
|
|
Size int64 `json:"size"`
|
|
IsDir bool `json:"is_dir"`
|
|
Modified time.Time `json:"modified"`
|
|
Created time.Time `json:"created"`
|
|
Sign string `json:"sign"`
|
|
Thumb string `json:"thumb"`
|
|
Type int `json:"type"`
|
|
HashInfoStr string `json:"hashinfo"`
|
|
HashInfo map[*utils.HashType]string `json:"hash_info"`
|
|
LabelList []model.Label `json:"label_list"`
|
|
}
|
|
|
|
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)
|
|
reqPath, err := user.JoinPath(req.Path)
|
|
if err != nil {
|
|
common.ErrorResp(c, err, 403)
|
|
return
|
|
}
|
|
meta, err := op.GetNearestMeta(reqPath)
|
|
if err != nil {
|
|
if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
|
|
common.ErrorResp(c, err, 500, true)
|
|
return
|
|
}
|
|
}
|
|
c.Set("meta", meta)
|
|
if !common.CanAccessWithRoles(user, meta, reqPath, req.Password) {
|
|
common.ErrorStrResp(c, "password is incorrect or you have no permission", 403)
|
|
return
|
|
}
|
|
perm := common.MergeRolePermissions(user, reqPath)
|
|
if !common.HasPermission(perm, common.PermWrite) && !common.CanWrite(meta, reqPath) && req.Refresh {
|
|
common.ErrorStrResp(c, "Refresh without permission", 403)
|
|
return
|
|
}
|
|
objs, err := fs.List(c, reqPath, &fs.ListArgs{Refresh: req.Refresh})
|
|
if err != nil {
|
|
common.ErrorResp(c, err, 500)
|
|
return
|
|
}
|
|
total, objs := pagination(objs, &req.PageReq)
|
|
provider := "unknown"
|
|
storage, err := fs.GetStorage(reqPath, &fs.GetStoragesArgs{})
|
|
if err == nil {
|
|
provider = storage.GetStorage().Driver
|
|
}
|
|
common.SuccessResp(c, FsListResp{
|
|
Content: toObjsResp(objs, reqPath, isEncrypt(meta, reqPath), user.ID),
|
|
Total: int64(total),
|
|
Readme: getReadme(meta, reqPath),
|
|
Header: getHeader(meta, reqPath),
|
|
Write: common.HasPermission(perm, common.PermWrite) || common.CanWrite(meta, reqPath),
|
|
Provider: provider,
|
|
})
|
|
}
|
|
|
|
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)
|
|
reqPath := req.Path
|
|
if req.ForceRoot {
|
|
if !user.IsAdmin() {
|
|
common.ErrorStrResp(c, "Permission denied", 403)
|
|
return
|
|
}
|
|
} else {
|
|
tmp, err := user.JoinPath(req.Path)
|
|
if err != nil {
|
|
common.ErrorResp(c, err, 403)
|
|
return
|
|
}
|
|
reqPath = tmp
|
|
}
|
|
meta, err := op.GetNearestMeta(reqPath)
|
|
if err != nil {
|
|
if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
|
|
common.ErrorResp(c, err, 500, true)
|
|
return
|
|
}
|
|
}
|
|
c.Set("meta", meta)
|
|
if !common.CanAccessWithRoles(user, meta, reqPath, req.Password) {
|
|
common.ErrorStrResp(c, "password is incorrect or you have no permission", 403)
|
|
return
|
|
}
|
|
objs, err := fs.List(c, reqPath, &fs.ListArgs{})
|
|
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 getHeader(meta *model.Meta, path string) string {
|
|
if meta != nil && (utils.PathEqual(meta.Path, path) || meta.HeaderSub) {
|
|
return meta.Header
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func isEncrypt(meta *model.Meta, path string) bool {
|
|
if common.IsStorageSignEnabled(path) {
|
|
return true
|
|
}
|
|
if meta == nil || meta.Password == "" {
|
|
return false
|
|
}
|
|
if !utils.PathEqual(meta.Path, path) && !meta.PSub {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func pagination(objs []model.Obj, req *model.PageReq) (int, []model.Obj) {
|
|
pageIndex, pageSize := req.Page, req.PerPage
|
|
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 toObjsResp(objs []model.Obj, parent string, encrypt bool, userId uint) []ObjLabelResp {
|
|
var resp []ObjLabelResp
|
|
for _, obj := range objs {
|
|
var labels []model.Label
|
|
if obj.IsDir() == false {
|
|
labels, _ = op.GetLabelByFileName(userId, obj.GetName())
|
|
}
|
|
thumb, _ := model.GetThumb(obj)
|
|
resp = append(resp, ObjLabelResp{
|
|
Id: obj.GetID(),
|
|
Path: obj.GetPath(),
|
|
Name: obj.GetName(),
|
|
Size: obj.GetSize(),
|
|
IsDir: obj.IsDir(),
|
|
Modified: obj.ModTime(),
|
|
Created: obj.CreateTime(),
|
|
HashInfoStr: obj.GetHash().String(),
|
|
HashInfo: obj.GetHash().Export(),
|
|
Sign: common.Sign(obj, parent, encrypt),
|
|
Thumb: thumb,
|
|
Type: utils.GetObjType(obj.GetName(), obj.IsDir()),
|
|
LabelList: labels,
|
|
})
|
|
}
|
|
return resp
|
|
}
|
|
|
|
type FsGetReq struct {
|
|
Path string `json:"path" form:"path"`
|
|
Password string `json:"password" form:"password"`
|
|
}
|
|
|
|
type FsGetResp struct {
|
|
ObjResp
|
|
RawURL string `json:"raw_url"`
|
|
Readme string `json:"readme"`
|
|
Header string `json:"header"`
|
|
Provider string `json:"provider"`
|
|
Related []ObjLabelResp `json:"related"`
|
|
}
|
|
|
|
func FsGet(c *gin.Context) {
|
|
var req FsGetReq
|
|
if err := c.ShouldBind(&req); err != nil {
|
|
common.ErrorResp(c, err, 400)
|
|
return
|
|
}
|
|
user := c.MustGet("user").(*model.User)
|
|
reqPath, err := user.JoinPath(req.Path)
|
|
if err != nil {
|
|
common.ErrorResp(c, err, 403)
|
|
return
|
|
}
|
|
meta, err := op.GetNearestMeta(reqPath)
|
|
if err != nil {
|
|
if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
|
|
common.ErrorResp(c, err, 500)
|
|
return
|
|
}
|
|
}
|
|
c.Set("meta", meta)
|
|
if !common.CanAccessWithRoles(user, meta, reqPath, req.Password) {
|
|
common.ErrorStrResp(c, "password is incorrect or you have no permission", 403)
|
|
return
|
|
}
|
|
obj, err := fs.Get(c, reqPath, &fs.GetArgs{})
|
|
if err != nil {
|
|
common.ErrorResp(c, err, 500)
|
|
return
|
|
}
|
|
var rawURL string
|
|
|
|
storage, err := fs.GetStorage(reqPath, &fs.GetStoragesArgs{})
|
|
provider := "unknown"
|
|
if err == nil {
|
|
provider = storage.Config().Name
|
|
}
|
|
if !obj.IsDir() {
|
|
if err != nil {
|
|
common.ErrorResp(c, err, 500)
|
|
return
|
|
}
|
|
if storage.Config().MustProxy() || storage.GetStorage().WebProxy {
|
|
query := ""
|
|
if isEncrypt(meta, reqPath) || setting.GetBool(conf.SignAll) {
|
|
query = "?sign=" + sign.Sign(reqPath)
|
|
}
|
|
if storage.GetStorage().DownProxyUrl != "" {
|
|
rawURL = fmt.Sprintf("%s%s?sign=%s",
|
|
strings.Split(storage.GetStorage().DownProxyUrl, "\n")[0],
|
|
utils.EncodePath(reqPath, true),
|
|
sign.Sign(reqPath))
|
|
} else {
|
|
rawURL = fmt.Sprintf("%s/p%s%s",
|
|
common.GetApiUrl(c.Request),
|
|
utils.EncodePath(reqPath, true),
|
|
query)
|
|
}
|
|
} else {
|
|
// file have raw url
|
|
if url, ok := model.GetUrl(obj); ok {
|
|
rawURL = url
|
|
} else {
|
|
// if storage is not proxy, use raw url by fs.Link
|
|
link, _, err := fs.Link(c, reqPath, model.LinkArgs{
|
|
IP: c.ClientIP(),
|
|
Header: c.Request.Header,
|
|
HttpReq: c.Request,
|
|
Redirect: true,
|
|
})
|
|
if err != nil {
|
|
common.ErrorResp(c, err, 500)
|
|
return
|
|
}
|
|
rawURL = link.URL
|
|
}
|
|
}
|
|
}
|
|
var related []model.Obj
|
|
parentPath := stdpath.Dir(reqPath)
|
|
sameLevelFiles, err := fs.List(c, parentPath, &fs.ListArgs{})
|
|
if err == nil {
|
|
related = filterRelated(sameLevelFiles, obj)
|
|
}
|
|
parentMeta, _ := op.GetNearestMeta(parentPath)
|
|
thumb, _ := model.GetThumb(obj)
|
|
common.SuccessResp(c, FsGetResp{
|
|
ObjResp: ObjResp{
|
|
Id: obj.GetID(),
|
|
Path: obj.GetPath(),
|
|
Name: obj.GetName(),
|
|
Size: obj.GetSize(),
|
|
IsDir: obj.IsDir(),
|
|
Modified: obj.ModTime(),
|
|
Created: obj.CreateTime(),
|
|
HashInfoStr: obj.GetHash().String(),
|
|
HashInfo: obj.GetHash().Export(),
|
|
Sign: common.Sign(obj, parentPath, isEncrypt(meta, reqPath)),
|
|
Type: utils.GetFileType(obj.GetName()),
|
|
Thumb: thumb,
|
|
},
|
|
RawURL: rawURL,
|
|
Readme: getReadme(meta, reqPath),
|
|
Header: getHeader(meta, reqPath),
|
|
Provider: provider,
|
|
Related: toObjsResp(related, parentPath, isEncrypt(parentMeta, parentPath), user.ID),
|
|
})
|
|
}
|
|
|
|
func filterRelated(objs []model.Obj, obj model.Obj) []model.Obj {
|
|
var related []model.Obj
|
|
nameWithoutExt := strings.TrimSuffix(obj.GetName(), stdpath.Ext(obj.GetName()))
|
|
for _, o := range objs {
|
|
if o.GetName() == obj.GetName() {
|
|
continue
|
|
}
|
|
if strings.HasPrefix(o.GetName(), nameWithoutExt) {
|
|
related = append(related, o)
|
|
}
|
|
}
|
|
return related
|
|
}
|
|
|
|
type FsOtherReq struct {
|
|
model.FsOtherArgs
|
|
Password string `json:"password" form:"password"`
|
|
}
|
|
|
|
func FsOther(c *gin.Context) {
|
|
var req FsOtherReq
|
|
if err := c.ShouldBind(&req); err != nil {
|
|
common.ErrorResp(c, err, 400)
|
|
return
|
|
}
|
|
user := c.MustGet("user").(*model.User)
|
|
var err error
|
|
req.Path, err = user.JoinPath(req.Path)
|
|
if err != nil {
|
|
common.ErrorResp(c, err, 403)
|
|
return
|
|
}
|
|
meta, err := op.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 !common.CanAccessWithRoles(user, meta, req.Path, req.Password) {
|
|
common.ErrorStrResp(c, "password is incorrect or you have no permission", 403)
|
|
return
|
|
}
|
|
res, err := fs.Other(c, req.FsOtherArgs)
|
|
if err != nil {
|
|
common.ErrorResp(c, err, 500)
|
|
return
|
|
}
|
|
common.SuccessResp(c, res)
|
|
}
|