diff --git a/.devproxy/api-specs/sharepoint.yaml b/.devproxy/api-specs/sharepoint.yaml index f88e20ec367..8f6934a02c9 100644 --- a/.devproxy/api-specs/sharepoint.yaml +++ b/.devproxy/api-specs/sharepoint.yaml @@ -57,6 +57,22 @@ components: User.Read.All: User.Read.All User.ReadWrite.All: User.ReadWrite.All paths: + /_api/Brandcenter/Configuration: + get: + security: + - delegated: + - AllSites.Read + - AllSites.Write + - AllSites.Manage + - AllSites.FullControl + - application: + - Sites.Read.All + - Sites.ReadWrite.All + - Sites.Manage.All + - Sites.FullControl.All + responses: + 200: + description: OK /_api/contextinfo: post: security: diff --git a/docs/docs/cmd/spo/brandcenter/brandcenter-settings-list.mdx b/docs/docs/cmd/spo/brandcenter/brandcenter-settings-list.mdx new file mode 100644 index 00000000000..4969870f43f --- /dev/null +++ b/docs/docs/cmd/spo/brandcenter/brandcenter-settings-list.mdx @@ -0,0 +1,151 @@ +import Global from '/docs/cmd/_global.mdx'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# spo brandcenter settings list + +Lists the brand center configuration + +## Usage + +```sh +m365 spo brandcenter settings list [options] +``` + +## Options + + + +## Permissions + + + + + | Resource | Permissions | + |-----------------|-----------------| + | Microsoft Graph | Sites.Read.All | + | SharePoint | AllSites.Read | + + + + + | Resource | Permissions | + |-----------------|------------------| + | Microsoft Graph | Sites.Read.All | + | SharePoint | Sites.Read.All | + + + + +## Examples + +List all brand center config + +```sh +m365 spo brandcenter settings list +``` + +## Response + + + + + ```json + { + "BrandColorsListId": "00000000-0000-0000-0000-000000000000", + "BrandColorsListUrl": null, + "BrandFontLibraryId": "23af51de-856c-4d00-aa11-0d03af0e46e3", + "BrandFontLibraryUrl": { + "DecodedUrl": "https://contoso.sharepoint.com/sites/BrandGuide/Fonts" + }, + "IsBrandCenterSiteFeatureEnabled": true, + "IsPublicCdnEnabled": true, + "OrgAssets": { + "CentralAssetRepositoryLibraries": null, + "Domain": { + "DecodedUrl": "https://contoso.sharepoint.com" + }, + "OrgAssetsLibraries": { + "OrgAssetsLibraries": [ + { + "DisplayName": "Fonts", + "FileType": "", + "LibraryUrl": { + "DecodedUrl": "sites/BrandGuide/Fonts" + }, + "ListId": "23af51de-856c-4d00-aa11-0d03af0e46e3", + "OrgAssetFlags": 0, + "OrgAssetType": 8, + "ThumbnailUrl": null, + "UniqueId": "00000000-0000-0000-0000-000000000000" + } + ], + "Items": [ + { + "DisplayName": "Fonts", + "FileType": "", + "LibraryUrl": { + "DecodedUrl": "sites/BrandGuide/Fonts" + }, + "ListId": "23af51de-856c-4d00-aa11-0d03af0e46e3", + "OrgAssetFlags": 0, + "OrgAssetType": 8, + "ThumbnailUrl": null, + "UniqueId": "00000000-0000-0000-0000-000000000000" + } + ] + }, + "SiteId": "52b46e48-9c0c-40cb-a955-13eb6c717ff3", + "Url": { + "DecodedUrl": "/sites/BrandGuide" + }, + "WebId": "206988d5-e133-4a24-819d-24101f3407ce" + }, + "SiteId": "52b46e48-9c0c-40cb-a955-13eb6c717ff3", + "SiteUrl": "https://contoso.sharepoint.com/sites/BrandGuide" + } + ``` + + + + + ```txt + BrandColorsListId : 00000000-0000-0000-0000-000000000000 + BrandColorsListUrl : null + BrandFontLibraryId : 23af51de-856c-4d00-aa11-0d03af0e46e3 + BrandFontLibraryUrl : {"DecodedUrl":"https://contoso.sharepoint.com/sites/BrandGuide/Fonts"} + IsBrandCenterSiteFeatureEnabled: true + IsPublicCdnEnabled : true + OrgAssets : {"CentralAssetRepositoryLibraries":null,"Domain":{"DecodedUrl":"https://contoso.sharepoint.com"},"OrgAssetsLibraries":{"OrgAssetsLibraries":[{"DisplayName":"Fonts","FileType":"","LibraryUrl":{"DecodedUrl":"sites/BrandGuide/Fonts"},"ListId":"23af51de-856c-4d00-aa11-0d03af0e46e3","OrgAssetFlags":0,"OrgAssetType":8,"ThumbnailUrl":null,"UniqueId":"00000000-0000-0000-0000-000000000000"}],"Items":[{"DisplayName":"Fonts","FileType":"","LibraryUrl":{"DecodedUrl":"sites/BrandGuide/Fonts"},"ListId":"23af51de-856c-4d00-aa11-0d03af0e46e3","OrgAssetFlags":0,"OrgAssetType":8,"ThumbnailUrl":null,"UniqueId":"00000000-0000-0000-0000-000000000000"}]},"SiteId":"52b46e48-9c0c-40cb-a955-13eb6c717ff3","Url":{"DecodedUrl":"/sites/BrandGuide"},"WebId":"206988d5-e133-4a24-819d-24101f3407ce"} + SiteId : 52b46e48-9c0c-40cb-a955-13eb6c717ff3 + SiteUrl : https://contoso.sharepoint.com/sites/BrandGuide + ``` + + + + + ```csv + BrandColorsListId,BrandColorsListUrl,BrandFontLibraryId,IsBrandCenterSiteFeatureEnabled,IsPublicCdnEnabled,SiteId,SiteUrl + 00000000-0000-0000-0000-000000000000,,23af51de-856c-4d00-aa11-0d03af0e46e3,1,1,52b46e48-9c0c-40cb-a955-13eb6c717ff3,https://contoso.sharepoint.com/sites/BrandGuide + ``` + + + + + ```md + # spo brandcenter settings list --debug "false" --verbose "false" + + Date: 12/1/2025 + + Property | Value + ---------|------- + BrandColorsListId | 00000000-0000-0000-0000-000000000000 + BrandFontLibraryId | 23af51de-856c-4d00-aa11-0d03af0e46e3 + IsBrandCenterSiteFeatureEnabled | true + IsPublicCdnEnabled | true + SiteId | 52b46e48-9c0c-40cb-a955-13eb6c717ff3 + SiteUrl | https://contoso.sharepoint.com/sites/BrandGuide + ``` + + + diff --git a/docs/src/config/sidebars.ts b/docs/src/config/sidebars.ts index 4496615bb50..8f1c548145c 100644 --- a/docs/src/config/sidebars.ts +++ b/docs/src/config/sidebars.ts @@ -2373,6 +2373,15 @@ const sidebars: SidebarsConfig = { } ] }, + { + brandcenter: [ + { + type: 'doc', + label: 'brandcenter settings list', + id: 'cmd/spo/brandcenter/brandcenter-settings-list' + } + ] + }, { cdn: [ { diff --git a/src/m365/spo/commands.ts b/src/m365/spo/commands.ts index 544c1f2a102..3c7ac84df5e 100644 --- a/src/m365/spo/commands.ts +++ b/src/m365/spo/commands.ts @@ -19,6 +19,7 @@ export default { APPLICATIONCUSTOMIZER_SET: `${prefix} applicationcustomizer set`, APPPAGE_ADD: `${prefix} apppage add`, APPPAGE_SET: `${prefix} apppage set`, + BRANDCENTER_SETTINGS_LIST: `${prefix} brandcenter settings list`, CDN_GET: `${prefix} cdn get`, CDN_ORIGIN_ADD: `${prefix} cdn origin add`, CDN_ORIGIN_LIST: `${prefix} cdn origin list`, diff --git a/src/m365/spo/commands/brandcenter/brandcenter-settings-list.spec.ts b/src/m365/spo/commands/brandcenter/brandcenter-settings-list.spec.ts new file mode 100644 index 00000000000..66aa87d6337 --- /dev/null +++ b/src/m365/spo/commands/brandcenter/brandcenter-settings-list.spec.ts @@ -0,0 +1,176 @@ +import assert from 'assert'; +import sinon from 'sinon'; +import auth from '../../../../Auth.js'; +import { cli } from '../../../../cli/cli.js'; +import { CommandInfo } from '../../../../cli/CommandInfo.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 { z } from 'zod'; +import commands from '../../commands.js'; +import command from './brandcenter-settings-list.js'; + +describe(commands.BRANDCENTER_SETTINGS_LIST, () => { + let log: any[]; + let logger: Logger; + let loggerLogSpy: sinon.SinonSpy; + let commandInfo: CommandInfo; + let commandOptionsSchema: z.ZodTypeAny; + + const successResponse = { + "BrandColorsListId": "00000000-0000-0000-0000-000000000000", + "BrandColorsListUrl": null, + "BrandFontLibraryId": "23af51de-856c-4d00-aa11-0d03af0e46e3", + "BrandFontLibraryUrl": { + "DecodedUrl": "https://contoso.sharepoint.com/sites/BrandGuide/Fonts" + }, + "IsBrandCenterSiteFeatureEnabled": true, + "IsPublicCdnEnabled": true, + "OrgAssets": { + "CentralAssetRepositoryLibraries": null, + "Domain": { + "DecodedUrl": "https://contoso.sharepoint.com" + }, + "OrgAssetsLibraries": { + "OrgAssetsLibraries": [ + { + "DisplayName": "Fonts", + "FileType": "", + "LibraryUrl": { + "DecodedUrl": "sites/BrandGuide/Fonts" + }, + "ListId": "23af51de-856c-4d00-aa11-0d03af0e46e3", + "OrgAssetFlags": 0, + "OrgAssetType": 8, + "ThumbnailUrl": null, + "UniqueId": "00000000-0000-0000-0000-000000000000" + } + ], + "Items": [ + { + "DisplayName": "Fonts", + "FileType": "", + "LibraryUrl": { + "DecodedUrl": "sites/BrandGuide/Fonts" + }, + "ListId": "23af51de-856c-4d00-aa11-0d03af0e46e3", + "OrgAssetFlags": 0, + "OrgAssetType": 8, + "ThumbnailUrl": null, + "UniqueId": "00000000-0000-0000-0000-000000000000" + } + ] + }, + "SiteId": "52b46e48-9c0c-40cb-a955-13eb6c717ff3", + "Url": { + "DecodedUrl": "/sites/BrandGuide" + }, + "WebId": "206988d5-e133-4a24-819d-24101f3407ce" + }, + "SiteId": "52b46e48-9c0c-40cb-a955-13eb6c717ff3", + "SiteUrl": "https://contoso.sharepoint.com/sites/BrandGuide" + }; + + before(() => { + sinon.stub(auth, 'restoreAuth').resolves(); + sinon.stub(telemetry, 'trackEvent').resolves(); + sinon.stub(pid, 'getProcessName').returns(''); + sinon.stub(session, 'getId').returns(''); + + auth.connection.active = true; + auth.connection.spoUrl = 'https://contoso.sharepoint.com'; + commandInfo = cli.getCommandInfo(command); + commandOptionsSchema = commandInfo.command.getSchemaToParse()!; + }); + + 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.BRANDCENTER_SETTINGS_LIST); + }); + + it('has a description', () => { + assert.notStrictEqual(command.description, null); + }); + + it('passes validation with no options', () => { + const actual = commandOptionsSchema.safeParse({}); + assert.strictEqual(actual.success, true); + }); + + it('fails validation with unknown options', () => { + const actual = commandOptionsSchema.safeParse({ option: "value" }); + assert.strictEqual(actual.success, false); + }); + + it('successfully lists brand center settings', async () => { + const getStub = sinon.stub(request, 'get').callsFake(async (opts: any) => { + if (opts.url === `https://contoso.sharepoint.com/_api/Brandcenter/Configuration`) { + return successResponse; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { options: {} }); + assert(getStub.calledOnce); + assert(loggerLogSpy.calledWith(successResponse)); + }); + + it('successfully lists brand center settings with verbose output', async () => { + const getStub = sinon.stub(request, 'get').callsFake(async (opts: any) => { + if (opts.url === `https://contoso.sharepoint.com/_api/Brandcenter/Configuration`) { + return successResponse; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { options: { verbose: true } }); + assert(getStub.calledOnce); + assert(loggerLogSpy.calledWith(successResponse)); + }); + + it('correctly handles error when retrieving settings', async () => { + sinon.stub(request, 'get').callsFake(async (opts) => { + if (opts.url === 'https://contoso.sharepoint.com/_api/Brandcenter/Configuration') { + throw 'An unknown error has occurred'; + } + + throw 'Invalid request'; + }); + + await assert.rejects(command.action(logger, { options: {} }), + new CommandError(`An unknown error has occurred`)); + }); +}); \ No newline at end of file diff --git a/src/m365/spo/commands/brandcenter/brandcenter-settings-list.ts b/src/m365/spo/commands/brandcenter/brandcenter-settings-list.ts new file mode 100644 index 00000000000..355bc50e193 --- /dev/null +++ b/src/m365/spo/commands/brandcenter/brandcenter-settings-list.ts @@ -0,0 +1,50 @@ +import commands from '../../commands.js'; +import { globalOptionsZod } from '../../../../Command.js'; +import { Logger } from '../../../../cli/Logger.js'; +import request, { CliRequestOptions } from '../../../../request.js'; +import { spo } from '../../../../utils/spo.js'; +import SpoCommand from '../../../base/SpoCommand.js'; +import { z } from 'zod'; + +const options = globalOptionsZod.strict(); + +class SpoBrandcenterSettingsListCommand extends SpoCommand { + public get name(): string { + return commands.BRANDCENTER_SETTINGS_LIST; + } + + public get description(): string { + return 'Lists the brand center configuration'; + } + + public get schema(): z.ZodTypeAny | undefined { + return options; + } + + public async commandAction(logger: Logger): Promise { + if (this.verbose) { + await logger.logToStderr(`Retrieving brand center configuration...`); + } + + try { + const spoUrl: string = await spo.getSpoUrl(logger, this.debug); + + const requestOptions: CliRequestOptions = { + url: `${spoUrl}/_api/Brandcenter/Configuration`, + headers: { + accept: 'application/json;odata=nometadata' + }, + responseType: 'json' + }; + + const res = await request.get(requestOptions); + await logger.log(res); + } + catch (err: any) { + this.handleRejectedODataJsonPromise(err); + } + } + +} + +export default new SpoBrandcenterSettingsListCommand(); \ No newline at end of file