rename file and edit file via sftp

This commit is contained in:
zhenorzz 2023-05-16 17:37:19 +08:00
parent 4fcd89ca25
commit 55e6299da0
14 changed files with 387 additions and 51 deletions

View File

@ -6,8 +6,9 @@ package middleware
import ( import (
"encoding/json" "encoding/json"
"fmt"
"github.com/zhenorzz/goploy/internal/log" "github.com/zhenorzz/goploy/internal/log"
model2 "github.com/zhenorzz/goploy/internal/model" "github.com/zhenorzz/goploy/internal/model"
"github.com/zhenorzz/goploy/internal/server" "github.com/zhenorzz/goploy/internal/server"
"github.com/zhenorzz/goploy/internal/server/response" "github.com/zhenorzz/goploy/internal/server/response"
"strconv" "strconv"
@ -26,7 +27,7 @@ func AddLoginLog(gp *server.Goploy, resp server.Response) {
account = reqData.Account account = reqData.Account
} }
err := model2.LoginLog{ err := model.LoginLog{
Account: account, Account: account,
RemoteAddr: gp.Request.RemoteAddr, RemoteAddr: gp.Request.RemoteAddr,
UserAgent: gp.Request.UserAgent(), UserAgent: gp.Request.UserAgent(),
@ -56,7 +57,7 @@ func AddOPLog(gp *server.Goploy, resp server.Response) {
responseData = string(jsonBytes) responseData = string(jsonBytes)
} }
} }
err := model2.OperationLog{ err := model.OperationLog{
NamespaceID: gp.Namespace.ID, NamespaceID: gp.Namespace.ID,
UserID: gp.UserInfo.ID, UserID: gp.UserInfo.ID,
Router: gp.Request.Header.Get("Router"), Router: gp.Request.Header.Get("Router"),
@ -82,13 +83,13 @@ func AddUploadLog(gp *server.Goploy, resp server.Response) {
_ = file.Close() _ = file.Close()
} }
err := model2.SftpLog{ err := model.SftpLog{
NamespaceID: gp.Namespace.ID, NamespaceID: gp.Namespace.ID,
UserID: gp.UserInfo.ID, UserID: gp.UserInfo.ID,
ServerID: serverID, ServerID: serverID,
RemoteAddr: gp.Request.RemoteAddr, RemoteAddr: gp.Request.RemoteAddr,
UserAgent: gp.Request.UserAgent(), UserAgent: gp.Request.UserAgent(),
Type: model2.SftpLogTypeUpload, Type: model.SftpLogTypeUpload,
Path: path, Path: path,
Reason: respJson.Message, Reason: respJson.Message,
}.AddRow() }.AddRow()
@ -97,6 +98,74 @@ func AddUploadLog(gp *server.Goploy, resp server.Response) {
} }
} }
func AddEditLog(gp *server.Goploy, resp server.Response) {
var serverID int64 = 0
var path = ""
respJson := resp.(response.JSON)
if respJson.Code != response.IllegalParam {
type ReqData struct {
ServerID int64 `json:"serverId"`
File string `json:"file"`
NewName string `json:"newName"`
CurrentName string `json:"currentName"`
}
var reqData ReqData
_ = json.Unmarshal(gp.Body, &reqData)
serverID = reqData.ServerID
path = reqData.File
}
err := model.SftpLog{
NamespaceID: gp.Namespace.ID,
UserID: gp.UserInfo.ID,
ServerID: serverID,
RemoteAddr: gp.Request.RemoteAddr,
UserAgent: gp.Request.UserAgent(),
Type: model.SftpLogTypeEdit,
Path: path,
Reason: respJson.Message,
}.AddRow()
if err != nil {
log.Error(err.Error())
}
}
func AddRenameLog(gp *server.Goploy, resp server.Response) {
var serverID int64 = 0
var dir = ""
var currentName = ""
var newName = ""
respJson := resp.(response.JSON)
if respJson.Code != response.IllegalParam {
type ReqData struct {
ServerID int64 `json:"serverId"`
Dir string `json:"dir"`
NewName string `json:"newName"`
CurrentName string `json:"currentName"`
}
var reqData ReqData
_ = json.Unmarshal(gp.Body, &reqData)
serverID = reqData.ServerID
dir = reqData.Dir
currentName = reqData.CurrentName
newName = reqData.NewName
}
err := model.SftpLog{
NamespaceID: gp.Namespace.ID,
UserID: gp.UserInfo.ID,
ServerID: serverID,
RemoteAddr: gp.Request.RemoteAddr,
UserAgent: gp.Request.UserAgent(),
Type: model.SftpLogTypeRename,
Path: fmt.Sprintf("%s/%s->%s", dir, currentName, newName),
Reason: respJson.Message,
}.AddRow()
if err != nil {
log.Error(err.Error())
}
}
func AddDeleteLog(gp *server.Goploy, resp server.Response) { func AddDeleteLog(gp *server.Goploy, resp server.Response) {
var serverID int64 = 0 var serverID int64 = 0
var path = "" var path = ""
@ -112,13 +181,13 @@ func AddDeleteLog(gp *server.Goploy, resp server.Response) {
path = reqData.File path = reqData.File
} }
err := model2.SftpLog{ err := model.SftpLog{
NamespaceID: gp.Namespace.ID, NamespaceID: gp.Namespace.ID,
UserID: gp.UserInfo.ID, UserID: gp.UserInfo.ID,
ServerID: serverID, ServerID: serverID,
RemoteAddr: gp.Request.RemoteAddr, RemoteAddr: gp.Request.RemoteAddr,
UserAgent: gp.Request.UserAgent(), UserAgent: gp.Request.UserAgent(),
Type: model2.SftpLogTypeDelete, Type: model.SftpLogTypeDelete,
Path: path, Path: path,
Reason: respJson.Message, Reason: respJson.Message,
}.AddRow() }.AddRow()
@ -142,13 +211,13 @@ func AddDownloadLog(gp *server.Goploy, resp server.Response) {
path = resp.(response.SftpFile).Filename path = resp.(response.SftpFile).Filename
} }
err := model2.SftpLog{ err := model.SftpLog{
NamespaceID: gp.Namespace.ID, NamespaceID: gp.Namespace.ID,
UserID: gp.UserInfo.ID, UserID: gp.UserInfo.ID,
ServerID: serverID, ServerID: serverID,
RemoteAddr: gp.Request.RemoteAddr, RemoteAddr: gp.Request.RemoteAddr,
UserAgent: gp.Request.UserAgent(), UserAgent: gp.Request.UserAgent(),
Type: model2.SftpLogTypeDownload, Type: model.SftpLogTypeDownload,
Path: path, Path: path,
Reason: msg, Reason: msg,
}.AddRow() }.AddRow()
@ -172,13 +241,13 @@ func AddPreviewLog(gp *server.Goploy, resp server.Response) {
path = resp.(response.SftpFile).Filename path = resp.(response.SftpFile).Filename
} }
err := model2.SftpLog{ err := model.SftpLog{
NamespaceID: gp.Namespace.ID, NamespaceID: gp.Namespace.ID,
UserID: gp.UserInfo.ID, UserID: gp.UserInfo.ID,
ServerID: serverID, ServerID: serverID,
RemoteAddr: gp.Request.RemoteAddr, RemoteAddr: gp.Request.RemoteAddr,
UserAgent: gp.Request.UserAgent(), UserAgent: gp.Request.UserAgent(),
Type: model2.SftpLogTypePreview, Type: model.SftpLogTypePreview,
Path: path, Path: path,
Reason: msg, Reason: msg,
}.AddRow() }.AddRow()

