feat(api): expand update_storage to support name, mount_path, host_path, content fields
Add support for updating additional storage fields via the API while enforcing read-only restrictions for storages managed by docker-compose or service definitions (only is_preview_suffix_enabled remains editable for those).
This commit is contained in:
parent
0488a188a0
commit
9d745fca75
3 changed files with 79 additions and 5 deletions
|
|
@ -4005,7 +4005,7 @@ public function storages(Request $request)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
requestBody: new OA\RequestBody(
|
requestBody: new OA\RequestBody(
|
||||||
description: 'Storage updated.',
|
description: 'Storage updated. For read-only storages (from docker-compose or services), only is_preview_suffix_enabled can be updated.',
|
||||||
required: true,
|
required: true,
|
||||||
content: [
|
content: [
|
||||||
new OA\MediaType(
|
new OA\MediaType(
|
||||||
|
|
@ -4017,6 +4017,10 @@ public function storages(Request $request)
|
||||||
'id' => ['type' => 'integer', 'description' => 'The ID of the storage.'],
|
'id' => ['type' => 'integer', 'description' => 'The ID of the storage.'],
|
||||||
'type' => ['type' => 'string', 'enum' => ['persistent', 'file'], 'description' => 'The type of storage: persistent or file.'],
|
'type' => ['type' => 'string', 'enum' => ['persistent', 'file'], 'description' => 'The type of storage: persistent or file.'],
|
||||||
'is_preview_suffix_enabled' => ['type' => 'boolean', 'description' => 'Whether to add -pr-N suffix for preview deployments.'],
|
'is_preview_suffix_enabled' => ['type' => 'boolean', 'description' => 'Whether to add -pr-N suffix for preview deployments.'],
|
||||||
|
'name' => ['type' => 'string', 'description' => 'The volume name (persistent only, not allowed for read-only storages).'],
|
||||||
|
'mount_path' => ['type' => 'string', 'description' => 'The container mount path (not allowed for read-only storages).'],
|
||||||
|
'host_path' => ['type' => 'string', 'nullable' => true, 'description' => 'The host path (persistent only, not allowed for read-only storages).'],
|
||||||
|
'content' => ['type' => 'string', 'nullable' => true, 'description' => 'The file content (file only, not allowed for read-only storages).'],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -4043,7 +4047,6 @@ public function storages(Request $request)
|
||||||
)]
|
)]
|
||||||
public function update_storage(Request $request)
|
public function update_storage(Request $request)
|
||||||
{
|
{
|
||||||
$allowedFields = ['id', 'type', 'is_preview_suffix_enabled'];
|
|
||||||
$teamId = getTeamIdFromToken();
|
$teamId = getTeamIdFromToken();
|
||||||
|
|
||||||
if (is_null($teamId)) {
|
if (is_null($teamId)) {
|
||||||
|
|
@ -4069,9 +4072,14 @@ public function update_storage(Request $request)
|
||||||
'id' => 'required|integer',
|
'id' => 'required|integer',
|
||||||
'type' => 'required|string|in:persistent,file',
|
'type' => 'required|string|in:persistent,file',
|
||||||
'is_preview_suffix_enabled' => 'boolean',
|
'is_preview_suffix_enabled' => 'boolean',
|
||||||
|
'name' => 'string',
|
||||||
|
'mount_path' => 'string',
|
||||||
|
'host_path' => 'string|nullable',
|
||||||
|
'content' => 'string|nullable',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
$allAllowedFields = ['id', 'type', 'is_preview_suffix_enabled', 'name', 'mount_path', 'host_path', 'content'];
|
||||||
|
$extraFields = array_diff(array_keys($request->all()), $allAllowedFields);
|
||||||
if ($validator->fails() || ! empty($extraFields)) {
|
if ($validator->fails() || ! empty($extraFields)) {
|
||||||
$errors = $validator->errors();
|
$errors = $validator->errors();
|
||||||
if (! empty($extraFields)) {
|
if (! empty($extraFields)) {
|
||||||
|
|
@ -4098,10 +4106,44 @@ public function update_storage(Request $request)
|
||||||
], 404);
|
], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$isReadOnly = $storage->shouldBeReadOnlyInUI();
|
||||||
|
$editableOnlyFields = ['name', 'mount_path', 'host_path', 'content'];
|
||||||
|
$requestedEditableFields = array_intersect($editableOnlyFields, array_keys($request->all()));
|
||||||
|
|
||||||
|
if ($isReadOnly && ! empty($requestedEditableFields)) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'This storage is read-only (managed by docker-compose or service definition). Only is_preview_suffix_enabled can be updated.',
|
||||||
|
'read_only_fields' => array_values($requestedEditableFields),
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always allowed
|
||||||
if ($request->has('is_preview_suffix_enabled')) {
|
if ($request->has('is_preview_suffix_enabled')) {
|
||||||
$storage->is_preview_suffix_enabled = $request->is_preview_suffix_enabled;
|
$storage->is_preview_suffix_enabled = $request->is_preview_suffix_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only for editable storages
|
||||||
|
if (! $isReadOnly) {
|
||||||
|
if ($request->type === 'persistent') {
|
||||||
|
if ($request->has('name')) {
|
||||||
|
$storage->name = $request->name;
|
||||||
|
}
|
||||||
|
if ($request->has('mount_path')) {
|
||||||
|
$storage->mount_path = $request->mount_path;
|
||||||
|
}
|
||||||
|
if ($request->has('host_path')) {
|
||||||
|
$storage->host_path = $request->host_path;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($request->has('mount_path')) {
|
||||||
|
$storage->mount_path = $request->mount_path;
|
||||||
|
}
|
||||||
|
if ($request->has('content')) {
|
||||||
|
$storage->content = $request->content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$storage->save();
|
$storage->save();
|
||||||
|
|
||||||
return response()->json($storage);
|
return response()->json($storage);
|
||||||
|
|
|
||||||
20
openapi.json
20
openapi.json
|
|
@ -3500,7 +3500,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
"description": "Storage updated.",
|
"description": "Storage updated. For read-only storages (from docker-compose or services), only is_preview_suffix_enabled can be updated.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"content": {
|
"content": {
|
||||||
"application\/json": {
|
"application\/json": {
|
||||||
|
|
@ -3525,6 +3525,24 @@
|
||||||
"is_preview_suffix_enabled": {
|
"is_preview_suffix_enabled": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Whether to add -pr-N suffix for preview deployments."
|
"description": "Whether to add -pr-N suffix for preview deployments."
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The volume name (persistent only, not allowed for read-only storages)."
|
||||||
|
},
|
||||||
|
"mount_path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The container mount path (not allowed for read-only storages)."
|
||||||
|
},
|
||||||
|
"host_path": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "The host path (persistent only, not allowed for read-only storages)."
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "The file content (file only, not allowed for read-only storages)."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
|
|
|
||||||
16
openapi.yaml
16
openapi.yaml
|
|
@ -2212,7 +2212,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
requestBody:
|
requestBody:
|
||||||
description: 'Storage updated.'
|
description: 'Storage updated. For read-only storages (from docker-compose or services), only is_preview_suffix_enabled can be updated.'
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
|
|
@ -2231,6 +2231,20 @@ paths:
|
||||||
is_preview_suffix_enabled:
|
is_preview_suffix_enabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'Whether to add -pr-N suffix for preview deployments.'
|
description: 'Whether to add -pr-N suffix for preview deployments.'
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: 'The volume name (persistent only, not allowed for read-only storages).'
|
||||||
|
mount_path:
|
||||||
|
type: string
|
||||||
|
description: 'The container mount path (not allowed for read-only storages).'
|
||||||
|
host_path:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
description: 'The host path (persistent only, not allowed for read-only storages).'
|
||||||
|
content:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
description: 'The file content (file only, not allowed for read-only storages).'
|
||||||
type: object
|
type: object
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue