Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds m365 spo tenant homesite add. Closes #6488 #6533

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions docs/docs/cmd/spo/tenant/tenant-homesite-add.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import Global from '/docs/cmd/_global.mdx';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# spo tenant homesite add

Adds a Home Site.

## Usage

```sh
m365 spo tenant homesite add [options]
```

## Options

```md definition-list
`-u, --url <url>`
: URL of the site to use as a home site.

`--isInDraftMode [isInDraftMode]`
: Specifies whether the home site is in draft mode. Accepts `true` or `false`. Default is true.

`--vivaConnectionsDefaultStart [vivaConnectionsDefaultStart]`
: Specifies whether the home site is the default start for Viva Connections. Accepts `true` or `false`. Default is true

`--audiences [audiences]`
: Comma-separated list of audience GUIDs which are GUIDs of Microsoft Entra groups.

`--order [order]`
: Order of the home site. Must be an integer.
```

reshmee011 marked this conversation as resolved.
Show resolved Hide resolved
<Global />

## Remarks

The corresponding site must already be present within the tenant.

## Examples

Add a Home Site

```sh
m365 spo tenant homesite add --url "https://contoso.sharepoint.com/sites/testcomms"
```

Add a Home Site with optional parameters

```sh
m365 spo tenant homesite add --url "https://contoso.sharepoint.com/sites/testcomms" --isInDraftMode true --vivaConnectionsDefaultStart false --audiences "af8c0bc8-7b1b-44b4-b087-ffcc8df70d16,754ff15c-76b1-44cb-88c7-0065a4d3cfb7" --order 2
```

## Response
reshmee011 marked this conversation as resolved.
Show resolved Hide resolved

<Tabs>
<TabItem value="JSON">

```json
{
"Audiences": [
{
"Email": "[email protected]",
"Id": "7a1eea7f-9ab0-40ff-8f2e-0083d9d63451",
"Title": "active Members"
}
],
"IsInDraftMode": true,
"IsVivaBackendSite": false,
"SiteId": "ca49054c-85f3-41eb-a290-46ffda8f219c",
"TargetedLicenseType": 0,
"Title": "testcommsite",
"Url": "https://contoso.sharepoint.com/sites/testcomms",
"VivaConnectionsDefaultStart": false,
"WebId": "256c4f0f-e372-47b4-a891-b4888e829e20"
}
```

</TabItem>
<TabItem value="Text">

```text
Audiences : [{"Email":"[email protected]","Id":"7a1eea7f-9ab0-40ff-8f2e-0083d9d63451","Title":"active Members"}]
IsInDraftMode : true
IsVivaBackendSite : false
SiteId : ca49054c-85f3-41eb-a290-46ffda8f219c
TargetedLicenseType : 0
Title : testcommsite
Url : https://contoso.sharepoint.com/sites/testcomms
VivaConnectionsDefaultStart: false
WebId : 256c4f0f-e372-47b4-a891-b4888e829e20
```

</TabItem>
<TabItem value="CSV">

```csv
IsInDraftMode,IsVivaBackendSite,SiteId,TargetedLicenseType,Title,Url,VivaConnectionsDefaultStart,WebId
1,0,ca49054c-85f3-41eb-a290-46ffda8f219c,0,testcommsite,https://contoso.sharepoint.com/sites/testcomms,0,256c4f0f-e372-47b4-a891-b4888e829e20
```

</TabItem>
<TabItem value="Markdown">

```md
# spo tenant homesite add --url "https://contoso.sharepoint.com/sites/testcomms"

Date: 12/23/2024

## testcommsite (https://contoso.sharepoint.com/sites/testcomms)

Property | Value
---------|-------
IsInDraftMode | true
IsVivaBackendSite | false
SiteId | ca49054c-85f3-41eb-a290-46ffda8f219c
TargetedLicenseType | 0
Title | testcommsite
Url | https://contoso.sharepoint.com/sites/testcomms
VivaConnectionsDefaultStart | false
WebId | 256c4f0f-e372-47b4-a891-b4888e829e20
```
</TabItem>
</Tabs>

## More information

