Skip to content

Commit 1657b82

Browse files
committed
addressed code review feedback
1 parent 12ddad9 commit 1657b82

File tree

3 files changed

+57
-156
lines changed

3 files changed

+57
-156
lines changed

docs/docs/cmd/spo/homesite/homesite-remove.mdx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import TabItem from '@theme/TabItem';
44

55
# spo homesite remove
66

7-
Removes the current Home Site
7+
Removes a Home Site
88

99
## Usage
1010

@@ -15,11 +15,11 @@ m365 spo homesite remove [options]
1515
## Options
1616

1717
```md definition-list
18-
`-f, --force`
19-
: Do not prompt for confirmation before removing the Home Site.
20-
2118
`-u, --url [url]`
2219
: URL of the home site to remove.
20+
21+
`-f, --force`
22+
: Do not prompt for confirmation before removing the Home Site.
2323
```
2424

2525
<Global />
@@ -34,16 +34,10 @@ To use this command you must be either **SharePoint Administrator** or **Global
3434

3535
## Examples
3636

37-
Removes the first Home Site without confirmation.
38-
39-
```sh
40-
m365 spo homesite remove --force
41-
```
42-
43-
Removes a Home site specified by URL without confirmation.
37+
Removes a Home site specified by URL without prompting for confirmation.
4438

4539
```sh
46-
m365 spo homesite remove -url "https://contoso.sharepoint.com/sites/testcomms" --force
40+
m365 spo homesite remove --url "https://contoso.sharepoint.com/sites/testcomms" --force
4741
```
4842

4943
## Response

src/m365/spo/commands/homesite/homesite-remove.spec.ts

