Skip to content

Commit

Permalink
New command: viva engage community remove
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinM85 committed Aug 30, 2024
1 parent 309a9b8 commit 16541f8
Show file tree
Hide file tree
Showing 8 changed files with 454 additions and 0 deletions.
52 changes: 52 additions & 0 deletions docs/docs/cmd/viva/engage/engage-community-remove.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import Global from '/docs/cmd/_global.mdx';

# viva engage community remove

Removes a Viva Engage community

## Usage

```sh
m365 viva engage community remove [options]
```

## Options

```md definition-list
`-i, --id [id]`
: The id of the community. Specify either `id` or `displayName` but not both.

`-n, --displayName [displayName]`
: The name of the community. Specify either `id` or `displayName` but not both.

`-f, --force`
: Don't prompt for confirmation.
```

<Global />

## Remarks

:::info

When the Viva Engage community is removed, all the associated Microsoft 365 content, including the M365 group, the document library, OneNote notebook, and Planner plans is deleted.

:::

## Examples

Remove a community specified by id without prompting

```sh
m365 viva engage community remove --id eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9 --force
```

Remove a community specified by name and prompt for confirmation

```sh
m365 viva engage community remove --displayName 'Software Engineers'
```

## Response

The command won't return a response on success
5 changes: 5 additions & 0 deletions docs/src/config/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4406,6 +4406,11 @@ const sidebars: SidebarsConfig = {
label: 'engage community get',
id: 'cmd/viva/engage/engage-community-get'
},
{
type: 'doc',
label: 'engage community remove',
id: 'cmd/viva/engage/engage-community-remove'
},
{
type: 'doc',
label: 'engage group list',
Expand Down
1 change: 1 addition & 0 deletions src/m365/viva/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
CONNECTIONS_APP_CREATE: `${prefix} connections app create`,
ENGAGE_COMMUNITY_ADD: `${prefix} engage community add`,
ENGAGE_COMMUNITY_GET: `${prefix} engage community get`,
ENGAGE_COMMUNITY_REMOVE: `${prefix} engage community remove`,
ENGAGE_GROUP_LIST: `${prefix} engage group list`,
ENGAGE_GROUP_USER_ADD: `${prefix} engage group user add`,
ENGAGE_GROUP_USER_REMOVE: `${prefix} engage group user remove`,
Expand Down
6 changes: 6 additions & 0 deletions src/m365/viva/commands/engage/Community.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Community {
id: string;
displayName: string;
description: string;
privacy: string;
}
141 changes: 141 additions & 0 deletions src/m365/viva/commands/engage/engage-community-remove.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import assert from 'assert';
import sinon from 'sinon';
import auth from '../../../../Auth.js';
import commands from '../../commands.js';
import request from '../../../../request.js';
import { telemetry } from '../../../../telemetry.js';
import { Logger } from '../../../../cli/Logger.js';
import { CommandError } from '../../../../Command.js';
import { pid } from '../../../../utils/pid.js';
import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import { cli } from '../../../../cli/cli.js';
import command from './engage-community-remove.js';
import { vivaEngage } from '../../../../utils/vivaEngage.js';

describe(commands.ENGAGE_COMMUNITY_REMOVE, () => {
const communityId = 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9';
const displayName = 'Software Engineers';

let log: string[];
let logger: Logger;
let promptIssued: boolean;

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);
}
};
sinon.stub(cli, 'promptForConfirmation').callsFake(() => {
promptIssued = true;
return Promise.resolve(false);
});

promptIssued = false;
});

afterEach(() => {
sinonUtil.restore([
request.delete,
vivaEngage.getCommunityIdByDisplayName,
cli.promptForConfirmation
]);
});

after(() => {
sinon.restore();
auth.connection.active = false;
});

it('has correct name', () => {
assert.strictEqual(command.name, commands.ENGAGE_COMMUNITY_REMOVE);
});

it('has a description', () => {
assert.notStrictEqual(command.description, null);
});

it('prompts before removing the community when confirm option not passed', async () => {
await command.action(logger, { options: { id: communityId } });

assert(promptIssued);
});

