This commit is contained in:
@@ -265,6 +265,9 @@ func main() {
|
|||||||
scriptsGroup.POST("/folder", scriptManageHandlers.CreateFolder)
|
scriptsGroup.POST("/folder", scriptManageHandlers.CreateFolder)
|
||||||
scriptsGroup.DELETE("/folder", scriptManageHandlers.DeleteFolder)
|
scriptsGroup.DELETE("/folder", scriptManageHandlers.DeleteFolder)
|
||||||
|
|
||||||
|
// Rename script or folder
|
||||||
|
scriptsGroup.POST("/rename", scriptManageHandlers.Rename)
|
||||||
|
|
||||||
// Get script by path
|
// Get script by path
|
||||||
scriptsGroup.GET("/by-path", scriptManageHandlers.GetScriptByPath)
|
scriptsGroup.GET("/by-path", scriptManageHandlers.GetScriptByPath)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2018,6 +2018,73 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/scripts/rename": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Renames a single script or all scripts under a folder prefix",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"scripts"
|
||||||
|
],
|
||||||
|
"summary": "Rename script or folder",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Rename request",
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/internal_handlers.RenameRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Rename result with count of renamed scripts",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "Conflict",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/scripts/run": {
|
"/scripts/run": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -2798,6 +2865,23 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"internal_handlers.RenameRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"new_path",
|
||||||
|
"old_path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"new_path": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "deploy/nginx-v2"
|
||||||
|
},
|
||||||
|
"old_path": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "deploy/nginx"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"internal_handlers.RunScriptIn": {
|
"internal_handlers.RunScriptIn": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -2007,6 +2007,73 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/scripts/rename": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Renames a single script or all scripts under a folder prefix",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"scripts"
|
||||||
|
],
|
||||||
|
"summary": "Rename script or folder",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Rename request",
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/internal_handlers.RenameRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Rename result with count of renamed scripts",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "Conflict",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/scripts/run": {
|
"/scripts/run": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -2787,6 +2854,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"internal_handlers.RenameRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"new_path",
|
||||||
|
"old_path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"new_path": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "deploy/nginx-v2"
|
||||||
|
},
|
||||||
|
"old_path": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "deploy/nginx"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"internal_handlers.RunScriptIn": {
|
"internal_handlers.RunScriptIn": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -477,6 +477,18 @@ definitions:
|
|||||||
client_cert:
|
client_cert:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
internal_handlers.RenameRequest:
|
||||||
|
properties:
|
||||||
|
new_path:
|
||||||
|
example: deploy/nginx-v2
|
||||||
|
type: string
|
||||||
|
old_path:
|
||||||
|
example: deploy/nginx
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- new_path
|
||||||
|
- old_path
|
||||||
|
type: object
|
||||||
internal_handlers.RunScriptIn:
|
internal_handlers.RunScriptIn:
|
||||||
properties:
|
properties:
|
||||||
agent_id:
|
agent_id:
|
||||||
@@ -1809,6 +1821,49 @@ paths:
|
|||||||
summary: Update interpreter
|
summary: Update interpreter
|
||||||
tags:
|
tags:
|
||||||
- scripts
|
- scripts
|
||||||
|
/scripts/rename:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Renames a single script or all scripts under a folder prefix
|
||||||
|
parameters:
|
||||||
|
- description: Rename request
|
||||||
|
in: body
|
||||||
|
name: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/internal_handlers.RenameRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Rename result with count of renamed scripts
|
||||||
|
schema:
|
||||||
|
additionalProperties: true
|
||||||
|
type: object
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"409":
|
||||||
|
description: Conflict
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Rename script or folder
|
||||||
|
tags:
|
||||||
|
- scripts
|
||||||
/scripts/run:
|
/scripts/run:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|||||||
@@ -280,6 +280,96 @@ type DeleteFolderRequest struct {
|
|||||||
Path string `json:"path" binding:"required" example:"deploy/nginx" description:"Folder path to delete"`
|
Path string `json:"path" binding:"required" example:"deploy/nginx" description:"Folder path to delete"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RenameRequest is the request body for renaming a script or folder.
|
||||||
|
type RenameRequest struct {
|
||||||
|
OldPath string `json:"old_path" binding:"required" example:"deploy/nginx" description:"Current path"`
|
||||||
|
NewPath string `json:"new_path" binding:"required" example:"deploy/nginx-v2" description:"New path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename renames a script or all scripts under a folder path.
|
||||||
|
// @Summary Rename script or folder
|
||||||
|
// @Description Renames a single script or all scripts under a folder prefix
|
||||||
|
// @Tags scripts
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body RenameRequest true "Rename request"
|
||||||
|
// @Success 200 {object} map[string]interface{} "Rename result with count of renamed scripts"
|
||||||
|
// @Failure 400 {object} map[string]string
|
||||||
|
// @Failure 404 {object} map[string]string
|
||||||
|
// @Failure 409 {object} map[string]string
|
||||||
|
// @Security Bearer
|
||||||
|
// @Router /scripts/rename [post]
|
||||||
|
func (sh *ScriptHandlersGroup) Rename(c *gin.Context) {
|
||||||
|
var req RenameRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate new path
|
||||||
|
if err := validateScriptPath(req.NewPath); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("invalid new path: %v", err)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate old path
|
||||||
|
if err := validateScriptPath(req.OldPath); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("invalid old path: %v", err)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all scripts
|
||||||
|
allScripts, err := sh.svc.Repo.ListScripts()
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list scripts"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find scripts to rename: exact match or folder prefix
|
||||||
|
prefix := req.OldPath + "/"
|
||||||
|
var toRename []repository.Script
|
||||||
|
for _, script := range allScripts {
|
||||||
|
if script.Path == req.OldPath || strings.HasPrefix(script.Path, prefix) {
|
||||||
|
toRename = append(toRename, script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(toRename) == 0 {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": "no scripts found with this path"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename each script
|
||||||
|
renamedCount := 0
|
||||||
|
for _, script := range toRename {
|
||||||
|
newPath := req.NewPath + strings.TrimPrefix(script.Path, req.OldPath)
|
||||||
|
|
||||||
|
// Check if new path already exists (excluding the scripts we're renaming)
|
||||||
|
for _, existing := range allScripts {
|
||||||
|
if existing.ID != script.ID && existing.Path == newPath {
|
||||||
|
c.JSON(http.StatusConflict, gin.H{"error": fmt.Sprintf("path '%s' already exists", newPath)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := sh.svc.Repo.UpdateScript(script.ID, repository.ScriptUpdate{
|
||||||
|
Path: &newPath,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to rename %s: %v", script.Path, err)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
renamedCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"message": "renamed",
|
||||||
|
"old_path": req.OldPath,
|
||||||
|
"new_path": req.NewPath,
|
||||||
|
"renamed_count": renamedCount,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// CreateFolder creates a virtual folder in the script tree.
|
// CreateFolder creates a virtual folder in the script tree.
|
||||||
// @Summary Create folder
|
// @Summary Create folder
|
||||||
// @Description Creates a virtual folder by creating a placeholder script with the folder path
|
// @Description Creates a virtual folder by creating a placeholder script with the folder path
|
||||||
|
|||||||
Reference in New Issue
Block a user