Skip to content

Commit

Permalink
New command: viva engage community set
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinM85 committed Oct 25, 2024
1 parent 4f69f8e commit 756450f
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 39 deletions.
13 changes: 11 additions & 2 deletions docs/docs/cmd/viva/engage/engage-community-set.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ m365 viva engage community set [options]

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

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

`--entraGroupId [entraGroupId]`
: The id of the Microsoft Entra group associated with the community. Specify either `id`, `displayName` or `entraGroupId`, but not multiple.

`--newDisplayName [newDisplayName]`
: New name for the community. The maximum length is 255 characters.
Expand Down Expand Up @@ -47,6 +50,12 @@ Update info about the community specified by name
m365 viva engage community set --displayName 'Developrs' --newDisplayName 'Developers'
```

Update info about the community specified by Entra group id

```sh
m365 viva engage community set --entraGroupId '0bed8b86-5026-4a93-ac7d-56750cc099f1' --newDisplayName 'Developers'
```

## Response

The command won't return a response on success.
7 changes: 4 additions & 3 deletions src/m365/viva/commands/engage/Community.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export interface Community {
id: string;
displayName: string;
id?: string;
displayName?: string;
description?: string;
privacy: string;
privacy?: string;
groupId?: string;
}
27 changes: 26 additions & 1 deletion src/m365/viva/commands/engage/engage-community-set.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { cli } from '../../../../cli/cli.js';
describe(commands.ENGAGE_COMMUNITY_SET, () => {
const communityId = 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9';
const displayName = 'Software Engineers';
const entraGroupId = '0bed8b86-5026-4a93-ac7d-56750cc099f1';
let log: string[];
let logger: Logger;
let commandInfo: CommandInfo;
Expand Down Expand Up @@ -74,6 +75,11 @@ describe(commands.ENGAGE_COMMUNITY_SET, () => {
assert.strictEqual(actual, true);
});

it('passes validation when entraGroupId is specified', async () => {
const actual = await command.validate({ options: { entraGroupId: '0bed8b86-5026-4a93-ac7d-56750cc099f1', description: 'Community for all devs' } }, commandInfo);
assert.strictEqual(actual, true);
});

it('fails validation when newDisplayName, description or privacy is not specified', async () => {
const actual = await command.validate({ options: { displayName: 'Software Engineers' } }, commandInfo);
assert.notStrictEqual(actual, true);
Expand Down Expand Up @@ -109,6 +115,11 @@ describe(commands.ENGAGE_COMMUNITY_SET, () => {
assert.notStrictEqual(actual, true);
});

it('fails validation when entraGroupId is not a valid GUID', async () => {
const actual = await command.validate({ options: { entraGroupId: 'foo', description: 'Community for all devs' } }, commandInfo);
assert.notStrictEqual(actual, true);
});

it('updates info about a community specified by id', async () => {
const patchRequestStub = sinon.stub(request, 'patch').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}`) {
Expand All @@ -123,7 +134,7 @@ describe(commands.ENGAGE_COMMUNITY_SET, () => {
});

it('updates info about a community specified by displayName', async () => {
sinon.stub(vivaEngage, 'getCommunityIdByDisplayName').resolves(communityId);
sinon.stub(vivaEngage, 'getCommunityByDisplayName').resolves({ id: communityId });
const patchRequestStub = sinon.stub(request, 'patch').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}`) {
return;
Expand All @@ -136,6 +147,20 @@ describe(commands.ENGAGE_COMMUNITY_SET, () => {
assert(patchRequestStub.called);
});

it('updates info about a community specified by entraGroupId', async () => {
sinon.stub(vivaEngage, 'getCommunityByEntraGroupId').resolves({ id: communityId });
const patchRequestStub = sinon.stub(request, 'patch').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}`) {
return;
}

throw 'Invalid request';
});

await command.action(logger, { options: { entraGroupId: entraGroupId, description: 'Community for all devs', privacy: 'Public', verbose: true } });
assert(patchRequestStub.called);
});

