@pnp/cli-microsoft365 5.7.0-beta.8be35f8 → 5.7.0-beta.bb14b6c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.devcontainer/Dockerfile +3 -1
- package/.devcontainer/devcontainer.json +1 -0
- package/dist/m365/aad/commands/app/app-add.js +161 -22
- package/dist/m365/booking/commands/business/business-get.js +86 -0
- package/dist/m365/booking/commands/business/business-list.js +30 -0
- package/dist/m365/booking/commands.js +8 -0
- package/dist/m365/search/commands/externalconnection/externalconnection-remove.js +101 -0
- package/dist/m365/search/commands.js +2 -1
- package/dist/m365/spfx/commands/spfx-doctor.js +15 -0
- package/docs/docs/cmd/aad/app/app-add.md +12 -1
- package/docs/docs/cmd/aad/app/app-set.md +1 -1
- package/docs/docs/cmd/booking/business/business-get.md +33 -0
- package/docs/docs/cmd/booking/business/business-list.md +21 -0
- package/docs/docs/cmd/search/externalconnection/externalconnection-remove.md +40 -0
- package/package.json +11 -1
package/.devcontainer/Dockerfile
CHANGED
|
@@ -27,7 +27,9 @@ RUN apt-get update && apt-get install -y \
|
|
|
27
27
|
&& apt-get install nodejs -y \
|
|
28
28
|
&& rm -rf /var/lib/apt/lists/*
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
COPY ../docs/pip_requirements.txt .
|
|
31
|
+
|
|
32
|
+
RUN pip install -r pip_requirements.txt
|
|
31
33
|
|
|
32
34
|
RUN useradd \
|
|
33
35
|
--user-group \
|
|
@@ -27,6 +27,7 @@ class AadAppAddCommand extends GraphCommand_1.default {
|
|
|
27
27
|
super();
|
|
28
28
|
_AadAppAddCommand_instances.add(this);
|
|
29
29
|
this.appName = '';
|
|
30
|
+
this.appPermissions = [];
|
|
30
31
|
__classPrivateFieldGet(this, _AadAppAddCommand_instances, "m", _AadAppAddCommand_initTelemetry).call(this);
|
|
31
32
|
__classPrivateFieldGet(this, _AadAppAddCommand_instances, "m", _AadAppAddCommand_initOptions).call(this);
|
|
32
33
|
__classPrivateFieldGet(this, _AadAppAddCommand_instances, "m", _AadAppAddCommand_initValidators).call(this);
|
|
@@ -50,6 +51,7 @@ class AadAppAddCommand extends GraphCommand_1.default {
|
|
|
50
51
|
return Promise.resolve(appInfo);
|
|
51
52
|
})
|
|
52
53
|
.then(appInfo => this.updateAppFromManifest(args, appInfo))
|
|
54
|
+
.then(appInfo => this.grantAdminConsent(appInfo, args.options.grantAdminConsent, logger))
|
|
53
55
|
.then(appInfo => this.configureUri(args, appInfo, logger))
|
|
54
56
|
.then(appInfo => this.configureSecret(args, appInfo, logger))
|
|
55
57
|
.then(appInfo => this.saveAppInfo(args, appInfo, logger))
|
|
@@ -120,6 +122,81 @@ class AadAppAddCommand extends GraphCommand_1.default {
|
|
|
120
122
|
return request_1.default.post(createApplicationRequestOptions);
|
|
121
123
|
});
|
|
122
124
|
}
|
|
125
|
+
grantAdminConsent(appInfo, adminConsent, logger) {
|
|
126
|
+
if (!adminConsent || this.appPermissions.length === 0) {
|
|
127
|
+
return Promise.resolve(appInfo);
|
|
128
|
+
}
|
|
129
|
+
return this.createServicePrincipal(appInfo.appId)
|
|
130
|
+
.then((sp) => {
|
|
131
|
+
if (this.debug) {
|
|
132
|
+
logger.logToStderr("Service principal created, returned object id: " + sp.id);
|
|
133
|
+
}
|
|
134
|
+
const tasks = [];
|
|
135
|
+
this.appPermissions.forEach(permission => {
|
|
136
|
+
if (permission.scope.length > 0) {
|
|
137
|
+
tasks.push(this.grantOAuth2Permission(sp.id, permission.resourceId, permission.scope.join(' ')));
|
|
138
|
+
if (this.debug) {
|
|
139
|
+
logger.logToStderr(`Admin consent granted for following resource ${permission.resourceId}, with delegated permissions: ${permission.scope.join(',')}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
permission.resourceAccess.filter(access => access.type === "Role").forEach((access) => {
|
|
143
|
+
tasks.push(this.addRoleToServicePrincipal(sp.id, permission.resourceId, access.id));
|
|
144
|
+
if (this.debug) {
|
|
145
|
+
logger.logToStderr(`Admin consent granted for following resource ${permission.resourceId}, with application permission: ${access.id}`);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
return Promise.all(tasks)
|
|
150
|
+
.then(_ => {
|
|
151
|
+
return appInfo;
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
addRoleToServicePrincipal(objectId, resourceId, appRoleId) {
|
|
156
|
+
const requestOptions = {
|
|
157
|
+
url: `${this.resource}/v1.0/myorganization/servicePrincipals/${objectId}/appRoleAssignments`,
|
|
158
|
+
headers: {
|
|
159
|
+
'Content-Type': 'application/json'
|
|
160
|
+
},
|
|
161
|
+
responseType: 'json',
|
|
162
|
+
data: {
|
|
163
|
+
appRoleId: appRoleId,
|
|
164
|
+
principalId: objectId,
|
|
165
|
+
resourceId: resourceId
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
return request_1.default.post(requestOptions);
|
|
169
|
+
}
|
|
170
|
+
grantOAuth2Permission(appId, resourceId, scopeName) {
|
|
171
|
+
const grantAdminConsentApplicationRequestOptions = {
|
|
172
|
+
url: `${this.resource}/v1.0/myorganization/oauth2PermissionGrants`,
|
|
173
|
+
headers: {
|
|
174
|
+
accept: 'application/json;odata.metadata=none'
|
|
175
|
+
},
|
|
176
|
+
responseType: 'json',
|
|
177
|
+
data: {
|
|
178
|
+
clientId: appId,
|
|
179
|
+
consentType: "AllPrincipals",
|
|
180
|
+
principalId: null,
|
|
181
|
+
resourceId: resourceId,
|
|
182
|
+
scope: scopeName
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
return request_1.default.post(grantAdminConsentApplicationRequestOptions);
|
|
186
|
+
}
|
|
187
|
+
createServicePrincipal(appId) {
|
|
188
|
+
const requestOptions = {
|
|
189
|
+
url: `${this.resource}/v1.0/myorganization/servicePrincipals`,
|
|
190
|
+
headers: {
|
|
191
|
+
'content-type': 'application/json'
|
|
192
|
+
},
|
|
193
|
+
data: {
|
|
194
|
+
appId: appId
|
|
195
|
+
},
|
|
196
|
+
responseType: 'json'
|
|
197
|
+
};
|
|
198
|
+
return request_1.default.post(requestOptions);
|
|
199
|
+
}
|
|
123
200
|
updateAppFromManifest(args, appInfo) {
|
|
124
201
|
if (!args.options.manifest) {
|
|
125
202
|
return Promise.resolve(appInfo);
|
|
@@ -135,6 +212,11 @@ class AadAppAddCommand extends GraphCommand_1.default {
|
|
|
135
212
|
// separately
|
|
136
213
|
const secrets = this.getSecretsFromManifest(v2Manifest);
|
|
137
214
|
// Azure Portal returns v2 manifest whereas the Graph API expects a v1.6
|
|
215
|
+
if (args.options.apisApplication || args.options.apisDelegated) {
|
|
216
|
+
// take submitted delegated / application permissions as options
|
|
217
|
+
// otherwise, they will be skipped in the app update
|
|
218
|
+
v2Manifest.requiredResourceAccess = appInfo.requiredResourceAccess;
|
|
219
|
+
}
|
|
138
220
|
const graphManifest = this.transformManifest(v2Manifest);
|
|
139
221
|
const updateAppRequestOptions = {
|
|
140
222
|
url: `${this.resource}/v1.0/myorganization/applications/${appInfo.id}`,
|
|
@@ -334,36 +416,69 @@ class AadAppAddCommand extends GraphCommand_1.default {
|
|
|
334
416
|
.then(_ => appInfo);
|
|
335
417
|
}
|
|
336
418
|
resolveApis(args, logger) {
|
|
337
|
-
|
|
419
|
+
var _a;
|
|
420
|
+
if (!args.options.apisDelegated && !args.options.apisApplication
|
|
421
|
+
&& (typeof ((_a = this.manifest) === null || _a === void 0 ? void 0 : _a.requiredResourceAccess) === 'undefined' || this.manifest.requiredResourceAccess.length === 0)) {
|
|
338
422
|
return Promise.resolve([]);
|
|
339
423
|
}
|
|
340
424
|
if (this.verbose) {
|
|
341
425
|
logger.logToStderr('Resolving requested APIs...');
|
|
342
426
|
}
|
|
343
427
|
return utils_1.odata
|
|
344
|
-
.getAllItems(`${this.resource}/v1.0/myorganization/servicePrincipals?$select=
|
|
428
|
+
.getAllItems(`${this.resource}/v1.0/myorganization/servicePrincipals?$select=appId,appRoles,id,oauth2PermissionScopes,servicePrincipalNames`)
|
|
345
429
|
.then(servicePrincipals => {
|
|
430
|
+
var _a;
|
|
431
|
+
let resolvedApis = [];
|
|
346
432
|
try {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
const resolvedApplicationApis = this.getRequiredResourceAccessForApis(servicePrincipals, args.options.apisApplication, 'Role', logger);
|
|
352
|
-
if (this.debug) {
|
|
353
|
-
logger.logToStderr(`Resolved application permissions: ${JSON.stringify(resolvedApplicationApis, null, 2)}`);
|
|
354
|
-
}
|
|
355
|
-
// merge resolved application APIs onto resolved delegated APIs
|
|
356
|
-
resolvedApplicationApis.forEach(resolvedRequiredResource => {
|
|
357
|
-
const requiredResource = resolvedApis.find(api => api.resourceAppId === resolvedRequiredResource.resourceAppId);
|
|
358
|
-
if (requiredResource) {
|
|
359
|
-
requiredResource.resourceAccess.push(...resolvedRequiredResource.resourceAccess);
|
|
433
|
+
if (args.options.apisDelegated || args.options.apisApplication) {
|
|
434
|
+
resolvedApis = this.getRequiredResourceAccessForApis(servicePrincipals, args.options.apisDelegated, 'Scope', logger);
|
|
435
|
+
if (this.verbose) {
|
|
436
|
+
logger.logToStderr(`Resolved delegated permissions: ${JSON.stringify(resolvedApis, null, 2)}`);
|
|
360
437
|
}
|
|
361
|
-
|
|
362
|
-
|
|
438
|
+
const resolvedApplicationApis = this.getRequiredResourceAccessForApis(servicePrincipals, args.options.apisApplication, 'Role', logger);
|
|
439
|
+
if (this.verbose) {
|
|
440
|
+
logger.logToStderr(`Resolved application permissions: ${JSON.stringify(resolvedApplicationApis, null, 2)}`);
|
|
363
441
|
}
|
|
364
|
-
|
|
365
|
-
|
|
442
|
+
// merge resolved application APIs onto resolved delegated APIs
|
|
443
|
+
resolvedApplicationApis.forEach(resolvedRequiredResource => {
|
|
444
|
+
const requiredResource = resolvedApis.find(api => api.resourceAppId === resolvedRequiredResource.resourceAppId);
|
|
445
|
+
if (requiredResource) {
|
|
446
|
+
requiredResource.resourceAccess.push(...resolvedRequiredResource.resourceAccess);
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
resolvedApis.push(resolvedRequiredResource);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
if (typeof ((_a = this.manifest) === null || _a === void 0 ? void 0 : _a.requiredResourceAccess) !== 'undefined' && this.manifest.requiredResourceAccess.length > 0) {
|
|
454
|
+
const manifestApis = this.manifest.requiredResourceAccess;
|
|
455
|
+
manifestApis.forEach(manifestApi => {
|
|
456
|
+
const requiredResource = resolvedApis.find(api => api.resourceAppId === manifestApi.resourceAppId);
|
|
457
|
+
if (requiredResource) {
|
|
458
|
+
// exclude if any duplicate required resources in both manifest and submitted options
|
|
459
|
+
requiredResource.resourceAccess.push(...manifestApi.resourceAccess.filter(manRes => !requiredResource.resourceAccess.some(res => res.id === manRes.id)));
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
resolvedApis.push(manifestApi);
|
|
463
|
+
}
|
|
464
|
+
const app = servicePrincipals.find(servicePrincipals => servicePrincipals.appId === manifestApi.resourceAppId);
|
|
465
|
+
if (app) {
|
|
466
|
+
manifestApi.resourceAccess.forEach((res => {
|
|
467
|
+
var _a;
|
|
468
|
+
const resourceAccessPermission = {
|
|
469
|
+
id: res.id,
|
|
470
|
+
type: res.type
|
|
471
|
+
};
|
|
472
|
+
const oAuthValue = (_a = app.oauth2PermissionScopes.find(scp => scp.id === res.id)) === null || _a === void 0 ? void 0 : _a.value;
|
|
473
|
+
this.updateAppPermissions(app.id, resourceAccessPermission, oAuthValue);
|
|
474
|
+
}));
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
if (this.verbose) {
|
|
366
479
|
logger.logToStderr(`Merged delegated and application permissions: ${JSON.stringify(resolvedApis, null, 2)}`);
|
|
480
|
+
logger.logToStderr(`App role assignments: ${JSON.stringify(this.appPermissions.flatMap(permission => permission.resourceAccess.filter(access => access.type === "Role")), null, 2)}`);
|
|
481
|
+
logger.logToStderr(`OAuth2 permissions: ${JSON.stringify(this.appPermissions.flatMap(permission => permission.scope), null, 2)}`);
|
|
367
482
|
}
|
|
368
483
|
return Promise.resolve(resolvedApis);
|
|
369
484
|
}
|
|
@@ -405,13 +520,34 @@ class AadAppAddCommand extends GraphCommand_1.default {
|
|
|
405
520
|
};
|
|
406
521
|
resolvedApis.push(resolvedApi);
|
|
407
522
|
}
|
|
408
|
-
|
|
523
|
+
const resourceAccessPermission = {
|
|
409
524
|
id: permission.id,
|
|
410
525
|
type: scopeType
|
|
411
|
-
}
|
|
526
|
+
};
|
|
527
|
+
resolvedApi.resourceAccess.push(resourceAccessPermission);
|
|
528
|
+
this.updateAppPermissions(servicePrincipal.id, resourceAccessPermission, permission.value);
|
|
412
529
|
});
|
|
413
530
|
return resolvedApis;
|
|
414
531
|
}
|
|
532
|
+
updateAppPermissions(spId, resourceAccessPermission, oAuth2PermissionValue) {
|
|
533
|
+
// During API resolution, we store globally both app role assignments and oauth2permissions
|
|
534
|
+
// So that we'll be able to parse them during the admin consent process
|
|
535
|
+
let existingPermission = this.appPermissions.find(oauth => oauth.resourceId === spId);
|
|
536
|
+
if (!existingPermission) {
|
|
537
|
+
existingPermission = {
|
|
538
|
+
resourceId: spId,
|
|
539
|
+
resourceAccess: [],
|
|
540
|
+
scope: []
|
|
541
|
+
};
|
|
542
|
+
this.appPermissions.push(existingPermission);
|
|
543
|
+
}
|
|
544
|
+
if (resourceAccessPermission.type === 'Scope' && oAuth2PermissionValue && !existingPermission.scope.find(scp => scp === oAuth2PermissionValue)) {
|
|
545
|
+
existingPermission.scope.push(oAuth2PermissionValue);
|
|
546
|
+
}
|
|
547
|
+
if (!existingPermission.resourceAccess.find(res => res.id === resourceAccessPermission.id)) {
|
|
548
|
+
existingPermission.resourceAccess.push(resourceAccessPermission);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
415
551
|
configureSecret(args, appInfo, logger) {
|
|
416
552
|
if (!args.options.withSecret) {
|
|
417
553
|
return Promise.resolve(appInfo);
|
|
@@ -523,7 +659,8 @@ _AadAppAddCommand_instances = new WeakSet(), _AadAppAddCommand_initTelemetry = f
|
|
|
523
659
|
withSecret: args.options.withSecret,
|
|
524
660
|
certificateFile: typeof args.options.certificateFile !== 'undefined',
|
|
525
661
|
certificateBase64Encoded: typeof args.options.certificateBase64Encoded !== 'undefined',
|
|
526
|
-
certificateDisplayName: typeof args.options.certificateDisplayName !== 'undefined'
|
|
662
|
+
certificateDisplayName: typeof args.options.certificateDisplayName !== 'undefined',
|
|
663
|
+
grantAdminConsent: typeof args.options.grantAdminConsent !== 'undefined'
|
|
527
664
|
});
|
|
528
665
|
});
|
|
529
666
|
}, _AadAppAddCommand_initOptions = function _AadAppAddCommand_initOptions() {
|
|
@@ -565,6 +702,8 @@ _AadAppAddCommand_instances = new WeakSet(), _AadAppAddCommand_initTelemetry = f
|
|
|
565
702
|
option: '--manifest [manifest]'
|
|
566
703
|
}, {
|
|
567
704
|
option: '--save'
|
|
705
|
+
}, {
|
|
706
|
+
option: '--grantAdminConsent'
|
|
568
707
|
});
|
|
569
708
|
}, _AadAppAddCommand_initValidators = function _AadAppAddCommand_initValidators() {
|
|
570
709
|
this.validators.push((args) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
6
|
+
};
|
|
7
|
+
var _BookingBusinessGetCommand_instances, _BookingBusinessGetCommand_initTelemetry, _BookingBusinessGetCommand_initOptions, _BookingBusinessGetCommand_initOptionSets;
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const request_1 = require("../../../../request");
|
|
10
|
+
const GraphCommand_1 = require("../../../base/GraphCommand");
|
|
11
|
+
const commands_1 = require("../../commands");
|
|
12
|
+
class BookingBusinessGetCommand extends GraphCommand_1.default {
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
_BookingBusinessGetCommand_instances.add(this);
|
|
16
|
+
__classPrivateFieldGet(this, _BookingBusinessGetCommand_instances, "m", _BookingBusinessGetCommand_initTelemetry).call(this);
|
|
17
|
+
__classPrivateFieldGet(this, _BookingBusinessGetCommand_instances, "m", _BookingBusinessGetCommand_initOptions).call(this);
|
|
18
|
+
__classPrivateFieldGet(this, _BookingBusinessGetCommand_instances, "m", _BookingBusinessGetCommand_initOptionSets).call(this);
|
|
19
|
+
}
|
|
20
|
+
get name() {
|
|
21
|
+
return commands_1.default.BUSINESS_GET;
|
|
22
|
+
}
|
|
23
|
+
get description() {
|
|
24
|
+
return 'Retrieve the specified Microsoft Bookings business.';
|
|
25
|
+
}
|
|
26
|
+
defaultProperties() {
|
|
27
|
+
return ['id', 'displayName', 'businessType', 'phone', 'email', 'defaultCurrencyIso'];
|
|
28
|
+
}
|
|
29
|
+
commandAction(logger, args, cb) {
|
|
30
|
+
this
|
|
31
|
+
.getBusinessId(args.options)
|
|
32
|
+
.then(businessId => {
|
|
33
|
+
const requestOptions = {
|
|
34
|
+
url: `${this.resource}/v1.0/solutions/bookingBusinesses/${encodeURIComponent(businessId)}`,
|
|
35
|
+
headers: {
|
|
36
|
+
accept: 'application/json;odata.metadata=none'
|
|
37
|
+
},
|
|
38
|
+
responseType: 'json'
|
|
39
|
+
};
|
|
40
|
+
return request_1.default.get(requestOptions);
|
|
41
|
+
})
|
|
42
|
+
.then(business => {
|
|
43
|
+
logger.log(business);
|
|
44
|
+
cb();
|
|
45
|
+
}, (err) => this.handleRejectedODataJsonPromise(err, logger, cb));
|
|
46
|
+
}
|
|
47
|
+
getBusinessId(options) {
|
|
48
|
+
if (options.id) {
|
|
49
|
+
return Promise.resolve(options.id);
|
|
50
|
+
}
|
|
51
|
+
const requestOptions = {
|
|
52
|
+
url: `${this.resource}/v1.0/solutions/bookingBusinesses`,
|
|
53
|
+
headers: {
|
|
54
|
+
accept: 'application/json;odata.metadata=none'
|
|
55
|
+
},
|
|
56
|
+
responseType: 'json'
|
|
57
|
+
};
|
|
58
|
+
return request_1.default
|
|
59
|
+
.get(requestOptions)
|
|
60
|
+
.then((response) => {
|
|
61
|
+
const name = options.name;
|
|
62
|
+
const bookingBusinesses = response.value.filter(val => { var _a; return ((_a = val.displayName) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase()) === name.toLocaleLowerCase(); });
|
|
63
|
+
if (!bookingBusinesses.length) {
|
|
64
|
+
return Promise.reject(`The specified business with name ${options.name} does not exist.`);
|
|
65
|
+
}
|
|
66
|
+
if (bookingBusinesses.length > 1) {
|
|
67
|
+
return Promise.reject(`Multiple businesses with name ${options.name} found. Please disambiguate: ${bookingBusinesses.map(x => x.id).join(', ')}`);
|
|
68
|
+
}
|
|
69
|
+
return bookingBusinesses[0].id;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
_BookingBusinessGetCommand_instances = new WeakSet(), _BookingBusinessGetCommand_initTelemetry = function _BookingBusinessGetCommand_initTelemetry() {
|
|
74
|
+
this.telemetry.push((args) => {
|
|
75
|
+
Object.assign(this.telemetryProperties, {
|
|
76
|
+
id: typeof args.options.id !== 'undefined',
|
|
77
|
+
name: typeof args.options.name !== 'undefined'
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}, _BookingBusinessGetCommand_initOptions = function _BookingBusinessGetCommand_initOptions() {
|
|
81
|
+
this.options.unshift({ option: '-i, --id [id]' }, { option: '-n, --name [name]' });
|
|
82
|
+
}, _BookingBusinessGetCommand_initOptionSets = function _BookingBusinessGetCommand_initOptionSets() {
|
|
83
|
+
this.optionSets.push(['id', 'name']);
|
|
84
|
+
};
|
|
85
|
+
module.exports = new BookingBusinessGetCommand();
|
|
86
|
+
//# sourceMappingURL=business-get.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../../../../utils");
|
|
4
|
+
const GraphCommand_1 = require("../../../base/GraphCommand");
|
|
5
|
+
const commands_1 = require("../../commands");
|
|
6
|
+
class BookingBusinessListCommand extends GraphCommand_1.default {
|
|
7
|
+
get name() {
|
|
8
|
+
return commands_1.default.BUSINESS_LIST;
|
|
9
|
+
}
|
|
10
|
+
get description() {
|
|
11
|
+
return 'Lists all Microsoft Bookings businesses that are created for the tenant.';
|
|
12
|
+
}
|
|
13
|
+
defaultProperties() {
|
|
14
|
+
return ['id', 'displayName'];
|
|
15
|
+
}
|
|
16
|
+
commandAction(logger, args, cb) {
|
|
17
|
+
const endpoint = `${this.resource}/v1.0/solutions/bookingBusinesses`;
|
|
18
|
+
utils_1.odata
|
|
19
|
+
.getAllItems(endpoint)
|
|
20
|
+
.then((items) => {
|
|
21
|
+
return Promise.resolve(items);
|
|
22
|
+
})
|
|
23
|
+
.then((items) => {
|
|
24
|
+
logger.log(items);
|
|
25
|
+
cb();
|
|
26
|
+
}, (err) => this.handleRejectedODataJsonPromise(err, logger, cb));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
module.exports = new BookingBusinessListCommand();
|
|
30
|
+
//# sourceMappingURL=business-list.js.map
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
6
|
+
};
|
|
7
|
+
var _SearchExternalConnectionRemoveCommand_instances, _SearchExternalConnectionRemoveCommand_initTelemetry, _SearchExternalConnectionRemoveCommand_initOptions, _SearchExternalConnectionRemoveCommand_initOptionSets;
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const cli_1 = require("../../../../cli");
|
|
10
|
+
const request_1 = require("../../../../request");
|
|
11
|
+
const GraphCommand_1 = require("../../../base/GraphCommand");
|
|
12
|
+
const commands_1 = require("../../commands");
|
|
13
|
+
class SearchExternalConnectionRemoveCommand extends GraphCommand_1.default {
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
_SearchExternalConnectionRemoveCommand_instances.add(this);
|
|
17
|
+
__classPrivateFieldGet(this, _SearchExternalConnectionRemoveCommand_instances, "m", _SearchExternalConnectionRemoveCommand_initTelemetry).call(this);
|
|
18
|
+
__classPrivateFieldGet(this, _SearchExternalConnectionRemoveCommand_instances, "m", _SearchExternalConnectionRemoveCommand_initOptions).call(this);
|
|
19
|
+
__classPrivateFieldGet(this, _SearchExternalConnectionRemoveCommand_instances, "m", _SearchExternalConnectionRemoveCommand_initOptionSets).call(this);
|
|
20
|
+
}
|
|
21
|
+
get name() {
|
|
22
|
+
return commands_1.default.EXTERNALCONNECTION_REMOVE;
|
|
23
|
+
}
|
|
24
|
+
get description() {
|
|
25
|
+
return 'Removes a specific External Connection from Microsoft Search';
|
|
26
|
+
}
|
|
27
|
+
getExternalConnectionId(args) {
|
|
28
|
+
if (args.options.id) {
|
|
29
|
+
return Promise.resolve(args.options.id);
|
|
30
|
+
}
|
|
31
|
+
const requestOptions = {
|
|
32
|
+
url: `${this.resource}/v1.0/external/connections?$filter=name eq '${encodeURIComponent(args.options.name)}'&$select=id`,
|
|
33
|
+
headers: {
|
|
34
|
+
accept: 'application/json;odata.metadata=none'
|
|
35
|
+
},
|
|
36
|
+
responseType: 'json'
|
|
37
|
+
};
|
|
38
|
+
return request_1.default
|
|
39
|
+
.get(requestOptions)
|
|
40
|
+
.then((res) => {
|
|
41
|
+
if (res.value.length === 1) {
|
|
42
|
+
return Promise.resolve(res.value[0].id);
|
|
43
|
+
}
|
|
44
|
+
if (res.value.length === 0) {
|
|
45
|
+
return Promise.reject(`The specified connection does not exist in Microsoft Search`);
|
|
46
|
+
}
|
|
47
|
+
return Promise.reject(`Multiple external connections with name ${args.options.name} found. Please disambiguate (IDs): ${res.value.map(x => x.id).join(', ')}`);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
commandAction(logger, args, cb) {
|
|
51
|
+
const removeExternalConnection = () => {
|
|
52
|
+
this
|
|
53
|
+
.getExternalConnectionId(args)
|
|
54
|
+
.then((externalConnectionId) => {
|
|
55
|
+
const requestOptions = {
|
|
56
|
+
url: `${this.resource}/v1.0/external/connections/${encodeURIComponent(externalConnectionId)}`,
|
|
57
|
+
headers: {
|
|
58
|
+
accept: 'application/json;odata.metadata=none'
|
|
59
|
+
},
|
|
60
|
+
responseType: 'json'
|
|
61
|
+
};
|
|
62
|
+
return request_1.default
|
|
63
|
+
.delete(requestOptions);
|
|
64
|
+
})
|
|
65
|
+
.then(_ => cb(), (rawRes) => this.handleRejectedODataJsonPromise(rawRes, logger, cb));
|
|
66
|
+
};
|
|
67
|
+
if (args.options.confirm) {
|
|
68
|
+
removeExternalConnection();
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
cli_1.Cli.prompt({
|
|
72
|
+
type: 'confirm',
|
|
73
|
+
name: 'continue',
|
|
74
|
+
default: false,
|
|
75
|
+
message: `Are you sure you want to remove the external connection '${args.options.id || args.options.name}'?`
|
|
76
|
+
}, (result) => {
|
|
77
|
+
if (!result.continue) {
|
|
78
|
+
cb();
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
removeExternalConnection();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
_SearchExternalConnectionRemoveCommand_instances = new WeakSet(), _SearchExternalConnectionRemoveCommand_initTelemetry = function _SearchExternalConnectionRemoveCommand_initTelemetry() {
|
|
88
|
+
this.telemetry.push((args) => {
|
|
89
|
+
Object.assign(this.telemetryProperties, {
|
|
90
|
+
id: typeof args.options.id !== 'undefined',
|
|
91
|
+
name: typeof args.options.name !== 'undefined',
|
|
92
|
+
confirm: (!(!args.options.confirm)).toString()
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}, _SearchExternalConnectionRemoveCommand_initOptions = function _SearchExternalConnectionRemoveCommand_initOptions() {
|
|
96
|
+
this.options.unshift({ option: '--id [id]' }, { option: '--name [name]' }, { option: '--confirm' });
|
|
97
|
+
}, _SearchExternalConnectionRemoveCommand_initOptionSets = function _SearchExternalConnectionRemoveCommand_initOptionSets() {
|
|
98
|
+
this.optionSets.push(['id', 'name']);
|
|
99
|
+
};
|
|
100
|
+
module.exports = new SearchExternalConnectionRemoveCommand();
|
|
101
|
+
//# sourceMappingURL=externalconnection-remove.js.map
|
|
@@ -4,6 +4,7 @@ const prefix = 'search';
|
|
|
4
4
|
exports.default = {
|
|
5
5
|
EXTERNALCONNECTION_ADD: `${prefix} externalconnection add`,
|
|
6
6
|
EXTERNALCONNECTION_GET: `${prefix} externalconnection get`,
|
|
7
|
-
EXTERNALCONNECTION_LIST: `${prefix} externalconnection list
|
|
7
|
+
EXTERNALCONNECTION_LIST: `${prefix} externalconnection list`,
|
|
8
|
+
EXTERNALCONNECTION_REMOVE: `${prefix} externalconnection remove`
|
|
8
9
|
};
|
|
9
10
|
//# sourceMappingURL=commands.js.map
|
|
@@ -414,6 +414,21 @@ class SpfxDoctorCommand extends AnonymousCommand_1.default {
|
|
|
414
414
|
range: '^4',
|
|
415
415
|
fix: 'npm i -g yo@4'
|
|
416
416
|
}
|
|
417
|
+
},
|
|
418
|
+
'1.15.2': {
|
|
419
|
+
gulp: {
|
|
420
|
+
range: '^4',
|
|
421
|
+
fix: 'npm i -g gulp@4'
|
|
422
|
+
},
|
|
423
|
+
node: {
|
|
424
|
+
range: '^12.13 || ^14.15 || ^16.13',
|
|
425
|
+
fix: 'Install Node.js v12.13, v14.15, v16.13 or higher'
|
|
426
|
+
},
|
|
427
|
+
sp: SharePointVersion.SPO,
|
|
428
|
+
yo: {
|
|
429
|
+
range: '^4',
|
|
430
|
+
fix: 'npm i -g yo@4'
|
|
431
|
+
}
|
|
417
432
|
}
|
|
418
433
|
};
|
|
419
434
|
__classPrivateFieldGet(this, _SpfxDoctorCommand_instances, "m", _SpfxDoctorCommand_initTelemetry).call(this);
|
|
@@ -58,6 +58,9 @@ m365 aad app add [options]
|
|
|
58
58
|
`--certificateDisplayName [certificateDisplayName]`
|
|
59
59
|
: Display name for the certificate. If not given, the displayName will be set to the certificate subject. When specified, also specify either `certificateFile` or `certificateBase64Encoded`
|
|
60
60
|
|
|
61
|
+
`--grantAdminConsent`
|
|
62
|
+
: When specified, grants application & delegated permissions through admin consent
|
|
63
|
+
|
|
61
64
|
`--manifest [manifest]`
|
|
62
65
|
: Azure AD app manifest as retrieved from the Azure Portal to create the app registration from
|
|
63
66
|
|
|
@@ -94,6 +97,8 @@ After creating the Azure AD app registration, this command returns the app ID an
|
|
|
94
97
|
|
|
95
98
|
If you want to store the information about the created Azure AD app registration, use the `--save` option. This is useful when you build solutions connected to Microsoft 365 and want to easily manage app registrations used with your solution. When you use the `--save` option, after you create the app registration, the command will write its ID and name to the `.m365rc.json` file in the current directory. If the file already exists, it will add the information about the to it, allowing you to track multiple apps. If the file doesn't exist, the command will create it.
|
|
96
99
|
|
|
100
|
+
When specifying `--grantAdminConsent` option, a service principal will be created for the app registration.
|
|
101
|
+
|
|
97
102
|
## Examples
|
|
98
103
|
|
|
99
104
|
Create new Azure AD app registration with the specified name
|
|
@@ -156,6 +161,12 @@ Create new Azure AD app registration with Application ID URI set to a value that
|
|
|
156
161
|
m365 aad app add --name 'My AAD app' --uri api://caf406b91cd4.ngrok.io/_appId_ --scopeName access_as_user --scopeAdminConsentDescription 'Access as a user' --scopeAdminConsentDisplayName 'Access as a user' --scopeConsentBy adminsAndUsers
|
|
157
162
|
```
|
|
158
163
|
|
|
164
|
+
Create new Azure AD app registration for a deamon app with specified Microsoft Graph application permissions, including admin consent
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
m365 aad app add --name 'My AAD app' --apisApplication 'https://graph.microsoft.com/Group.ReadWrite.All' --grantAdminConsent
|
|
168
|
+
```
|
|
169
|
+
|
|
159
170
|
Create new Azure AD app registration with the specified name. Store information about the created app registration in the _.m365rc.json_ file in the current directory.
|
|
160
171
|
|
|
161
172
|
```sh
|
|
@@ -165,5 +176,5 @@ m365 aad app add --name 'My AAD app' --save
|
|
|
165
176
|
Create new Azure AD app registration with a certificate
|
|
166
177
|
|
|
167
178
|
```sh
|
|
168
|
-
m365 aad app add --name 'My AAD app' --certificateDisplayName "Some certificate name" --certificateFile c:\temp\some-certificate.cer
|
|
179
|
+
m365 aad app add --name 'My AAD app' --certificateDisplayName "Some certificate name" --certificateFile "c:\temp\some-certificate.cer"
|
|
169
180
|
```
|
|
@@ -85,5 +85,5 @@ m365 aad app set --objectId 95cfe30d-ed44-4f9d-b73d-c66560f72e83 --redirectUris
|
|
|
85
85
|
Add a certificate to the app
|
|
86
86
|
|
|
87
87
|
```sh
|
|
88
|
-
m365 aad app set --certificateDisplayName "Some certificate name" --certificateFile c:\temp\some-certificate.cer
|
|
88
|
+
m365 aad app set --appId e75be2e1-0204-4f95-857d-51a37cf40be8 --certificateDisplayName "Some certificate name" --certificateFile "c:\temp\some-certificate.cer"
|
|
89
89
|
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# booking business get
|
|
2
|
+
|
|
3
|
+
Retrieve the specified Microsoft Bookings business.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
m365 booking business get [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Options
|
|
12
|
+
|
|
13
|
+
`-i, --id [id]`
|
|
14
|
+
: ID of the business. Specify either `id` or `name` but not both.
|
|
15
|
+
|
|
16
|
+
`-n, --name [name]`
|
|
17
|
+
: Name of the business. Specify either `id` or `name` but not both.
|
|
18
|
+
|
|
19
|
+
--8<-- "docs/cmd/_global.md"
|
|
20
|
+
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
Retrieve the specified Microsoft Bookings business with id _business@contoso.onmicrosoft.com_.
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
m365 booking business get --id 'business@contoso.onmicrosoft.com'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Retrieve the specified Microsoft Bookings business with name _business name_.
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
m365 booking business get --name 'business name'
|
|
33
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# booking business list
|
|
2
|
+
|
|
3
|
+
Lists all Microsoft Bookings businesses that are created for the tenant.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
m365 booking business list [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Options
|
|
12
|
+
|
|
13
|
+
--8<-- "docs/cmd/_global.md"
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
Returns a list of all Microsoft Bookings businesses that are created for the tenant.
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
m365 booking business list
|
|
21
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# search externalconnection remove
|
|
2
|
+
|
|
3
|
+
Allow the administrator to remove a specific external connection used in Microsoft Search.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
m365 search externalconnection remove [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Options
|
|
12
|
+
|
|
13
|
+
`-i, --id [id]`
|
|
14
|
+
: ID of the External Connection to remove. Specify either `id` or `name`
|
|
15
|
+
|
|
16
|
+
`-n, --name [name]`
|
|
17
|
+
: Name of the External Connection to remove. Specify either `id` or `name`
|
|
18
|
+
|
|
19
|
+
`--confirm`
|
|
20
|
+
: Don't prompt for confirming removing the connection
|
|
21
|
+
|
|
22
|
+
--8<-- "docs/cmd/_global.md"
|
|
23
|
+
|
|
24
|
+
## Remarks
|
|
25
|
+
|
|
26
|
+
If the command finds multiple external connections used in Microsoft Search with the specified name, it will prompt you to disambiguate which external connection it should remove, listing the discovered IDs.
|
|
27
|
+
|
|
28
|
+
## Examples
|
|
29
|
+
|
|
30
|
+
Removes external connection with id _MyApp_
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
m365 search externalconnection remove --id "MyApp"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Removes external connection with name _Test_. Will NOT prompt for confirmation before removing.
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
m365 search externalconnection remove --name "Test" --confirm
|
|
40
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnp/cli-microsoft365",
|
|
3
|
-
"version": "5.7.0-beta.
|
|
3
|
+
"version": "5.7.0-beta.bb14b6c",
|
|
4
4
|
"description": "Manage Microsoft 365 and SharePoint Framework projects on any platform",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/api.js",
|
|
@@ -86,6 +86,16 @@
|
|
|
86
86
|
"name": "Martin Lingstuyl",
|
|
87
87
|
"email": "mlingstuyl@live.com",
|
|
88
88
|
"web": "https://www.blimped.nl/"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "Jasey Waegebaert",
|
|
92
|
+
"email": "jaseyw@gmigroup.be",
|
|
93
|
+
"web": "https://github.com/Jwaegebaert"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "Milan Holemans",
|
|
97
|
+
"email": "Milan.Holemans@vanroey.be",
|
|
98
|
+
"web": "https://github.com/milanholemans"
|
|
89
99
|
}
|
|
90
100
|
],
|
|
91
101
|
"contributors": [
|