diff --git a/backend/internal/api/docs/docs.go b/backend/internal/api/docs/docs.go index 4cee56d..654da88 100644 --- a/backend/internal/api/docs/docs.go +++ b/backend/internal/api/docs/docs.go @@ -188,6 +188,160 @@ const docTemplate = `{ } } }, + "/api/v1/rdp/sessions/{session_id}/files": { + "get": { + "description": "Get file list for RDP session drive", + "tags": [ + "RDP File" + ], + "summary": "List RDP session files", + "parameters": [ + { + "type": "string", + "description": "Session ID", + "name": "session_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Directory path", + "name": "path", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/api/v1/rdp/sessions/{session_id}/files/download": { + "get": { + "description": "Download file from RDP session drive", + "consumes": [ + "application/json" + ], + "produces": [ + "application/octet-stream" + ], + "tags": [ + "RDP File" + ], + "summary": "Download file from RDP session", + "parameters": [ + { + "type": "string", + "description": "Session ID", + "name": "session_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "File path", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "file" + } + } + } + } + }, + "/api/v1/rdp/sessions/{session_id}/files/mkdir": { + "post": { + "description": "Create directory in RDP session drive", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "RDP File" + ], + "summary": "Create directory in RDP session", + "parameters": [ + { + "type": "string", + "description": "Session ID", + "name": "session_id", + "in": "path", + "required": true + }, + { + "description": "Directory creation request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.RDPMkdirRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/api/v1/rdp/sessions/{session_id}/files/upload": { + "post": { + "description": "Upload file to RDP session drive", + "consumes": [ + "multipart/form-data" + ], + "tags": [ + "RDP File" + ], + "summary": "Upload file to RDP session", + "parameters": [ + { + "type": "string", + "description": "Session ID", + "name": "session_id", + "in": "path", + "required": true + }, + { + "type": "file", + "description": "File to upload", + "name": "file", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "Target directory path", + "name": "path", + "in": "formData" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, "/asset": { "get": { "tags": [ @@ -823,17 +977,10 @@ const docTemplate = `{ }, { "type": "string", - "description": "filename", - "name": "filename", + "description": "names (comma-separated for multiple files)", + "name": "names", "in": "query", "required": true - }, - { - "type": "string", - "description": "file field name", - "name": "file", - "in": "formData", - "required": true } ], "responses": { @@ -905,7 +1052,7 @@ const docTemplate = `{ { "type": "integer", "description": "account id", - "name": "accout_id", + "name": "account_id", "in": "query" }, { @@ -953,7 +1100,7 @@ const docTemplate = `{ } }, "/file/ls/:asset_id/:account_id": { - "post": { + "get": { "tags": [ "file" ], @@ -978,6 +1125,12 @@ const docTemplate = `{ "name": "dir", "in": "query", "required": true + }, + { + "type": "boolean", + "description": "show hidden files (default: false)", + "name": "show_hidden", + "in": "query" } ], "responses": { @@ -993,7 +1146,7 @@ const docTemplate = `{ "/file/mkdir/:asset_id/:account_id": { "post": { "tags": [ - "account" + "file" ], "parameters": [ { @@ -1432,6 +1585,12 @@ const docTemplate = `{ "description": "include itself and its parent", "name": "self_parent", "in": "query" + }, + { + "type": "boolean", + "description": "return tree structure with children", + "name": "recursive", + "in": "query" } ], "responses": { @@ -2724,6 +2883,17 @@ const docTemplate = `{ } } }, + "controller.RDPMkdirRequest": { + "type": "object", + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + } + } + }, "model.AccessAuth": { "type": "object", "properties": { @@ -3090,6 +3260,12 @@ const docTemplate = `{ "authorization": { "$ref": "#/definitions/model.Map-int-model_Slice-int" }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/model.Node" + } + }, "comment": { "type": "string" }, @@ -3224,6 +3400,21 @@ const docTemplate = `{ "copy": { "type": "boolean" }, + "create_drive_path": { + "type": "boolean" + }, + "disable_download": { + "type": "boolean" + }, + "disable_upload": { + "type": "boolean" + }, + "drive_path": { + "type": "string" + }, + "enable_drive": { + "type": "boolean" + }, "paste": { "type": "boolean" } diff --git a/backend/internal/api/docs/swagger.json b/backend/internal/api/docs/swagger.json index bd63804..8d183ec 100644 --- a/backend/internal/api/docs/swagger.json +++ b/backend/internal/api/docs/swagger.json @@ -177,6 +177,160 @@ } } }, + "/api/v1/rdp/sessions/{session_id}/files": { + "get": { + "description": "Get file list for RDP session drive", + "tags": [ + "RDP File" + ], + "summary": "List RDP session files", + "parameters": [ + { + "type": "string", + "description": "Session ID", + "name": "session_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Directory path", + "name": "path", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/api/v1/rdp/sessions/{session_id}/files/download": { + "get": { + "description": "Download file from RDP session drive", + "consumes": [ + "application/json" + ], + "produces": [ + "application/octet-stream" + ], + "tags": [ + "RDP File" + ], + "summary": "Download file from RDP session", + "parameters": [ + { + "type": "string", + "description": "Session ID", + "name": "session_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "File path", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "file" + } + } + } + } + }, + "/api/v1/rdp/sessions/{session_id}/files/mkdir": { + "post": { + "description": "Create directory in RDP session drive", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "RDP File" + ], + "summary": "Create directory in RDP session", + "parameters": [ + { + "type": "string", + "description": "Session ID", + "name": "session_id", + "in": "path", + "required": true + }, + { + "description": "Directory creation request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.RDPMkdirRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/api/v1/rdp/sessions/{session_id}/files/upload": { + "post": { + "description": "Upload file to RDP session drive", + "consumes": [ + "multipart/form-data" + ], + "tags": [ + "RDP File" + ], + "summary": "Upload file to RDP session", + "parameters": [ + { + "type": "string", + "description": "Session ID", + "name": "session_id", + "in": "path", + "required": true + }, + { + "type": "file", + "description": "File to upload", + "name": "file", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "Target directory path", + "name": "path", + "in": "formData" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, "/asset": { "get": { "tags": [ @@ -812,17 +966,10 @@ }, { "type": "string", - "description": "filename", - "name": "filename", + "description": "names (comma-separated for multiple files)", + "name": "names", "in": "query", "required": true - }, - { - "type": "string", - "description": "file field name", - "name": "file", - "in": "formData", - "required": true } ], "responses": { @@ -894,7 +1041,7 @@ { "type": "integer", "description": "account id", - "name": "accout_id", + "name": "account_id", "in": "query" }, { @@ -942,7 +1089,7 @@ } }, "/file/ls/:asset_id/:account_id": { - "post": { + "get": { "tags": [ "file" ], @@ -967,6 +1114,12 @@ "name": "dir", "in": "query", "required": true + }, + { + "type": "boolean", + "description": "show hidden files (default: false)", + "name": "show_hidden", + "in": "query" } ], "responses": { @@ -982,7 +1135,7 @@ "/file/mkdir/:asset_id/:account_id": { "post": { "tags": [ - "account" + "file" ], "parameters": [ { @@ -1421,6 +1574,12 @@ "description": "include itself and its parent", "name": "self_parent", "in": "query" + }, + { + "type": "boolean", + "description": "return tree structure with children", + "name": "recursive", + "in": "query" } ], "responses": { @@ -2713,6 +2872,17 @@ } } }, + "controller.RDPMkdirRequest": { + "type": "object", + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + } + } + }, "model.AccessAuth": { "type": "object", "properties": { @@ -3079,6 +3249,12 @@ "authorization": { "$ref": "#/definitions/model.Map-int-model_Slice-int" }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/model.Node" + } + }, "comment": { "type": "string" }, @@ -3213,6 +3389,21 @@ "copy": { "type": "boolean" }, + "create_drive_path": { + "type": "boolean" + }, + "disable_download": { + "type": "boolean" + }, + "disable_upload": { + "type": "boolean" + }, + "drive_path": { + "type": "string" + }, + "enable_drive": { + "type": "boolean" + }, "paste": { "type": "boolean" } diff --git a/backend/internal/api/docs/swagger.yaml b/backend/internal/api/docs/swagger.yaml index d2fc9c6..0b616de 100644 --- a/backend/internal/api/docs/swagger.yaml +++ b/backend/internal/api/docs/swagger.yaml @@ -15,6 +15,13 @@ definitions: items: {} type: array type: object + controller.RDPMkdirRequest: + properties: + path: + type: string + required: + - path + type: object model.AccessAuth: properties: allow: @@ -257,6 +264,10 @@ definitions: type: integer authorization: $ref: '#/definitions/model.Map-int-model_Slice-int' + children: + items: + $ref: '#/definitions/model.Node' + type: array comment: type: string created_at: @@ -347,6 +358,16 @@ definitions: properties: copy: type: boolean + create_drive_path: + type: boolean + disable_download: + type: boolean + disable_upload: + type: boolean + drive_path: + type: string + enable_drive: + type: boolean paste: type: boolean type: object @@ -668,6 +689,108 @@ paths: $ref: '#/definitions/controller.HttpResponse' tags: - account + /api/v1/rdp/sessions/{session_id}/files: + get: + description: Get file list for RDP session drive + parameters: + - description: Session ID + in: path + name: session_id + required: true + type: string + - description: Directory path + in: query + name: path + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.HttpResponse' + summary: List RDP session files + tags: + - RDP File + /api/v1/rdp/sessions/{session_id}/files/download: + get: + consumes: + - application/json + description: Download file from RDP session drive + parameters: + - description: Session ID + in: path + name: session_id + required: true + type: string + - description: File path + in: query + name: path + required: true + type: string + produces: + - application/octet-stream + responses: + "200": + description: OK + schema: + type: file + summary: Download file from RDP session + tags: + - RDP File + /api/v1/rdp/sessions/{session_id}/files/mkdir: + post: + consumes: + - application/json + description: Create directory in RDP session drive + parameters: + - description: Session ID + in: path + name: session_id + required: true + type: string + - description: Directory creation request + in: body + name: request + required: true + schema: + $ref: '#/definitions/controller.RDPMkdirRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.HttpResponse' + summary: Create directory in RDP session + tags: + - RDP File + /api/v1/rdp/sessions/{session_id}/files/upload: + post: + consumes: + - multipart/form-data + description: Upload file to RDP session drive + parameters: + - description: Session ID + in: path + name: session_id + required: true + type: string + - description: File to upload + in: formData + name: file + required: true + type: file + - description: Target directory path + in: formData + name: path + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.HttpResponse' + summary: Upload file to RDP session + tags: + - RDP File /asset: get: parameters: @@ -1054,14 +1177,9 @@ paths: name: dir required: true type: string - - description: filename + - description: names (comma-separated for multiple files) in: query - name: filename - required: true - type: string - - description: file field name - in: formData - name: file + name: names required: true type: string responses: @@ -1110,7 +1228,7 @@ paths: type: integer - description: account id in: query - name: accout_id + name: account_id type: integer - description: client_ip in: query @@ -1136,7 +1254,7 @@ paths: tags: - file /file/ls/:asset_id/:account_id: - post: + get: parameters: - description: asset_id in: path @@ -1153,6 +1271,10 @@ paths: name: dir required: true type: string + - description: 'show hidden files (default: false)' + in: query + name: show_hidden + type: boolean responses: "200": description: OK @@ -1184,7 +1306,7 @@ paths: schema: $ref: '#/definitions/controller.HttpResponse' tags: - - account + - file /file/upload/:asset_id/:account_id: post: parameters: @@ -1436,6 +1558,10 @@ paths: in: query name: self_parent type: integer + - description: return tree structure with children + in: query + name: recursive + type: boolean responses: "200": description: OK diff --git a/backend/internal/api/middleware/error.go b/backend/internal/api/middleware/error.go index bafd5a0..8cd27ff 100644 --- a/backend/internal/api/middleware/error.go +++ b/backend/internal/api/middleware/error.go @@ -23,7 +23,10 @@ func (w bodyWriter) Write(b []byte) (int, error) { func Error2RespMiddleware() gin.HandlerFunc { return func(ctx *gin.Context) { - if strings.Contains(ctx.Request.URL.String(), "session/replay") { + // Skip middleware for session replay and file download endpoints + urlPath := ctx.Request.URL.String() + if strings.Contains(urlPath, "session/replay") || + strings.Contains(urlPath, "/file/download/") { ctx.Next() return } diff --git a/backend/internal/api/router/router.go b/backend/internal/api/router/router.go index 0814f35..ff1575c 100644 --- a/backend/internal/api/router/router.go +++ b/backend/internal/api/router/router.go @@ -151,5 +151,14 @@ func SetupRouter(r *gin.Engine) { preference.GET("", c.GetPreference) preference.PUT("", c.UpdatePreference) } + + // RDP file transfer routes + rdpGroup := v1.Group("/rdp") + { + rdpGroup.GET("/sessions/:session_id/files", c.RDPFileList) + rdpGroup.POST("/sessions/:session_id/files/upload", c.RDPFileUpload) + rdpGroup.GET("/sessions/:session_id/files/download", c.RDPFileDownload) + rdpGroup.POST("/sessions/:session_id/files/mkdir", c.RDPFileMkdir) + } } }