- SharePoint home sites [Viva Connections set up](https://learn.microsoft.com/en-us/viva/connections/set-up-admin-center)

5 changes: 5 additions & 0 deletions docs/src/config/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3822,6 +3822,11 @@ const sidebars: SidebarsConfig = {
label: 'tenant commandset set',
id: 'cmd/spo/tenant/tenant-commandset-set'
},
{
type: 'doc',
label: 'tenant homesite add',
id: 'cmd/spo/tenant/tenant-homesite-add'
},
{
type: 'doc',
label: 'tenant homesite list',
Expand Down
1 change: 1 addition & 0 deletions src/m365/spo/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ export default {
TENANT_COMMANDSET_LIST: `${prefix} tenant commandset list`,
TENANT_COMMANDSET_REMOVE: `${prefix} tenant commandset remove`,
TENANT_COMMANDSET_SET: `${prefix} tenant commandset set`,
TENANT_HOMESITE_ADD: `${prefix} tenant homesite add`,
TENANT_HOMESITE_LIST: `${prefix} tenant homesite list`,
TENANT_RECYCLEBINITEM_LIST: `${prefix} tenant recyclebinitem list`,
TENANT_RECYCLEBINITEM_REMOVE: `${prefix} tenant recyclebinitem remove`,
Expand Down
197 changes: 197 additions & 0 deletions src/m365/spo/commands/tenant/tenant-homesite-add.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import assert from 'assert';
import sinon from 'sinon';
import auth from '../../../../Auth.js';
import { cli } from '../../../../cli/cli.js';
import { Logger } from '../../../../cli/Logger.js';
import { CommandError } from '../../../../Command.js';
import { CommandInfo } from '../../../../cli/CommandInfo.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 './tenant-homesite-add.js';

describe(commands.TENANT_HOMESITE_ADD, () => {
let log: string[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
const homeSite = "https://contoso.sharepoint.com/sites/testcomms";
const homeSites = {
"Audiences": [],
"IsInDraftMode": true,
"IsVivaBackendSite": false,
"SiteId": "ca49054c-85f3-41eb-a290-46ffda8f219c",
"TargetedLicenseType": 0,
"Title": "testcommsite",
"Url": homeSite,
"VivaConnectionsDefaultStart": false,
"WebId": "256c4f0f-e372-47b4-a891-b4888e829e20"
};

const homeSiteConfig = {
"Audiences": [
{
"Email": "[email protected]",
"Id": "af8c0bc8-7b1b-44b4-b087-ffcc8df70d16",
"Title": "SharingTest Members"
}
],
"IsInDraftMode": true,
"IsVivaBackendSite": false,
"SiteId": "ca49054c-85f3-41eb-a290-46ffda8f219c",
"TargetedLicenseType": 0,
"Title": "testcommsite",
"Url": "https://contoso.sharepoint.com/sites/testcomms",
"VivaConnectionsDefaultStart": false,
"WebId": "256c4f0f-e372-47b4-a891-b4888e829e20"
};

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;
auth.connection.spoUrl = 'https://contoso.sharepoint.com';
});

beforeEach(() => {
log = [];
logger = {
log: async (msg: string) => {
log.push(msg);
},
logRaw: async (msg: string) => {
log.push(msg);
},
logToStderr: async (msg: string) => {
log.push(msg);
}
};
loggerLogSpy = sinon.spy(logger, 'log');
commandInfo = cli.getCommandInfo(command);
});

afterEach(() => {
sinonUtil.restore([
request.post
]);
});

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

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

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

it('correctly logs command response', async () => {
sinon.stub(request, 'post').callsFake(async (opts) => {
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPHSite/AddHomeSite`) {
return homeSites;
}

throw opts.url;
});

await command.action(logger, { options: { url: homeSite, verbose: true } });
assert(loggerLogSpy.calledWith(homeSites));
});

it('adds a home site with the specified URL, isInDraftMode, vivaConnectionsDefaultStart, and audiences', async () => {
const postStub = sinon.stub(request, 'post').callsFake(async (opts) => {
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPHSite/AddHomeSite`) {
return homeSiteConfig;
}
throw 'Invalid request';
});

await command.action(logger, {
options: {
url: homeSite,
isInDraftMode: 'true',
vivaConnectionsDefaultStart: 'false',
audiences: 'af8c0bc8-7b1b-44b4-b087-ffcc8df70d16',
order: 2
}
});

const expectedData = {
"audiences": [
"af8c0bc8-7b1b-44b4-b087-ffcc8df70d16"
],
"isInDraftMode": "true",
"order": 2,
"siteUrl": "https://contoso.sharepoint.com/sites/testcomms",
"vivaConnectionsDefaultStart": "false"
};
assert.deepStrictEqual(postStub.lastCall.args[0].data, expectedData);
});

it('fails validation if the url is not a valid SharePoint url', async () => {
const actual = await command.validate({
options: {
url: "test"
}
}, commandInfo);
assert.notStrictEqual(actual, true);
});

it('correctly handles non-integer order', async () => {
const result = await command.validate({
options: {
url: homeSite,
order: 'invalid-order'
}
}, commandInfo);
assert.strictEqual(result, 'invalid-order is not a positive integer');
});

it('correctly handles invalid GUIDs in audiences', async () => {
const result = await command.validate({
options: {
url: homeSite,
audiences: 'invalid-guid'
}
}, commandInfo);
assert.strictEqual(result, `The following GUIDs are invalid for the option 'ids': invalid-guid.`);
});

it('passes validation with URL', async () => {
const actual = await command.validate({
options: {
url: homeSite
}
}, commandInfo);
assert.strictEqual(actual, true);
});
reshmee011 marked this conversation as resolved.
Show resolved Hide resolved

it('passes validation with URL and optional parameters', async () => {
const actual = await command.validate({
options: {
url: homeSite,
isInDraftMode: 'true',
vivaConnectionsDefaultStart: 'false',
audiences: 'af8c0bc8-7b1b-44b4-b087-ffcc8df70d16',
order: 2
}
}, commandInfo);
assert.strictEqual(actual, true);
});

it('correctly handles OData error when adding a home site', async () => {
sinon.stub(request, 'post').rejects({ error: { 'odata.error': { message: { value: 'An error has occurred' } } } });

await assert.rejects(command.action(logger, { options: { url: 'https://....' } } as any), new CommandError('An error has occurred'));
});
});
Loading
Loading