it('aborts removing the community when prompt not confirmed', async () => {
const deleteSpy = sinon.stub(request, 'delete').resolves();

await command.action(logger, { options: { id: communityId } });
assert(deleteSpy.notCalled);
});

it('removes the community specified by id without prompting for confirmation', async () => {
const deleteRequestStub = sinon.stub(request, 'delete').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}`) {
return;
}

throw 'Invalid request';
});

await command.action(logger, { options: { id: communityId, force: true, verbose: true } });
assert(deleteRequestStub.called);
});

it('removes the community specified by displayName while prompting for confirmation', async () => {
sinon.stub(vivaEngage, 'getCommunityIdByDisplayName').resolves(communityId);

const deleteRequestStub = sinon.stub(request, 'delete').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}`) {
return;
}

throw 'Invalid request';
});

sinonUtil.restore(cli.promptForConfirmation);
sinon.stub(cli, 'promptForConfirmation').resolves(true);

await command.action(logger, { options: { displayName: displayName } });
assert(deleteRequestStub.called);
});

it('throws an error when the community specified by id cannot be found', async () => {
const error = {
error: {
code: 'notFound',
message: 'Not found.',
innerError: {
date: '2024-08-30T06:25:04',
'request-id': '186480bb-73a7-4164-8a10-b05f45a94a4f',
'client-request-id': '186480bb-73a7-4164-8a10-b05f45a94a4f'
}
}
};
sinon.stub(request, 'delete').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}`) {
throw error;
}

throw 'Invalid request';
});

await assert.rejects(command.action(logger, { options: { id: communityId, force: true } }),
new CommandError(error.error.message));
});
});
113 changes: 113 additions & 0 deletions src/m365/viva/commands/engage/engage-community-remove.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import GlobalOptions from '../../../../GlobalOptions.js';
import { Logger } from '../../../../cli/Logger.js';
import { cli } from '../../../../cli/cli.js';
import request, { CliRequestOptions } from '../../../../request.js';
import { vivaEngage } from '../../../../utils/vivaEngage.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';

interface CommandArgs {
options: Options;
}

interface Options extends GlobalOptions {
id?: string;
displayName?: string;
force?: boolean
}

class VivaEngageCommunityRemoveCommand extends GraphCommand {
public get name(): string {
return commands.ENGAGE_COMMUNITY_REMOVE;
}
public get description(): string {
return 'Removes a community';
}

constructor() {
super();

this.#initTelemetry();
this.#initOptions();
this.#initOptionSets();
this.#initTypes();
}

#initTelemetry(): void {
this.telemetry.push((args: CommandArgs) => {
Object.assign(this.telemetryProperties, {
id: args.options.id !== 'undefined',
displayName: args.options.displayName !== 'undefined',
force: !!args.options.force
});
});
}

#initOptions(): void {
this.options.unshift(
{
option: '-i, --id [id]'
},
{
option: '-n, --displayName [displayName]'
},
{
option: '-f, --force'
}
);
}

#initOptionSets(): void {
this.optionSets.push(
{
options: ['id', 'displayName']
}
);
}

#initTypes(): void {
this.types.string.push('id', 'displayName');
}

public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {

const removeCommunity = async (): Promise<void> => {
try {
let communityId = args.options.id;

if (args.options.displayName) {
communityId = await vivaEngage.getCommunityIdByDisplayName(args.options.displayName);
}

if (args.options.verbose) {
await logger.logToStderr(`Removing Viva Engage community with ID ${communityId}...`);
}

const requestOptions: CliRequestOptions = {
url: `${this.resource}/v1.0/employeeExperience/communities/${communityId}`,
headers: {
accept: 'application/json;odata.metadata=none'
}
};

await request.delete(requestOptions);
}
catch (err: any) {
this.handleRejectedODataJsonPromise(err);
}
};

if (args.options.force) {
await removeCommunity();
}
else {
const result = await cli.promptForConfirmation({ message: `Are you sure you want to remove Viva Engage community '${args.options.id || args.options.displayName}'?` });

if (result) {
await removeCommunity();
}
}
}
}

export default new VivaEngageCommunityRemoveCommand();
Loading

0 comments on commit 16541f8

Please sign in to comment.