it('handles error when updating Viva Engage community failed', async () => {
sinon.stub(request, 'patch').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}`) {
Expand Down
17 changes: 14 additions & 3 deletions src/m365/viva/commands/engage/engage-community-set.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import GlobalOptions from '../../../../GlobalOptions.js';
import { Logger } from '../../../../cli/Logger.js';
import request, { CliRequestOptions } from '../../../../request.js';
import { validation } from '../../../../utils/validation.js';
import { vivaEngage } from '../../../../utils/vivaEngage.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';
Expand All @@ -12,6 +13,7 @@ interface CommandArgs {
interface Options extends GlobalOptions {
id?: string;
displayName?: string;
entraGroupId?: string;
newDisplayName?: string;
description?: string;
privacy?: string;
Expand Down Expand Up @@ -58,6 +60,9 @@ class VivaEngageCommunitySetCommand extends GraphCommand {
{
option: '-d, --displayName [displayName]'
},
{
option: '--entraGroupId [entraGroupId]'
},
{
option: '--newDisplayName [newDisplayName]'
},
Expand All @@ -74,6 +79,10 @@ class VivaEngageCommunitySetCommand extends GraphCommand {
#initValidators(): void {
this.validators.push(
async (args: CommandArgs) => {
if (args.options.entraGroupId && !validation.isValidGuid(args.options.entraGroupId)) {
return `${args.options.entraGroupId} is not a valid GUID for the option 'entraGroupId'.`;
}

if (args.options.newDisplayName && args.options.newDisplayName.length > 255) {
return `The maximum amount of characters for 'newDisplayName' is 255.`;
}
Expand All @@ -100,15 +109,17 @@ class VivaEngageCommunitySetCommand extends GraphCommand {
}

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

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

let communityId = args.options.id;

if (args.options.displayName) {
communityId = await vivaEngage.getCommunityIdByDisplayName(args.options.displayName);
communityId = (await vivaEngage.getCommunityByDisplayName(args.options.displayName, ['id'])).id!;
}
else if (args.options.entraGroupId) {
communityId = (await vivaEngage.getCommunityByEntraGroupId(args.options.entraGroupId, ['id'])).id!;
}

if (this.verbose) {
Expand Down
128 changes: 106 additions & 22 deletions src/utils/vivaEngage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ import { settingsNames } from '../settingsNames.js';
describe('utils/vivaEngage', () => {
const displayName = 'All Company';
const invalidDisplayName = 'All Compayn';
const entraGroupId = '0bed8b86-5026-4a93-ac7d-56750cc099f1';
const communityId = 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9';
const communityResponse = {
"id": "eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9",
"description": "This is the default group for everyone in the network",
"displayName": "All Company",
"privacy": "Public"
"privacy": "Public",
"groupId": "0bed8b86-5026-4a93-ac7d-56750cc099f1"
};
const anotherCommunityResponse = {
"id": "eyJfdHlwZ0NzY5SIwiIiSJ9IwO6IaWQiOIMTM1ODikdyb3Vw",
"description": "Test only",
"displayName": "All Company",
"privacy": "Private"
"privacy": "Private",
"groupId": "0bed8b86-5026-4a93-ac7d-56750cc099f1"
};

afterEach(() => {
Expand All @@ -31,56 +35,58 @@ describe('utils/vivaEngage', () => {
]);
});

it('correctly get single community id by name using getCommunityIdByDisplayName', async () => {
it('correctly get single community id by name using getCommunityByDisplayName', async () => {
sinon.stub(request, 'get').callsFake(async opts => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`) {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'&$select=id`) {
return {
value: [
communityResponse
{
id: communityId
}
]
};
}

return 'Invalid Request';
});

const actual = await vivaEngage.getCommunityIdByDisplayName(displayName);
assert.deepStrictEqual(actual, 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9');
const actual = await vivaEngage.getCommunityByDisplayName(displayName, ['id']);
assert.deepStrictEqual(actual, { id: communityId });
});

