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

Extends 'spo site set' command with ability to set thumbnail. Closes #5495 #5547

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
15 changes: 15 additions & 0 deletions docs/docs/cmd/spo/site/site-set.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
87 changes: 87 additions & 0 deletions src/m365/spo/commands/site/site-set.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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') {
Expand Down
42 changes: 41 additions & 1 deletion src/m365/spo/commands/site/site-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -136,6 +138,9 @@ class SpoSiteSetCommand extends SpoCommand {
{
option: '--siteLogoUrl [siteLogoUrl]'
},
{
option: '--siteThumbnailUrl [siteThumbnailUrl]'
},
{
option: '--sharingCapability [sharingCapability]',
autocomplete: this.sharingCapabilities
Expand Down Expand Up @@ -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' &&
Expand All @@ -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`;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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<void> {
if (typeof args.options.siteThumbnailUrl === 'undefined') {
return;
}

if (this.debug) {
await logger.logToStderr(`Setting the site 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'
};
Expand Down