@pnp/cli-microsoft365 10.8.0-beta.708bf27 → 10.8.0-beta.a1c69a6

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.
Files changed (68) hide show
  1. package/.eslintrc.cjs +2 -1
  2. package/README.md +3 -1
  3. package/allCommands.json +1 -1
  4. package/allCommandsFull.json +1 -1
  5. package/dist/Auth.js +82 -22
  6. package/dist/cli/cli.js +1 -1
  7. package/dist/config.js +1 -0
  8. package/dist/m365/adaptivecard/commands/adaptivecard-send.js +54 -67
  9. package/dist/m365/app/commands/app-get.js +5 -2
  10. package/dist/m365/app/commands/app-open.js +9 -22
  11. package/dist/m365/app/commands/permission/permission-add.js +18 -30
  12. package/dist/m365/app/commands/permission/permission-list.js +5 -2
  13. package/dist/m365/base/AppCommand.js +9 -25
  14. package/dist/m365/booking/commands/business/business-get.js +18 -25
  15. package/dist/m365/cli/commands/app/app-reconsent.js +103 -0
  16. package/dist/m365/cli/commands.js +1 -0
  17. package/dist/m365/commands/login.js +1 -1
  18. package/dist/m365/commands/setup.js +1 -2
  19. package/dist/m365/context/commands/context-remove.js +12 -25
  20. package/dist/m365/context/commands/option/option-remove.js +11 -25
  21. package/dist/m365/entra/commands/organization/organization-list.js +51 -0
  22. package/dist/m365/entra/commands.js +1 -0
  23. package/dist/m365/graph/commands/directoryextension/directoryextension-list.js +74 -0
  24. package/dist/m365/graph/commands/openextension/openextension-set.js +107 -0
  25. package/dist/m365/graph/commands.js +2 -0
  26. package/dist/m365/spe/commands/container/container-add.js +85 -0
  27. package/dist/m365/spe/commands/container/container-list.js +2 -9
  28. package/dist/m365/spe/commands/container/container-permission-list.js +52 -0
  29. package/dist/m365/spe/commands/container/container-recyclebinitem-list.js +62 -0
  30. package/dist/m365/spe/commands/container/container-remove.js +99 -0
  31. package/dist/m365/spe/commands/containertype/containertype-add.js +11 -11
  32. package/dist/m365/spe/commands/containertype/containertype-get.js +28 -32
  33. package/dist/m365/spe/commands/containertype/containertype-list.js +14 -4
  34. package/dist/m365/spe/commands/containertype/containertype-remove.js +81 -0
  35. package/dist/m365/spe/commands.js +6 -1
  36. package/dist/m365/spo/commands/list/list-get.js +12 -6
  37. package/dist/m365/spo/commands/page/page-section-add.js +20 -23
  38. package/dist/m365/spp/commands/model/model-apply.js +130 -0
  39. package/dist/m365/spp/commands/model/model-get.js +7 -24
  40. package/dist/m365/spp/commands/model/model-list.js +1 -1
  41. package/dist/m365/spp/commands/model/model-remove.js +1 -1
  42. package/dist/m365/spp/commands.js +1 -0
  43. package/dist/utils/entraServicePrincipal.js +11 -0
  44. package/dist/utils/formatting.js +12 -0
  45. package/dist/utils/spe.js +77 -0
  46. package/dist/utils/spo.js +0 -18
  47. package/dist/utils/spp.js +59 -1
  48. package/dist/utils/zod.js +26 -1
  49. package/docs/docs/cmd/adaptivecard/adaptivecard-send.mdx +1 -1
  50. package/docs/docs/cmd/cli/app/app-reconsent.mdx +63 -0
  51. package/docs/docs/cmd/entra/organization/organization-list.mdx +154 -0
  52. package/docs/docs/cmd/graph/directoryextension/directoryextension-list.mdx +135 -0
  53. package/docs/docs/cmd/graph/openextension/openextension-set.mdx +97 -0
  54. package/docs/docs/cmd/spe/container/container-activate.mdx +0 -2
  55. package/docs/docs/cmd/spe/container/container-add.mdx +128 -0
  56. package/docs/docs/cmd/spe/container/container-permission-list.mdx +90 -0
  57. package/docs/docs/cmd/spe/container/container-recyclebinitem-list.mdx +96 -0
  58. package/docs/docs/cmd/spe/container/container-remove.mdx +65 -0
  59. package/docs/docs/cmd/spe/containertype/containertype-add.mdx +9 -1
  60. package/docs/docs/cmd/spe/containertype/containertype-get.mdx +8 -0
  61. package/docs/docs/cmd/spe/containertype/containertype-list.mdx +8 -0
  62. package/docs/docs/cmd/spe/containertype/containertype-remove.mdx +52 -0
  63. package/docs/docs/cmd/spo/field/field-get.mdx +0 -1
  64. package/docs/docs/cmd/spo/list/list-get.mdx +12 -3
  65. package/docs/docs/cmd/spp/model/model-apply.mdx +79 -0
  66. package/npm-shrinkwrap.json +894 -477
  67. package/package.json +11 -11
  68. package/dist/m365/spe/ContainerProperties.js +0 -2