it('handles selecting single community when multiple communities with the specified name found using getCommunityIdByDisplayName and cli is set to prompt', async () => {
it('handles selecting single community when multiple communities with the specified name found using getCommunityByDisplayName and cli is set to prompt', async () => {
sinon.stub(request, 'get').callsFake(async opts => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`) {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'&$select=id`) {
return {
value: [
communityResponse,
anotherCommunityResponse
{ id: communityId },
{ id: "eyJfdHlwZ0NzY5SIwiIiSJ9IwO6IaWQiOIMTM1ODikdyb3Vw" }
]
};
}

return 'Invalid Request';
});

sinon.stub(cli, 'handleMultipleResultsFound').resolves(communityResponse);
sinon.stub(cli, 'handleMultipleResultsFound').resolves({ id: communityId });

const actual = await vivaEngage.getCommunityIdByDisplayName(displayName);
assert.deepStrictEqual(actual, 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9');
const actual = await vivaEngage.getCommunityByDisplayName(displayName, ['id']);
assert.deepStrictEqual(actual, { id: 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9' });
});

it('throws error message when no community was found using getCommunityIdByDisplayName', async () => {
it('throws error message when no community was found using getCommunityByDisplayName', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(invalidDisplayName)}'`) {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(invalidDisplayName)}'&$select=id`) {
return { value: [] };
}

throw 'Invalid Request';
});

await assert.rejects(vivaEngage.getCommunityIdByDisplayName(invalidDisplayName)), Error(`The specified Viva Engage community '${invalidDisplayName}' does not exist.`);
await assert.rejects(vivaEngage.getCommunityByDisplayName(invalidDisplayName, ['id'])), Error(`The specified Viva Engage community '${invalidDisplayName}' does not exist.`);
});

it('throws error message when multiple communities were found using getCommunityIdByDisplayName', async () => {
it('throws error message when multiple communities were found using getCommunityByDisplayName', async () => {
sinon.stub(cli, 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => {
if (settingName === settingsNames.prompt) {
return false;
Expand All @@ -90,19 +96,97 @@ describe('utils/vivaEngage', () => {
});

sinon.stub(request, 'get').callsFake(async opts => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`) {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'&$select=id`) {
return {
value: [
communityResponse,
anotherCommunityResponse
{ id: communityId },
{ id: "eyJfdHlwZ0NzY5SIwiIiSJ9IwO6IaWQiOIMTM1ODikdyb3Vw" }
]
};
}

return 'Invalid Request';
});

await assert.rejects(vivaEngage.getCommunityIdByDisplayName(displayName),
await assert.rejects(vivaEngage.getCommunityByDisplayName(displayName, ['id']),
Error(`Multiple Viva Engage communities with name '${displayName}' found. Found: ${communityResponse.id}, ${anotherCommunityResponse.id}.`));
});

it('correctly get single community by group id using getCommunityByEntraGroupId', async () => {
sinon.stub(request, 'get').callsFake(async opts => {
if (opts.url === 'https://graph.microsoft.com/v1.0/employeeExperience/communities?$select=id,groupId') {
return {
value: [
{
id: communityId,
groupId: entraGroupId
}
]
};
}

return 'Invalid Request';
});

const actual = await vivaEngage.getCommunityByEntraGroupId(entraGroupId, ['id']);
assert.deepStrictEqual(actual, { id: communityId, groupId: entraGroupId });
});

it('correctly get single community by group id using getCommunityByEntraGroupId and multiple properties', async () => {
sinon.stub(request, 'get').callsFake(async opts => {
if (opts.url === 'https://graph.microsoft.com/v1.0/employeeExperience/communities?$select=id,groupId,displayName') {
return {
value: [
{
id: communityId,
groupId: entraGroupId,
displayName: displayName
}
]
};
}

return 'Invalid Request';
});

const actual = await vivaEngage.getCommunityByEntraGroupId(entraGroupId, ['id', 'groupId', 'displayName']);
assert.deepStrictEqual(actual, { id: communityId, groupId: entraGroupId, displayName: displayName });
});

it('throws error message when no community was found using getCommunityByEntraGroupId', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === 'https://graph.microsoft.com/v1.0/employeeExperience/communities?$select=id,groupId') {
return { value: [] };
}

throw 'Invalid Request';
});

await assert.rejects(vivaEngage.getCommunityByEntraGroupId(entraGroupId, ['id'])), Error(`The Microsoft Entra group with id '${entraGroupId}' is not associated with any Viva Engage community.`);
});

it('correctly gets Entra group ID by community ID using getEntraGroupIdByCommunityId', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}?$select=groupId`) {
return { groupId: entraGroupId };
}

throw 'Invalid Request';
});

const actual = await vivaEngage.getCommunityById(communityId, ['groupId']);
assert.deepStrictEqual(actual, { groupId: '0bed8b86-5026-4a93-ac7d-56750cc099f1' });
});

it('throws error message when no Entra group ID was found using getCommunityById', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}?$select=groupId`) {
return null;
}

throw 'Invalid Request';
});

await assert.rejects(vivaEngage.getCommunityById(communityId, ['groupId'])), Error(`The specified Viva Engage community with ID '${communityId}' does not exist.`);
});
});
Loading

0 comments on commit 756450f

Please sign in to comment.