Lines changed: 30 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -23,43 +23,6 @@ describe(commands.HOMESITE_REMOVE, () => {
2323
let commandInfo: CommandInfo;
2424
let commandOptionsSchema: z.ZodTypeAny;
2525
const siteId = '00000000-0000-0000-0000-000000000010';
26-
const homeSites = {
27-
"value": [
28-
{
29-
"Audiences": [
30-
{
31-
"Email": "[email protected]",
32-
"Id": "978b5280-4f80-47ea-a1db-b0d1d2fb1ba4",
33-
"Title": "ColumnSearchable Members"
34-
},
35-
{
36-
"Email": "[email protected]",
37-
"Id": "21af775d-17b3-4637-94a4-2ba8625277cb",
38-
"Title": "Contoso TeamR Members"
39-
}
40-
],
41-
"IsInDraftMode": false,
42-
"IsVivaBackendSite": false,
43-
"SiteId": "431d7819-4aaf-49a1-b664-b2fe9e609b63",
44-
"TargetedLicenseType": 2,
45-
"Title": "The Landing",
46-
"Url": "https://contoso.sharepoint.com/sites/TheLanding",
47-
"VivaConnectionsDefaultStart": true,
48-
"WebId": "626c1724-8ac8-45d5-af87-c07c752fab75"
49-
},
50-
{
51-
"Audiences": [],
52-
"IsInDraftMode": false,
53-
"IsVivaBackendSite": false,
54-
"SiteId": "45d4a135-40e4-4571-8340-61d17fdfd58a",
55-
"TargetedLicenseType": 0,
56-
"Title": "Contoso Electronics",
57-
"Url": "https://contoso.sharepoint.com/sites/contosoportal",
58-
"VivaConnectionsDefaultStart": true,
59-
"WebId": "9418e2a1-855c-4752-8dd4-48693f43b10a"
60-
}
61-
]
62-
};
6326

6427
before(() => {
6528
sinon.stub(auth, 'restoreAuth').resolves();
@@ -143,17 +106,7 @@ describe(commands.HOMESITE_REMOVE, () => {
143106
assert.strictEqual(actual.success, false);
144107
});
145108

146-
it('removes the Home Site using legacy method when only one Home Site exists and prompt is confirmed', async () => {
147-
sinon.stub(request, 'get').callsFake(async (opts) => {
148-
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPO.Tenant/GetTargetedSitesDetails`) {
149-
return { value: [homeSites.value[0]] };
150-
}
151-
152-
throw 'Invalid request';
153-
});
154-
155-
sinon.stub(spo, 'getSiteAdminPropertiesByUrl').resolves({ SiteId: siteId } as any);
156-
109+
it('removes the Home Site when prompt confirmed', async () => {
157110
let homeSiteRemoveCallIssued = false;
158111

159112
sinon.stub(request, 'post').callsFake(async (opts) => {
@@ -182,24 +135,14 @@ describe(commands.HOMESITE_REMOVE, () => {
182135
assert(homeSiteRemoveCallIssued);
183136
});
184137

185-
it('removes the first Home Site when multiple Home Sites exist and url is not specified', async () => {
186-
sinon.stub(request, 'get').callsFake(async (opts) => {
187-
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPO.Tenant/GetTargetedSitesDetails`) {
188-
return homeSites;
189-
}
190-
191-
throw 'Invalid request';
192-
});
138+
it('removes the Home Site whithout confirm prompt', async () => {
139+
let homeSiteRemoveCallIssued = false;
193140

194-
sinon.stub(spo, 'getSiteAdminPropertiesByUrl').resolves({ SiteId: siteId } as any);
141+
sinon.stub(request, 'post').callsFake(async (opts) => {
142+
if (opts.data === `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="28" ObjectPathId="27" /><Method Name="RemoveSPHSite" Id="29" ObjectPathId="27" /></Actions><ObjectPaths><Constructor Id="27" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`) {
195143

196-
const postStub = sinon.stub(request, 'post').callsFake(async (opts) => {
197-
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPO.Tenant/RemoveTargetedSite` &&
198-
opts.data.siteId === siteId) {
199-
return {};
200-
}
144+
homeSiteRemoveCallIssued = true;
201145

202-
if (opts.data === `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="28" ObjectPathId="27" /><Method Name="RemoveSPHSite" Id="29" ObjectPathId="27" /></Actions><ObjectPaths><Constructor Id="27" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`) {
203146
return JSON.stringify(
204147
[
205148
{
@@ -215,36 +158,15 @@ describe(commands.HOMESITE_REMOVE, () => {
215158
});
216159

217160
await command.action(logger, { options: { force: true } });
218-
assert(postStub.calledOnce);
219-
assert.deepStrictEqual(postStub.lastCall.args[0].url, "https://contoso-admin.sharepoint.com/_api/SPO.Tenant/RemoveTargetedSite");
161+
assert(homeSiteRemoveCallIssued);
220162
});
221163

222164
it('removes the Home Site specified by URL', async () => {
223-
sinon.stub(request, 'get').callsFake(async (opts) => {
224-
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPO.Tenant/GetTargetedSitesDetails`) {
225-
return homeSites;
226-
}
227-
228-
throw 'Invalid request';
229-
});
230-
231165
sinon.stub(spo, 'getSiteAdminPropertiesByUrl').resolves({ SiteId: siteId } as any);
232-
const postStub = sinon.stub(request, 'post').callsFake(async (opts) => {
233-
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPO.Tenant/RemoveTargetedSite` &&
234-
opts.data?.siteId === siteId) {
235-
return {};
236-
}
237166

238-
if (opts.data === `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="28" ObjectPathId="27" /><Method Name="RemoveSPHSite" Id="29" ObjectPathId="27" /></Actions><ObjectPaths><Constructor Id="27" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`) {
239-
return JSON.stringify(
240-
[
241-
{
242-
"SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.8929.1227", "ErrorInfo": null, "TraceCorrelationId": "e4f2e59e-c0a9-0000-3dd0-1d8ef12cc742"
243-
}, 57, {
244-
"IsNull": false
245-
}, 58, "The Home site has been removed."
246-
]
247-
);
167+
const postStub = sinon.stub(request, 'post').callsFake(async (opts) => {
168+
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPO.Tenant/RemoveTargetedSite`) {
169+
return;
248170
}
249171

250172
throw 'Invalid request';
@@ -255,19 +177,10 @@ describe(commands.HOMESITE_REMOVE, () => {
255177

256178
await command.action(logger, { options: { url: 'https://contoso.sharepoint.com' } });
257179
assert(postStub.calledOnce);
180+
assert.deepStrictEqual(postStub.lastCall.args[0].data, { siteId });
258181
});
259182

260183
it('correctly handles error when removing the Home Site (debug)', async () => {
261-
sinon.stub(request, 'get').callsFake(async (opts) => {
262-
if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPO.Tenant/GetTargetedSitesDetails`) {
263-
return { value: [homeSites.value[0]] };
264-
}
265-
266-
throw 'Invalid request';
267-
});
268-
269-
sinon.stub(spo, 'getSiteAdminPropertiesByUrl').resolves({ SiteId: siteId } as any);
270-
271184
sinon.stub(request, 'post').callsFake(async (opts) => {
272185
if (opts.data === `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="28" ObjectPathId="27" /><Method Name="RemoveSPHSite" Id="29" ObjectPathId="27" /></Actions><ObjectPaths><Constructor Id="27" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`) {
273186
return JSON.stringify(
@@ -287,4 +200,23 @@ describe(commands.HOMESITE_REMOVE, () => {
287200
await assert.rejects(command.action(logger, { options: { debug: true, force: true } } as any),
288201
new CommandError(`The requested operation is part of an experimental feature that is not supported in the current environment.`));
289202
});
203+
204+
it('correctly handles error when attempting to remove a site that is not a home site or Viva Connections', async () => {
205+
sinon.stub(request, 'post').rejects({
206+
error: {
207+
"odata.error": {
208+
"code": "-2146232832, Microsoft.SharePoint.SPException",
209+
"message": {
210+
"lang": "en-US",
211+
"value": "[Error ID: 03fc404e-0f70-4607-82e8-8fdb014e8658] The site with ID \"8e4686ed-b00c-4c5f-a0e2-4197081df5d5\" has not been added as a home site or Viva Connections. Check aka.ms/homesites for details."
212+
}
213+
}
214+
}
215+
});
216+
217+
await assert.rejects(
218+
command.action(logger, { options: { debug: true, force: true } } as any),
219+
new CommandError('[Error ID: 03fc404e-0f70-4607-82e8-8fdb014e8658] The site with ID \"8e4686ed-b00c-4c5f-a0e2-4197081df5d5\" has not been added as a home site or Viva Connections. Check aka.ms/homesites for details.')
220+
);
221+
});
290222
});

src/m365/spo/commands/homesite/homesite-remove.ts

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { globalOptionsZod } from '../../../../Command.js';
44
import { validation } from '../../../../utils/validation.js';
55
import { cli } from '../../../../cli/cli.js';
66
import { Logger } from '../../../../cli/Logger.js';
7-
import { odata } from '../../../../utils/odata.js';
87
import config from '../../../../config.js';
98
import request, { CliRequestOptions } from '../../../../request.js';
109
import { ClientSvcResponse, ClientSvcResponseContents, spo } from '../../../../utils/spo.js';
@@ -13,11 +12,11 @@ import commands from '../../commands.js';
1312

1413
const options = globalOptionsZod
1514
.extend({
16-
url: zod.alias('u', z.string()
17-
.refine((url: string) => validation.isValidSharePointUrl(url) === true, url => ({
15+
url: zod.alias('u', z.string().optional()
16+
.refine(url => url === undefined || validation.isValidSharePointUrl(url) === true, url => ({
1817
message: `'${url}' is not a valid SharePoint Online site URL.`
1918
}))
20-
).optional(),
19+
),
2120
force: zod.alias('f', z.boolean().optional())
2221
})
2322
.strict();
@@ -51,36 +50,25 @@ class SpoHomeSiteRemoveCommand extends SpoCommand {
5150
await this.removeHomeSiteByUrl(args.options.url, spoAdminUrl, logger);
5251
}
5352
else {
54-
await this.showDeprecationWarning(
55-
logger,
56-
commands.HOMESITE_REMOVE,
57-
`${commands.HOMESITE_REMOVE} --url <url>`
58-
);
59-
60-
const homeSites = await this.getHomeSites(spoAdminUrl);
61-
62-
if (homeSites.length > 1) {
63-
await this.removeHomeSiteByUrl(homeSites[0].Url, spoAdminUrl, logger);
53+
await this.showDeprecationWarning(logger, commands.HOMESITE_REMOVE, `--url <url>`);
54+
55+
const requestOptions: CliRequestOptions = {
56+
url: `${spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
57+
headers: {
58+
'X-RequestDigest': reqDigest.FormDigestValue
59+
},
60+
data: `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="28" ObjectPathId="27" /><Method Name="RemoveSPHSite" Id="29" ObjectPathId="27" /></Actions><ObjectPaths><Constructor Id="27" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`
61+
};
62+
63+
const res = await request.post<string>(requestOptions);
64+
65+
const json: ClientSvcResponse = JSON.parse(res);
66+
const response: ClientSvcResponseContents = json[0];
67+
if (response.ErrorInfo) {
68+
throw response.ErrorInfo.ErrorMessage;
6469
}
6570
else {
66-
const requestOptions: CliRequestOptions = {
67-
url: `${spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
68-
headers: {
69-
'X-RequestDigest': reqDigest.FormDigestValue
70-
},
71-
data: `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="28" ObjectPathId="27" /><Method Name="RemoveSPHSite" Id="29" ObjectPathId="27" /></Actions><ObjectPaths><Constructor Id="27" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`
72-
};
73-
74-
const res = await request.post<string>(requestOptions);
75-
76-
const json: ClientSvcResponse = JSON.parse(res);
77-
const response: ClientSvcResponseContents = json[0];
78-
if (response.ErrorInfo) {
79-
throw response.ErrorInfo.ErrorMessage;
80-
}
81-
else {
82-
await logger.log(json[json.length - 1]);
83-
}
71+
await logger.log(json[json.length - 1]);
8472
}
8573
}
8674
}
@@ -89,7 +77,6 @@ class SpoHomeSiteRemoveCommand extends SpoCommand {
8977
}
9078
};
9179

92-
9380
if (args.options.force) {
9481
await removeHomeSite();
9582
}
@@ -112,7 +99,7 @@ class SpoHomeSiteRemoveCommand extends SpoCommand {
11299
const requestOptions: CliRequestOptions = {
113100
url: `${spoAdminUrl}/_api/SPO.Tenant/RemoveTargetedSite`,
114101
headers: {
115-
'Accept': 'application/json;odata=nometadata'
102+
accept: 'application/json;odata=nometadata'
116103
},
117104
data: {
118105
siteId: siteAdminProperties.SiteId
@@ -123,18 +110,6 @@ class SpoHomeSiteRemoveCommand extends SpoCommand {
123110

124111
await logger.log(`${siteUrl} has been removed as a Home Site. It may take some time for the change to apply. Check aka.ms/homesites for details.`);
125112
}
126-
127-
private async getHomeSites(spoAdminUrl: string): Promise<any[]> {
128-
const requestOptions: CliRequestOptions = {
129-
url: `${spoAdminUrl}/_api/SPO.Tenant/GetTargetedSitesDetails`,
130-
headers: {
131-
accept: 'application/json;odata=nometadata'
132-
},
133-
responseType: 'json'
134-
};
135-
136-
return await odata.getAllItems(requestOptions);
137-
}
138113
}
139114

140115
export default new SpoHomeSiteRemoveCommand();

0 commit comments

Comments
 (0)