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 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
97 changes: 97 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,97 @@
import Global from '/docs/cmd/_global.mdx';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# spo tenant homesite add

Add a Home Site.

## Usage

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

## Options

<Global />

## Examples

Add a Home Site

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

```

## Response

<Tabs>
<TabItem value="JSON">

```json
{
"Audiences": [],
"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 : []
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 @@ -3766,6 +3766,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 @@ -318,6 +318,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
116 changes: 116 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,116 @@
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"
};

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('adds available home sites', async () => {
sinon.stub(request, 'post').callsFake(async (opts) => {
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPO.Tenant/AddHomeSite`) {
return homeSites;
}

throw opts.url;
});

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

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('passes validation', async () => {
const actual = await command.validate({
options: {
url: homeSite
}
}, 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: {} } as any), new CommandError('An error has occurred'));
});
});
87 changes: 87 additions & 0 deletions src/m365/spo/commands/tenant/tenant-homesite-add.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Logger } from '../../../../cli/Logger.js';
import GlobalOptions from '../../../../GlobalOptions.js';
import { spo } from '../../../../utils/spo.js';
import { validation } from '../../../../utils/validation.js';
import SpoCommand from '../../../base/SpoCommand.js';
import commands from '../../commands.js';
import request, { CliRequestOptions } from '../../../../request.js';

interface CommandArgs {
options: Options;
}

interface Options extends GlobalOptions {
url: string;
}

class SpoTenantHomeSiteAddCommand extends SpoCommand {
public get name(): string {
return commands.TENANT_HOMESITE_ADD;
}

public get description(): string {
return 'Add a Home Site';
}

constructor() {
super();

this.#initTelemetry();
this.#initOptions();
this.#initValidators();
}

#initTelemetry(): void {
this.telemetry.push((args: CommandArgs) => {
Object.assign(this.telemetryProperties, {
url: args.options.url
});
});
}

#initOptions(): void {
this.options.unshift(
{
option: '-u, --url <url>'
}
);
}

#initValidators(): void {
this.validators.push(
async (args: CommandArgs) => {
const isValidSharePointUrl: boolean | string = validation.isValidSharePointUrl(args.options.url);
if (isValidSharePointUrl !== true) {
return isValidSharePointUrl;
}
return true;
}
);
}

public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {
try {
const spoAdminUrl: string = await spo.getSpoAdminUrl(logger, this.verbose);
const requestOptions: CliRequestOptions = {
url: `${spoAdminUrl}/_api/SPO.Tenant/AddHomeSite`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @reshmee011, I've noticed in this command, we can only provide the URL of the home site, and nothing else. What I'm missing here, are the other properties like isInDraftMode, vivaConnectionsDefaultStart etc that cannot be set with this API request (or am I wrong here?) Currently, if we want to set these options, we'll have to execute a separate command, which is annoying of course. Do you know whether it's possible to provide the extra options?

I found following request, which is capable of doing so:

POST https://contoso-admin.sharepoint.com/_api/SPHSite/AddHomeSite
{
    "siteUrl": "https://contoso.sharepoint.com/sites/homesite",
    "audiences": ["<audiences>"],
    "vivaConnectionsDefaultStart": false,
    "isInDraftMode": false
}

Maybe we should roll with this one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, I will check if those additional parameters: isInDraftMode, vivaConnectionsDefaultStart work with the endpoint AddHomeSite. Have you tried them out?
Definitely those can be passed to the endpoint /_api/SPO.Tenant/UpdateTargetedSite.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@milanholemans : I get the following error with the AddHomeSite endpoint.
-vivaConnectionsDefaultStart
{"odata.error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"The parameter vivaConnectionsDefaultStart does not exist in
| method AddHomeSite."}}}
-isInDraftMode
{"odata.error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"The parameter isInDraftMode does not exist in method
| AddHomeSite."}}}
-siteUrl
{"odata.error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"The parameter siteUrl does not exist in method
| AddHomeSite."}}}

It seems to accept only the parameter homeSiteUrl.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I've tried some things as well, and didn't get it to work, unfortunately. It did work for the _api/SPHSite/AddHomeSite API request, I have no idea if there's any difference, but it seems to be working for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@milanholemans : _api/SPHSite/AddHomeSite works with these 3 parameters: audiences, vivaConnectionsDefaultStart and isInDraftMode. I will amend the code to use _api/SPHSite/AddHomeSite and add these three parameters.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the _api/SPHSite/AddHomeSite API body, we can provide more options:

image

I think we can use all these options in this command. That would mean that we have to add them as input for the command. Sorry that we didn't figure this out when speccing the command.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@milanholemans : I will add order as well, out of curiosity where did you find information on this endpoint?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@milanholemans : thanks for sharing.

headers: {
accept: 'application/json;odata=nometadata'
},
responseType: 'json',
data: {
homeSiteUrl: args.options.url
}
};
if (this.verbose) {
await logger.logToStderr(`Adding the home site...`);
}
const res = await request.post(requestOptions);
await logger.log(res);
}
catch (err: any) {
this.handleRejectedODataJsonPromise(err);
}
}
}

export default new SpoTenantHomeSiteAddCommand();
Loading