diff --git a/docs/docs/cmd/spo/tenant/tenant-homesite-list.mdx b/docs/docs/cmd/spo/tenant/tenant-homesite-list.mdx new file mode 100644 index 0000000000..aca1da65c8 --- /dev/null +++ b/docs/docs/cmd/spo/tenant/tenant-homesite-list.mdx @@ -0,0 +1,95 @@ +import Global from '/docs/cmd/_global.mdx'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# spo homesite list + +Lists all home sites + +## Usage + +```sh +m365 spo tenant homesite list [options] +``` + +## Options + + + +## Examples + +List all home sites + +```sh +m365 spo tenant homesite list +``` + +## Response + + + + + ```json + [ + { + "Audiences": [ + { + "Email": "ColumnSearchable@contoso.onmicrosoft.com", + "Id": "978b5280-4f80-47ea-a1db-b0d1d2fb1ba4", + "Title": "ColumnSearchable Members" + } + ], + "IsInDraftMode": false, + "IsVivaBackendSite": false, + "SiteId": "431d7819-4aaf-49a1-b664-b2fe9e609b63", + "TargetedLicenseType": 2, + "Title": "The Landing", + "Url": "https://contoso.sharepoint.com/sites/TheLanding", + "VivaConnectionsDefaultStart": true, + "WebId": "626c1724-8ac8-45d5-af87-c07c752fab75" + } + ] + ``` + + + + + ```text + Url Title + ----------------------------------------------- ----------- + https://contoso.sharepoint.com/sites/TheLanding The Landing + ``` + + + + + ```csv + IsInDraftMode,IsVivaBackendSite,SiteId,TargetedLicenseType,Title,Url,VivaConnectionsDefaultStart,WebId + 0,0,431d7819-4aaf-49a1-b664-b2fe9e609b63,2,The Landing,https://contoso.sharepoint.com/sites/TheLanding,1,626c1724-8ac8-45d5-af87-c07c752fab75 + ``` + + + + + ```md + # spo homesite list + + Date: 11/18/2024 + + Property | Value + ---------|------- + IsInDraftMode | false + IsVivaBackendSite | false + SiteId | 431d7819-4aaf-49a1-b664-b2fe9e609b63 + TargetedLicenseType | 2 + Title | The Landing + Url | https://contoso.sharepoint.com/sites/TheLanding + VivaConnectionsDefaultStart | true + WebId | 626c1724-8ac8-45d5-af87-c07c752fab75 + ``` + + + +## More information + +- SharePoint home sites [Viva Connections set up](https://learn.microsoft.com/en-us/viva/connections/set-up-admin-center) diff --git a/docs/src/config/sidebars.ts b/docs/src/config/sidebars.ts index 06ed8558b5..4cc2725043 100644 --- a/docs/src/config/sidebars.ts +++ b/docs/src/config/sidebars.ts @@ -3737,6 +3737,11 @@ const sidebars: SidebarsConfig = { label: 'tenant commandset set', id: 'cmd/spo/tenant/tenant-commandset-set' }, + { + type: 'doc', + label: 'homesite list', + id: 'cmd/spo/tenant/tenant-homesite-list' + }, { type: 'doc', label: 'tenant recyclebinitem list', diff --git a/src/m365/spo/commands.ts b/src/m365/spo/commands.ts index 9ad1de6b0f..f17b2edca2 100644 --- a/src/m365/spo/commands.ts +++ b/src/m365/spo/commands.ts @@ -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_LIST: `${prefix} tenant homesite list`, TENANT_RECYCLEBINITEM_LIST: `${prefix} tenant recyclebinitem list`, TENANT_RECYCLEBINITEM_REMOVE: `${prefix} tenant recyclebinitem remove`, TENANT_RECYCLEBINITEM_RESTORE: `${prefix} tenant recyclebinitem restore`, diff --git a/src/m365/spo/commands/tenant/tenant-homesite-list.spec.ts b/src/m365/spo/commands/tenant/tenant-homesite-list.spec.ts new file mode 100644 index 0000000000..c046e6d4b7 --- /dev/null +++ b/src/m365/spo/commands/tenant/tenant-homesite-list.spec.ts @@ -0,0 +1,123 @@ +import assert from 'assert'; +import sinon from 'sinon'; +import auth from '../../../../Auth.js'; +import { Logger } from '../../../../cli/Logger.js'; +import { CommandError } from '../../../../Command.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-list.js'; + +describe(commands.TENANT_HOMESITE_LIST, () => { + let log: string[]; + let logger: Logger; + let loggerLogSpy: sinon.SinonSpy; + const homeSites = { + "value": [ + { + "Audiences": [ + { + "Email": "ColumnSearchable@contoso.onmicrosoft.com", + "Id": "978b5280-4f80-47ea-a1db-b0d1d2fb1ba4", + "Title": "ColumnSearchable Members" + }, + { + "Email": "contosoteam@contoso.onmicrosoft.com", + "Id": "21af775d-17b3-4637-94a4-2ba8625277cb", + "Title": "Contoso TeamR Members" + } + ], + "IsInDraftMode": false, + "IsVivaBackendSite": false, + "SiteId": "431d7819-4aaf-49a1-b664-b2fe9e609b63", + "TargetedLicenseType": 2, + "Title": "The Landing", + "Url": "https://contoso.sharepoint.com/sites/TheLanding", + "VivaConnectionsDefaultStart": true, + "WebId": "626c1724-8ac8-45d5-af87-c07c752fab75" + }, + { + "Audiences": [], + "IsInDraftMode": false, + "IsVivaBackendSite": false, + "SiteId": "45d4a135-40e4-4571-8340-61d17fdfd58a", + "TargetedLicenseType": 0, + "Title": "Contoso Electronics", + "Url": "https://contoso.sharepoint.com/sites/contosoportal", + "VivaConnectionsDefaultStart": true, + "WebId": "9418e2a1-855c-4752-8dd4-48693f43b10a" + } + ] + }; + + 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'); + }); + + afterEach(() => { + sinonUtil.restore([ + request.get + ]); + }); + + after(() => { + sinon.restore(); + auth.connection.active = false; + auth.connection.spoUrl = undefined; + }); + + it('has correct name', () => { + assert.strictEqual(command.name, commands.TENANT_HOMESITE_LIST); + }); + + it('has a description', () => { + assert.notStrictEqual(command.description, null); + }); + + it('defines correct properties for the default output', () => { + assert.deepStrictEqual(command.defaultProperties(), ['Url', 'Title']); + }); + + it('lists available home sites', async () => { + sinon.stub(request, 'get').callsFake(async (opts) => { + if (opts.url === `https://contoso-admin.sharepoint.com/_api/SPO.Tenant/GetTargetedSitesDetails`) { + return homeSites; + } + + throw opts.url; + }); + + await command.action(logger, { options: { verbose: true } }); + assert(loggerLogSpy.calledWith(homeSites.value)); + }); + + it('correctly handles OData error when retrieving available home sites', async () => { + sinon.stub(request, 'get').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')); + }); +}); diff --git a/src/m365/spo/commands/tenant/tenant-homesite-list.ts b/src/m365/spo/commands/tenant/tenant-homesite-list.ts new file mode 100644 index 0000000000..5595fb3920 --- /dev/null +++ b/src/m365/spo/commands/tenant/tenant-homesite-list.ts @@ -0,0 +1,43 @@ +import { Logger } from '../../../../cli/Logger.js'; +import { odata } from '../../../../utils/odata.js'; +import { spo } from '../../../../utils/spo.js'; +import SpoCommand from '../../../base/SpoCommand.js'; +import commands from '../../commands.js'; +import { CliRequestOptions } from "../../../../request.js"; + +class SpoTenantHomeSiteListCommand extends SpoCommand { + public get name(): string { + return commands.TENANT_HOMESITE_LIST; + } + + public get description(): string { + return 'Lists all home sites'; + } + + public defaultProperties(): string[] | undefined { + return ['Url', 'Title']; + } + + public async commandAction(logger: Logger): Promise { + try { + const spoAdminUrl: string = await spo.getSpoAdminUrl(logger, this.verbose); + const requestOptions: CliRequestOptions = { + url: `${spoAdminUrl}/_api/SPO.Tenant/GetTargetedSitesDetails`, + headers: { + accept: 'application/json;odata=nometadata' + }, + responseType: 'json' + }; + if (this.verbose) { + await logger.logToStderr(`Retrieving all home sites...`); + } + const res = await odata.getAllItems(requestOptions); + await logger.log(res); + } + catch (err: any) { + this.handleRejectedODataJsonPromise(err); + } + } +} + +export default new SpoTenantHomeSiteListCommand(); \ No newline at end of file