mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-24 14:38:23 +08:00
feat: 文件管理增加用户/用户组设置 (#803)
This commit is contained in:
parent
db2aa35b2f
commit
7887bf96de
19 changed files with 701 additions and 14 deletions
|
|
@ -186,7 +186,29 @@ func (b *BaseApi) ChangeFileMode(c *gin.Context) {
|
|||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Change file owner
|
||||
// @Description 修改文件用户/组
|
||||
// @Accept json
|
||||
// @Param request body request.FileRoleUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/owner [post]
|
||||
// @x-panel-log {"bodyKeys":["path","user","group"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改用户/组 [paths] => [user]/[group]","formatEN":"Change owner [paths] => [user]/[group]"}
|
||||
func (b *BaseApi) ChangeFileOwner(c *gin.Context) {
|
||||
var req request.FileRoleUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := fileService.ChangeOwner(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ func (b *BaseApi) UpdatePassword(c *gin.Context) {
|
|||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/ssl/update [post]
|
||||
// @x-panel-log {"bodyKeys":[ssl],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统 ssl => [ssl]","formatEN":"update system ssl => [ssl]"}
|
||||
// @x-panel-log {"bodyKeys":["ssl"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统 ssl => [ssl]","formatEN":"update system ssl => [ssl]"}
|
||||
func (b *BaseApi) UpdateSSL(c *gin.Context) {
|
||||
var req dto.SSLUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
|
|
|
|||
|
|
@ -88,3 +88,10 @@ type DirSizeReq struct {
|
|||
type FileProcessReq struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type FileRoleUpdate struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
User string `json:"user" validate:"required"`
|
||||
Group string `json:"group" validate:"required"`
|
||||
Sub bool `json:"sub" validate:"required"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ type IFileService interface {
|
|||
ChangeName(req request.FileRename) error
|
||||
Wget(w request.FileWget) (string, error)
|
||||
MvFile(m request.FileMove) error
|
||||
ChangeOwner(req request.FileRoleUpdate) error
|
||||
}
|
||||
|
||||
func NewIFileService() IFileService {
|
||||
|
|
@ -162,6 +163,11 @@ func (f *FileService) ChangeMode(op request.FileCreate) error {
|
|||
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
||||
}
|
||||
|
||||
func (f *FileService) ChangeOwner(req request.FileRoleUpdate) error {
|
||||
fo := files.NewFileOp()
|
||||
return fo.ChownR(req.Path, req.User, req.Group, req.Sub)
|
||||
}
|
||||
|
||||
func (f *FileService) Compress(c request.FileCompress) error {
|
||||
fo := files.NewFileOp()
|
||||
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
|
|||
fileRouter.POST("/del", baseApi.DeleteFile)
|
||||
fileRouter.POST("/batch/del", baseApi.BatchDeleteFile)
|
||||
fileRouter.POST("/mode", baseApi.ChangeFileMode)
|
||||
fileRouter.POST("/owner", baseApi.ChangeFileOwner)
|
||||
fileRouter.POST("/compress", baseApi.CompressFile)
|
||||
fileRouter.POST("/decompress", baseApi.DeCompressFile)
|
||||
fileRouter.POST("/content", baseApi.GetContent)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
|
@ -106,7 +107,7 @@ func (f FileOp) SaveFile(dst string, content string, mode fs.FileMode) error {
|
|||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(string(content))
|
||||
_, _ = write.WriteString(content)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
|
@ -119,6 +120,34 @@ func (f FileOp) Chown(dst string, uid int, gid int) error {
|
|||
return f.Fs.Chown(dst, uid, gid)
|
||||
}
|
||||
|
||||
func (f FileOp) ChownR(dst string, uid string, gid string, sub bool) error {
|
||||
cmdStr := fmt.Sprintf("sudo chown %s:%s %s", uid, gid, dst)
|
||||
if sub {
|
||||
cmdStr = fmt.Sprintf("sudo chown -R %s:%s %s", uid, gid, dst)
|
||||
}
|
||||
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
|
||||
if msg != "" {
|
||||
return errors.New(msg)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f FileOp) ChmodR(dst string, mode fs.FileMode) error {
|
||||
cmdStr := fmt.Sprintf("chmod -R %v %s", mode, dst)
|
||||
if cmd.HasNoPasswordSudo() {
|
||||
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
|
||||
}
|
||||
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
|
||||
if msg != "" {
|
||||
return errors.New(msg)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f FileOp) Rename(oldName string, newName string) error {
|
||||
return f.Fs.Rename(oldName, newName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
|
|
@ -73,6 +74,8 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
|
|||
Extension: filepath.Ext(info.Name()),
|
||||
IsHidden: IsHidden(op.Path),
|
||||
Mode: fmt.Sprintf("%04o", info.Mode().Perm()),
|
||||
User: GetUsername(info.Sys().(*syscall.Stat_t).Uid),
|
||||
Group: GetGroup(info.Sys().(*syscall.Stat_t).Gid),
|
||||
MimeType: GetMimeType(op.Path),
|
||||
}
|
||||
if file.IsSymlink {
|
||||
|
|
@ -202,6 +205,8 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
|
|||
Path: fPath,
|
||||
Mode: fmt.Sprintf("%04o", df.Mode().Perm()),
|
||||
MimeType: GetMimeType(fPath),
|
||||
User: GetUsername(df.Sys().(*syscall.Stat_t).Uid),
|
||||
Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid),
|
||||
}
|
||||
|
||||
if isSymlink {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import (
|
|||
"github.com/gabriel-vasile/mimetype"
|
||||
"github.com/spf13/afero"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
|
|
@ -28,6 +30,22 @@ func GetSymlink(path string) string {
|
|||
return linkPath
|
||||
}
|
||||
|
||||
func GetUsername(uid uint32) string {
|
||||
usr, err := user.LookupId(strconv.Itoa(int(uid)))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return usr.Username
|
||||
}
|
||||
|
||||
func GetGroup(gid uint32) string {
|
||||
usr, err := user.LookupGroupId(strconv.Itoa(int(gid)))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return usr.Name
|
||||
}
|
||||
|
||||
func ScanDir(fs afero.Fs, path string, dirMap *sync.Map, wg *sync.WaitGroup) {
|
||||
afs := &afero.Afero{Fs: fs}
|
||||
files, _ := afs.ReadDir(path)
|
||||
|
|
|
|||
|
|
@ -4529,6 +4529,50 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/files/owner": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改文件用户/组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Change file owner",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.FileRoleUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path",
|
||||
"user",
|
||||
"group"
|
||||
],
|
||||
"formatEN": "Change owner [paths] =\u003e [user]/[group]",
|
||||
"formatZH": "修改用户/组 [paths] =\u003e [user]/[group]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/rename": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
|
@ -7431,6 +7475,70 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/settings/ssl/info": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取证书信息",
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Load system cert info",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SettingInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/ssl/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统 ssl 登录",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Update system ssl",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SSLUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"ssl"
|
||||
],
|
||||
"formatEN": "update system ssl =\u003e [ssl]",
|
||||
"formatZH": "修改系统 ssl =\u003e [ssl]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/time/sync": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
|
@ -11440,10 +11548,16 @@ const docTemplate = `{
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"containerPort": {
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"hostIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostPort": {
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -11669,6 +11783,36 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.SSLUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ssl"
|
||||
],
|
||||
"properties": {
|
||||
"cert": {
|
||||
"type": "string"
|
||||
},
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"enable",
|
||||
"disable"
|
||||
]
|
||||
},
|
||||
"sslID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sslType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SearchForTree": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -11851,6 +11995,12 @@ const docTemplate = `{
|
|||
"sessionTimeout": {
|
||||
"type": "string"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "string"
|
||||
},
|
||||
"sslType": {
|
||||
"type": "string"
|
||||
},
|
||||
"systemVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -12796,6 +12946,29 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"request.FileRoleUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"path",
|
||||
"sub",
|
||||
"user"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"sub": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FileWget": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -4522,6 +4522,50 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/files/owner": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改文件用户/组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Change file owner",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.FileRoleUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path",
|
||||
"user",
|
||||
"group"
|
||||
],
|
||||
"formatEN": "Change owner [paths] =\u003e [user]/[group]",
|
||||
"formatZH": "修改用户/组 [paths] =\u003e [user]/[group]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/rename": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
|
@ -7424,6 +7468,70 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/settings/ssl/info": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取证书信息",
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Load system cert info",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SettingInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/ssl/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统 ssl 登录",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Update system ssl",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SSLUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"ssl"
|
||||
],
|
||||
"formatEN": "update system ssl =\u003e [ssl]",
|
||||
"formatZH": "修改系统 ssl =\u003e [ssl]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/time/sync": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
|
@ -11433,10 +11541,16 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"containerPort": {
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"hostIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostPort": {
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -11662,6 +11776,36 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.SSLUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ssl"
|
||||
],
|
||||
"properties": {
|
||||
"cert": {
|
||||
"type": "string"
|
||||
},
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"enable",
|
||||
"disable"
|
||||
]
|
||||
},
|
||||
"sslID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sslType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SearchForTree": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -11844,6 +11988,12 @@
|
|||
"sessionTimeout": {
|
||||
"type": "string"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "string"
|
||||
},
|
||||
"sslType": {
|
||||
"type": "string"
|
||||
},
|
||||
"systemVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -12789,6 +12939,29 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"request.FileRoleUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"path",
|
||||
"sub",
|
||||
"user"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"sub": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FileWget": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -1201,9 +1201,13 @@ definitions:
|
|||
dto.PortHelper:
|
||||
properties:
|
||||
containerPort:
|
||||
type: integer
|
||||
type: string
|
||||
hostIP:
|
||||
type: string
|
||||
hostPort:
|
||||
type: integer
|
||||
type: string
|
||||
protocol:
|
||||
type: string
|
||||
type: object
|
||||
dto.PortRuleOperate:
|
||||
properties:
|
||||
|
|
@ -1354,6 +1358,26 @@ definitions:
|
|||
used_memory_rss:
|
||||
type: string
|
||||
type: object
|
||||
dto.SSLUpdate:
|
||||
properties:
|
||||
cert:
|
||||
type: string
|
||||
domain:
|
||||
type: string
|
||||
key:
|
||||
type: string
|
||||
ssl:
|
||||
enum:
|
||||
- enable
|
||||
- disable
|
||||
type: string
|
||||
sslID:
|
||||
type: integer
|
||||
sslType:
|
||||
type: string
|
||||
required:
|
||||
- ssl
|
||||
type: object
|
||||
dto.SearchForTree:
|
||||
properties:
|
||||
info:
|
||||
|
|
@ -1475,6 +1499,10 @@ definitions:
|
|||
type: string
|
||||
sessionTimeout:
|
||||
type: string
|
||||
ssl:
|
||||
type: string
|
||||
sslType:
|
||||
type: string
|
||||
systemVersion:
|
||||
type: string
|
||||
theme:
|
||||
|
|
@ -2101,6 +2129,22 @@ definitions:
|
|||
- newName
|
||||
- oldName
|
||||
type: object
|
||||
request.FileRoleUpdate:
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
sub:
|
||||
type: boolean
|
||||
user:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- path
|
||||
- sub
|
||||
- user
|
||||
type: object
|
||||
request.FileWget:
|
||||
properties:
|
||||
name:
|
||||
|
|
@ -5899,6 +5943,35 @@ paths:
|
|||
formatEN: Move [oldPaths] => [newPath]
|
||||
formatZH: 移动文件 [oldPaths] => [newPath]
|
||||
paramKeys: []
|
||||
/files/owner:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改文件用户/组
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.FileRoleUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Change file owner
|
||||
tags:
|
||||
- File
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- path
|
||||
- user
|
||||
- group
|
||||
formatEN: Change owner [paths] => [user]/[group]
|
||||
formatZH: 修改用户/组 [paths] => [user]/[group]
|
||||
paramKeys: []
|
||||
/files/rename:
|
||||
post:
|
||||
consumes:
|
||||
|
|
@ -7742,6 +7815,46 @@ paths:
|
|||
summary: Page system snapshot
|
||||
tags:
|
||||
- System Setting
|
||||
/settings/ssl/info:
|
||||
get:
|
||||
description: 获取证书信息
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SettingInfo'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Load system cert info
|
||||
tags:
|
||||
- System Setting
|
||||
/settings/ssl/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改系统 ssl 登录
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SSLUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update system ssl
|
||||
tags:
|
||||
- System Setting
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- ssl
|
||||
formatEN: update system ssl => [ssl]
|
||||
formatZH: 修改系统 ssl => [ssl]
|
||||
paramKeys: []
|
||||
/settings/time/sync:
|
||||
post:
|
||||
description: 系统时间同步
|
||||
|
|
|
|||
2
frontend/package-lock.json
generated
2
frontend/package-lock.json
generated
|
|
@ -17,7 +17,7 @@
|
|||
"axios": "^0.27.2",
|
||||
"echarts": "^5.3.0",
|
||||
"echarts-liquidfill": "^3.1.0",
|
||||
"element-plus": "^2.2.32",
|
||||
"element-plus": "^2.3.4",
|
||||
"fit2cloud-ui-plus": "^1.0.7",
|
||||
"js-base64": "^3.7.2",
|
||||
"js-md5": "^0.7.3",
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
"axios": "^0.27.2",
|
||||
"echarts": "^5.3.0",
|
||||
"echarts-liquidfill": "^3.1.0",
|
||||
"element-plus": "^2.2.32",
|
||||
"element-plus": "^2.3.4",
|
||||
"fit2cloud-ui-plus": "^1.0.7",
|
||||
"js-base64": "^3.7.2",
|
||||
"js-md5": "^0.7.3",
|
||||
|
|
|
|||
|
|
@ -90,6 +90,13 @@ export namespace File {
|
|||
newName: string;
|
||||
}
|
||||
|
||||
export interface FileOwner {
|
||||
path: string;
|
||||
user: string;
|
||||
group: string;
|
||||
sub: boolean;
|
||||
}
|
||||
|
||||
export interface FileWget {
|
||||
path: string;
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ export const RenameRile = (params: File.FileRename) => {
|
|||
return http.post<File.File>('files/rename', params);
|
||||
};
|
||||
|
||||
export const ChangeOwner = (params: File.FileOwner) => {
|
||||
return http.post<File.File>('files/owner', params);
|
||||
};
|
||||
|
||||
export const WgetFile = (params: File.FileWget) => {
|
||||
return http.post<File.FileWgetRes>('files/wget', params);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -800,6 +800,10 @@ const message = {
|
|||
copyDir: 'Copy Dir',
|
||||
paste: 'Paste',
|
||||
cancel: 'Cancel',
|
||||
changeOwner: 'Modify user and user group',
|
||||
containSub: 'Modify sub-file attributes at the same time',
|
||||
ownerHelper:
|
||||
'The default user of the PHP operating environment: the user group is 1000:1000, it is normal that the users inside and outside the container show inconsistencies',
|
||||
},
|
||||
setting: {
|
||||
all: 'All',
|
||||
|
|
|
|||
|
|
@ -807,6 +807,9 @@ const message = {
|
|||
copyDir: '复制路径',
|
||||
paste: '粘贴',
|
||||
cancel: '取消',
|
||||
changeOwner: '修改用户和用户组',
|
||||
containSub: '同时修改子文件属性',
|
||||
ownerHelper: 'PHP 运行环境默认用户:用户组为 1000:1000, 容器内外用户显示不一致为正常现象',
|
||||
},
|
||||
setting: {
|
||||
all: '全部',
|
||||
|
|
|
|||
108
frontend/src/views/host/file-management/chown/index.vue
Normal file
108
frontend/src/views/host/file-management/chown/index.vue
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<el-drawer v-model="open" size="40%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('file.changeOwner')" :back="handleClose" />
|
||||
</template>
|
||||
<el-row>
|
||||
<el-col :span="22" :offset="1">
|
||||
<el-form
|
||||
ref="fileForm"
|
||||
label-position="top"
|
||||
:model="addForm"
|
||||
label-width="100px"
|
||||
:rules="rules"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-form-item :label="$t('file.user')" prop="user">
|
||||
<el-input v-model.trim="addForm.user" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('file.group')" prop="group">
|
||||
<el-input v-model.trim="addForm.group" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="isDir">
|
||||
<el-checkbox v-model="addForm.sub">{{ $t('file.containSub') }}</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-alert :title="$t('file.ownerHelper')" type="info" :closable="false" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit(fileForm)">{{ $t('commons.button.confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ChangeOwner } from '@/api/modules/files';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { FormInstance, FormRules } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
interface OwnerProps {
|
||||
path: string;
|
||||
user: string;
|
||||
group: string;
|
||||
isDir: boolean;
|
||||
}
|
||||
|
||||
const fileForm = ref<FormInstance>();
|
||||
const loading = ref(false);
|
||||
const open = ref(false);
|
||||
const isDir = ref(false);
|
||||
|
||||
const addForm = reactive({
|
||||
path: '',
|
||||
user: '',
|
||||
group: '',
|
||||
sub: false,
|
||||
});
|
||||
|
||||
const rules = reactive<FormRules>({
|
||||
user: [Rules.requiredInput],
|
||||
group: [Rules.requiredInput],
|
||||
});
|
||||
|
||||
const em = defineEmits(['close']);
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
if (fileForm.value) {
|
||||
fileForm.value.resetFields();
|
||||
}
|
||||
em('close', false);
|
||||
};
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
ChangeOwner(addForm)
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||
handleClose();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const acceptParams = (props: OwnerProps) => {
|
||||
addForm.user = props.user;
|
||||
addForm.path = props.path;
|
||||
addForm.group = props.group;
|
||||
isDir.value = props.isDir;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
defineExpose({ acceptParams });
|
||||
</script>
|
||||
|
|
@ -123,8 +123,16 @@
|
|||
<el-link :underline="false" @click="openMode(row)" type="primary">{{ row.mode }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column :label="$t('file.user')" prop="user" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('file.group')" prop="group"></el-table-column> -->
|
||||
<el-table-column :label="$t('file.user')" prop="user" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-link :underline="false" @click="openChown(row)" type="primary">{{ row.user }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('file.group')" prop="group">
|
||||
<template #default="{ row }">
|
||||
<el-link :underline="false" @click="openChown(row)" type="primary">{{ row.group }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('file.size')" prop="size" max-width="50">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.isDir">
|
||||
|
|
@ -167,6 +175,7 @@
|
|||
<Move ref="moveRef" @close="closeMovePage" />
|
||||
<Download ref="downloadRef" @close="search" />
|
||||
<Process :open="processPage.open" @close="closeProcess" />
|
||||
<Owner ref="chownRef" @close="search"></Owner>
|
||||
<!-- <Detail ref="detailRef" /> -->
|
||||
</LayoutContent>
|
||||
</div>
|
||||
|
|
@ -191,6 +200,7 @@ import CodeEditor from './code-editor/index.vue';
|
|||
import Wget from './wget/index.vue';
|
||||
import Move from './move/index.vue';
|
||||
import Download from './download/index.vue';
|
||||
import Owner from './chown/index.vue';
|
||||
import { Mimetypes, Languages } from '@/global/mimetype';
|
||||
import Process from './process/index.vue';
|
||||
// import Detail from './detail/index.vue';
|
||||
|
|
@ -251,7 +261,7 @@ const moveRef = ref();
|
|||
const downloadRef = ref();
|
||||
const pathRef = ref();
|
||||
const breadCrumbRef = ref();
|
||||
|
||||
const chownRef = ref();
|
||||
const moveOpen = ref(false);
|
||||
|
||||
// editablePath
|
||||
|
|
@ -443,6 +453,10 @@ const openMode = (item: File.File) => {
|
|||
roleRef.value.acceptParams(item);
|
||||
};
|
||||
|
||||
const openChown = (item: File.File) => {
|
||||
chownRef.value.acceptParams(item);
|
||||
};
|
||||
|
||||
const openCompress = (items: File.File[]) => {
|
||||
const paths = [];
|
||||
for (const item of items) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue