diff --git a/docs/docs/cmd/spe/container/container-activate.mdx b/docs/docs/cmd/spe/container/container-activate.mdx new file mode 100644 index 00000000000..8fa2c20df6f --- /dev/null +++ b/docs/docs/cmd/spe/container/container-activate.mdx @@ -0,0 +1,34 @@ +import Global from '/docs/cmd/_global.mdx'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# spe container activate + +Activates a container + +## Usage + +```sh +m365 spe container activate [options] +``` + +## Options + +```md definition-list +`-i, --id ` +: The Id of the container instance. +``` + + + +## Examples + +Activates a container. + +```sh +m365 spe container activate --id "b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z" +``` + +## Response + +The command won't return a response on success. diff --git a/docs/src/config/sidebars.ts b/docs/src/config/sidebars.ts index c995ffe5bdb..f92d1408661 100644 --- a/docs/src/config/sidebars.ts +++ b/docs/src/config/sidebars.ts @@ -1960,6 +1960,15 @@ const sidebars: SidebarsConfig = { }, { 'SharePoint Embedded (spe)': [ + { + container: [ + { + type: 'doc', + label: 'container activate', + id: 'cmd/spe/container/container-activate' + } + ] + }, { containertype: [ { diff --git a/src/m365/spe/commands.ts b/src/m365/spe/commands.ts index ecd05a6e954..914930114e1 100644 --- a/src/m365/spe/commands.ts +++ b/src/m365/spe/commands.ts @@ -1,6 +1,7 @@ const prefix: string = 'spe'; export default { + CONTAINER_ACTIVATE: `${prefix} container activate`, CONTAINERTYPE_ADD: `${prefix} containertype add`, CONTAINERTYPE_LIST: `${prefix} containertype list` }; \ No newline at end of file diff --git a/src/m365/spe/commands/container/container-activate.spec.ts b/src/m365/spe/commands/container/container-activate.spec.ts new file mode 100644 index 00000000000..cece94f08d8 --- /dev/null +++ b/src/m365/spe/commands/container/container-activate.spec.ts @@ -0,0 +1,100 @@ +import assert from 'assert'; +import sinon from 'sinon'; +import auth from '../../../../Auth.js'; +import { Logger } from '../../../../cli/Logger.js'; +import request from '../../../../request.js'; +import { telemetry } from '../../../../telemetry.js'; +import { pid } from '../../../../utils/pid.js'; +import { session } from '../../../../utils/session.js'; +import { sinonUtil } from '../../../../utils/sinonUtil.js'; +import commands from '../../commands.js'; +import command from './container-activate.js'; +import { CommandError } from '../../../../Command.js'; +import { formatting } from '../../../../utils/formatting.js'; + +describe(commands.CONTAINER_ACTIVATE, () => { + let log: string[]; + let logger: Logger; + + const containerId = 'b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z'; + + before(() => { + sinon.stub(auth, 'restoreAuth').resolves(); + sinon.stub(telemetry, 'trackEvent').returns(); + sinon.stub(pid, 'getProcessName').returns(''); + sinon.stub(session, 'getId').returns(''); + auth.connection.active = true; + }); + + beforeEach(() => { + log = []; + logger = { + log: async (msg: string) => { + log.push(msg); + }, + logRaw: async (msg: string) => { + log.push(msg); + }, + logToStderr: async (msg: string) => { + log.push(msg); + } + }; + }); + + afterEach(() => { + sinonUtil.restore([ + request.post + ]); + }); + + after(() => { + sinon.restore(); + auth.connection.active = false; + }); + + it('has correct name', () => { + assert.strictEqual(command.name, commands.CONTAINER_ACTIVATE); + }); + + it('has a description', () => { + assert.notStrictEqual(command.description, null); + }); + + it('activates container by id', async () => { + const postStub = sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/storage/fileStorage/containers/${formatting.encodeQueryParameter(containerId)}/activate`) { + return; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { options: { id: containerId, verbose: true } }); + assert(postStub.calledOnce); + }); + + it('correctly handles error when container specified by id is not found', async () => { + const error = { + error: { + code: 'itemNotFound', + message: 'Item not found', + innerError: { + date: '2024-10-18T09:58:41', + 'request-id': 'ec6a7cf6-4017-4af2-a3aa-82cac95dced7', + 'client-request-id': '2453c2e7-e937-52ff-1478-647fc551d4e4' + } + } + }; + + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/storage/fileStorage/containers/${formatting.encodeQueryParameter(containerId)}/activate`) { + throw error; + } + + throw 'Invalid request'; + }); + + await assert.rejects(command.action(logger, { options: { id: containerId, verbose: true } } as any), + new CommandError(error.error.message)); + }); +}); \ No newline at end of file diff --git a/src/m365/spe/commands/container/container-activate.ts b/src/m365/spe/commands/container/container-activate.ts new file mode 100644 index 00000000000..33102c2da02 --- /dev/null +++ b/src/m365/spe/commands/container/container-activate.ts @@ -0,0 +1,65 @@ +import GlobalOptions from '../../../../GlobalOptions.js'; +import { Logger } from '../../../../cli/Logger.js'; +import GraphCommand from '../../../base/GraphCommand.js'; +import commands from '../../commands.js'; +import request, { CliRequestOptions } from '../../../../request.js'; +import { formatting } from '../../../../utils/formatting.js'; + +interface CommandArgs { + options: Options; +} + +interface Options extends GlobalOptions { + id: string; +} + +class SpeContainerActivateCommand extends GraphCommand { + public get name(): string { + return commands.CONTAINER_ACTIVATE; + } + + public get description(): string { + return 'Activates a container'; + } + + constructor() { + super(); + + this.#initOptions(); + this.#initTypes(); + } + + #initOptions(): void { + this.options.unshift( + { option: '-i, --id ' } + ); + } + + #initTypes(): void { + this.types.string.push('id'); + } + + public async commandAction(logger: Logger, args: CommandArgs): Promise { + if (this.verbose) { + await logger.logToStderr(`Activating a container with id '${args.options.id}'...`); + } + + try { + const requestOptions: CliRequestOptions = { + url: `${this.resource}/v1.0/storage/fileStorage/containers/${formatting.encodeQueryParameter(args.options.id)}/activate`, + headers: { + 'content-type': 'application/json;odata=nometadata', + 'accept': 'application/json;odata.metadata=none' + }, + responseType: 'json' + }; + + await request.post(requestOptions); + } + catch (err: any) { + this.handleRejectedODataJsonPromise(err); + } + } +} + +export default new SpeContainerActivateCommand(); \ No newline at end of file