@@ -59,19 +59,25 @@ class SpoPageSectionAddCommand extends SpoCommand {
59
59
  };
60
60
  await request.post(requestOptions);
61
61
  }
62
- // get columns
63
- const columns = canvasContent
64
- .filter(c => typeof c.controlType === 'undefined');
65
62
  // get unique zoneIndex values given each section can have 1 or more
66
63
  // columns each assigned to the zoneIndex of the corresponding section
67
- const zoneIndices = columns
64
+ const zoneIndices = canvasContent
65
+ // Exclude the vertical section
66
+ .filter(c => c.position)
68
67
  .map(c => c.position.zoneIndex)
69
68
  .filter((value, index, array) => {
70
69
  return array.indexOf(value) === index;
71
70
  })
72
- .sort();
73
- // zoneIndex for the new section to add
74
- const zoneIndex = this.getSectionIndex(zoneIndices, args.options.order);
71
+ .sort((a, b) => a - b);
72
+ // Add a new zoneIndex at the end of the array
73
+ zoneIndices.push(zoneIndices.length > 0 ? zoneIndices[zoneIndices.length - 1] + 1 : 1);
74
+ // get section number. if not specified, get the last section
75
+ let section = args.options.order || zoneIndices.length;
76
+ if (section > zoneIndices.length) {
77
+ section = zoneIndices.length;
78
+ }
79
+ // zoneIndex that represents the section where the web part should be added
80
+ const zoneIndex = zoneIndices[section - 1];
75
81
  let zoneId;
76
82
  let backgroundControlToAdd = undefined;
77
83
  if (args.options.zoneEmphasis && ['image', 'gradient'].includes(args.options.zoneEmphasis.toLowerCase())) {
@@ -83,11 +89,17 @@ class SpoPageSectionAddCommand extends SpoCommand {
83
89
  canvasContent.push(backgroundControlToAdd);
84
90
  }
85
91
  }
92
+ // Increment the zoneIndex of all columns that are greater than or equal to the new zoneIndex
93
+ canvasContent.forEach((c) => {
94
+ if (c.position && c.position.zoneIndex >= zoneIndex) {
95
+ c.position.zoneIndex += 1;
96
+ }
97
+ });
86
98
  // get the list of columns to insert based on the selected template
87
99
  const columnsToAdd = this.getColumns(zoneIndex, args, zoneId);
88
100
  // insert the column in the right place in the array so that
89
101
  // it stays sorted ascending by zoneIndex
90
- let pos = canvasContent.findIndex(c => typeof c.controlType === 'undefined' && c.position && c.position.zoneIndex > zoneIndex);
102
+ let pos = canvasContent.findIndex(c => c.position && c.position.zoneIndex >= zoneIndex);
91
103
  if (pos === -1) {
92
104
  pos = canvasContent.length - 1;
93
105
  }
@@ -109,21 +121,6 @@ class SpoPageSectionAddCommand extends SpoCommand {
109
121
  this.handleRejectedODataJsonPromise(err);
110
122
  }
111
123
  }
