-
Notifications
You must be signed in to change notification settings - Fork 327
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New command: viva engage community remove
- Loading branch information
Showing
8 changed files
with
454 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
141
src/m365/viva/commands/engage/engage-community-remove.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
113
src/m365/viva/commands/engage/engage-community-remove.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
Oops, something went wrong.