Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Added the spo site get command solving pnp#114
  • Loading branch information
waldekmastykarz committed Dec 17, 2017
1 parent bd23617 commit 9916cd0
Show file tree
Hide file tree
Showing 5 changed files with 529 additions and 1 deletion.
36 changes: 36 additions & 0 deletions docs/manual/docs/cmd/spo/site/site-get.md
@@ -0,0 +1,36 @@
# spo site get

Get information about the specific site collection

## Usage

```sh
spo site get [options]
```

## Options

Option|Description
------|-----------
`--help`|output usage information
`-u, --url <url>`|URL of the site to retrieve information for
`-o, --output <output>`|Output type. `json|text`. Default `text`
`--verbose`|Runs command with verbose logging
`--debug`|Runs command with debug logging

!!! important
Before using this command, connect to a SharePoint Online tenant admin site, using the [spo connect](../connect.md) command.

## Remarks

To get information about a site collection, you have to first connect to a tenant admin site using the [spo connect](../connect.md) command, eg. `spo connect https://contoso-admin.sharepoint.com`. If you are connected to a different site and will try to to get site collection information, you will get an error.

This command can retrieve information for both classic and modern sites.

## Examples

Return information about the _https://contoso.sharepoint.com/sites/project-x_ site collection.

```sh
spo site get -u https://contoso.sharepoint.com/sites/project-x
```
2 changes: 2 additions & 0 deletions docs/manual/mkdocs.yml
Expand Up @@ -26,6 +26,8 @@ pages:
- customaction:
- customaction get: 'cmd/spo/customaction/customaction-get.md'
- customaction list: 'cmd/spo/customaction/customaction-list.md'
- site:
- site get: 'cmd/spo/site/site-get.md'
- storageentity:
- storageentity get: 'cmd/spo/storageentity/storageentity-get.md'
- storageentity list: 'cmd/spo/storageentity/storageentity-list.md'
Expand Down
3 changes: 2 additions & 1 deletion src/o365/spo/commands.ts
Expand Up @@ -24,5 +24,6 @@ export default {
CDN_POLICY_LIST: `${prefix} cdn policy list`,
CDN_POLICY_SET: `${prefix} cdn policy set`,
CUSTOMACTION_GET: `${prefix} customaction get`,
CUSTOMACTION_LIST: `${prefix} customaction list`
CUSTOMACTION_LIST: `${prefix} customaction list`,
SITE_GET: `${prefix} site get`
};
341 changes: 341 additions & 0 deletions src/o365/spo/commands/site/site-get.spec.ts
@@ -0,0 +1,341 @@
import commands from '../../commands';
import Command, { CommandValidate, CommandOption, CommandError } from '../../../../Command';
import config from '../../../../config';
import * as sinon from 'sinon';
import appInsights from '../../../../appInsights';
import auth, { Site } from '../../SpoAuth';
const command: Command = require('./site-get');
import * as assert from 'assert';
import * as request from 'request-promise-native';
import Utils from '../../../../Utils';