View File

@ -13,7 +13,7 @@ import (
"github.com/zhenorzz/goploy/cmd/server/api/middleware" "github.com/zhenorzz/goploy/cmd/server/api/middleware"
"github.com/zhenorzz/goploy/config" "github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/log" "github.com/zhenorzz/goploy/internal/log"
model2 "github.com/zhenorzz/goploy/internal/model" "github.com/zhenorzz/goploy/internal/model"
"github.com/zhenorzz/goploy/internal/pkg" "github.com/zhenorzz/goploy/internal/pkg"
"github.com/zhenorzz/goploy/internal/server" "github.com/zhenorzz/goploy/internal/server"
"github.com/zhenorzz/goploy/internal/server/response" "github.com/zhenorzz/goploy/internal/server/response"
@ -43,6 +43,8 @@ func (s Server) Handler() []server.Route {
server.NewRoute("/server/previewFile", http.MethodGet, s.PreviewFile).Permissions(config.SFTPPreviewFile).LogFunc(middleware.AddPreviewLog), server.NewRoute("/server/previewFile", http.MethodGet, s.PreviewFile).Permissions(config.SFTPPreviewFile).LogFunc(middleware.AddPreviewLog),
server.NewRoute("/server/downloadFile", http.MethodGet, s.DownloadFile).Permissions(config.SFTPDownloadFile).LogFunc(middleware.AddDownloadLog), server.NewRoute("/server/downloadFile", http.MethodGet, s.DownloadFile).Permissions(config.SFTPDownloadFile).LogFunc(middleware.AddDownloadLog),
server.NewRoute("/server/uploadFile", http.MethodPost, s.UploadFile).Permissions(config.SFTPTransferFile).LogFunc(middleware.AddUploadLog), server.NewRoute("/server/uploadFile", http.MethodPost, s.UploadFile).Permissions(config.SFTPTransferFile).LogFunc(middleware.AddUploadLog),
server.NewRoute("/server/editFile", http.MethodPut, s.EditFile).Permissions(config.SFTPEditFile).LogFunc(middleware.AddEditLog),
server.NewRoute("/server/renameFile", http.MethodPut, s.RenameFile).Permissions(config.SFTPRenameFile).LogFunc(middleware.AddRenameLog),
server.NewRoute("/server/deleteFile", http.MethodDelete, s.DeleteFile).Permissions(config.SFTPDeleteFile).LogFunc(middleware.AddDeleteLog), server.NewRoute("/server/deleteFile", http.MethodDelete, s.DeleteFile).Permissions(config.SFTPDeleteFile).LogFunc(middleware.AddDeleteLog),
server.NewRoute("/server/transferFile", http.MethodPost, s.TransferFile).Permissions(config.SFTPUploadFile), server.NewRoute("/server/transferFile", http.MethodPost, s.TransferFile).Permissions(config.SFTPUploadFile),
server.NewRoute("/server/report", http.MethodGet, s.Report).Permissions(config.ShowServerMonitorPage), server.NewRoute("/server/report", http.MethodGet, s.Report).Permissions(config.ShowServerMonitorPage),
@ -60,25 +62,25 @@ func (s Server) Handler() []server.Route {
} }
func (Server) GetList(gp *server.Goploy) server.Response { func (Server) GetList(gp *server.Goploy) server.Response {
serverList, err := model2.Server{NamespaceID: gp.Namespace.ID}.GetList() serverList, err := model.Server{NamespaceID: gp.Namespace.ID}.GetList()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
return response.JSON{ return response.JSON{
Data: struct { Data: struct {
Servers model2.Servers `json:"list"` Servers model.Servers `json:"list"`
}{Servers: serverList}, }{Servers: serverList},
} }
} }
func (Server) GetOption(gp *server.Goploy) server.Response { func (Server) GetOption(gp *server.Goploy) server.Response {
serverList, err := model2.Server{NamespaceID: gp.Namespace.ID}.GetAll() serverList, err := model.Server{NamespaceID: gp.Namespace.ID}.GetAll()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
return response.JSON{ return response.JSON{
Data: struct { Data: struct {
Servers model2.Servers `json:"list"` Servers model.Servers `json:"list"`
}{Servers: serverList}, }{Servers: serverList},
} }
} }
@ -194,7 +196,7 @@ func (Server) Import(gp *server.Goploy) server.Response {
wg.Add(1) wg.Add(1)
go func() { go func() {
errMsg := "" errMsg := ""
srv := model2.Server{ srv := model.Server{
NamespaceID: gp.Namespace.ID, NamespaceID: gp.Namespace.ID,
} }
srv.Name = record[headerIdx["name"]] srv.Name = record[headerIdx["name"]]
@ -301,7 +303,7 @@ func (s Server) Add(gp *server.Goploy) server.Response {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
srv := model2.Server{ srv := model.Server{
NamespaceID: reqData.NamespaceID, NamespaceID: reqData.NamespaceID,
Name: reqData.Name, Name: reqData.Name,
OS: reqData.OS, OS: reqData.OS,
@ -353,7 +355,7 @@ func (s Server) Edit(gp *server.Goploy) server.Response {
if err := decodeJson(gp.Body, &reqData); err != nil { if err := decodeJson(gp.Body, &reqData); err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
srv := model2.Server{ srv := model.Server{
ID: reqData.ID, ID: reqData.ID,
NamespaceID: reqData.NamespaceID, NamespaceID: reqData.NamespaceID,
Name: reqData.Name, Name: reqData.Name,
@ -388,7 +390,7 @@ func (Server) Toggle(gp *server.Goploy) server.Response {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
if err := (model2.Server{ID: reqData.ID, State: reqData.State}).ToggleRow(); err != nil { if err := (model.Server{ID: reqData.ID, State: reqData.State}).ToggleRow(); err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
return response.JSON{} return response.JSON{}
@ -415,7 +417,7 @@ func (Server) InstallAgent(gp *server.Goploy) server.Response {
for _, id := range reqData.IDs { for _, id := range reqData.IDs {
go func(id int64) { go func(id int64) {
srv, err := (model2.Server{ID: id}).GetData() srv, err := (model.Server{ID: id}).GetData()
if err != nil { if err != nil {
log.Error(fmt.Sprintf("Error on %d server, %s", id, err.Error())) log.Error(fmt.Sprintf("Error on %d server, %s", id, err.Error()))
return return
@ -471,7 +473,7 @@ func (Server) PreviewFile(gp *server.Goploy) server.Response {
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: "invalid server id"} return response.JSON{Code: response.Error, Message: "invalid server id"}
} }
srv, err := (model2.Server{ID: id}).GetData() srv, err := (model.Server{ID: id}).GetData()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
@ -488,7 +490,7 @@ func (Server) DownloadFile(gp *server.Goploy) server.Response {
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: "invalid server id"} return response.JSON{Code: response.Error, Message: "invalid server id"}
} }
srv, err := (model2.Server{ID: id}).GetData() srv, err := (model.Server{ID: id}).GetData()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
@ -516,7 +518,7 @@ func (Server) UploadFile(gp *server.Goploy) server.Response {
} }
defer file.Close() defer file.Close()
srv, err := (model2.Server{ID: reqData.ID}).GetData() srv, err := (model.Server{ID: reqData.ID}).GetData()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
@ -547,6 +549,80 @@ func (Server) UploadFile(gp *server.Goploy) server.Response {
return response.JSON{} return response.JSON{}
} }
func (Server) EditFile(gp *server.Goploy) server.Response {
type ReqData struct {
ServerID int64 `json:"serverId" validate:"gt=0"`
File string `json:"file" validate:"required"`
Content string `json:"content" validate:"required"`
}
var reqData ReqData
if err := decodeJson(gp.Body, &reqData); err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
srv, err := (model.Server{ID: reqData.ServerID}).GetData()
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
client, err := srv.ToSSHConfig().Dial()
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
defer client.Close()
sftpClient, err := sftp.NewClient(client)
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
defer sftpClient.Close()
remoteFile, err := sftpClient.Create(reqData.File)
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
_, err = remoteFile.Write([]byte(reqData.Content))
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
return response.JSON{}
}
func (Server) RenameFile(gp *server.Goploy) server.Response {
type ReqData struct {
ServerID int64 `json:"serverId" validate:"gt=0"`
Dir string `json:"dir" validate:"required"`
NewName string `json:"newName" validate:"required"`
CurrentName string `json:"currentName" validate:"required"`
}
var reqData ReqData
if err := decodeJson(gp.Body, &reqData); err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
srv, err := (model.Server{ID: reqData.ServerID}).GetData()
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
client, err := srv.ToSSHConfig().Dial()
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
defer client.Close()
sftpClient, err := sftp.NewClient(client)
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
defer sftpClient.Close()
err = sftpClient.Rename(path.Join(reqData.Dir, reqData.CurrentName), path.Join(reqData.Dir, reqData.NewName))
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
return response.JSON{}
}
func (Server) DeleteFile(gp *server.Goploy) server.Response { func (Server) DeleteFile(gp *server.Goploy) server.Response {
type ReqData struct { type ReqData struct {
File string `json:"file" validate:"required"` File string `json:"file" validate:"required"`
@ -557,7 +633,7 @@ func (Server) DeleteFile(gp *server.Goploy) server.Response {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
srv, err := (model2.Server{ID: reqData.ServerID}).GetData() srv, err := (model.Server{ID: reqData.ServerID}).GetData()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
@ -603,7 +679,7 @@ func (Server) TransferFile(gp *server.Goploy) server.Response {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
sourceServer, err := (model2.Server{ID: reqData.SourceServerID}).GetData() sourceServer, err := (model.Server{ID: reqData.SourceServerID}).GetData()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
@ -621,7 +697,7 @@ func (Server) TransferFile(gp *server.Goploy) server.Response {
defer sftpClient.Close() defer sftpClient.Close()
for _, destServerID := range reqData.DestServerIDs { for _, destServerID := range reqData.DestServerIDs {
destServer, err := (model2.Server{ID: destServerID}).GetData() destServer, err := (model.Server{ID: destServerID}).GetData()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
@ -734,7 +810,7 @@ func (Server) Report(gp *server.Goploy) server.Response {
if len(datetimeRange) != 2 { if len(datetimeRange) != 2 {
return response.JSON{Code: response.Error, Message: "invalid datetime range"} return response.JSON{Code: response.Error, Message: "invalid datetime range"}
} }
serverAgentLogs, err := (model2.ServerAgentLog{ServerID: reqData.ServerID, Type: reqData.Type}).GetListBetweenTime(datetimeRange[0], datetimeRange[1]) serverAgentLogs, err := (model.ServerAgentLog{ServerID: reqData.ServerID, Type: reqData.Type}).GetListBetweenTime(datetimeRange[0], datetimeRange[1])
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
@ -753,7 +829,7 @@ func (Server) Report(gp *server.Goploy) server.Response {
flagMap[serverAgentLog.Item] = Flag{Count: flagMap[serverAgentLog.Item].Count + 1} flagMap[serverAgentLog.Item] = Flag{Count: flagMap[serverAgentLog.Item].Count + 1}
} }
serverAgentMap := map[string]model2.ServerAgentLogs{} serverAgentMap := map[string]model.ServerAgentLogs{}
for _, serverAgentLog := range serverAgentLogs { for _, serverAgentLog := range serverAgentLogs {
flagMap[serverAgentLog.Item] = Flag{ flagMap[serverAgentLog.Item] = Flag{
Count: flagMap[serverAgentLog.Item].Count, Count: flagMap[serverAgentLog.Item].Count,
@ -769,20 +845,20 @@ func (Server) Report(gp *server.Goploy) server.Response {
return response.JSON{ return response.JSON{
Data: struct { Data: struct {
ServerAgentMap map[string]model2.ServerAgentLogs `json:"map"` ServerAgentMap map[string]model.ServerAgentLogs `json:"map"`
}{ServerAgentMap: serverAgentMap}, }{ServerAgentMap: serverAgentMap},
} }
} }
func (Server) GetAllMonitor(gp *server.Goploy) server.Response { func (Server) GetAllMonitor(gp *server.Goploy) server.Response {
serverID, err := strconv.ParseInt(gp.URLQuery.Get("serverId"), 10, 64) serverID, err := strconv.ParseInt(gp.URLQuery.Get("serverId"), 10, 64)
serverMonitorList, err := model2.ServerMonitor{ServerID: serverID}.GetAll() serverMonitorList, err := model.ServerMonitor{ServerID: serverID}.GetAll()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
return response.JSON{ return response.JSON{
Data: struct { Data: struct {
List model2.ServerMonitors `json:"list"` List model.ServerMonitors `json:"list"`
}{List: serverMonitorList}, }{List: serverMonitorList},
} }
} }
@ -808,7 +884,7 @@ func (s Server) AddMonitor(gp *server.Goploy) server.Response {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
id, err := model2.ServerMonitor{ id, err := model.ServerMonitor{
ServerID: reqData.ServerID, ServerID: reqData.ServerID,
Item: reqData.Item, Item: reqData.Item,
Formula: reqData.Formula, Formula: reqData.Formula,
@ -855,7 +931,7 @@ func (s Server) EditMonitor(gp *server.Goploy) server.Response {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
err := model2.ServerMonitor{ err := model.ServerMonitor{
ID: reqData.ID, ID: reqData.ID,
Item: reqData.Item, Item: reqData.Item,
Formula: reqData.Formula, Formula: reqData.Formula,
@ -887,7 +963,7 @@ func (s Server) DeleteMonitor(gp *server.Goploy) server.Response {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
err := model2.ServerMonitor{ err := model.ServerMonitor{
ID: reqData.ID, ID: reqData.ID,
}.DeleteRow() }.DeleteRow()
@ -899,13 +975,13 @@ func (s Server) DeleteMonitor(gp *server.Goploy) server.Response {
} }
func (Server) GetProcessList(gp *server.Goploy) server.Response { func (Server) GetProcessList(gp *server.Goploy) server.Response {
list, err := model2.ServerProcess{NamespaceID: gp.Namespace.ID}.GetList() list, err := model.ServerProcess{NamespaceID: gp.Namespace.ID}.GetList()
if err != nil { if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
return response.JSON{ return response.JSON{
Data: struct { Data: struct {
List model2.ServerProcesses `json:"list"` List model.ServerProcesses `json:"list"`
}{List: list}, }{List: list},
} }
} }
@ -921,7 +997,7 @@ func (Server) AddProcess(gp *server.Goploy) server.Response {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
id, err := model2.ServerProcess{ id, err := model.ServerProcess{
NamespaceID: gp.Namespace.ID, NamespaceID: gp.Namespace.ID,
Name: reqData.Name, Name: reqData.Name,
Items: reqData.Items, Items: reqData.Items,
@ -948,7 +1024,7 @@ func (Server) EditProcess(gp *server.Goploy) server.Response {
if err := decodeJson(gp.Body, &reqData); err != nil { if err := decodeJson(gp.Body, &reqData); err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
err := model2.ServerProcess{ err := model.ServerProcess{
ID: reqData.ID, ID: reqData.ID,
Name: reqData.Name, Name: reqData.Name,
Items: reqData.Items, Items: reqData.Items,
@ -969,7 +1045,7 @@ func (Server) DeleteProcess(gp *server.Goploy) server.Response {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
if err := (model2.ServerProcess{ID: reqData.ID}).DeleteRow(); err != nil { if err := (model.ServerProcess{ID: reqData.ID}).DeleteRow(); err != nil {
return response.JSON{Code: response.Error, Message: err.Error()} return response.JSON{Code: response.Error, Message: err.Error()}
} }
@ -1001,18 +1077,18 @@ func (Server) ExecProcess(gp *server.Goploy) server.Response {
return response.JSON{Data: respData} return response.JSON{Data: respData}
} }
serverProcess, err := model2.ServerProcess{ID: reqData.ID}.GetData() serverProcess, err := model.ServerProcess{ID: reqData.ID}.GetData()
if err != nil { if err != nil {
respData.Stderr = err.Error() respData.Stderr = err.Error()
return response.JSON{Data: respData} return response.JSON{Data: respData}
} }
srv, err := (model2.Server{ID: reqData.ServerID}).GetData() srv, err := (model.Server{ID: reqData.ServerID}).GetData()
if err != nil { if err != nil {
respData.Stderr = err.Error() respData.Stderr = err.Error()
return response.JSON{Data: respData} return response.JSON{Data: respData}
} }
var processItems model2.ServerProcessItems var processItems model.ServerProcessItems
if err := json.Unmarshal([]byte(serverProcess.Items), &processItems); err != nil { if err := json.Unmarshal([]byte(serverProcess.Items), &processItems); err != nil {
respData.Stderr = err.Error() respData.Stderr = err.Error()
return response.JSON{Data: respData} return response.JSON{Data: respData}
@ -1080,7 +1156,7 @@ func (Server) ExecScript(gp *server.Goploy) server.Response {
ServerID: serverId, ServerID: serverId,
} }
srv, err := (model2.Server{ID: serverId}).GetData() srv, err := (model.Server{ID: serverId}).GetData()
if err != nil { if err != nil {
serverResp.ExecRes = false serverResp.ExecRes = false
serverResp.Stderr = err.Error() serverResp.Stderr = err.Error()

View File

@ -82,4 +82,6 @@ const (
SFTPTransferFile = 75 SFTPTransferFile = 75
SFTPDeleteFile = 76 SFTPDeleteFile = 76
ShowServerScriptPage = 77 ShowServerScriptPage = 77
SFTPRenameFile = 78
SFTPEditFile = 79
) )

View File

@ -2,4 +2,7 @@ ALTER TABLE monitor ADD success_script text;
ALTER TABLE monitor ADD fail_script text; ALTER TABLE monitor ADD fail_script text;
ALTER TABLE monitor ADD success_server_id INT ( 10 ) UNSIGNED NOT NULL DEFAULT 0; ALTER TABLE monitor ADD success_server_id INT ( 10 ) UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE monitor ADD fail_server_id INT ( 10 ) UNSIGNED NOT NULL DEFAULT 0; ALTER TABLE monitor ADD fail_server_id INT ( 10 ) UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE project ADD tag VARCHAR ( 6382 ) NOT NULL DEFAULT ''; ALTER TABLE project ADD tag VARCHAR ( 6382 ) NOT NULL DEFAULT '';
INSERT IGNORE INTO `permission` (`id`, `pid`, `name`, `sort`, `description`) VALUES (78, 23, 'SFTPRenameFile', 0, '');
INSERT IGNORE INTO `permission` (`id`, `pid`, `name`, `sort`, `description`) VALUES (79, 23, 'SFTPEditFile', 0, '');

View File

@ -473,6 +473,8 @@ INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALU
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (75, 23, 'SFTPTransferFile', 0, ''); INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (75, 23, 'SFTPTransferFile', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (76, 23, 'SFTPDeleteFile', 0, ''); INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (76, 23, 'SFTPDeleteFile', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (77, 23, 'ShowServerScriptPage', 0, ''); INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (77, 23, 'ShowServerScriptPage', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (78, 23, 'SFTPRenameFile', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (79, 23, 'SFTPEditFile', 0, '');
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 13); INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 13);
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 14); INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 14);
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 15); INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 15);

View File

@ -32,6 +32,8 @@ const (
SftpLogTypeUpload = "UPLOAD" SftpLogTypeUpload = "UPLOAD"
SftpLogTypeRead = "READ" SftpLogTypeRead = "READ"
SftpLogTypePreview = "PREVIEW" SftpLogTypePreview = "PREVIEW"
SftpLogTypeRename = "RENAME"
SftpLogTypeEdit = "EDIT"
SftpLogTypeDelete = "DELETE" SftpLogTypeDelete = "DELETE"
) )

1
web/components.d.ts vendored
View File

@ -25,6 +25,7 @@ declare module '@vue/runtime-core' {
ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm'] ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon'] ElIcon: typeof import('element-plus/es')['ElIcon']

View File

@ -394,6 +394,37 @@ export class ServerExecProcess extends Request {
} }
} }
export class ServerRenameFile extends Request {
readonly url = '/server/renameFile'
readonly method = 'put'
readonly timeout = 0
public param: {
serverId: number
dir: string
currentName: string
newName: string
}
constructor(param: ServerRenameFile['param']) {
super()
this.param = param
}
}
export class ServerEditFile extends Request {
readonly url = '/server/editFile'
readonly method = 'put'
readonly timeout = 0
public param: {
serverId: number
file: string
content: string
}
constructor(param: ServerEditFile['param']) {
super()
this.param = param
}
}
export class ServerDeleteFile extends Request { export class ServerDeleteFile extends Request {
readonly url = '/server/deleteFile' readonly url = '/server/deleteFile'
readonly method = 'delete' readonly method = 'delete'
@ -407,6 +438,7 @@ export class ServerDeleteFile extends Request {
this.param = param this.param = param
} }
} }
export class ServerTransferFile extends Request { export class ServerTransferFile extends Request {
readonly url = '/server/transferFile' readonly url = '/server/transferFile'
readonly method = 'post' readonly method = 'post'

View File

@ -90,6 +90,7 @@
"edit": "Edit", "edit": "Edit",
"copy": "Copy", "copy": "Copy",
"transfer": "Transfer", "transfer": "Transfer",
"rename": "Rename",
"approve": "Approve", "approve": "Approve",
"deny": "Deny", "deny": "Deny",
"preview": "Preview", "preview": "Preview",
@ -305,7 +306,8 @@
"advance": "Advanced setting", "advance": "Advanced setting",
"transferFile": "Transfer file", "transferFile": "Transfer file",
"sftpFileCount": "items", "sftpFileCount": "items",
"saveTemplate": "Save template" "saveTemplate": "Save template",
"renameTips": "rename {name}"
}, },
"monitorPage": { "monitorPage": {
"defaultServer": "Follow Host", "defaultServer": "Follow Host",

View File

@ -90,6 +90,7 @@
"edit": "编辑", "edit": "编辑",
"copy": "复制", "copy": "复制",
"transfer": "传输", "transfer": "传输",
"rename": "重命名",
"approve": "同意", "approve": "同意",
"deny": "拒绝", "deny": "拒绝",
"preview": "预览", "preview": "预览",
@ -288,7 +289,8 @@
"advance": "高级选项", "advance": "高级选项",
"transferFile": "传输文件", "transferFile": "传输文件",
"sftpFileCount": "个项目", "sftpFileCount": "个项目",
"saveTemplate": "保存模板" "saveTemplate": "保存模板",
"renameTips": "重命名{name}"
}, },
"monitorPage": { "monitorPage": {
"scriptMode": "脚本类型", "scriptMode": "脚本类型",

View File

@ -76,4 +76,6 @@ export default Object.freeze({
SFTPTransferFile: 75, SFTPTransferFile: 75,
SFTPDeleteFile: 76, SFTPDeleteFile: 76,
ShowServerScriptPage: 77, ShowServerScriptPage: 77,
SFTPRenameFile: 78,
SFTPEditFile: 79,
}) })

View File

@ -287,7 +287,7 @@
<VAceEditor <VAceEditor
v-model:value="formProps.script" v-model:value="formProps.script"
lang="sh" lang="sh"
theme="github" :theme="isDark ? 'one_dark' : 'github'"
style="height: 360px; width: 100%" style="height: 360px; width: 100%"
:options="{ newLineMode: 'unix' }" :options="{ newLineMode: 'unix' }"
/> />

View File

@ -157,6 +157,13 @@
{{ $t('preview') }} {{ $t('preview') }}
</Link> </Link>
</el-dropdown-item> </el-dropdown-item>
<DropdownItem
v-if="selectedFile['isDir'] === false"
:permissions="[permission.SFTPEditFile]"
@click="editFile"
>
{{ $t('edit') }}
</DropdownItem>
<el-dropdown-item <el-dropdown-item
v-if="selectedFile['isDir'] === false" v-if="selectedFile['isDir'] === false"
style="padding: 0" style="padding: 0"
@ -171,6 +178,12 @@
{{ $t('download') }} {{ $t('download') }}
</Link> </Link>
</el-dropdown-item> </el-dropdown-item>
<DropdownItem
:permissions="[permission.SFTPRenameFile]"
@click="rename"
>
{{ $t('rename') }}
</DropdownItem>
<DropdownItem <DropdownItem
v-if="selectedFile['isDir'] === false" v-if="selectedFile['isDir'] === false"
:permissions="[permission.SFTPDeleteFile]" :permissions="[permission.SFTPDeleteFile]"
@ -223,14 +236,18 @@ import path from 'path-browserify'
import { humanSize, parseTime } from '@/utils' import { humanSize, parseTime } from '@/utils'
import { NamespaceKey, getNamespaceId } from '@/utils/namespace' import { NamespaceKey, getNamespaceId } from '@/utils/namespace'
import type { ElUpload } from 'element-plus' import type { ElUpload } from 'element-plus'
import { ServerData, ServerSFTPFile, ServerDeleteFile } from '@/api/server' import {
ServerData,
ServerSFTPFile,
ServerRenameFile,
ServerDeleteFile,
} from '@/api/server'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { HttpResponse } from '@/api/types' import { HttpResponse } from '@/api/types'
import { ref, PropType, computed, onBeforeUnmount } from 'vue' import { ref, PropType, computed, onBeforeUnmount } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
const { t } = useI18n() const { t } = useI18n()
const emit = defineEmits(['dir-change', 'edit-file', 'transfer-file'])
const emit = defineEmits(['dir-change', 'transfer-file'])
const props = defineProps({ const props = defineProps({
uuid: { uuid: {
type: Number, type: Number,
@ -443,6 +460,43 @@ function deleteFile() {
.catch() .catch()
} }
function editFile() {
emit('edit-file', selectedFile.value)
}
function rename() {
ElMessageBox.prompt(
t('serverPage.renameTips', { name: selectedFile.value.name }),
t('rename'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
inputPattern: /.+/,
inputErrorMessage: 'Name required',
}
)
.then(({ value }) => {
fileListLoading.value = true
new ServerRenameFile({
serverId: serverId.value,
dir: dir.value,
currentName: selectedFile.value.name,
newName: value,
})
.request()
.then(() => {
const pos = fileList.value.findIndex(
(item) => item.name === selectedFile.value.name
)
fileList.value[pos].name = value
})
.finally(() => {
fileListLoading.value = false
})
})
.catch()
}
function transferFile() { function transferFile() {
emit('transfer-file', selectedFile.value) emit('transfer-file', selectedFile.value)
} }

View File

@ -56,6 +56,7 @@
:key="item.uuid" :key="item.uuid"
:server="item.server" :server="item.server"
@dir-change="handleDirChange" @dir-change="handleDirChange"
@edit-file="handleEditFile"
@transfer-file="handleTransferFile" @transfer-file="handleTransferFile"
></explorer> ></explorer>
<el-dialog <el-dialog
@ -130,6 +131,36 @@
</el-button> </el-button>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog
v-model="fileEditorDialogVisible"
:fullscreen="$store.state.app.device === 'mobile'"
:title="selectedFile['name']"
:close-on-click-modal="false"
>
<VAceEditor
ref="fileEditor"
v-model:value="fileContent"
v-loading="formProps.disabled"
:lang="getModeForPath(selectedFile['name']).name"
:theme="isDark ? 'one_dark' : 'github'"
style="height: 360px; width: 100%"
/>
<template #footer>
<el-button
:disabled="formProps.disabled"
@click="fileEditorDialogVisible = false"
>
{{ $t('cancel') }}
</el-button>
<el-button
type="primary"
:loading="formProps.disabled"
@click="editFile"
>
{{ $t('confirm') }}
</el-button>
</template>
</el-dialog>
</el-row> </el-row>
</template> </template>
@ -141,20 +172,36 @@ import explorer from './explorer.vue'
import path from 'path-browserify' import path from 'path-browserify'
import type { ElForm } from 'element-plus' import type { ElForm } from 'element-plus'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { VAceEditor } from 'vue3-ace-editor'
import * as ace from 'ace-builds/src-noconflict/ace'
import { getModeForPath } from 'ace-builds/src-noconflict/ext-modelist'
import { NamespaceKey, getNamespaceId } from '@/utils/namespace'
import { import {
ServerOption, ServerOption,
ServerData, ServerData,
ServerSFTPFile, ServerSFTPFile,
ServerEditFile,
ServerTransferFile, ServerTransferFile,
} from '@/api/server' } from '@/api/server'
import { useDark } from '@vueuse/core'
import { ref } from 'vue' import { ref } from 'vue'
interface sftp { interface sftp {
uuid: number uuid: number
server: ServerData server: ServerData
dir: string dir: string
} }
ace.config.set(
'basePath',
'https://cdn.jsdelivr.net/npm/ace-builds@' + ace.version + '/src-noconflict/'
)
ace.config.set(
'themePath',
'https://cdn.jsdelivr.net/npm/ace-builds@' + ace.version + '/src-noconflict/'
)
const isDark = useDark()
const currentUUID = ref(0) const currentUUID = ref(0)
const transferFileDialogVisible = ref(false) const transferFileDialogVisible = ref(false)
const fileEditorDialogVisible = ref(false)
const serverOption = ref<ServerOption['datagram']['list']>([]) const serverOption = ref<ServerOption['datagram']['list']>([])
const serverId = ref('') const serverId = ref('')
const serverList = ref<sftp[]>([]) const serverList = ref<sftp[]>([])
@ -171,6 +218,8 @@ const formProps = ref({
errorLog: '', errorLog: '',
}) })
const fileContent = ref('')
getServerOption() getServerOption()
function getServerOption() { function getServerOption() {
@ -212,6 +261,46 @@ function handleDirChange(dir: string) {
selectedSFTP.value.dir = dir selectedSFTP.value.dir = dir
} }
function handleEditFile(file: ServerSFTPFile) {
selectedFile.value = file
fileContent.value = ''
fileEditorDialogVisible.value = true
formProps.value.disabled = true
const f = path.normalize(`${selectedSFTP.value.dir}/${file.name}`)
fetch(
`${
import.meta.env.VITE_APP_BASE_API
}/server/previewFile?${NamespaceKey}=${getNamespaceId()}&id=${
selectedSFTP.value.server.id
}&file=${f}`
)
.then((response) => response.text())
.then((content) => {
fileContent.value = content
})
.finally(() => {
formProps.value.disabled = false
})
}
function editFile() {
formProps.value.disabled = true
new ServerEditFile({
serverId: selectedSFTP.value.server.id,
file: path.normalize(
`${selectedSFTP.value.dir}/${selectedFile.value.name}`
),
content: fileContent.value,
})
.request()
.then(() => {
ElMessage.success('Success')
})
.finally(() => {
formProps.value.disabled = false
})
}
function handleTransferFile(file: ServerSFTPFile) { function handleTransferFile(file: ServerSFTPFile) {
formData.value.destDir = selectedSFTP.value.dir formData.value.destDir = selectedSFTP.value.dir
formData.value.sourceFile = path.normalize( formData.value.sourceFile = path.normalize(