112
- getSectionIndex(zoneIndices, order) {
113
- // zoneIndex of the first column on the page
114
- const minIndex = zoneIndices.length === 0 ? 0 : zoneIndices[0];
115
- // zoneIndex of the last column on the page
116
- const maxIndex = zoneIndices.length === 0 ? 0 : zoneIndices[zoneIndices.length - 1];
117
- if (!order || order > zoneIndices.length) {
118
- // no order specified, add section to the end
119
- return maxIndex === 0 ? 1 : maxIndex * 2;
120
- }
121
- // add to the beginning
122
- if (order === 1) {
123
- return minIndex / 2;
124
- }
125
- return zoneIndices[order - 2] + ((zoneIndices[order - 1] - zoneIndices[order - 2]) / 2);
126
- }
127
124
  getColumns(zoneIndex, args, zoneId) {
128
125
  const columns = [];
129
126
  let sectionIndex = 1;
@@ -0,0 +1,130 @@
1
+ import request from '../../../../request.js';
2
+ import { formatting } from '../../../../utils/formatting.js';
3
+ import { spp } from '../../../../utils/spp.js';
4
+ import { urlUtil } from '../../../../utils/urlUtil.js';
5
+ import { validation } from '../../../../utils/validation.js';
6
+ import SpoCommand from '../../../base/SpoCommand.js';
7
+ import commands from '../../commands.js';
8
+ import { z } from 'zod';
9
+ import { globalOptionsZod } from '../../../../Command.js';
10
+ import { zod } from '../../../../utils/zod.js';
11
+ const options = globalOptionsZod
12
+ .extend({
13
+ contentCenterUrl: zod.alias('c', z.string()
14
+ .refine(url => validation.isValidSharePointUrl(url) === true, url => ({
15
+ message: `'${url}' is not a valid SharePoint Online site URL.`
16
+ }))),
17
+ webUrl: zod.alias('u', z.string()
18
+ .refine(url => validation.isValidSharePointUrl(url) === true, url => ({
19
+ message: `'${url}' is not a valid SharePoint Online site URL.`
20
+ }))),
21
+ id: zod.alias('i', z.string()
22
+ .refine(id => validation.isValidGuid(id) === true, id => ({
23
+ message: `${id} is not a valid GUID.`
24
+ })).optional()),
25
+ title: zod.alias('t', z.string()).optional(),
26
+ listTitle: z.string().optional(),
27
+ listId: z.string()
28
+ .refine(listId => validation.isValidGuid(listId) === true, listId => ({
29
+ message: `${listId} is not a valid GUID.`
30
+ })).optional(),
31
+ listUrl: z.string().optional(),
32
+ viewOption: z.enum(['NewViewAsDefault', 'DoNotChangeDefault', 'TileViewAsDefault']).optional()
33
+ })
34
+ .strict();
35
+ class SppModelApplyCommand extends SpoCommand {
36
+ get name() {
37
+ return commands.MODEL_APPLY;
38
+ }
39
+ get description() {
40
+ return 'Applies (or syncs) a trained document understanding model to a document library';
41
+ }
42
+ get schema() {
43
+ return options;
44
+ }
45
+ getRefinedSchema(schema) {
46
+ return schema
47
+ .refine(options => [options.id, options.title].filter(x => x !== undefined).length === 1, {
48
+ message: `Specify exactly one of the following options: 'id' or 'title'.`
49
+ })
50
+ .refine(options => [options.listTitle, options.listId, options.listUrl].filter(x => x !== undefined).length === 1, {
51
+ message: `Specify exactly one of the following options: 'listTitle', 'listId' or 'listUrl'.`
52
+ });
53
+ }
54
+ async commandAction(logger, args) {
55
+ try {
56
+ const contentCenterUrl = urlUtil.removeTrailingSlashes(args.options.contentCenterUrl);
57
+ await spp.assertSiteIsContentCenter(contentCenterUrl, logger, this.verbose);
58
+ let model = null;
59
+ if (args.options.title) {
60
+ model = await spp.getModelByTitle(contentCenterUrl, args.options.title, logger, this.verbose);
61
+ }
62
+ else {
63
+ model = await spp.getModelById(contentCenterUrl, args.options.id, logger, this.verbose);
64
+ }
65
+ if (this.verbose) {
66
+ await logger.log(`Retrieving list information...`);
67
+ }
68
+ const listInstance = await this.getListInfo(args.options.webUrl, args.options.listId, args.options.listTitle, args.options.listUrl);
69
+ if (listInstance.BaseType !== 1) {
70
+ throw `The specified list is not a document library.`;
71
+ }
72
+ if (this.verbose) {
73
+ await logger.log(`Applying model '${model.ModelName}' to document library '${listInstance.RootFolder.ServerRelativeUrl}'...`);
74
+ }
75
+ const requestOptions = {
76
+ url: `${contentCenterUrl}/_api/machinelearning/publications`,
77
+ headers: {
78
+ accept: 'application/json;odata=nometadata',
79
+ 'Content-Type': 'application/json;odata=verbose'
80
+ },
81
+ responseType: 'json',
82
+ data: {
83
+ __metadata: { type: 'Microsoft.Office.Server.ContentCenter.SPMachineLearningPublicationsEntityData' },
84
+ Publications: {
85
+ results: [
86
+ {
87
+ ModelUniqueId: model.UniqueId,
88
+ TargetSiteUrl: args.options.webUrl,
89
+ TargetWebServerRelativeUrl: urlUtil.getServerRelativeSiteUrl(args.options.webUrl),
90
+ TargetLibraryServerRelativeUrl: listInstance.RootFolder.ServerRelativeUrl,
91
+ ViewOption: args.options.viewOption ?? "NewViewAsDefault"
92
+ }
93
+ ]
94
+ }
95
+ }
96
+ };
97
+ const result = await request.post(requestOptions);
98
+ const resultDetails = result.Details;
99
+ if (resultDetails && resultDetails[0]?.ErrorMessage) {
100
+ throw resultDetails[0].ErrorMessage;
101
+ }
102
+ }
103
+ catch (err) {
104
+ this.handleRejectedODataJsonPromise(err);
105
+ }
106
+ }
107
+ getListInfo(webUrl, listId, listTitle, listUrl) {
108
+ let requestUrl = `${webUrl}/_api/web`;
109
+ if (listId) {
110
+ requestUrl += `/lists(guid'${formatting.encodeQueryParameter(listId)}')`;
111
+ }
112
+ else if (listTitle) {
113
+ requestUrl += `/lists/getByTitle('${formatting.encodeQueryParameter(listTitle)}')`;
114
+ }
115
+ else if (listUrl) {
116
+ const listServerRelativeUrl = urlUtil.getServerRelativePath(webUrl, listUrl);
117
+ requestUrl += `/GetList('${formatting.encodeQueryParameter(listServerRelativeUrl)}')`;
118
+ }
119
+ const requestOptions = {
120
+ url: `${requestUrl}?$select=BaseType,RootFolder/ServerRelativeUrl&$expand=RootFolder`,
121
+ headers: {
122
+ accept: 'application/json;odata=nometadata'
123
+ },
124
+ responseType: 'json'
125
+ };
126
+ return request.get(requestOptions);
127
+ }
128
+ }
129
+ export default new SppModelApplyCommand();
130
+ //# sourceMappingURL=model-apply.js.map
@@ -4,8 +4,6 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
6
  var _SppModelGetCommand_instances, _SppModelGetCommand_initTelemetry, _SppModelGetCommand_initOptions, _SppModelGetCommand_initValidators, _SppModelGetCommand_initOptionSets, _SppModelGetCommand_initTypes;
7
- import request from '../../../../request.js';
8
- import { formatting } from '../../../../utils/formatting.js';
9
7
  import { odata } from '../../../../utils/odata.js';
10
8
  import { spp } from '../../../../utils/spp.js';
11
9
  import { urlUtil } from '../../../../utils/urlUtil.js';
@@ -30,34 +28,19 @@ class SppModelGetCommand extends SpoCommand {
30
28
  }
31
29
  async commandAction(logger, args) {
32
30
  try {
33
- if (this.verbose) {
34
- await logger.log(`Retrieving model information from ${args.options.siteUrl}...`);
35
- }
36
31
  const siteUrl = urlUtil.removeTrailingSlashes(args.options.siteUrl);
37
- await spp.assertSiteIsContentCenter(siteUrl);
38
- let requestUrl = `${siteUrl}/_api/machinelearning/models/`;
32
+ await spp.assertSiteIsContentCenter(siteUrl, logger, this.verbose);
33
+ let result = null;
39
34
  if (args.options.title) {
40
- let requestTitle = args.options.title.toLowerCase();
41
- if (!requestTitle.endsWith('.classifier')) {
42
- requestTitle += '.classifier';
43
- }
44
- requestUrl += `getbytitle('${formatting.encodeQueryParameter(requestTitle)}')`;
35
+ result = await spp.getModelByTitle(siteUrl, args.options.title, logger, this.verbose);
45
36
  }
46
37
  else {
47
- requestUrl += `getbyuniqueid('${args.options.id}')`;
48
- }
49
- const requestOptions = {
50
- url: requestUrl,
51
- headers: {
52
- accept: 'application/json;odata=nometadata'
53
- },
54
- responseType: 'json'
55
- };
56
- const result = await request.get(requestOptions);
57
- if (result['odata.null'] === true) {
58
- throw 'Model not found.';
38
+ result = await spp.getModelById(siteUrl, args.options.id, logger, this.verbose);
59
39
  }
60
40
  if (args.options.withPublications) {
41
+ if (this.verbose) {
42
+ await logger.log(`Retrieving publications for model...`);
43
+ }
61
44
  result.Publications = await odata.getAllItems(`${siteUrl}/_api/machinelearning/publications/getbymodeluniqueid('${result.UniqueId}')`);
62
45
  }
63
46
  await logger.log({
@@ -33,7 +33,7 @@ class SppModelListCommand extends SpoCommand {
33
33
  await logger.log(`Retrieving models from ${args.options.siteUrl}...`);
34
34
  }
35
35
  const siteUrl = urlUtil.removeTrailingSlashes(args.options.siteUrl);
36
- await spp.assertSiteIsContentCenter(siteUrl);
36
+ await spp.assertSiteIsContentCenter(siteUrl, logger, this.verbose);
37
37
  const result = await odata.getAllItems(`${siteUrl}/_api/machinelearning/models`);
38
38
  await logger.log(result);
39
39
  }
@@ -40,7 +40,7 @@ class SppModelRemoveCommand extends SpoCommand {
40
40
  await logger.log(`Removing model from ${args.options.siteUrl}...`);
41
41
  }
42
42
  const siteUrl = urlUtil.removeTrailingSlashes(args.options.siteUrl);
43
- await spp.assertSiteIsContentCenter(siteUrl);
43
+ await spp.assertSiteIsContentCenter(siteUrl, logger, this.verbose);
44
44
  let requestUrl = `${siteUrl}/_api/machinelearning/models/`;
45
45
  if (args.options.title) {
46
46
  let requestTitle = args.options.title.toLowerCase();
@@ -1,6 +1,7 @@
1
1
  const prefix = 'spp';
2
2
  export default {
3
3
  CONTENTCENTER_LIST: `${prefix} contentcenter list`,
4
+ MODEL_APPLY: `${prefix} model apply`,
4
5
  MODEL_GET: `${prefix} model get`,
5
6
  MODEL_LIST: `${prefix} model list`,
6
7
  MODEL_REMOVE: `${prefix} model remove`
@@ -41,6 +41,17 @@ export const entraServicePrincipal = {
41
41
  return await cli.handleMultipleResultsFound(`Multiple service principals with name '${appName}' found in Microsoft Entra ID.`, resultAsKeyValuePair);
42
42
  }
43
43
  return apps[0];
44
+ },
45
+ /**
46
+ * Get all available service principals.
47
+ * @param properties Comma-separated list of properties to include in the response.
48
+ */
49
+ async getServicePrincipals(properties) {
50
+ let url = `https://graph.microsoft.com/v1.0/servicePrincipals`;
51
+ if (properties) {
52
+ url += `?$select=${properties}`;
53
+ }
54
+ return odata.getAllItems(url);
44
55
  }
45
56
  };
46
57
  //# sourceMappingURL=entraServicePrincipal.js.map
@@ -177,6 +177,18 @@ export const formatting = {
177
177
  resultAsKeyValuePair[obj[key]] = obj;
178
178
  });
179
179
  return resultAsKeyValuePair;
180
+ },
181
+ /**
182
+ * Extracts the GUID from a string in CSOM format.
183
+ * @param str The string to extract the GUID from
184
+ * @description The string should be in the format /Guid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)/
185
+ * @returns The extracted GUID or the original string if no match is found
186
+ * @example /Guid(eae15efb-ac09-49b9-8906-e579efd622e4)/ => eae15efb-ac09-49b9-8906-e579efd622e4
187
+ */
188
+ extractCsomGuid(str) {
189
+ const guidPattern = /\/Guid\(([0-9a-f-]+)\)\//i;
190
+ const match = str.match(guidPattern);
191
+ return match ? match[1] : str;
180
192
  }
181
193
  };
182
194
  //# sourceMappingURL=formatting.js.map
@@ -0,0 +1,77 @@
1
+ import request from '../request.js';
2
+ import { formatting } from './formatting.js';
3
+ import { cli } from '../cli/cli.js';
4
+ import config from '../config.js';
5
+ import { odata } from './odata.js';
6
+ const graphResource = 'https://graph.microsoft.com';
7
+ export const spe = {
8
+ /**
9
+ * Get all container types.
10
+ * @param spoAdminUrl The URL of the SharePoint Online admin center site (e.g. https://contoso-admin.sharepoint.com)
11
+ * @returns Array of container types
12
+ */
13
+ async getAllContainerTypes(spoAdminUrl) {
14
+ const requestOptions = {
15
+ url: `${spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
16
+ headers: {
17
+ accept: 'application/json;odata=nometadata'
18
+ },
19
+ responseType: 'json',
20
+ data: `<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="46" ObjectPathId="45" /><Method Name="GetSPOContainerTypes" Id="47" ObjectPathId="45"><Parameters><Parameter Type="Enum">1</Parameter></Parameters></Method></Actions><ObjectPaths><Constructor Id="45" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`
21
+ };
22
+ const json = await request.post(requestOptions);
23
+ const response = json[0];
24
+ if (response.ErrorInfo) {
25
+ throw new Error(response.ErrorInfo.ErrorMessage);
26
+ }
27
+ const containerTypes = json[json.length - 1];
28
+ // Format the response to remove CSOM GUIDs and convert them to real GUIDs
29
+ containerTypes.forEach(ct => {
30
+ delete ct._ObjectType_;
31
+ ct.AzureSubscriptionId = formatting.extractCsomGuid(ct.AzureSubscriptionId);
32
+ ct.ContainerTypeId = formatting.extractCsomGuid(ct.ContainerTypeId);
33
+ ct.OwningAppId = formatting.extractCsomGuid(ct.OwningAppId);
34
+ ct.OwningTenantId = formatting.extractCsomGuid(ct.OwningTenantId);
35
+ });
36
+ return containerTypes;
37
+ },
38
+ /**
39
+ * Get the ID of a container type by its name.
40
+ * @param spoAdminUrl SharePoint Online admin center URL (e.g. https://contoso-admin.sharepoint.com)
41
+ * @param name Name of the container type to search for
42
+ * @returns ID of the container type
43
+ */
44
+ async getContainerTypeIdByName(spoAdminUrl, name) {
45
+ const allContainerTypes = await this.getAllContainerTypes(spoAdminUrl);
46
+ const containerTypes = allContainerTypes.filter(ct => ct.DisplayName.toLowerCase() === name.toLowerCase());
47
+ if (containerTypes.length === 0) {
48
+ throw new Error(`The specified container type '${name}' does not exist.`);
49
+ }
50
+ if (containerTypes.length > 1) {
51
+ const containerTypeKeyValuePair = formatting.convertArrayToHashTable('ContainerTypeId', containerTypes);
52
+ const containerType = await cli.handleMultipleResultsFound(`Multiple container types with name '${name}' found.`, containerTypeKeyValuePair);
53
+ return containerType.ContainerTypeId;
54
+ }
55
+ return containerTypes[0].ContainerTypeId;
56
+ },
57
+ /**
58
+ * Get the ID of a container by its name.
59
+ * @param containerTypeId ID of the container type.
60
+ * @param name Name of the container to search for.
61
+ * @returns ID of the container.
62
+ */
63
+ async getContainerIdByName(containerTypeId, name) {
64
+ const containers = await odata.getAllItems(`${graphResource}/v1.0/storage/fileStorage/containers?$filter=containerTypeId eq ${containerTypeId}&$select=id,displayName`);
65
+ const matchingContainers = containers.filter(c => c.displayName.toLowerCase() === name.toLowerCase());
66
+ if (matchingContainers.length === 0) {
67
+ throw new Error(`The specified container '${name}' does not exist.`);
68
+ }
69
+ if (matchingContainers.length > 1) {
70
+ const containerKeyValuePair = formatting.convertArrayToHashTable('id', matchingContainers);
71
+ const container = await cli.handleMultipleResultsFound(`Multiple containers with name '${name}' found.`, containerKeyValuePair);
72
+ return container.id;
73
+ }
74
+ return matchingContainers[0].id;
75
+ }
76
+ };
77
+ //# sourceMappingURL=spe.js.map
package/dist/utils/spo.js CHANGED
@@ -53,24 +53,6 @@ export const spo = {
53
53
  };
54
54
  return context;
55
55
  },
56
- async getAllContainerTypes(spoAdminUrl, logger, verbose) {
57
- const formDigestInfo = await spo.ensureFormDigest(spoAdminUrl, logger, undefined, verbose);
58
- const requestOptions = {
59
- url: `${spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
60
- headers: {
61
- 'X-RequestDigest': formDigestInfo.FormDigestValue
62
- },
63
- data: `<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="46" ObjectPathId="45" /><Method Name="GetSPOContainerTypes" Id="47" ObjectPathId="45"><Parameters><Parameter Type="Enum">1</Parameter></Parameters></Method></Actions><ObjectPaths><Constructor Id="45" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`
64
- };
65
- const res = await request.post(requestOptions);
66
- const json = JSON.parse(res);
67
- const response = json[0];
68
- if (response.ErrorInfo) {
69
- throw new Error(response.ErrorInfo.ErrorMessage);
70
- }
71
- const containerTypes = json[json.length - 1];
72
- return containerTypes;
73
- },
74
56
  async waitUntilFinished({ operationId, siteUrl, logger, currentContext, debug, verbose }) {
75
57
  const resFormDigest = await spo.ensureFormDigest(siteUrl, logger, currentContext, debug);
76
58
  currentContext = resFormDigest;
package/dist/utils/spp.js CHANGED
@@ -1,11 +1,17 @@
1
1
  import request from '../request.js';
2
+ import { formatting } from './formatting.js';
2
3
  export const spp = {
3
4
  /**
4
5
  * Asserts whether the specified site is a content center
5
6
  * @param siteUrl The URL of the site to check
7
+ * @param logger Logger instance
8
+ * @param verbose Whether to log verbose messages
6
9
  * @throws error when site is not a content center.
7
10
  */
8
- async assertSiteIsContentCenter(siteUrl) {
11
+ async assertSiteIsContentCenter(siteUrl, logger, verbose) {
12
+ if (verbose) {
13
+ await logger.log(`Checking if '${siteUrl}' is a valid content center site...`);
14
+ }
9
15
  const requestOptions = {
10
16
  url: `${siteUrl}/_api/web?$select=WebTemplateConfiguration`,
11
17
  headers: {
@@ -17,6 +23,58 @@ export const spp = {
17
23
  if (response.WebTemplateConfiguration !== 'CONTENTCTR#0') {
18
24
  throw Error(`${siteUrl} is not a content site.`);
19
25
  }
26
+ },
27
+ /**
28
+ * Gets a SharePoint Premium model by title
29
+ * @param contentCenterUrl a content center site URL
30
+ * @param title model title
31
+ * @param logger Logger instance
32
+ * @param verbose Whether to log verbose messages
33
+ * @returns SharePoint Premium model
34
+ */
35
+ async getModelByTitle(contentCenterUrl, title, logger, verbose) {
36
+ if (verbose) {
37
+ await logger.log(`Retrieving model information...`);
38
+ }
39
+ let requestTitle = title.toLowerCase();
40
+ if (!requestTitle.endsWith('.classifier')) {
41
+ requestTitle += '.classifier';
42
+ }
43
+ const requestUrl = `${contentCenterUrl}/_api/machinelearning/models/getbytitle('${formatting.encodeQueryParameter(requestTitle)}')`;
44
+ const requestOptions = {
45
+ url: requestUrl,
46
+ headers: {
47
+ accept: 'application/json;odata=nometadata'
48
+ },
49
+ responseType: 'json'
50
+ };
51
+ const result = await request.get(requestOptions);
52
+ if (result['odata.null'] === true) {
53
+ throw Error(`Model '${title}' was not found.`);
54
+ }
55
+ return result;
56
+ },
57
+ /**
58
+ * Gets a SharePoint Premium model by unique id
59
+ * @param contentCenterUrl a content center site URL
60
+ * @param id model unique id
61
+ * @param logger Logger instance
62
+ * @param verbose Whether to log verbose messages
63
+ * @returns SharePoint Premium model
64
+ */
65
+ async getModelById(contentCenterUrl, id, logger, verbose) {
66
+ if (verbose) {
67
+ await logger.log(`Retrieving model information...`);
68
+ }
69
+ const requestUrl = `${contentCenterUrl}/_api/machinelearning/models/getbyuniqueid('${id}')`;
70
+ const requestOptions = {
71
+ url: requestUrl,
72
+ headers: {
73
+ accept: 'application/json;odata=nometadata'
74
+ },
75
+ responseType: 'json'
76
+ };
77
+ return await request.get(requestOptions);
20
78
  }
21
79
  };
22
80
  //# sourceMappingURL=spp.js.map
package/dist/utils/zod.js CHANGED
@@ -110,16 +110,41 @@ function parseDef(def, options, currentOption) {
110
110
  }
111
111
  } while (parsedDef);
112
112
  }
113
+ function optionToString(optionInfo) {
114
+ let s = '';
115
+ if (optionInfo.short) {
116
+ s += `-${optionInfo.short}, `;
117
+ }
118
+ s += `--${optionInfo.long}`;
119
+ if (optionInfo.type !== 'boolean') {
120
+ s += ' ';
121
+ s += optionInfo.required ? '<' : '[';
122
+ s += optionInfo.long;
123
+ s += optionInfo.required ? '>' : ']';
124
+ }
125
+ return s;
126
+ }
127
+ ;
113
128
  export const zod = {
114
129
  alias(alias, type) {
115
130
  type._def.alias = alias;
116
131
  return type;
117
132
  },
118
- schemaToOptions(schema) {
133
+ schemaToOptionInfo(schema) {
119
134
  const options = [];
120
135
  parseDef(schema._def, options);
121
136
  return options;
122
137
  },
138
+ schemaToOptions(schema) {
139
+ const optionsInfo = this.schemaToOptionInfo(schema);
140
+ const options = optionsInfo.map(option => {
141
+ return {
142
+ option: optionToString(option),
143
+ autocomplete: option.autocomplete
144
+ };
145
+ });
146
+ return options;
147
+ },
123
148
  coercedEnum: (e) => z.preprocess(val => {
124
149
  const target = String(val)?.toLowerCase();
125
150
  for (const k of Object.values(e)) {
@@ -17,7 +17,7 @@ m365 adaptivecard send [options]
17
17
  : URL where to send the card to.
18
18
 
19
19
  `-t, --title [title]`
20
- : Title of the card. Specify either `title` or `card` but not both.
20
+ : Title of the card. If you specify `title` and `card`, the `title` will be merged into the card.
21
21
 
22
22
  `-d, --description [description]`
23
23
  : Contents of the card.
@@ -0,0 +1,63 @@
1
+ import Global from '/docs/cmd/_global.mdx';
2
+ import Tabs from '@theme/Tabs';
3
+ import TabItem from '@theme/TabItem';
4
+
5
+ # cli app reconsent
6
+
7
+ Reconsent all permission scopes used in CLI for Microsoft 365
8
+
9
+ ## Usage
10
+
11
+ ```sh
12
+ m365 cli app reconsent [options]
13
+ ```
14
+
15
+ ## Options
16
+
17
+ <Global />
18
+
19
+ ## Remarks
20
+
21
+ This command will add all missing scopes used in CLI for Microsoft 365 to your current app registration. It will only add missing scopes and won't remove any scopes that are already present in the app registration.
22
+
23
+ ## Examples
24
+
25
+ Consent all permission scopes used in CLI for Microsoft 365 to the current app registration
26
+
27
+ ```sh
28
+ m365 cli app reconsent
29
+ ```
30
+
31
+ ## Response
32
+
33
+ <Tabs>
34
+ <TabItem value="JSON">
35
+
36
+ ```json
37
+ "To consent to the new scopes for your Microsoft Entra application registration, please navigate to the following URL: https://login.microsoftonline.com/f72203fd-b0a0-472d-85eb-079a117a80de/adminconsent?client_id=62b981af-59d3-4d25-8baf-6cc067a03102"
38
+ ```
39
+
40
+ </TabItem>
41
+ <TabItem value="Text">
42
+
43
+ ```text
44
+ To consent to the new scopes for your Microsoft Entra application registration, please navigate to the following URL: https://login.microsoftonline.com/f72203fd-b0a0-472d-85eb-079a117a80de/adminconsent?client_id=62b981af-59d3-4d25-8baf-6cc067a03102
45
+ ```
46
+
47
+ </TabItem>
48
+ <TabItem value="CSV">
49
+
50
+ ```csv
51
+ To consent to the new scopes for your Microsoft Entra application registration, please navigate to the following URL: https://login.microsoftonline.com/f72203fd-b0a0-472d-85eb-079a117a80de/adminconsent?client_id=62b981af-59d3-4d25-8baf-6cc067a03102
52
+ ```
53
+
54
+ </TabItem>
55
+ <TabItem value="Markdown">
56
+
57
+ ```md
58
+ To consent to the new scopes for your Microsoft Entra application registration, please navigate to the following URL: https://login.microsoftonline.com/f72203fd-b0a0-472d-85eb-079a117a80de/adminconsent?client_id=62b981af-59d3-4d25-8baf-6cc067a03102
59
+ ```
60
+
61
+ </TabItem>
62
+ </Tabs>
63
+