From ee72caa0e2c31093e146e81a527ae776caf3ca7e Mon Sep 17 00:00:00 2001 From: Reshmee Auckloo Date: Wed, 4 Oct 2023 17:11:45 +0100 Subject: [PATCH 1/5] Update-SetSiteLogoThumbnail --- src/m365/spo/commands/site/site-set.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m365/spo/commands/site/site-set.ts b/src/m365/spo/commands/site/site-set.ts index c4e9d202608..5b137d664ad 100644 --- a/src/m365/spo/commands/site/site-set.ts +++ b/src/m365/spo/commands/site/site-set.ts @@ -292,7 +292,7 @@ class SpoSiteSetCommand extends SpoCommand { } } - private async setLogo(logger: Logger, args: CommandArgs): Promise { + private async setLogoThumbNail(logger: Logger, args: CommandArgs): Promise { if (typeof args.options.siteLogoUrl === 'undefined') { return Promise.resolve(); } From dc3884c12f8f0035b60f7abce2900f8de9ec5d0c Mon Sep 17 00:00:00 2001 From: Reshmee Auckloo Date: Thu, 5 Oct 2023 22:13:12 +0000 Subject: [PATCH 2/5] Add ability to update site thumbnail --- src/m365/spo/commands/site/site-set.spec.ts | 87 +++++++++++++++++++++ src/m365/spo/commands/site/site-set.ts | 44 ++++++++++- 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/src/m365/spo/commands/site/site-set.spec.ts b/src/m365/spo/commands/site/site-set.spec.ts index 01ffadef591..7ca395c5f02 100644 --- a/src/m365/spo/commands/site/site-set.spec.ts +++ b/src/m365/spo/commands/site/site-set.spec.ts @@ -194,6 +194,11 @@ describe(commands.SITE_SET, () => { assert.notStrictEqual(actual, true); }); + it('fails validation if siteThumbnailUrl is not a string', async () => { + const actual = await command.validate({ options: { url: 'https://contoso.sharepoint.com/sites/logo', siteThumbnailUrl: true } }, commandInfo); + assert.notStrictEqual(actual, true); + }); + it('fails validation if non-GUID value specified for siteDesignId', async () => { const actual = await command.validate({ options: { url: 'https://contoso.sharepoint.com', siteDesignId: 'Invalid' } }, commandInfo); assert.notStrictEqual(actual, true); @@ -2337,6 +2342,88 @@ describe(commands.SITE_SET, () => { assert.strictEqual(data.relativeLogoUrl, ""); }); + it('applies site relative thumbnail url to the specified site', async () => { + let data: any = {}; + + sinon.stub(request, 'get').callsFake(async (opts) => { + if (opts.url === 'https://contoso.sharepoint.com/sites/logo/_api/site?$select=GroupId,Id') { + return { + Id: '255a50b2-527f-4413-8485-57f4c17a24d1', + GroupId: 'e10a459e-60c8-4000-8240-a68d6a12d39e' + }; + } + + throw 'Invalid request'; + }); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === 'https://contoso.sharepoint.com/sites/logo/_api/siteiconmanager/setsitelogo') { + data = opts.data; + return; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { options: { url: 'https://contoso.sharepoint.com/sites/logo', siteThumbnailUrl: "/sites/logo/SiteAssets/parker-ms-1200.png" } }); + assert.strictEqual(data.relativeLogoUrl, "/sites/logo/SiteAssets/parker-ms-1200.png"); + }); + + it('applies site absolute thumbnail url to the specified site', async () => { + let data: any = {}; + + sinon.stub(request, 'get').callsFake(async (opts) => { + if (opts.url === 'https://contoso.sharepoint.com/sites/logo/_api/site?$select=GroupId,Id') { + return { + Id: '255a50b2-527f-4413-8485-57f4c17a24d1', + GroupId: 'e10a459e-60c8-4000-8240-a68d6a12d39e' + }; + } + + throw 'Invalid request'; + }); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === 'https://contoso.sharepoint.com/sites/logo/_api/siteiconmanager/setsitelogo') { + data = opts.data; + return; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { options: { url: 'https://contoso.sharepoint.com/sites/logo', siteThumbnailUrl: "https://contoso.sharepoint.com/sites/logo/SiteAssets/parker-ms-1200.png" } }); + assert.strictEqual(data.relativeLogoUrl, "/sites/logo/SiteAssets/parker-ms-1200.png"); + }); + + it('correctly handles unsetting the thumbnail from the specified site', async () => { + let data: any = {}; + + sinon.stub(request, 'get').callsFake(async (opts) => { + if (opts.url === 'https://contoso.sharepoint.com/sites/logo/_api/site?$select=GroupId,Id') { + return { + Id: '255a50b2-527f-4413-8485-57f4c17a24d1', + GroupId: 'e10a459e-60c8-4000-8240-a68d6a12d39e' + }; + } + + throw 'Invalid request'; + }); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === 'https://contoso.sharepoint.com/sites/logo/_api/siteiconmanager/setsitelogo') { + data = opts.data; + return; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { options: { debug: true, url: 'https://contoso.sharepoint.com/sites/logo', siteThumbnailUrl: "" } }); + assert.strictEqual(data.relativeLogoUrl, ""); + }); + + it('correctly handles error when applying site design to the specified site', async () => { sinon.stub(request, 'get').callsFake(async (opts) => { if (opts.url === 'https://contoso.sharepoint.com/sites/Sales/_api/site?$select=GroupId,Id') { diff --git a/src/m365/spo/commands/site/site-set.ts b/src/m365/spo/commands/site/site-set.ts index 5b137d664ad..426279d1b38 100644 --- a/src/m365/spo/commands/site/site-set.ts +++ b/src/m365/spo/commands/site/site-set.ts @@ -34,6 +34,7 @@ export interface Options extends GlobalOptions { url: string; sharingCapability?: string; siteLogoUrl?: string; + siteThumbnailUrl?: string; resourceQuota?: string | number; resourceQuotaWarningLevel?: string | number; storageQuota?: string | number; @@ -82,6 +83,7 @@ class SpoSiteSetCommand extends SpoCommand { siteDesignId: typeof args.options.siteDesignId !== undefined, sharingCapabilities: args.options.sharingCapability, siteLogoUrl: typeof args.options.siteLogoUrl !== 'undefined', + siteThumbnailUrl: typeof args.options.siteThumbnailUrl !== 'undefined', resourceQuota: args.options.resourceQuota, resourceQuotaWarningLevel: args.options.resourceQuotaWarningLevel, storageQuota: args.options.storageQuota, @@ -136,6 +138,9 @@ class SpoSiteSetCommand extends SpoCommand { { option: '--siteLogoUrl [siteLogoUrl]' }, + { + option: '--siteThumbnailUrl [siteThumbnailUrl]' + }, { option: '--sharingCapability [sharingCapability]', autocomplete: this.sharingCapabilities @@ -189,6 +194,7 @@ class SpoSiteSetCommand extends SpoCommand { typeof args.options.siteDesignId === 'undefined' && typeof args.options.sharingCapability === 'undefined' && typeof args.options.siteLogoUrl === 'undefined' && + typeof args.options.siteThumbnailUrl === 'undefined' && typeof args.options.resourceQuota === 'undefined' && typeof args.options.resourceQuotaWarningLevel === 'undefined' && typeof args.options.storageQuota === 'undefined' && @@ -203,6 +209,10 @@ class SpoSiteSetCommand extends SpoCommand { return `${args.options.siteLogoUrl} is not a valid value for the siteLogoUrl option. Specify the logo URL or an empty string "" to unset the logo.`; } + if (typeof args.options.siteThumbnailUrl !== 'undefined' && typeof args.options.siteThumbnailUrl !== 'string') { + return `${args.options.siteThumbnailUrl} is not a valid value for the siteThumbnailUrl option. Specify the logo URL or an empty string "" to unset the logo.`; + } + if (args.options.siteDesignId) { if (!validation.isValidGuid(args.options.siteDesignId)) { return `${args.options.siteDesignId} is not a valid GUID`; @@ -280,6 +290,7 @@ class SpoSiteSetCommand extends SpoCommand { await this.waitForSiteUpdateCompletion(logger, args, siteProps); await this.applySiteDesign(logger, args); await this.setLogo(logger, args); + await this.setThumbnail(logger, args); const lockState = await this.updateSiteLockState(logger, args); await this.waitForSiteUpdateCompletion(logger, args, lockState); } @@ -292,7 +303,7 @@ class SpoSiteSetCommand extends SpoCommand { } } - private async setLogoThumbNail(logger: Logger, args: CommandArgs): Promise { + private async setLogo(logger: Logger, args: CommandArgs): Promise { if (typeof args.options.siteLogoUrl === 'undefined') { return Promise.resolve(); } @@ -309,7 +320,36 @@ class SpoSiteSetCommand extends SpoCommand { accept: 'application/json;odata=nometadata' }, data: { - relativeLogoUrl: logoUrl + aspect: 1, + relativeLogoUrl: logoUrl, + type: 0 + }, + responseType: 'json' + }; + + return request.post(requestOptions); + } + + private async setThumbnail(logger: Logger, args: CommandArgs): Promise { + if (typeof args.options.siteThumbnailUrl === 'undefined') { + return Promise.resolve(); + } + + if (this.debug) { + await logger.logToStderr(`Setting the site its Thumbnail...`); + } + + const thumbnailUrl = args.options.siteThumbnailUrl ? urlUtil.getServerRelativePath(args.options.url, args.options.siteThumbnailUrl) : ""; + + const requestOptions: any = { + url: `${args.options.url}/_api/siteiconmanager/setsitelogo`, + headers: { + accept: 'application/json;odata=nometadata' + }, + data: { + aspect: 0, + relativeLogoUrl: thumbnailUrl, + type: 0 }, responseType: 'json' }; From 9933dc735a26ed1a7fed6f1beef7e3da3d9eb8d5 Mon Sep 17 00:00:00 2001 From: Reshmee Auckloo Date: Thu, 5 Oct 2023 22:25:43 +0000 Subject: [PATCH 3/5] Update spo site set doc --- docs/docs/cmd/spo/site/site-set.mdx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/docs/cmd/spo/site/site-set.mdx b/docs/docs/cmd/spo/site/site-set.mdx index c50a797c8fd..05c1cfd062a 100644 --- a/docs/docs/cmd/spo/site/site-set.mdx +++ b/docs/docs/cmd/spo/site/site-set.mdx @@ -49,6 +49,9 @@ m365 spo site set [options] `--siteLogoUrl [siteLogoUrl]` : Set the logo for the site collection. This can be an absolute or relative URL to a file on the current site collection. +`--siteThumbnailUrl [siteThumbnailUrl]` +: Set the thumbnail for the site collection. This can be an absolute or relative URL to a file on the current site collection. + `--resourceQuota [resourceQuota]` : The quota for this site collection in Sandboxed Solutions units @@ -184,6 +187,18 @@ Unset the logo on the site m365 spo site set --url https://contoso.sharepoint.com/sites/sales --siteLogoUrl "" ``` +Set the thumbnail on the site + +```sh +m365 spo site set --url https://contoso.sharepoint.com/sites/sales --siteThumbnailUrl "/sites/sales/SiteAssets/parker-ms-1200.png" +``` + +Unset the thumbnail on the site + +```sh +m365 spo site set --url https://contoso.sharepoint.com/sites/sales --siteThumbnailUrl "" +``` + Lock the site preventing users from accessing it. Wait for the configuration to complete ```sh From d3abe0da4152c2298bcebf6dde4d931a835a0b63 Mon Sep 17 00:00:00 2001 From: Reshmee Auckloo Date: Tue, 7 Nov 2023 06:29:13 +0000 Subject: [PATCH 4/5] Update src/m365/spo/commands/site/site-set.ts Co-authored-by: Martin Lingstuyl --- src/m365/spo/commands/site/site-set.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m365/spo/commands/site/site-set.ts b/src/m365/spo/commands/site/site-set.ts index 426279d1b38..f3fc80a4999 100644 --- a/src/m365/spo/commands/site/site-set.ts +++ b/src/m365/spo/commands/site/site-set.ts @@ -336,7 +336,7 @@ class SpoSiteSetCommand extends SpoCommand { } if (this.debug) { - await logger.logToStderr(`Setting the site its Thumbnail...`); + await logger.logToStderr(`Setting the site thumbnail...`); } const thumbnailUrl = args.options.siteThumbnailUrl ? urlUtil.getServerRelativePath(args.options.url, args.options.siteThumbnailUrl) : ""; From 7ab67a0cbdfc53ad3563a6c0d5dc6c7c9d61aa83 Mon Sep 17 00:00:00 2001 From: Reshmee Auckloo Date: Tue, 7 Nov 2023 06:29:28 +0000 Subject: [PATCH 5/5] Update src/m365/spo/commands/site/site-set.ts Co-authored-by: Martin Lingstuyl --- src/m365/spo/commands/site/site-set.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m365/spo/commands/site/site-set.ts b/src/m365/spo/commands/site/site-set.ts index f3fc80a4999..928e0f832fc 100644 --- a/src/m365/spo/commands/site/site-set.ts +++ b/src/m365/spo/commands/site/site-set.ts @@ -332,7 +332,7 @@ class SpoSiteSetCommand extends SpoCommand { private async setThumbnail(logger: Logger, args: CommandArgs): Promise { if (typeof args.options.siteThumbnailUrl === 'undefined') { - return Promise.resolve(); + return; } if (this.debug) {