feat: 添加操作日志拦截中间件

This commit is contained in:
ssongliu 2022-12-13 18:54:28 +08:00 committed by ssongliu
parent 5272d44558
commit 2a0f2dcd6a
59 changed files with 1162 additions and 437 deletions

View File

@ -127,17 +127,12 @@ func (b *BaseApi) UpdateBackup(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
upMap := make(map[string]interface{})
upMap["bucket"] = req.Bucket
upMap["credential"] = req.Credential
upMap["vars"] = req.Vars
if err := backupService.Update(id, upMap); err != nil {
if err := backupService.Update(req.ID, upMap); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@ -82,16 +82,11 @@ func (b *BaseApi) UpdateCommand(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
upMap := make(map[string]interface{})
upMap["name"] = req.Name
upMap["command"] = req.Command
if err := commandService.Update(id, upMap); err != nil {
if err := commandService.Update(req.ID, upMap); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@ -82,16 +82,11 @@ func (b *BaseApi) UpdateComposeTemplate(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
upMap := make(map[string]interface{})
upMap["content"] = req.Content
upMap["description"] = req.Description
if err := composeTemplateService.Update(id, upMap); err != nil {
if err := composeTemplateService.Update(req.ID, upMap); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@ -97,13 +97,8 @@ func (b *BaseApi) UpdateCronjob(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := cronjobService.Update(id, req); err != nil {
if err := cronjobService.Update(req.ID, req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
@ -148,12 +143,17 @@ func (b *BaseApi) TargetDownload(c *gin.Context) {
}
func (b *BaseApi) HandleOnce(c *gin.Context) {
id, err := helper.GetParamID(c)
if err != nil {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := cronjobService.HandleOnce(id); err != nil {
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := cronjobService.HandleOnce(req.ID); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@ -79,6 +79,10 @@ func (b *BaseApi) UpdateMysqlConfByFile(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := mysqlService.UpdateConfByFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@ -123,6 +127,10 @@ func (b *BaseApi) BackupMysql(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := mysqlService.Backup(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@ -138,6 +146,10 @@ func (b *BaseApi) RecoverMysqlByUpload(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := mysqlService.RecoverByUpload(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@ -153,6 +165,10 @@ func (b *BaseApi) RecoverMysql(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := mysqlService.Recover(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@ -163,13 +179,17 @@ func (b *BaseApi) RecoverMysql(c *gin.Context) {
}
func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
apps, err := mysqlService.DeleteCheck(id)
apps, err := mysqlService.DeleteCheck(req.ID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@ -178,13 +198,17 @@ func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
}
func (b *BaseApi) DeleteMysql(c *gin.Context) {
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := mysqlService.Delete(id); err != nil {
if err := mysqlService.Delete(req.ID); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@ -26,13 +26,17 @@ func (b *BaseApi) CreateGroup(c *gin.Context) {
}
func (b *BaseApi) DeleteGroup(c *gin.Context) {
id, err := helper.GetParamID(c)
if err != nil {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := groupService.Delete(id); err != nil {
if err := groupService.Delete(req.ID); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
@ -49,13 +53,8 @@ func (b *BaseApi) UpdateGroup(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := groupService.Update(id, req.Name); err != nil {
if err := groupService.Update(req.ID, req.Name); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@ -90,13 +90,17 @@ func (b *BaseApi) GetHostInfo(c *gin.Context) {
}
func (b *BaseApi) DeleteHost(c *gin.Context) {
id, err := helper.GetParamID(c)
if err != nil {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := hostService.Delete(id); err != nil {
if err := hostService.Delete(req.ID); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
@ -113,11 +117,6 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
upMap := make(map[string]interface{})
upMap["name"] = req.Name
@ -128,7 +127,7 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
upMap["auth_mode"] = req.AuthMode
upMap["password"] = req.Password
upMap["private_key"] = req.PrivateKey
if err := hostService.Update(id, upMap); err != nil {
if err := hostService.Update(req.ID, upMap); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@ -86,11 +86,6 @@ func (b *BaseApi) UpdateRepo(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
upMap := make(map[string]interface{})
upMap["download_url"] = req.DownloadUrl
@ -98,7 +93,7 @@ func (b *BaseApi) UpdateRepo(c *gin.Context) {
upMap["username"] = req.Username
upMap["password"] = req.Password
upMap["auth"] = req.Auth
if err := imageRepoService.Update(id, upMap); err != nil {
if err := imageRepoService.Update(req.ID, upMap); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@ -3,6 +3,7 @@ package dto
import "time"
type BackupOperate struct {
ID uint `json:"id"`
Type string `json:"type" validate:"required"`
Bucket string `json:"bucket"`
Credential string `json:"credential"`

View File

@ -1,6 +1,7 @@
package dto
type CommandOperate struct {
ID uint `json:"id"`
Name string `json:"name" validate:"required"`
Command string `json:"command" validate:"required"`
}

View File

@ -14,6 +14,10 @@ type OperationWithName struct {
Name string `json:"name" validate:"required"`
}
type OperateByID struct {
ID uint `json:"id" validate:"required"`
}
type BatchDeleteReq struct {
Ids []uint `json:"ids" validate:"required"`
}

View File

@ -9,6 +9,7 @@ type ComposeTemplateCreate struct {
}
type ComposeTemplateUpdate struct {
ID uint `json:"id"`
Description string `json:"description"`
Content string `json:"content"`
}

View File

@ -65,9 +65,9 @@ type ContainerLog struct {
}
type ContainerOperation struct {
ContainerID string `json:"containerID" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=start stop restart kill pause unpause rename remove"`
NewName string `json:"newName"`
Name string `json:"name" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=start stop restart kill pause unpause rename remove"`
NewName string `json:"newName"`
}
type Network struct {
@ -106,7 +106,7 @@ type VolumeCreat struct {
}
type BatchDelete struct {
Ids []string `json:"ids" validate:"required"`
Names []string `json:"names" validate:"required"`
}
type ComposeInfo struct {
@ -138,6 +138,7 @@ type ComposeOperation struct {
Operation string `json:"operation" validate:"required,oneof=start stop down"`
}
type ComposeUpdate struct {
Name string `json:"name" validate:"required"`
Path string `json:"path" validate:"required"`
Content string `json:"content" validate:"required"`
}

View File

@ -23,6 +23,7 @@ type CronjobCreate struct {
}
type CronjobUpdate struct {
ID uint `json:"id" validate:"required"`
Name string `json:"name" validate:"required"`
SpecType string `json:"specType" validate:"required"`
Week int `json:"week" validate:"number,max=7,min=1"`

View File

@ -1,6 +1,7 @@
package dto
type GroupOperate struct {
ID uint `json:"id"`
Name string `json:"name" validate:"required"`
Type string `json:"type" validate:"required"`
}

View File

@ -5,6 +5,7 @@ import (
)
type HostOperate struct {
ID uint `json:"id"`
GroupBelong string `json:"groupBelong" validate:"required"`
Name string `json:"name" validate:"required"`
Addr string `json:"addr" validate:"required,ip"`

View File

@ -5,23 +5,20 @@ import (
)
type OperationLog struct {
ID uint `json:"id"`
Group string `json:"group"`
Source string `json:"source"`
Action string `json:"action"`
ID uint `json:"id"`
Group string `json:"group"`
IP string `json:"ip"`
Path string `json:"path"`
Method string `json:"method"`
UserAgent string `json:"userAgent"`
Body string `json:"body"`
Resp string `json:"resp"`
Status int `json:"status"`
Latency time.Duration `json:"latency"`
ErrorMessage string `json:"errorMessage"`
Latency time.Duration `json:"latency"`
Status string `json:"status"`
Message string `json:"message"`
Detail string `json:"detail"`
DetailZH string `json:"detailZH"`
DetailEN string `json:"detailEN"`
CreatedAt time.Time `json:"createdAt"`
}

View File

@ -6,20 +6,19 @@ import (
type OperationLog struct {
BaseModel
Group string `gorm:"type:varchar(64)" json:"group"`
Source string `gorm:"type:varchar(64)" json:"source"`
Action string `gorm:"type:varchar(64)" json:"action"`
Group string `gorm:"type:varchar(64)" json:"group"`
IP string `gorm:"type:varchar(64)" json:"ip"`
Path string `gorm:"type:varchar(64)" json:"path"`
Method string `gorm:"type:varchar(64)" json:"method"`
UserAgent string `gorm:"type:varchar(256)" json:"userAgent"`
Body string `gorm:"type:longText" json:"body"`
Resp string `gorm:"type:longText" json:"resp"`
Latency time.Duration `gorm:"type:varchar(64)" json:"latency"`
Status string `gorm:"type:varchar(64)" json:"status"`
Message string `gorm:"type:varchar(256)" json:"message"`
Detail string `gorm:"type:longText" json:"detail"`
DetailZH string `gorm:"type:varchar(256)" json:"detailZH"`
DetailEN string `gorm:"type:varchar(256)" json:"detailEN"`
}
type LoginLog struct {

View File

@ -180,21 +180,21 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
}
switch req.Operation {
case constant.ContainerOpStart:
err = client.ContainerStart(ctx, req.ContainerID, types.ContainerStartOptions{})
err = client.ContainerStart(ctx, req.Name, types.ContainerStartOptions{})
case constant.ContainerOpStop:
err = client.ContainerStop(ctx, req.ContainerID, nil)
err = client.ContainerStop(ctx, req.Name, nil)
case constant.ContainerOpRestart:
err = client.ContainerRestart(ctx, req.ContainerID, nil)
err = client.ContainerRestart(ctx, req.Name, nil)
case constant.ContainerOpKill:
err = client.ContainerKill(ctx, req.ContainerID, "SIGKILL")
err = client.ContainerKill(ctx, req.Name, "SIGKILL")
case constant.ContainerOpPause:
err = client.ContainerPause(ctx, req.ContainerID)
err = client.ContainerPause(ctx, req.Name)
case constant.ContainerOpUnpause:
err = client.ContainerUnpause(ctx, req.ContainerID)
err = client.ContainerUnpause(ctx, req.Name)
case constant.ContainerOpRename:
err = client.ContainerRename(ctx, req.ContainerID, req.NewName)
err = client.ContainerRename(ctx, req.Name, req.NewName)
case constant.ContainerOpRemove:
err = client.ContainerRemove(ctx, req.ContainerID, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
err = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
}
return err
}

View File

@ -66,7 +66,7 @@ func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
if err != nil {
return err
}
for _, id := range req.Ids {
for _, id := range req.Names {
if err := client.NetworkRemove(context.TODO(), id); err != nil {
return err
}

View File

@ -77,7 +77,7 @@ func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error {
if err != nil {
return err
}
for _, id := range req.Ids {
for _, id := range req.Names {
if err := client.VolumeRemove(context.TODO(), id, true); err != nil {
return err
}

View File

@ -325,7 +325,7 @@ func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
if err != nil {
return err
}
for _, ids := range req.Ids {
for _, ids := range req.Names {
if _, err := client.ImageRemove(context.TODO(), ids, types.ImageRemoveOptions{Force: true, PruneChildren: true}); err != nil {
return err
}

View File

@ -1,12 +1,9 @@
package service
import (
"encoding/json"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
)
@ -56,17 +53,6 @@ func (u *LogService) PageOperationLog(search dto.PageInfo) (int64, interface{},
if err := copier.Copy(&item, &op); err != nil {
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
item.Body = filterSensitive(item.Body)
var res dto.Response
if err := json.Unmarshal([]byte(item.Resp), &res); err != nil {
global.LOG.Errorf("unmarshal failed, err: %+v", err)
dtoOps = append(dtoOps, item)
continue
}
item.Status = res.Code
if item.Status != 200 {
item.ErrorMessage = res.Message
}
dtoOps = append(dtoOps, item)
}
return total, dtoOps, err
@ -78,24 +64,3 @@ func (u *LogService) CleanLogs(logtype string) error {
}
return logRepo.CleanLogin()
}
func filterSensitive(vars string) string {
var Sensitives = []string{"password", "Password", "credential", "privateKey"}
ops := make(map[string]interface{})
if err := json.Unmarshal([]byte(vars), &ops); err != nil {
return vars
}
for k := range ops {
for _, sen := range Sensitives {
if k == sen {
delete(ops, k)
continue
}
}
}
backStr, err := json.Marshal(ops)
if err != nil {
return ""
}
return string(backStr)
}

View File

@ -38,6 +38,7 @@ func setWebStatic(rootRouter *gin.Engine) {
func Routers() *gin.Engine {
Router := gin.Default()
Router.Use(middleware.OperationLog())
Router.Use(middleware.CSRF())
Router.Use(middleware.LoadCsrfToken())

View File

@ -3,59 +3,98 @@ package middleware
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/service"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/cmd/server/operation"
"github.com/gin-gonic/gin"
)
func OperationRecord() gin.HandlerFunc {
func OperationLog() gin.HandlerFunc {
return func(c *gin.Context) {
var body []byte
if strings.Contains(c.Request.URL.Path, "search") {
if strings.Contains(c.Request.URL.Path, "search") || c.Request.Method == http.MethodGet {
c.Next()
return
}
if c.Request.Method == http.MethodGet {
query := c.Request.URL.RawQuery
query, _ = url.QueryUnescape(query)
split := strings.Split(query, "&")
m := make(map[string]string)
for _, v := range split {
kv := strings.Split(v, "=")
if len(kv) == 2 {
m[kv[0]] = kv[1]
}
}
body, _ = json.Marshal(&m)
} else {
var err error
body, err = ioutil.ReadAll(c.Request.Body)
if err != nil {
global.LOG.Errorf("read body from request failed, err: %v", err)
} else {
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
}
}
pathInfo := loadLogInfo(c.Request.URL.Path)
group := loadLogInfo(c.Request.URL.Path)
record := model.OperationLog{
Group: pathInfo.group,
Source: pathInfo.source,
Action: pathInfo.action,
Group: group,
IP: c.ClientIP(),
Method: c.Request.Method,
Path: c.Request.URL.Path,
UserAgent: c.Request.UserAgent(),
Body: string(body),
}
var (
operationDics []operationJson
operationDic operationJson
)
if err := json.Unmarshal(operation.OperationJosn, &operationDics); err != nil {
c.Next()
return
}
for _, dic := range operationDics {
if dic.API == record.Path && dic.Method == record.Method {
operationDic = dic
break
}
}
if len(operationDic.API) == 0 {
c.Next()
return
}
formatMap := make(map[string]interface{})
if len(operationDic.BodyKeys) != 0 {
body, err := ioutil.ReadAll(c.Request.Body)
if err == nil {
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
}
bodyMap := make(map[string]interface{})
_ = json.Unmarshal(body, &bodyMap)
for _, key := range operationDic.BodyKeys {
if _, ok := bodyMap[key]; ok {
formatMap[key] = bodyMap[key]
}
}
}
if len(operationDic.BeforeFuntions) != 0 {
for _, funcs := range operationDic.BeforeFuntions {
for key, value := range formatMap {
if funcs.Info == key {
var names []string
if funcs.IsList {
if key == "ids" {
sql := fmt.Sprintf("SELECT %s FROM %s where id in (?);", funcs.Key, funcs.DB)
fmt.Println(value)
_ = global.DB.Raw(sql, value).Scan(&names)
}
} else {
_ = global.DB.Raw(fmt.Sprintf("select %s from %s where %s = ?;", funcs.Key, funcs.DB, key), value).Scan(&names)
}
formatMap[funcs.Value] = strings.Join(names, ",")
break
}
}
}
}
var values []interface{}
for key, value := range formatMap {
if strings.Contains(operationDic.FormatEN, key) {
operationDic.FormatZH = strings.ReplaceAll(operationDic.FormatZH, key, "%v")
operationDic.FormatEN = strings.ReplaceAll(operationDic.FormatEN, key, "%v")
values = append(values, value)
}
}
record.DetailZH = fmt.Sprintf(operationDic.FormatZH, values...)
record.DetailEN = fmt.Sprintf(operationDic.FormatEN, values...)
writer := responseBodyWriter{
ResponseWriter: c.Writer,
@ -66,9 +105,17 @@ func OperationRecord() gin.HandlerFunc {
c.Next()
var res response
_ = json.Unmarshal(writer.body.Bytes(), &res)
if res.Code == 200 {
record.Status = constant.StatusSuccess
} else {
record.Status = constant.StatusFailed
record.Message = res.Message
}
latency := time.Since(now)
record.Latency = latency
record.Resp = writer.body.String()
if err := service.NewILogService().CreateOperationLog(record); err != nil {
global.LOG.Errorf("create operation record failed, err: %v", err)
@ -76,6 +123,28 @@ func OperationRecord() gin.HandlerFunc {
}
}
type operationJson struct {
API string `json:"api"`
Method string `json:"method"`
BodyKeys []string `json:"bodyKeys"`
ParamKeys []string `json:"paramKeys"`
BeforeFuntions []functionInfo `json:"beforeFuntions"`
FormatZH string `json:"formatZH"`
FormatEN string `json:"formatEN"`
}
type functionInfo struct {
Info string `json:"info"`
IsList bool `json:"isList"`
DB string `json:"db"`
Key string `json:"key"`
Value string `json:"value"`
}
type response struct {
Code int `json:"code"`
Message string `json:"message"`
}
type responseBodyWriter struct {
gin.ResponseWriter
body *bytes.Buffer
@ -86,26 +155,14 @@ func (r responseBodyWriter) Write(b []byte) (int, error) {
return r.ResponseWriter.Write(b)
}
type pathInfo struct {
group string
source string
action string
}
func loadLogInfo(path string) pathInfo {
func loadLogInfo(path string) string {
path = strings.ReplaceAll(path, "/api/v1", "")
if !strings.Contains(path, "/") {
return pathInfo{}
return ""
}
pathArrys := strings.Split(path, "/")
if len(pathArrys) < 2 {
return pathInfo{}
return ""
}
if len(pathArrys) == 2 {
return pathInfo{group: pathArrys[1]}
}
if len(pathArrys) == 3 {
return pathInfo{group: pathArrys[1], source: pathArrys[2]}
}
return pathInfo{group: pathArrys[1], source: pathArrys[2], action: pathArrys[3]}
return pathArrys[1]
}

View File

@ -14,20 +14,15 @@ func (s *BackupRouter) InitBackupRouter(Router *gin.RouterGroup) {
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
withRecordRouter := Router.Group("backups").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired()).
Use(middleware.OperationRecord())
baseApi := v1.ApiGroupApp.BaseApi
{
baRouter.GET("/search", baseApi.ListBackup)
baRouter.POST("/buckets", baseApi.ListBuckets)
withRecordRouter.POST("", baseApi.CreateBackup)
withRecordRouter.POST("/del", baseApi.DeleteBackup)
withRecordRouter.POST("/record/search", baseApi.SearchBackupRecords)
withRecordRouter.POST("/record/download", baseApi.DownloadRecord)
withRecordRouter.POST("/record/del", baseApi.DeleteBackupRecord)
withRecordRouter.PUT(":id", baseApi.UpdateBackup)
baRouter.POST("", baseApi.CreateBackup)
baRouter.POST("/del", baseApi.DeleteBackup)
baRouter.POST("/update", baseApi.UpdateBackup)
baRouter.POST("/record/search", baseApi.SearchBackupRecords)
baRouter.POST("/record/download", baseApi.DownloadRecord)
baRouter.POST("/record/del", baseApi.DeleteBackupRecord)
}
}

View File

@ -14,17 +14,12 @@ func (s *CommandRouter) InitCommandRouter(Router *gin.RouterGroup) {
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
withRecordRouter := Router.Group("commands").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired()).
Use(middleware.OperationRecord())
baseApi := v1.ApiGroupApp.BaseApi
{
withRecordRouter.POST("", baseApi.CreateCommand)
withRecordRouter.POST("/del", baseApi.DeleteCommand)
withRecordRouter.PUT(":id", baseApi.UpdateCommand)
cmdRouter.POST("/search", baseApi.SearchCommand)
cmdRouter.GET("", baseApi.ListCommand)
cmdRouter.POST("", baseApi.CreateCommand)
cmdRouter.POST("/del", baseApi.DeleteCommand)
cmdRouter.POST("/search", baseApi.SearchCommand)
cmdRouter.POST("/update", baseApi.UpdateCommand)
}
}

View File

@ -13,41 +13,36 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
withRecordRouter := Router.Group("containers").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired()).
Use(middleware.OperationRecord())
baseApi := v1.ApiGroupApp.BaseApi
{
baRouter.GET("/exec", baseApi.ContainerExec)
baRouter.GET("/stats/:id", baseApi.ContainerStats)
baRouter.POST("/search", baseApi.SearchContainer)
baRouter.POST("/inspect", baseApi.Inspect)
baRouter.POST("", baseApi.ContainerCreate)
baRouter.POST("/log", baseApi.ContainerLogs)
withRecordRouter.POST("operate", baseApi.ContainerOperation)
baRouter.POST("/search", baseApi.SearchContainer)
baRouter.POST("/search/log", baseApi.ContainerLogs)
baRouter.POST("/inspect", baseApi.Inspect)
baRouter.POST("/operate", baseApi.ContainerOperation)
baRouter.POST("/repo/search", baseApi.SearchRepo)
baRouter.PUT("/repo/:id", baseApi.UpdateRepo)
baRouter.GET("/repo", baseApi.ListRepo)
withRecordRouter.POST("/repo", baseApi.CreateRepo)
withRecordRouter.POST("/repo/del", baseApi.DeleteRepo)
baRouter.POST("/repo/search", baseApi.SearchRepo)
baRouter.POST("/repo/update", baseApi.UpdateRepo)
baRouter.POST("/repo", baseApi.CreateRepo)
baRouter.POST("/repo/del", baseApi.DeleteRepo)
baRouter.POST("/compose/search", baseApi.SearchCompose)
baRouter.POST("/compose", baseApi.CreateCompose)
baRouter.POST("/compose/operate", baseApi.OperatorCompose)
baRouter.POST("/compose/update", baseApi.ComposeUpdate)
baRouter.POST("/template/search", baseApi.SearchComposeTemplate)
baRouter.PUT("/template/:id", baseApi.UpdateComposeTemplate)
baRouter.GET("/template", baseApi.ListComposeTemplate)
withRecordRouter.POST("/template", baseApi.CreateComposeTemplate)
withRecordRouter.POST("/template/del", baseApi.DeleteComposeTemplate)
baRouter.POST("/template/search", baseApi.SearchComposeTemplate)
baRouter.POST("/template/update", baseApi.UpdateComposeTemplate)
baRouter.POST("/template", baseApi.CreateComposeTemplate)
baRouter.POST("/template/del", baseApi.DeleteComposeTemplate)
baRouter.POST("/image/search", baseApi.SearchImage)
baRouter.GET("/image", baseApi.ListImage)
baRouter.POST("/image/search", baseApi.SearchImage)
baRouter.POST("/image/pull", baseApi.ImagePull)
baRouter.POST("/image/push", baseApi.ImagePush)
baRouter.POST("/image/save", baseApi.ImageSave)
@ -56,12 +51,12 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
baRouter.POST("/image/tag", baseApi.ImageTag)
baRouter.POST("/image/build", baseApi.ImageBuild)
baRouter.GET("/volume", baseApi.ListVolume)
baRouter.POST("/network/del", baseApi.DeleteNetwork)
baRouter.POST("/network/search", baseApi.SearchNetwork)
baRouter.POST("/network", baseApi.CreateNetwork)
baRouter.POST("/volume/del", baseApi.DeleteVolume)
baRouter.POST("/volume/search", baseApi.SearchVolume)
baRouter.GET("/volume", baseApi.ListVolume)
baRouter.POST("/volume", baseApi.CreateVolume)
baRouter.GET("/daemonjson", baseApi.LoadDaemonJson)

View File

@ -14,18 +14,13 @@ func (s *CronjobRouter) InitCronjobRouter(Router *gin.RouterGroup) {
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
withRecordRouter := Router.Group("cronjobs").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired()).
Use(middleware.OperationRecord())
baseApi := v1.ApiGroupApp.BaseApi
{
withRecordRouter.POST("", baseApi.CreateCronjob)
withRecordRouter.POST("/del", baseApi.DeleteCronjob)
withRecordRouter.PUT(":id", baseApi.UpdateCronjob)
withRecordRouter.POST("/status", baseApi.UpdateCronjobStatus)
cmdRouter.POST("/handle/:id", baseApi.HandleOnce)
cmdRouter.POST("", baseApi.CreateCronjob)
cmdRouter.POST("/del", baseApi.DeleteCronjob)
cmdRouter.POST("/update", baseApi.UpdateCronjob)
cmdRouter.POST("/status", baseApi.UpdateCronjobStatus)
cmdRouter.POST("/handle", baseApi.HandleOnce)
cmdRouter.POST("/download", baseApi.TargetDownload)
cmdRouter.POST("/search", baseApi.SearchCronjob)
cmdRouter.POST("/search/records", baseApi.SearchJobRecords)

View File

@ -14,23 +14,18 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
withRecordRouter := Router.Group("databases").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired()).
Use(middleware.OperationRecord())
baseApi := v1.ApiGroupApp.BaseApi
{
withRecordRouter.POST("", baseApi.CreateMysql)
withRecordRouter.POST("/change/access", baseApi.ChangeMysqlAccess)
withRecordRouter.POST("/change/password", baseApi.ChangeMysqlPassword)
withRecordRouter.POST("/backup", baseApi.BackupMysql)
withRecordRouter.POST("/recover/byupload", baseApi.RecoverMysqlByUpload)
withRecordRouter.POST("/recover", baseApi.RecoverMysql)
withRecordRouter.POST("/del/check/:id", baseApi.DeleteCheckMysql)
withRecordRouter.POST("/del/:id", baseApi.DeleteMysql)
withRecordRouter.POST("/variables/update", baseApi.UpdateMysqlVariables)
withRecordRouter.POST("/conf/update/byfile", baseApi.UpdateMysqlConfByFile)
cmdRouter.POST("", baseApi.CreateMysql)
cmdRouter.POST("/change/access", baseApi.ChangeMysqlAccess)
cmdRouter.POST("/change/password", baseApi.ChangeMysqlPassword)
cmdRouter.POST("/backup", baseApi.BackupMysql)
cmdRouter.POST("/recover/byupload", baseApi.RecoverMysqlByUpload)
cmdRouter.POST("/recover", baseApi.RecoverMysql)
cmdRouter.POST("/del/check", baseApi.DeleteCheckMysql)
cmdRouter.POST("/del", baseApi.DeleteMysql)
cmdRouter.POST("/variables/update", baseApi.UpdateMysqlVariables)
cmdRouter.POST("/conffile/update", baseApi.UpdateMysqlConfByFile)
cmdRouter.POST("/search", baseApi.SearchMysql)
cmdRouter.GET("/variables", baseApi.LoadVariables)
cmdRouter.GET("/status", baseApi.LoadStatus)
@ -45,9 +40,9 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/redis/password", baseApi.ChangeRedisPassword)
cmdRouter.POST("/redis/backup", baseApi.RedisBackup)
cmdRouter.POST("/redis/recover", baseApi.RedisRecover)
cmdRouter.POST("/redis/backup/records", baseApi.RedisBackupList)
cmdRouter.POST("/redis/backuplist/search", baseApi.RedisBackupList)
cmdRouter.POST("/redis/conf/update", baseApi.UpdateRedisConf)
cmdRouter.POST("/redis/conf/update/byfile", baseApi.UpdateRedisConfByFile)
cmdRouter.POST("/redis/conf/update/persistence", baseApi.UpdateRedisPersistenceConf)
cmdRouter.POST("/redis/conffile/update", baseApi.UpdateRedisConfByFile)
cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf)
}
}

View File

@ -14,16 +14,11 @@ func (s *GroupRouter) InitGroupRouter(Router *gin.RouterGroup) {
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
withRecordRouter := Router.Group("groups").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired()).
Use(middleware.OperationRecord())
baseApi := v1.ApiGroupApp.BaseApi
{
withRecordRouter.POST("", baseApi.CreateGroup)
withRecordRouter.DELETE(":id", baseApi.DeleteGroup)
withRecordRouter.PUT(":id", baseApi.UpdateGroup)
groupRouter.POST("", baseApi.CreateGroup)
groupRouter.POST("/del", baseApi.DeleteGroup)
groupRouter.POST("/update", baseApi.UpdateGroup)
groupRouter.POST("/search", baseApi.ListGroup)
groupRouter.GET(":id", baseApi.GetGroupInfo)
}

View File

@ -14,16 +14,11 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
withRecordRouter := Router.Group("hosts").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired()).
Use(middleware.OperationRecord())
baseApi := v1.ApiGroupApp.BaseApi
{
withRecordRouter.POST("", baseApi.CreateHost)
withRecordRouter.DELETE(":id", baseApi.DeleteHost)
withRecordRouter.PUT(":id", baseApi.UpdateHost)
hostRouter.POST("", baseApi.CreateHost)
hostRouter.POST("/del", baseApi.DeleteHost)
hostRouter.POST("/update", baseApi.UpdateHost)
hostRouter.POST("/search", baseApi.HostTree)
hostRouter.POST("/testconn", baseApi.TestConn)
hostRouter.GET(":id", baseApi.GetHostInfo)

View File

@ -14,17 +14,12 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
withRecordRouter := Router.Group("settings").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired()).
Use(middleware.OperationRecord())
baseApi := v1.ApiGroupApp.BaseApi
{
baseRouter.POST("/search", baseApi.GetSettingInfo)
baseRouter.PUT("/expired/handle", baseApi.HandlePasswordExpired)
withRecordRouter.PUT("", baseApi.UpdateSetting)
settingRouter.PUT("/password", baseApi.UpdatePassword)
baseRouter.POST("/expired/handle", baseApi.HandlePasswordExpired)
baseRouter.POST("/update", baseApi.UpdateSetting)
settingRouter.POST("/password/update", baseApi.UpdatePassword)
settingRouter.POST("/time/sync", baseApi.SyncTime)
settingRouter.POST("/monitor/clean", baseApi.CleanMonitor)
settingRouter.GET("/mfa", baseApi.GetMFA)

View File

@ -0,0 +1,6 @@
package operation
import _ "embed"
//go:embed operation.json
var OperationJosn []byte

View File

@ -0,0 +1,817 @@
[
{
"api": "/api/v1/containers",
"method": "POST",
"bodyKeys": [
"name",
"image"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建容器 name[image]",
"formatEN": "create container name[image]"
},
{
"api": "/api/v1/containers/operate",
"method": "POST",
"bodyKeys": [
"name",
"operation",
"newName"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "容器 [name] 执行 [operation] newName",
"formatEN": "container [operation] [name] newName"
},
{
"api": "/api/v1/containers/repo",
"method": "POST",
"bodyKeys": [
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建镜像仓库 [name]",
"formatEN": "create image repo [name]"
},
{
"api": "/api/v1/containers/repo/update",
"method": "POST",
"bodyKeys": [
"id"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "id",
"isList": false,
"db": "image_repos",
"key": "name",
"value": "name"
}
],
"formatZH": "更新镜像仓库 [name]",
"formatEN": "update image repo information [name]"
},
{
"api": "/api/v1/containers/repo/del",
"method": "POST",
"bodyKeys": [
"ids"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "ids",
"isList": true,
"db": "image_repos",
"key": "name",
"value": "names"
}
],
"formatZH": "删除镜像仓库 names",
"formatEN": "delete image repo names"
},
{
"api": "/api/v1/containers/compose",
"method": "POST",
"bodyKeys": [
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建 compose [name]",
"formatEN": "create compose [name]"
},
{
"api": "/api/v1/containers/compose/operate",
"method": "POST",
"bodyKeys": [
"name",
"operation"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "compose [operation] [name]",
"formatEN": "compose [operation] [name]"
},
{
"api": "/api/v1/containers/compose/update",
"method": "POST",
"bodyKeys": [
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新 compose [name]",
"formatEN": "update compose information [name]"
},
{
"api": "/api/v1/containers/template/update",
"method": "POST",
"bodyKeys": [
"id"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "id",
"isList": false,
"db": "compose_templates",
"key": "name",
"value": "name"
}
],
"formatZH": "更新 compose 模版 [name]",
"formatEN": "update compose template information [name]"
},
{
"api": "/api/v1/containers/template",
"method": "POST",
"bodyKeys": [
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建 compose 模版 [name]",
"formatEN": "create compose template [name]"
},
{
"api": "/api/v1/containers/template/del",
"method": "POST",
"bodyKeys": [
"ids"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "ids",
"isList": true,
"db": "compose_templates",
"key": "name",
"value": "names"
}
],
"formatZH": "删除 compose 模版 names",
"formatEN": "delete compose template names"
},
{
"api": "/api/v1/containers/image/pull",
"method": "POST",
"bodyKeys": [
"repoID",
"imageName"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "repoID",
"isList": false,
"db": "image_repos",
"key": "name",
"value": "reponame"
}
],
"formatZH": "镜像拉取 [reponame]imageName",
"formatEN": "image pull [reponame]imageName"
},
{
"api": "/api/v1/containers/image/push",
"method": "POST",
"bodyKeys": [
"repoID",
"tagName",
"name"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "repoID",
"isList": false,
"db": "image_repos",
"key": "name",
"value": "reponame"
}
],
"formatZH": "[tagName] 推送到 [reponame]name",
"formatEN": "push [tagName] to [reponame]name"
},
{
"api": "/api/v1/containers/image/save",
"method": "POST",
"bodyKeys": [
"tagName",
"path",
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "保留 [tagName] 为 [path/name]",
"formatEN": "save [tagName] as [path/name]"
},
{
"api": "/api/v1/containers/image/load",
"method": "POST",
"bodyKeys": [
"path"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "从 [path] 加载镜像",
"formatEN": "load image from [path]"
},
{
"api": "/api/v1/containers/image/remove",
"method": "POST",
"bodyKeys": [
"names"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "移除镜像 names",
"formatEN": "remove image names"
},
{
"api": "/api/v1/containers/image/tag",
"method": "POST",
"bodyKeys": [
"repoID",
"targetName"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "repoID",
"isList": false,
"db": "image_repos",
"key": "name",
"value": "reponame"
}
],
"formatZH": "tag 镜像 [reponame]targetName",
"formatEN": "tag image [reponame]targetName"
},
{
"api": "/api/v1/containers/image/build",
"method": "POST",
"bodyKeys": [
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "构建镜像 [name]",
"formatEN": "build image [name]"
},
{
"api": "/api/v1/containers/network",
"method": "POST",
"bodyKeys": [
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建容器网络 name",
"formatEN": "create container network [name]"
},
{
"api": "/api/v1/containers/network/del",
"method": "POST",
"bodyKeys": [
"names"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "删除容器网络 names",
"formatEN": "delete container network names"
},
{
"api": "/api/v1/containers/volume",
"method": "POST",
"bodyKeys": [
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建容器存储卷 [name]",
"formatEN": "create container volume [name]"
},
{
"api": "/api/v1/containers/volume/del",
"method": "POST",
"bodyKeys": [
"names"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "删除容器存储卷 names",
"formatEN": "delete container volume names"
},
{
"api": "/api/v1/containers/docker/operate",
"method": "POST",
"bodyKeys": [
"operation"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "docker 服务 [operation]",
"formatEN": "operation docker service"
},
{
"api": "/api/v1/containers/daemonjson/update",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新 docker daemon.json 配置",
"formatEN": "Updated the docker daemon.json configuration"
},
{
"api": "/api/v1/containers/daemonjson/update/byfile",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新 docker daemon.json 配置",
"formatEN": "Updated the docker daemon.json configuration"
},
{
"api": "/api/v1/cronjobs/del",
"method": "POST",
"bodyKeys": [
"ids"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "ids",
"isList": true,
"db": "cronjobs",
"key": "name",
"value": "names"
}
],
"formatZH": "删除计划任务 names",
"formatEN": "delete cronjob names"
},
{
"api": "/api/v1/cronjobs/update",
"method": "POST",
"bodyKeys": [
"id"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "id",
"isList": false,
"db": "cronjobs",
"key": "name",
"value": "name"
}
],
"formatZH": "更新计划任务 [name]",
"formatEN": "update cronjob [name]"
},
{
"api": "/api/v1/cronjobs/status",
"method": "POST",
"bodyKeys": [
"id",
"status"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "id",
"isList": false,
"db": "cronjobs",
"key": "name",
"value": "name"
}
],
"formatZH": "修改计划任务 [name] 状态为 [status]",
"formatEN": "change the status of cronjob [name] to [status]."
},
{
"api": "/api/v1/cronjobs/handle",
"method": "POST",
"bodyKeys": [
"id"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "id",
"isList": false,
"db": "cronjobs",
"key": "name",
"value": "name"
}
],
"formatZH": "手动执行计划任务 [name]",
"formatEN": "manually execute the cronjob [name]"
},
{
"api": "/api/v1/databases",
"method": "POST",
"bodyKeys": [
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建 mysql 数据库 [name]",
"formatEN": "create mysql database [name]"
},
{
"api": "/api/v1/databases/backup",
"method": "POST",
"bodyKeys": [
"mysqlName",
"dbName"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "备份 mysql 数据库 mysqlName[dbName]",
"formatEN": "backup mysql database mysqlName[dbName]"
},
{
"api": "/api/v1/databases/recover",
"method": "POST",
"bodyKeys": [
"mysqlName",
"dbName",
"backupName"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "恢复 mysql 数据库 mysqlName[dbName] backupName",
"formatEN": "恢复 mysql 数据库 mysqlName[dbName] backupName"
},
{
"api": "/api/v1/databases/recover/byupload",
"method": "POST",
"bodyKeys": [
"fileDir",
"fileName",
"mysqlName",
"dbName"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "mysql 数据库从 [fileDir/fileName] 恢复 [mysqlName]dbName",
"formatEN": "mysql database recover [fileDir/fileName] from [mysqlName]dbName"
},
{
"api": "/api/v1/databases/del",
"method": "POST",
"bodyKeys": [
"id"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "id",
"isList": false,
"db": "database_mysqls",
"key": "name",
"value": "name"
}
],
"formatZH": "删除 mysql 数据库 [name]",
"formatEN": "delete mysql database [name]"
},
{
"api": "/api/v1/databases/variables/update",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "调整 mysql 数据库性能参数",
"formatEN": "adjust mysql database performance parameters"
},
{
"api": "/api/v1/databases/conffile/update",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新 mysql 数据库配置信息",
"formatEN": "update the mysql database configuration information"
},
{
"api": "/api/v1/databases/redis/password",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "修改 redis 数据库密码",
"formatEN": "change the password of the redis database"
},
{
"api": "/api/v1/databases/redis/backup",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "备份 redis 数据库",
"formatEN": "backup redis database"
},
{
"api": "/api/v1/databases/redis/recover",
"method": "POST",
"bodyKeys": [
"fileDir",
"fileName"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "redis 数据库从 fileDir/fileName 恢复",
"formatEN": "redis database recover from fileDir/fileName"
},
{
"api": "/api/v1/databases/redis/conf/update",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新 redis 数据库配置信息",
"formatEN": "update the redis database configuration information"
},
{
"api": "/api/v1/databases/redis/conffile/update",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新 redis 数据库配置信息",
"formatEN": "update the redis database configuration information"
},
{
"api": "/api/v1/databases/redis/persistence/update",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "redis 数据库持久化配置更新",
"formatEN": "redis database persistence configuration update"
},
{
"api": "/api/v1/commands",
"method": "POST",
"bodyKeys": [
"name",
"command"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建快捷命令 name[command]",
"formatEN": "create quick command name[command]"
},
{
"api": "/api/v1/commands/del",
"method": "POST",
"bodyKeys": [
"ids"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "ids",
"isList": true,
"db": "commands",
"key": "name",
"value": "names"
}
],
"formatZH": "删除快捷命令 names",
"formatEN": "delete quick command names"
},
{
"api": "/api/v1/commands/update",
"method": "POST",
"bodyKeys": [
"name"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新快捷命令 [name]",
"formatEN": "update quick command [name]"
},
{
"api": "/api/v1/backups",
"method": "POST",
"bodyKeys": [
"type"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建备份账号 [type]",
"formatEN": "create backup account [type]"
},
{
"api": "/api/v1/backups/del",
"method": "POST",
"bodyKeys": [
"ids"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "ids",
"isList": true,
"db": "backup_accounts",
"key": "type",
"value": "types"
}
],
"formatZH": "删除备份账号 [types]",
"formatEN": "delete backup account [types]"
},
{
"api": "/api/v1/backups/update",
"method": "POST",
"bodyKeys": [
"type"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新备份账号 [types]",
"formatEN": "update backup account [types]"
},
{
"api": "/api/v1/backups/record/download",
"method": "POST",
"bodyKeys": [
"source",
"fileName"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "下载备份记录 [source]fileName",
"formatEN": "download backup records [source]fileName"
},
{
"api": "/api/v1/backups/record/del",
"method": "POST",
"bodyKeys": [
"ids"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "ids",
"isList": true,
"db": "backup_records",
"key": "file_name",
"value": "files"
}
],
"formatZH": "删除备份记录 [files]",
"formatEN": "delete backup records [files]"
},
{
"api": "/api/v1/groups/del",
"method": "POST",
"bodyKeys": [
"id"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "id",
"isList": false,
"db": "groups",
"key": "name",
"value": "name"
}
],
"formatZH": "删除组 [name]",
"formatEN": "delete group [name]"
},
{
"api": "/api/v1/groups/update",
"method": "POST",
"bodyKeys": [
"name",
"type"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新组 [name]type",
"formatEN": "update group [name]type"
},
{
"api": "/api/v1/groups",
"method": "POST",
"bodyKeys": [
"name",
"type"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建组 [name]type",
"formatEN": "create group [name]type"
},
{
"api": "/api/v1/hosts/del",
"method": "POST",
"bodyKeys": [
"id"
],
"paramKeys": [],
"BeforeFuntions": [
{
"info": "id",
"isList": false,
"db": "hosts",
"key": "addr",
"value": "addr"
}
],
"formatZH": "删除主机 [addr]",
"formatEN": "delete host [addr]"
},
{
"api": "/api/v1/hosts/update",
"method": "POST",
"bodyKeys": [
"name",
"addr"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "更新主机信息 [name]addr",
"formatEN": "update host [name]addr"
},
{
"api": "/api/v1/hosts",
"method": "POST",
"bodyKeys": [
"name",
"addr"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "创建主机 [name]addr",
"formatEN": "create host [name]addr"
},
{
"api": "/api/v1/settings/expired/handle",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "重置过期密码",
"formatEN": "reset an expired Password"
},
{
"api": "/api/v1/settings/update",
"method": "POST",
"bodyKeys": [
"key",
"value"
],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "修改系统配置 [key] => [value]",
"formatEN": "update system setting [key] => [value]"
},
{
"api": "/api/v1/settings/password/update",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "修改系统密码",
"formatEN": "update system password"
},
{
"api": "/api/v1/settings/time/sync",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "系统时间同步",
"formatEN": "sync system time"
},
{
"api": "/api/v1/settings/monitor/clean",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "清空监控数据",
"formatEN": "clean monitor datas"
},
{
"api": "/api/v1/settings/mfa/bind",
"method": "POST",
"bodyKeys": [],
"paramKeys": [],
"BeforeFuntions": [],
"formatZH": "mfa 绑定",
"formatEN": "bind mfa"
}
]

View File

@ -2,7 +2,7 @@ import { ReqPage } from '.';
export namespace Container {
export interface ContainerOperate {
containerID: string;
name: string;
operation: string;
newName: string;
}
@ -198,6 +198,7 @@ export namespace Container {
path: string;
}
export interface ComposeUpdate {
name: string;
path: string;
content: string;
}
@ -227,7 +228,7 @@ export namespace Container {
}
export interface BatchDelete {
ids: Array<string>;
names: Array<string>;
}
export interface DaemonJsonUpdateByFile {

View File

@ -11,7 +11,7 @@ export const addBackup = (params: Backup.BackupOperate) => {
};
export const editBackup = (params: Backup.BackupOperate) => {
return http.put(`/backups/` + params.id, params);
return http.post(`/backups/update`, params);
};
export const deleteBackup = (params: { ids: number[] }) => {

View File

@ -15,7 +15,7 @@ export const addCommand = (params: Command.CommandOperate) => {
};
export const editCommand = (params: Command.CommandOperate) => {
return http.put(`/commands/${params.id}`, params);
return http.post(`/commands/update`, params);
};
export const deleteCommand = (params: { ids: number[] }) => {

View File

@ -9,7 +9,7 @@ export const createContainer = (params: Container.ContainerCreate) => {
return http.post(`/containers`, params);
};
export const logContainer = (params: Container.ContainerLogSearch) => {
return http.post<string>(`/containers/log`, params);
return http.post<string>(`/containers/search/log`, params);
};
export const ContainerStats = (id: string) => {
return http.get<Container.ContainerStats>(`/containers/stats/${id}`);
@ -86,7 +86,7 @@ export const createImageRepo = (params: Container.RepoCreate) => {
return http.post(`/containers/repo`, params);
};
export const updateImageRepo = (params: Container.RepoUpdate) => {
return http.put(`/containers/repo/${params.id}`, params);
return http.post(`/containers/repo/update`, params);
};
export const deleteImageRepo = (params: { ids: number[] }) => {
return http.post(`/containers/repo/del`, params);
@ -106,7 +106,7 @@ export const createComposeTemplate = (params: Container.TemplateCreate) => {
return http.post(`/containers/template`, params);
};
export const updateComposeTemplate = (params: Container.TemplateUpdate) => {
return http.put(`/containers/template/${params.id}`, params);
return http.post(`/containers/template/update`, params);
};
// compose

View File

@ -11,7 +11,7 @@ export const addCronjob = (params: Cronjob.CronjobCreate) => {
};
export const editCronjob = (params: Cronjob.CronjobUpdate) => {
return http.put(`/cronjobs/${params.id}`, params);
return http.post(`/cronjobs/update`, params);
};
export const deleteCronjob = (params: { ids: number[] }) => {

View File

@ -29,13 +29,13 @@ export const updateMysqlVariables = (params: Array<Database.VariablesUpdate>) =>
return http.post(`/databases/variables/update`, params);
};
export const updateMysqlConfByFile = (params: Database.MysqlConfUpdateByFile) => {
return http.post(`/databases/conf/update/byfile`, params);
return http.post(`/databases/conffile/update`, params);
};
export const deleteCheckMysqlDB = (id: number) => {
return http.post<Array<string>>(`/databases/del/check/${id}`);
return http.post<Array<string>>(`/databases/del/check`, { id: id });
};
export const deleteMysqlDB = (id: number) => {
return http.post(`/databases/del/${id}`);
return http.post(`/databases/del`, { id: id });
};
export const loadMysqlBaseInfo = () => {
@ -68,13 +68,13 @@ export const changeRedisPassword = (params: Database.ChangeInfo) => {
return http.post(`/databases/redis/password`, params);
};
export const updateRedisPersistenceConf = (params: Database.RedisConfPersistenceUpdate) => {
return http.post(`/databases/redis/conf/update/persistence`, params);
return http.post(`/databases/redis/persistence/update`, params);
};
export const updateRedisConf = (params: Database.RedisConfUpdate) => {
return http.post(`/databases/redis/conf/update`, params);
};
export const updateRedisConfByFile = (params: Database.RedisConfUpdateByFile) => {
return http.post(`/databases/redis/conf/update/byfile`, params);
return http.post(`/databases/redis/conffile/update`, params);
};
export const backupRedis = () => {
return http.post(`/databases/redis/backup`);

View File

@ -10,9 +10,9 @@ export const addGroup = (params: Group.GroupOperate) => {
};
export const editGroup = (params: Group.GroupOperate) => {
return http.put(`/groups/` + params.id, params);
return http.post(`/groups/update`, params);
};
export const deleteGroup = (id: number) => {
return http.delete(`/groups/` + id);
return http.post(`/groups/del`, { id: id });
};

View File

@ -18,9 +18,9 @@ export const testConn = (params: Host.HostConnTest) => {
};
export const editHost = (params: Host.HostOperate) => {
return http.put(`/hosts/` + params.id, params);
return http.post(`/hosts/update`, params);
};
export const deleteHost = (id: number) => {
return http.delete(`/hosts/` + id);
return http.post(`/hosts/del`, { id: id });
};

View File

@ -6,15 +6,15 @@ export const getSettingInfo = () => {
};
export const updateSetting = (param: Setting.SettingUpdate) => {
return http.put(`/settings`, param);
return http.post(`/settings`, param);
};
export const updatePassword = (param: Setting.PasswordUpdate) => {
return http.put(`/settings/password`, param);
return http.post(`/settings/password`, param);
};
export const handleExpired = (param: Setting.PasswordUpdate) => {
return http.put(`/settings/expired/handle`, param);
return http.post(`/settings/expired/handle`, param);
};
export const syncTime = () => {

View File

@ -135,6 +135,8 @@ export default {
status: {
running: 'running',
stopped: 'stopped',
success: 'success',
failed: 'failed',
error: 'error',
created: 'created',
restarting: 'restarting',
@ -567,6 +569,9 @@ export default {
loginAddress: 'Login address',
loginAgent: 'Login agent',
loginStatus: 'Login status',
deleteLogs: 'Clearing Logs',
resource: 'Resource',
operate: 'Operate',
detail: {
users: 'User',
hosts: 'Host',
@ -577,20 +582,11 @@ export default {
settings: 'Panel Setting',
cronjobs: 'Cronjob',
databases: 'Database',
status: ' Update status',
auth: 'User',
login: ' login',
operate: ' operate',
logout: ' logout',
post: ' create',
put: ' update',
update: ' update',
delete: ' delete',
del: 'delete',
},
status: 'status',
request: 'request',
response: 'response',
},
file: {
dir: 'folder',

View File

@ -135,6 +135,8 @@ export default {
},
status: {
running: '已启动',
success: '成功',
failed: '失败',
stopped: '已停止',
error: '失败',
created: '已创建',
@ -580,6 +582,8 @@ export default {
loginStatus: '登录状态',
system: '系统日志',
deleteLogs: '清空日志',
resource: '资源',
operate: '操作',
detail: {
users: '用户',
hosts: '主机',
@ -590,23 +594,11 @@ export default {
settings: '面板设置',
cronjobs: '计划任务',
databases: '数据库',
status: '状态修改',
auth: '用户',
post: '创建',
put: '更新',
update: '更新',
delete: '删除',
login: '登录',
backup: '备份',
recover: '恢复',
operate: '操作',
logout: '退出',
del: '删除',
},
operatoin: '操作',
status: '状态',
request: '请求',
response: '响应',
},
file: {
dir: '文件夹',

View File

@ -66,7 +66,11 @@
min-width="100"
prop="imageName"
/>
<el-table-column :label="$t('commons.table.status')" min-width="50" prop="state" fix />
<el-table-column :label="$t('commons.table.status')" min-width="50" prop="state" fix>
<template #default="{ row }">
<Status :key="row.state" :status="row.state"></Status>
</template>
</el-table-column>
<el-table-column :label="$t('container.upTime')" min-width="100" prop="runTime" fix />
<el-table-column
prop="createTime"
@ -105,6 +109,7 @@ import ContainerLogDialog from '@/views/container/container/log/index.vue';
import TerminalDialog from '@/views/container/container/terminal/index.vue';
import CodemirrorDialog from '@/components/codemirror-dialog/codemirror.vue';
import ComplexTable from '@/components/complex-table/index.vue';
import Status from '@/components/status/index.vue';
import { dateFromat } from '@/utils/util';
import { composeOperator, ContainerOperator, inspect, searchContainer } from '@/api/modules/container';
import { ElMessage, ElMessageBox } from 'element-plus';
@ -201,7 +206,7 @@ const onOperate = async (operation: string) => {
let ps = [];
for (const item of selects.value) {
const param = {
containerID: item.containerID,
name: item.name,
operation: operation,
newName: '',
};

View File

@ -48,9 +48,11 @@ const composeVisiable = ref(false);
const extensions = [javascript(), oneDark];
const path = ref();
const content = ref();
const name = ref();
const onSubmitEdit = async () => {
const param = {
name: name.value,
path: path.value,
content: content.value,
};
@ -67,6 +69,7 @@ const onSubmitEdit = async () => {
};
interface DialogProps {
name: string;
path: string;
content: string;
}
@ -74,6 +77,7 @@ interface DialogProps {
const acceptParams = (props: DialogProps): void => {
composeVisiable.value = true;
path.value = props.path;
name.value = props.name;
content.value = props.content;
};

View File

@ -156,6 +156,7 @@ const dialogEditRef = ref();
const onEdit = async (row: Container.ComposeInfo) => {
const res = await LoadFile({ path: row.path });
let params = {
name: row.name,
path: row.path,
content: res.data,
};

View File

@ -56,7 +56,11 @@
min-width="100"
prop="imageName"
/>
<el-table-column :label="$t('commons.table.status')" min-width="50" prop="state" fix />
<el-table-column :label="$t('commons.table.status')" min-width="50" prop="state" fix>
<template #default="{ row }">
<Status :key="row.state" :status="row.state"></Status>
</template>
</el-table-column>
<el-table-column :label="$t('container.upTime')" min-width="100" prop="runTime" fix />
<el-table-column
prop="createTime"
@ -92,6 +96,7 @@ import MonitorDialog from '@/views/container/container/monitor/index.vue';
import ContainerLogDialog from '@/views/container/container/log/index.vue';
import TerminalDialog from '@/views/container/container/terminal/index.vue';
import CodemirrorDialog from '@/components/codemirror-dialog/codemirror.vue';
import Status from '@/components/status/index.vue';
import Submenu from '@/views/container/index.vue';
import { reactive, onMounted, ref } from 'vue';
import { dateFromat } from '@/utils/util';
@ -220,7 +225,7 @@ const onOperate = async (operation: string) => {
let ps = [];
for (const item of selects.value) {
const param = {
containerID: item.containerID,
name: item.name,
operation: operation,
newName: '',
};
@ -259,7 +264,8 @@ const buttons = [
{
label: i18n.global.t('container.rename'),
click: (row: Container.ContainerInfo) => {
dialogReNameRef.value!.acceptParams({ containerID: row.containerID, container: row.name });
console.log(row.name);
dialogReNameRef.value!.acceptParams({ container: row.name });
},
},
{

View File

@ -39,7 +39,7 @@ import { reactive, ref } from 'vue';
const loading = ref(false);
const renameForm = reactive({
containerID: '',
name: '',
operation: 'rename',
newName: '',
});
@ -70,11 +70,12 @@ const onSubmitName = async (formEl: FormInstance | undefined) => {
};
interface DialogProps {
containerID: string;
container: string;
}
const acceptParams = (props: DialogProps): void => {
renameForm.containerID = props.containerID;
console.log(props.container);
renameForm.name = props.container;
renameForm.newName = '';
newNameVisiable.value = true;
};

View File

@ -20,9 +20,6 @@
<el-button @click="onOpenBuild">
{{ $t('container.build') }}
</el-button>
<el-button type="danger" plain :disabled="selects.length === 0" @click="batchDelete('byid')">
{{ $t('commons.button.delete') }}
</el-button>
</template>
<el-table-column type="selection" fix />
<el-table-column label="ID" show-overflow-tooltip prop="id" min-width="60" />
@ -71,11 +68,7 @@
<template #footer>
<span class="dialog-footer">
<el-button @click="deleteVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button
type="primary"
:disabled="deleteForm.deleteTags.length === 0"
@click="batchDelete('byname')"
>
<el-button type="primary" :disabled="deleteForm.deleteTags.length === 0" @click="batchDelete()">
{{ $t('commons.button.delete') }}
</el-button>
</span>
@ -156,7 +149,7 @@ const loadRepos = async () => {
const onOpenPull = () => {
let params = {
repos: repos,
repos: repos.value,
};
dialogPullRef.value!.acceptParams(params);
};
@ -169,18 +162,12 @@ const onOpenload = () => {
dialogLoadRef.value!.acceptParams();
};
const batchDelete = async (option: string) => {
let ids: Array<string> = [];
if (option === 'byid') {
selects.value.forEach((item: Container.NetworkInfo) => {
ids.push(item.id);
});
} else {
for (const item of deleteForm.deleteTags) {
ids.push(item);
}
const batchDelete = async () => {
let names: Array<string> = [];
for (const item of deleteForm.deleteTags) {
names.push(item);
}
await useDeleteData(imageRemove, { ids: ids }, 'commons.msg.delete');
await useDeleteData(imageRemove, { names: names }, 'commons.msg.delete');
deleteVisiable.value = false;
search();
};

View File

@ -16,7 +16,7 @@
prop="repoID"
>
<el-select style="width: 100%" filterable v-model="form.repoID">
<el-option v-for="item in dialogData.repos" :key="item.id" :value="item.id" :label="item.name" />
<el-option v-for="item in repos" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
</el-form-item>
<el-form-item :label="$t('container.imageName')" :rules="Rules.requiredInput" prop="targetName">
@ -49,6 +49,7 @@ import { Container } from '@/api/interface/container';
const loading = ref(false);
const tagVisiable = ref(false);
const repos = ref();
const form = reactive({
sourceID: '',
fromRepo: true,
@ -60,10 +61,6 @@ interface DialogProps {
repos: Array<Container.RepoOptions>;
sourceID: string;
}
const dialogData = ref<DialogProps>({
repos: [] as Array<Container.RepoOptions>,
sourceID: '',
});
const acceptParams = async (params: DialogProps): Promise<void> => {
tagVisiable.value = true;
@ -71,7 +68,7 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
form.sourceID = params.sourceID;
form.targetName = '';
form.fromRepo = true;
dialogData.value.repos = params.repos;
repos.value = params.repos;
};
const emit = defineEmits<{ (e: 'search'): void }>();
@ -101,7 +98,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
};
function loadDetailInfo(id: number) {
for (const item of dialogData.value.repos) {
for (const item of repos.value) {
if (item.id === id) {
return item.downloadUrl;
}

View File

@ -121,15 +121,15 @@ const search = async () => {
};
const batchDelete = async (row: Container.NetworkInfo | null) => {
let ids: Array<string> = [];
let names: Array<string> = [];
if (row === null) {
selects.value.forEach((item: Container.NetworkInfo) => {
ids.push(item.id);
names.push(item.name);
});
} else {
ids.push(row.id);
names.push(row.name);
}
await useDeleteData(deleteNetwork, { ids: ids }, 'commons.msg.delete');
await useDeleteData(deleteNetwork, { names: names }, 'commons.msg.delete');
search();
};

View File

@ -113,15 +113,15 @@ const onInspect = async (id: string) => {
};
const batchDelete = async (row: Container.VolumeInfo | null) => {
let ids: Array<string> = [];
let names: Array<string> = [];
if (row === null) {
selects.value.forEach((item: Container.VolumeInfo) => {
ids.push(item.name);
names.push(item.name);
});
} else {
ids.push(row.name);
names.push(row.name);
}
await useDeleteData(deleteVolume, { ids: ids }, 'commons.msg.delete');
await useDeleteData(deleteVolume, { names: names }, 'commons.msg.delete');
search();
};

View File

@ -17,7 +17,7 @@
<fu-table-operations :buttons="buttons" :label="$t('commons.table.operate')" fix />
</ComplexTable>
</el-card>
<el-dialog v-model="cmdVisiable" :title="$t('terminal.addHost')" width="30%">
<el-dialog v-model="cmdVisiable" :title="$t('commons.button.' + operate)" width="30%">
<el-form ref="commandInfoRef" label-width="100px" label-position="left" :model="commandInfo" :rules="rules">
<el-form-item :label="$t('commons.table.name')" prop="name">
<el-input clearable v-model="commandInfo.name" />

View File

@ -9,60 +9,32 @@
</el-button>
</template>
<el-table-column :label="$t('logs.operatoin')" fix>
<el-table-column :label="$t('logs.resource')" prop="group" fix>
<template #default="{ row }">
{{ fmtOperation(row) }}
{{ $t('logs.detail.' + row.group) }}
</template>
</el-table-column>
<el-table-column :label="$t('logs.operate')" min-width="150px" prop="detailZH" />
<el-table-column :label="$t('logs.status')" prop="status">
<template #default="{ row }">
<el-tag v-if="row.status == '200'" class="ml-2" type="success">{{ row.status }}</el-tag>
<el-tag v-if="row.status === 'Success'" class="ml-2" type="success">
{{ $t('commons.status.success') }}
</el-tag>
<div v-else>
<el-popover
placement="top-start"
:title="$t('commons.table.message')"
:width="400"
trigger="hover"
:content="row.errorMessage"
:content="row.message"
>
<template #reference>
<el-tag class="ml-2" type="warning">{{ row.status }}</el-tag>
<el-tag class="ml-2" type="danger">{{ $t('commons.status.failed') }}</el-tag>
</template>
</el-popover>
</div>
</template>
</el-table-column>
<el-table-column label="IP" prop="ip" />
<el-table-column :label="$t('logs.request')" prop="path">
<template #default="{ row }">
<div>
<el-popover :width="500" v-if="row.body" placement="left-start" trigger="click">
<div style="word-wrap: break-word; font-size: 12px; white-space: normal">
<pre class="pre">{{ fmtBody(row.body) }}</pre>
</div>
<template #reference>
<el-icon style="cursor: pointer"><warning /></el-icon>
</template>
</el-popover>
<span v-else>-</span>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('logs.response')" prop="path">
<template #default="{ row }">
<div>
<el-popover :width="500" v-if="row.resp" placement="left-start" trigger="click">
<div style="word-wrap: break-word; font-size: 12px; white-space: normal">
<pre class="pre">{{ fmtBody(row.resp) }}</pre>
</div>
<template #reference>
<el-icon style="cursor: pointer"><warning /></el-icon>
</template>
</el-popover>
<span v-else>-</span>
</div>
</template>
</el-table-column>
<el-table-column
prop="createdAt"
:label="$t('commons.table.date')"
@ -83,7 +55,6 @@ import { dateFromat } from '@/utils/util';
import { cleanLogs, getOperationLogs } from '@/api/modules/log';
import Submenu from '@/views/log/index.vue';
import { onMounted, reactive, ref } from '@vue/runtime-core';
import { Log } from '@/api/interface/log';
import i18n from '@/lang';
import { ElMessage } from 'element-plus';
@ -105,43 +76,6 @@ const search = async () => {
paginationConfig.total = res.data.total;
};
const fmtOperation = (row: Log.OperationLog) => {
if (row.method.toLocaleLowerCase() === 'post') {
if (row.source == '' && row.action == '') {
return (
i18n.global.t('logs.detail.' + row.group.toLocaleLowerCase()) +
i18n.global.t('logs.detail.' + row.method.toLocaleLowerCase())
);
}
if (row.action == '') {
return (
i18n.global.t('logs.detail.' + row.group.toLocaleLowerCase()) +
i18n.global.t('logs.detail.' + row.source.toLocaleLowerCase())
);
}
return;
}
if (row.action == '') {
return (
i18n.global.t('logs.detail.' + row.group.toLocaleLowerCase()) +
i18n.global.t('logs.detail.' + row.method.toLocaleLowerCase())
);
} else {
return (
i18n.global.t('logs.detail.' + row.group.toLocaleLowerCase()) +
i18n.global.t('logs.detail.' + row.source.toLocaleLowerCase())
);
}
};
const fmtBody = (value: string) => {
try {
return JSON.parse(value);
} catch (err) {
return value;
}
};
const onClean = async () => {
let params = {
header: i18n.global.t('logs.deleteLogs'),
@ -161,13 +95,3 @@ onMounted(() => {
search();
});
</script>
<style scoped lang="scss">
.pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
}
</style>

1
go.mod
View File

@ -29,7 +29,6 @@ require (
github.com/mholt/archiver/v4 v4.0.0-alpha.7
github.com/minio/minio-go/v7 v7.0.36
github.com/mojocn/base64Captcha v1.3.5
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/nicksnyder/go-i18n/v2 v2.1.2
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799
github.com/pkg/errors v0.9.1

3
go.sum
View File

@ -731,8 +731,6 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/nicksnyder/go-i18n/v2 v2.1.2 h1:QHYxcUJnGHBaq7XbvgunmZ2Pn0focXFqTD61CkH146c=
github.com/nicksnyder/go-i18n/v2 v2.1.2/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs=
@ -1465,7 +1463,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=