describe(commands.SITE_GET, () => {
let vorpal: Vorpal;
let log: any[];
let cmdInstance: any;
let cmdInstanceLogSpy: sinon.SinonSpy;
let trackEvent: any;
let telemetry: any;

before(() => {
sinon.stub(auth, 'restoreAuth').callsFake(() => Promise.resolve());
sinon.stub(auth, 'ensureAccessToken').callsFake(() => { return Promise.resolve('ABC'); });
sinon.stub(command as any, 'getRequestDigest').callsFake(() => { return { FormDigestValue: 'abc' }; });
trackEvent = sinon.stub(appInsights, 'trackEvent').callsFake((t) => {
telemetry = t;
});
});

beforeEach(() => {
vorpal = require('../../../../vorpal-init');
log = [];
cmdInstance = {
log: (msg: string) => {
log.push(msg);
}
};
cmdInstanceLogSpy = sinon.spy(cmdInstance, 'log');
auth.site = new Site();
telemetry = null;
});

afterEach(() => {
Utils.restore(vorpal.find);
});

after(() => {
Utils.restore([
appInsights.trackEvent,
auth.ensureAccessToken,
auth.restoreAuth,
(command as any).getRequestDigest
]);
});

it('has correct name', () => {
assert.equal(command.name.startsWith(commands.SITE_GET), true);
});

it('has a description', () => {
assert.notEqual(command.description, null);
});

it('calls telemetry', (done) => {
cmdInstance.action = command.action();
cmdInstance.action({ options: {} }, () => {
try {
assert(trackEvent.called);
done();
}
catch (e) {
done(e);
}
});
});

it('logs correct telemetry event', (done) => {
cmdInstance.action = command.action();
cmdInstance.action({ options: {} }, () => {
try {
assert.equal(telemetry.name, commands.SITE_GET);
done();
}
catch (e) {
done(e);
}
});
});

it('aborts when not connected to a SharePoint site', (done) => {
auth.site = new Site();
auth.site.connected = false;
cmdInstance.action = command.action();
cmdInstance.action({ options: { debug: true } }, () => {
try {
assert(cmdInstanceLogSpy.calledWith(new CommandError('Connect to a SharePoint Online site first')));
done();
}
catch (e) {
done(e);
}
});
});

it('aborts when not connected to a SharePoint tenant admin site', (done) => {
auth.site = new Site();
auth.site.connected = true;
auth.site.url = 'https://contoso.sharepoint.com';
cmdInstance.action = command.action();
cmdInstance.action({ options: { debug: true } }, () => {
try {
assert(cmdInstanceLogSpy.calledWith(new CommandError(`https://contoso.sharepoint.com is not a tenant admin site. Connect to your tenant admin site and try again`)));
done();
}
catch (e) {
done(e);
}
});
});

it('retrieves the information for the specified site', (done) => {
const siteProperties = {
"_ObjectType_": "Microsoft.Online.SharePoint.TenantAdministration.SiteProperties", "_ObjectIdentity_": "2868379e-c0b6-4000-823f-d9e855fd1204|908bed80-a04a-4433-b4a0-883d9847d110:67753f63-bc14-4012-869e-f808a43fe023\nSiteProperties\nhttps%3a%2f%2fm365x324230.sharepoint.com%2fsites%2fcomtest_001", "AllowDownloadingNonWebViewableFiles": true, "AllowEditing": true, "AllowSelfServiceUpgrade": true, "AverageResourceUsage": 0, "CommentsOnSitePagesDisabled": false, "CompatibilityLevel": 15, "ConditionalAccessPolicy": 0, "CurrentResourceUsage": 0, "DenyAddAndCustomizePages": 2, "DisableAppViews": 2, "DisableCompanyWideSharingLinks": 2, "DisableFlows": 2, "HasHolds": false, "LastContentModifiedDate": "\/Date(2017,11,17,4,6,59,233)\/", "Lcid": 1033, "LockIssue": null, "LockState": "Unlock", "NewUrl": "", "Owner": "admin@m365x324230.onmicrosoft.com", "OwnerEmail": "admin@M365x324230.onmicrosoft.com", "PWAEnabled": 0, "RestrictedToRegion": 3, "SandboxedCodeActivationCapability": 2, "SharingAllowedDomainList": "", "SharingBlockedDomainList": "", "SharingCapability": 0, "SharingDomainRestrictionMode": 0, "ShowPeoplePickerSuggestionsForGuestUsers": false, "SiteDefinedSharingCapability": 0, "Status": "Active", "StorageMaximumLevel": 26214400, "StorageQuotaType": null, "StorageUsage": 1, "StorageWarningLevel": 25574400, "Template": "SITEPAGEPUBLISHING#0", "TimeZoneId": 13, "Title": "ComTest 001", "Url": "https:\u002f\u002fm365x324230.sharepoint.com\u002fsites\u002fcomtest_001", "UserCodeMaximumLevel": 300, "UserCodeWarningLevel": 200, "WebsCount": 1
};
const response = [
{
"SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.7206.1204", "ErrorInfo": null, "TraceCorrelationId": "2868379e-c0b6-4000-823f-d9e855fd1204"
}, 2, {
"IsNull": false
}, 4, {
"IsNull": false
}, 5, siteProperties
];
sinon.stub(request, 'post').callsFake((opts) => {
if (opts.url.indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) {
if (opts.headers.authorization &&
opts.headers.authorization.indexOf('Bearer ') === 0 &&
opts.headers['X-RequestDigest'] &&
opts.headers['X-RequestDigest'] === 'abc' &&
opts.body === `<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="2" ObjectPathId="1" /><ObjectPath Id="4" ObjectPathId="3" /><Query Id="5" ObjectPathId="3"><Query SelectAllProperties="true"><Properties /></Query></Query></Actions><ObjectPaths><Constructor Id="1" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /><Method Id="3" ParentId="1" Name="GetSitePropertiesByUrl"><Parameters><Parameter Type="String">https://contoso.sharepoint.com/sites/project-x</Parameter><Parameter Type="Boolean">true</Parameter></Parameters></Method></ObjectPaths></Request>`) {
return Promise.resolve(JSON.stringify(response));
}
}

return Promise.reject('Invalid request');
});

auth.site = new Site();
auth.site.connected = true;
auth.site.url = 'https://contoso-admin.sharepoint.com';
auth.site.tenantId = 'abc';
cmdInstance.action = command.action();
cmdInstance.action({ options: { debug: false, url: 'https://contoso.sharepoint.com/sites/project-x' } }, () => {
const expected = siteProperties;
delete expected._ObjectIdentity_;
delete expected._ObjectType_;
try {
assert(cmdInstanceLogSpy.calledWith(expected));
done();
}
catch (e) {
done(e);
}
finally {
Utils.restore(request.post);
}
});
});

it('retrieves the information for the specified site (debug)', (done) => {
const siteProperties = {
"_ObjectType_": "Microsoft.Online.SharePoint.TenantAdministration.SiteProperties", "_ObjectIdentity_": "2868379e-c0b6-4000-823f-d9e855fd1204|908bed80-a04a-4433-b4a0-883d9847d110:67753f63-bc14-4012-869e-f808a43fe023\nSiteProperties\nhttps%3a%2f%2fm365x324230.sharepoint.com%2fsites%2fcomtest_001", "AllowDownloadingNonWebViewableFiles": true, "AllowEditing": true, "AllowSelfServiceUpgrade": true, "AverageResourceUsage": 0, "CommentsOnSitePagesDisabled": false, "CompatibilityLevel": 15, "ConditionalAccessPolicy": 0, "CurrentResourceUsage": 0, "DenyAddAndCustomizePages": 2, "DisableAppViews": 2, "DisableCompanyWideSharingLinks": 2, "DisableFlows": 2, "HasHolds": false, "LastContentModifiedDate": "\/Date(2017,11,17,4,6,59,233)\/", "Lcid": 1033, "LockIssue": null, "LockState": "Unlock", "NewUrl": "", "Owner": "admin@m365x324230.onmicrosoft.com", "OwnerEmail": "admin@M365x324230.onmicrosoft.com", "PWAEnabled": 0, "RestrictedToRegion": 3, "SandboxedCodeActivationCapability": 2, "SharingAllowedDomainList": "", "SharingBlockedDomainList": "", "SharingCapability": 0, "SharingDomainRestrictionMode": 0, "ShowPeoplePickerSuggestionsForGuestUsers": false, "SiteDefinedSharingCapability": 0, "Status": "Active", "StorageMaximumLevel": 26214400, "StorageQuotaType": null, "StorageUsage": 1, "StorageWarningLevel": 25574400, "Template": "SITEPAGEPUBLISHING#0", "TimeZoneId": 13, "Title": "ComTest 001", "Url": "https:\u002f\u002fm365x324230.sharepoint.com\u002fsites\u002fcomtest_001", "UserCodeMaximumLevel": 300, "UserCodeWarningLevel": 200, "WebsCount": 1
};
const response = [
{
"SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.7206.1204", "ErrorInfo": null, "TraceCorrelationId": "2868379e-c0b6-4000-823f-d9e855fd1204"
}, 2, {
"IsNull": false
}, 4, {
"IsNull": false
}, 5, siteProperties
];
sinon.stub(request, 'post').callsFake((opts) => {
if (opts.url.indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) {
if (opts.headers.authorization &&
opts.headers.authorization.indexOf('Bearer ') === 0 &&
opts.headers['X-RequestDigest'] &&
opts.headers['X-RequestDigest'] === 'abc' &&
opts.body === `<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="2" ObjectPathId="1" /><ObjectPath Id="4" ObjectPathId="3" /><Query Id="5" ObjectPathId="3"><Query SelectAllProperties="true"><Properties /></Query></Query></Actions><ObjectPaths><Constructor Id="1" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /><Method Id="3" ParentId="1" Name="GetSitePropertiesByUrl"><Parameters><Parameter Type="String">https://contoso.sharepoint.com/sites/project-x</Parameter><Parameter Type="Boolean">true</Parameter></Parameters></Method></ObjectPaths></Request>`) {
return Promise.resolve(JSON.stringify(response));
}
}

return Promise.reject('Invalid request');
});

auth.site = new Site();
auth.site.connected = true;
auth.site.url = 'https://contoso-admin.sharepoint.com';
auth.site.tenantId = 'abc';
cmdInstance.action = command.action();
cmdInstance.action({ options: { debug: true, url: 'https://contoso.sharepoint.com/sites/project-x' } }, () => {
const expected = siteProperties;
delete expected._ObjectIdentity_;
delete expected._ObjectType_;
try {
assert(cmdInstanceLogSpy.calledWith(expected));
done();
}
catch (e) {
done(e);
}
finally {
Utils.restore(request.post);
}
});
});

it('correctly handles error when getting information for a site that doesn\'t exist', (done) => {
Utils.restore(request.post);
sinon.stub(request, 'post').callsFake((opts) => {
if (opts.url.indexOf('/_vti_bin/client.svc/ProcessQuery') > -1) {
return Promise.resolve(JSON.stringify([
{
"SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.7206.1204", "ErrorInfo": {
"ErrorMessage": "Cannot get site https:\u002f\u002fcontoso.sharepoint.com\u002fsites\u002fproject-x.", "ErrorValue": null, "TraceCorrelationId": "1b68379e-2051-4000-8242-711d8fb38a57", "ErrorCode": -1, "ErrorTypeName": "Microsoft.Online.SharePoint.Common.SpoNoSiteException"
}, "TraceCorrelationId": "1b68379e-2051-4000-8242-711d8fb38a57"
}
]));
}

return Promise.reject('Invalid request');
});

auth.site = new Site();
auth.site.connected = true;
auth.site.url = 'https://contoso-admin.sharepoint.com';
auth.site.tenantId = 'abc';
cmdInstance.action = command.action();
cmdInstance.action({ options: { debug: true, url: 'https://contoso.sharepoint.com/sites/project-x' } }, () => {
try {
assert(cmdInstanceLogSpy.calledWith(new CommandError('Cannot get site https://contoso.sharepoint.com/sites/project-x.')));
done();
}
catch (e) {
done(e);
}
finally {
Utils.restore(request.post);
}
});
});

it('supports debug mode', () => {
const options = (command.options() as CommandOption[]);
let containsDebugOption = false;
options.forEach(o => {
if (o.option === '--debug') {
containsDebugOption = true;
}
});
assert(containsDebugOption);
});

it('supports specifying URL', () => {
const options = (command.options() as CommandOption[]);
let containsTypeOption = false;
options.forEach(o => {
if (o.option.indexOf('<url>') > -1) {
containsTypeOption = true;
}
});
assert(containsTypeOption);
});

it('fails validation if the url option not specified', () => {
const actual = (command.validate() as CommandValidate)({ options: { } });
assert.notEqual(actual, true);
});

it('fails validation if the url option is not a valid SharePoint site URL', () => {
const actual = (command.validate() as CommandValidate)({ options: { url: 'foo' } });
assert.notEqual(actual, true);
});

it('passes validation if the url option is a valid SharePoint site URL', () => {
const actual = (command.validate() as CommandValidate)({ options: { url: 'https://contoso.sharepoint.com' } });
assert(actual);
});

it('has help referring to the right command', () => {
const cmd: any = {
log: (msg: string) => { },
prompt: () => { },
helpInformation: () => { }
};
const find = sinon.stub(vorpal, 'find').callsFake(() => cmd);
cmd.help = command.help();
cmd.help({}, () => { });
assert(find.calledWith(commands.SITE_GET));
});

it('has help with examples', () => {
const _log: string[] = [];
const cmd: any = {
log: (msg: string) => {
_log.push(msg);
},
prompt: () => { },
helpInformation: () => { }
};
sinon.stub(vorpal, 'find').callsFake(() => cmd);
cmd.help = command.help();
cmd.help({}, () => { });
let containsExamples: boolean = false;
_log.forEach(l => {
if (l && l.indexOf('Examples:') > -1) {
containsExamples = true;
}
});
Utils.restore(vorpal.find);
assert(containsExamples);
});

it('correctly handles lack of valid access token', (done) => {
Utils.restore(auth.ensureAccessToken);
sinon.stub(auth, 'ensureAccessToken').callsFake(() => { return Promise.reject(new Error('Error getting access token')); });
auth.site = new Site();
auth.site.connected = true;
auth.site.url = 'https://contoso-admin.sharepoint.com';
cmdInstance.action = command.action();
cmdInstance.action({ options: { debug: true } }, () => {
try {
assert(cmdInstanceLogSpy.calledWith(new CommandError('Error getting access token')));
done();
}
catch (e) {
done(e);
}
});
});
});

0 comments on commit 9916cd0

Please sign in to comment.