import Boom from '@hapi/boom' ; import { omit } from 'lodash' ; import type { ISavedObjectsRepository , SavedObject } from 'src/core/server' ; import type { GetAllSpacesOptions , GetAllSpacesPurpose , GetSpaceResult , LegacyUrlAliasTarget , Space , } from '../../common' ; import { isReservedSpace } from '../../common' ; import type { ConfigType } from '../config' ; const SUPPORTED_GET_SPACE_PURPOSES = [ 'any' , 'copySavedObjectsIntoSpace' , 'findSavedObjects' , 'shareSavedObjectsIntoSpace' , ] ; const DEFAULT_PURPOSE = 'any' ; const LEGACY_URL_ALIAS_TYPE = 'legacy-url-alias' ; /**
 * Client interface for interacting with spaces.
 */ export interface ISpacesClient { param options getAll ( options ? ) : Promise < GetSpaceResult [ ] > ; param id get ( id ) : Promise < Space > ; param space create ( space ) : Promise < Space > ; param id param space update ( id , space ) : Promise < Space > ; param id delete ( id ) : Promise < void > ; param aliases disableLegacyUrlAliases ( aliases ) : Promise < void > ; } /**
 * Client for interacting with spaces.
 */ export class SpacesClient implements ISpacesClient { constructor ( private readonly debugLogger , private readonly config , private readonly repository ) { } public async getAll ( options = { } ) { const { purpose = DEFAULT_PURPOSE } = options ; if ( ! SUPPORTED_GET_SPACE_PURPOSES . includes ( purpose ) ) { throw Boom . badRequest ( `unsupported space purpose: ${ purpose }` ) ; } this . debugLogger ( `SpacesClient.getAll(). querying all spaces` ) ; const { saved_objects : savedObjects } = await this . repository . find ( { type : 'space' , page : 1 , perPage : this . config . maxSpaces , sortField : 'name.keyword' , } ) ; this . debugLogger ( `SpacesClient.getAll(). Found ${ savedObjects . length } spaces.` ) ; return savedObjects . map ( this . transformSavedObjectToSpace ) ; } public async get ( id ) { const savedObject = await this . repository . get ( 'space' , id ) ; return this . transformSavedObjectToSpace ( savedObject ) ; } public async create ( space ) { const { total } = await this . repository . find ( { type : 'space' , page : 1 , perPage : 0 , } ) ; if ( total >= this . config . maxSpaces ) { throw Boom . badRequest ( 'Unable to create Space, this exceeds the maximum number of spaces set by the xpack.spaces.maxSpaces setting' ) ; } this . debugLogger ( `SpacesClient.create(), using RBAC. Attempting to create space` ) ; const attributes = omit ( space , [ 'id' , '_reserved' ] ) ; const id = space . id ; const createdSavedObject = await this . repository . create ( 'space' , attributes , { id } ) ; this . debugLogger ( `SpacesClient.create(), created space object` ) ; return this . transformSavedObjectToSpace ( createdSavedObject ) ; } public async update ( id , space ) { const attributes = omit ( space , 'id' , '_reserved' ) ; await this . repository . update ( 'space' , id , attributes ) ; const updatedSavedObject = await this . repository . get ( 'space' , id ) ; return this . transformSavedObjectToSpace ( updatedSavedObject ) ; } public async delete ( id ) { const existingSavedObject = await this . repository . get ( 'space' , id ) ; if ( isReservedSpace ( this . transformSavedObjectToSpace ( existingSavedObject ) ) ) { throw Boom . badRequest ( `The ${ id } space cannot be deleted because it is reserved.` ) ; } await this . repository . deleteByNamespace ( id ) ; await this . repository . delete ( 'space' , id ) ; } public async disableLegacyUrlAliases ( aliases ) { const attributes = { disabled : true } ; const objectsToUpdate = aliases . map ( ( { targetSpace , targetType , sourceId } ) => { const id = `${ targetSpace }:${ targetType }:${ sourceId }` ; return { type : LEGACY_URL_ALIAS_TYPE , id , attributes } ; } ) ; await this . repository . bulkUpdate ( objectsToUpdate ) ; } private transformSavedObjectToSpace ( savedObject ) { return { id : savedObject . id , ... savedObject . attributes , } as Space ; } }