From d6999ac5e3fed2ad6884d14762b86719eb663d05 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Mon, 15 Apr 2024 14:16:57 +0800 Subject: [PATCH] [Backport workspace-pr-integr][Workspace] Support workspace in saved objects client in server side (#6365) (#327) * [Workspace] Support workspace in saved objects client in server side. (#6365) * Support workspace in saved objects client in server side. (#293) * feat: POC implementation Signed-off-by: SuZhou-Joe * feat: add some comment Signed-off-by: SuZhou-Joe * feat: revert dependency Signed-off-by: SuZhou-Joe * feat: update comment Signed-off-by: SuZhou-Joe * feat: address one TODO Signed-off-by: SuZhou-Joe * feat: address TODO Signed-off-by: SuZhou-Joe * feat: add unit test Signed-off-by: SuZhou-Joe * feat: some special logic on specific operation Signed-off-by: SuZhou-Joe * feat: add integration test Signed-off-by: SuZhou-Joe * feat: declare workspaces as empty array for advanced settings Signed-off-by: SuZhou-Joe * feat: unified workspaces parameters when parsing from router Signed-off-by: SuZhou-Joe * feat: improve code coverage Signed-off-by: SuZhou-Joe * feat: declare workspaces as null Signed-off-by: SuZhou-Joe * feat: use unified types Signed-off-by: SuZhou-Joe * feat: update comment Signed-off-by: SuZhou-Joe * feat: remove null Signed-off-by: SuZhou-Joe * feat: address comments Signed-off-by: SuZhou-Joe * feat: use request app to store request workspace id Signed-off-by: SuZhou-Joe * feat: use app state to store request workspace id Signed-off-by: SuZhou-Joe * refact: update types declaration Signed-off-by: SuZhou-Joe * fix: unit test error Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe * fix: import error Signed-off-by: SuZhou-Joe * feat: add integration test Signed-off-by: SuZhou-Joe * feat: add unit test Signed-off-by: SuZhou-Joe * feat: update CHANGELOG Signed-off-by: SuZhou-Joe * feat: use consts and add comment Signed-off-by: SuZhou-Joe * feat: change the priority value Signed-off-by: SuZhou-Joe * feat: update Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe * feat: remove useless code Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe --- .../import/create_saved_objects.ts | 2 +- src/plugins/workspace/common/constants.ts | 10 +++++++ src/plugins/workspace/server/plugin.ts | 9 ++++-- .../workspace_id_consumer_wrapper.test.ts | 28 +++++++++++++++++++ ...ts_wrapper_for_check_workspace_conflict.ts | 6 ++-- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/core/server/saved_objects/import/create_saved_objects.ts b/src/core/server/saved_objects/import/create_saved_objects.ts index 35d0ddd349fa..c78375dafd71 100644 --- a/src/core/server/saved_objects/import/create_saved_objects.ts +++ b/src/core/server/saved_objects/import/create_saved_objects.ts @@ -176,7 +176,7 @@ export const createSavedObjects = async ({ const bulkCreateResponse = await savedObjectsClient.bulkCreate(objectsToCreate, { namespace, overwrite, - workspaces, + ...(workspaces ? { workspaces } : {}), }); expectedResults = bulkCreateResponse.saved_objects; } diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index 1781b7e32771..9e749e275828 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -22,3 +22,13 @@ export enum WorkspacePermissionMode { } export const WORKSPACE_ID_CONSUMER_WRAPPER_ID = 'workspace_id_consumer'; + +/** + * The priority for these wrappers matters: + * 1. WORKSPACE_ID_CONSUMER should be placed before the other two wrappers(smaller than the other two wrappers) as it cost little + * and will append the essential workspaces field into the options, which will be honored by permission control wrapper and conflict wrapper. + * 2. The order of permission wrapper and conflict wrapper does not matter as no dependency between these two wrappers. + */ +export const PRIORITY_FOR_WORKSPACE_ID_CONSUMER_WRAPPER = -2; +export const PRIORITY_FOR_PERMISSION_CONTROL_WRAPPER = 0; +export const PRIORITY_FOR_WORKSPACE_CONFLICT_CONTROL_WRAPPER = -1; diff --git a/src/plugins/workspace/server/plugin.ts b/src/plugins/workspace/server/plugin.ts index b4601d5d71dc..a1f8f7cc3ece 100644 --- a/src/plugins/workspace/server/plugin.ts +++ b/src/plugins/workspace/server/plugin.ts @@ -17,6 +17,9 @@ import { WORKSPACE_SAVED_OBJECTS_CLIENT_WRAPPER_ID, WORKSPACE_CONFLICT_CONTROL_SAVED_OBJECTS_CLIENT_WRAPPER_ID, WORKSPACE_ID_CONSUMER_WRAPPER_ID, + PRIORITY_FOR_WORKSPACE_CONFLICT_CONTROL_WRAPPER, + PRIORITY_FOR_WORKSPACE_ID_CONSUMER_WRAPPER, + PRIORITY_FOR_PERMISSION_CONTROL_WRAPPER, } from '../common/constants'; import { IWorkspaceClientImpl, @@ -107,7 +110,7 @@ export class WorkspacePlugin implements Plugin { ) ); }); + + it('import within workspace', async () => { + await clearFooAndBar(); + + const importWithWorkspacesResult = await osdTestServer.request + .post(root, `/w/${createdFooWorkspace.id}/api/saved_objects/_import?overwrite=false`) + .attach( + 'file', + Buffer.from( + [ + JSON.stringify({ + ...dashboard, + id: 'bar', + }), + ].join('\n'), + 'utf-8' + ), + 'tmp.ndjson' + ) + .expect(200); + + const findResult = await osdTestServer.request + .get(root, `/w/${createdFooWorkspace.id}/api/saved_objects/_find?type=${dashboard.type}`) + .expect(200); + + expect(importWithWorkspacesResult.body.success).toEqual(true); + expect(findResult.body.saved_objects[0].workspaces).toEqual([createdFooWorkspace.id]); + }); }); }); diff --git a/src/plugins/workspace/server/saved_objects/saved_objects_wrapper_for_check_workspace_conflict.ts b/src/plugins/workspace/server/saved_objects/saved_objects_wrapper_for_check_workspace_conflict.ts index 298d0448031a..838b689328bf 100644 --- a/src/plugins/workspace/server/saved_objects/saved_objects_wrapper_for_check_workspace_conflict.ts +++ b/src/plugins/workspace/server/saved_objects/saved_objects_wrapper_for_check_workspace_conflict.ts @@ -20,8 +20,8 @@ import { const errorContent = (error: Boom.Boom) => error.output.payload; const filterWorkspacesAccordingToSourceWorkspaces = ( - targetWorkspaces?: string[], - baseWorkspaces?: string[] + targetWorkspaces?: SavedObjectsBaseOptions['workspaces'], + baseWorkspaces?: SavedObjectsBaseOptions['workspaces'] ): string[] => targetWorkspaces?.filter((item) => !baseWorkspaces?.includes(item)) || []; export class WorkspaceConflictSavedObjectsClientWrapper { @@ -110,7 +110,7 @@ export class WorkspaceConflictSavedObjectsClientWrapper { }) : []; const objectsConflictWithWorkspace: SavedObject[] = []; - const objectsMapWorkspaces: Record = {}; + const objectsMapWorkspaces: Record = {}; if (bulkGetDocs.length) { /** * Get latest status of objects