@pnp/cli-microsoft365 7.0.0-beta.99e75a7 → 7.0.0-beta.b2eab57

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 (31) hide show
  1. package/dist/cli/Cli.js +19 -2
  2. package/dist/m365/spo/commands/file/file-move.js +73 -97
  3. package/dist/m365/spo/commands/folder/folder-copy.js +89 -45
  4. package/dist/m365/spo/commands/folder/folder-move.js +89 -47
  5. package/dist/m365/spo/commands/propertybag/propertybag-base.js +63 -59
  6. package/dist/m365/spo/commands/propertybag/propertybag-remove.js +28 -31
  7. package/dist/m365/spo/commands/site/FlowsPolicy.js +7 -0
  8. package/dist/m365/spo/commands/site/site-ensure.js +3 -3
  9. package/dist/m365/spo/commands/site/site-hubsite-disconnect.js +22 -22
  10. package/dist/m365/spo/commands/site/site-list.js +29 -39
  11. package/dist/m365/spo/commands/site/site-set.js +58 -47
  12. package/dist/m365/spo/commands/theme/theme-remove.js +24 -24
  13. package/dist/m365/spo/commands/theme/theme-set.js +0 -1
  14. package/dist/m365/spo/commands/user/user-remove.js +27 -27
  15. package/dist/m365/spo/commands/web/web-reindex.js +35 -42
  16. package/dist/m365/spo/commands/web/web-remove.js +21 -21
  17. package/dist/m365/spo/commands/web/web-roleassignment-add.js +16 -31
  18. package/dist/m365/spo/commands/web/web-roleassignment-remove.js +33 -44
  19. package/dist/m365/spo/commands/web/web-roleinheritance-break.js +18 -18
  20. package/dist/m365/spo/commands/web/web-roleinheritance-reset.js +19 -19
  21. package/dist/m365/yammer/commands/message/message-like-set.js +27 -28
  22. package/dist/m365/yammer/commands/message/message-list.js +62 -81
  23. package/dist/m365/yammer/commands/message/message-remove.js +18 -18
  24. package/dist/m365/yammer/commands/yammer-search.js +53 -69
  25. package/dist/utils/spo.js +12 -53
  26. package/docs/docs/cmd/spo/file/file-move.mdx +36 -18
  27. package/docs/docs/cmd/spo/folder/folder-copy.mdx +39 -12
  28. package/docs/docs/cmd/spo/folder/folder-move.mdx +40 -13
  29. package/docs/docs/cmd/spo/site/site-ensure.mdx +1 -1
  30. package/npm-shrinkwrap.json +1 -1
  31. package/package.json +1 -1
package/dist/cli/Cli.js CHANGED
@@ -761,8 +761,9 @@ export class Cli {
761
761
  }
762
762
  static log(message, ...optionalParams) {
763
763
  const cli = Cli.getInstance();
764
+ const spinnerSpinning = cli.spinner.isSpinning;
764
765
  /* c8 ignore next 3 */
765
- if (cli.spinner.isSpinning) {
766
+ if (spinnerSpinning) {
766
767
  cli.spinner.stop();
767
768
  }
768
769
  if (message) {
@@ -771,15 +772,31 @@ export class Cli {
771
772
  else {
772
773
  console.log();
773
774
  }
775
+ // Restart the spinner if it was running before the log
776
+ /* c8 ignore next 3 */
777
+ if (spinnerSpinning) {
778
+ cli.spinner.start();
779
+ }
774
780
  }
775
781
  static async error(message, ...optionalParams) {
776
- const errorOutput = await Cli.getInstance().getSettingWithDefaultValue(settingsNames.errorOutput, 'stderr');
782
+ const cli = Cli.getInstance();
783
+ const spinnerSpinning = cli.spinner.isSpinning;
784
+ /* c8 ignore next 3 */
785
+ if (spinnerSpinning) {
786
+ cli.spinner.stop();
787
+ }
788
+ const errorOutput = cli.getSettingWithDefaultValue(settingsNames.errorOutput, 'stderr');
777
789
  if (errorOutput === 'stdout') {
778
790
  console.log(message, ...optionalParams);
779
791
  }
780
792
  else {
781
793
  console.error(message, ...optionalParams);
782
794
  }
795
+ // Restart the spinner if it was running before the log
796
+ /* c8 ignore next 3 */
797
+ if (spinnerSpinning) {
798
+ cli.spinner.start();
799
+ }
783
800
  }
784
801
  static async prompt(options, answers) {
785
802
  const inquirer = await import('inquirer');
@@ -3,17 +3,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
3
  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");
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _SpoFileMoveCommand_instances, _SpoFileMoveCommand_initTelemetry, _SpoFileMoveCommand_initOptions, _SpoFileMoveCommand_initValidators;
7
- import url from 'url';
8
- import { Cli } from '../../../../cli/Cli.js';
6
+ var _SpoFileMoveCommand_instances, _SpoFileMoveCommand_initTelemetry, _SpoFileMoveCommand_initOptions, _SpoFileMoveCommand_initValidators, _SpoFileMoveCommand_initOptionSets;
9
7
  import request from '../../../../request.js';
10
- import { formatting } from '../../../../utils/formatting.js';
11
- import { spo } from '../../../../utils/spo.js';
12
8
  import { urlUtil } from '../../../../utils/urlUtil.js';
13
9
  import { validation } from '../../../../utils/validation.js';
14
10
  import SpoCommand from '../../../base/SpoCommand.js';
15
11
  import commands from '../../commands.js';
16
- import removeCommand from './file-remove.js';
17
12
  class SpoFileMoveCommand extends SpoCommand {
18
13
  get name() {
19
14
  return commands.FILE_MOVE;
@@ -24,143 +19,124 @@ class SpoFileMoveCommand extends SpoCommand {
24
19
  constructor() {
25
20
  super();
26
21
  _SpoFileMoveCommand_instances.add(this);
22
+ this.nameConflictBehaviorOptions = ['fail', 'replace', 'rename'];
27
23
  __classPrivateFieldGet(this, _SpoFileMoveCommand_instances, "m", _SpoFileMoveCommand_initTelemetry).call(this);
28
24
  __classPrivateFieldGet(this, _SpoFileMoveCommand_instances, "m", _SpoFileMoveCommand_initOptions).call(this);
29
25
  __classPrivateFieldGet(this, _SpoFileMoveCommand_instances, "m", _SpoFileMoveCommand_initValidators).call(this);
26
+ __classPrivateFieldGet(this, _SpoFileMoveCommand_instances, "m", _SpoFileMoveCommand_initOptionSets).call(this);
30
27
  }
31
28
  getExcludedOptionsWithUrls() {
32
29
  return ['targetUrl', 'sourceUrl'];
33
30
  }
34
31
  async commandAction(logger, args) {
35
- const webUrl = args.options.webUrl;
36
- const parsedUrl = url.parse(webUrl);
37
- const tenantUrl = `${parsedUrl.protocol}//${parsedUrl.hostname}`;
38
32
  try {
39
- const serverRelativePath = urlUtil.getServerRelativePath(webUrl, args.options.sourceUrl);
40
- // Check if the source file exists.
41
- // Called on purpose, we explicitly check if user specified file
42
- // in the sourceUrl option.
43
- // The CreateCopyJobs endpoint accepts file, folder or batch from both.
44
- // A user might enter folder instead of file as source url by mistake
45
- // then there are edge cases when deleteIfAlreadyExists flag is set
46
- // the user can receive misleading error message.
47
- await this.fileExists(webUrl, serverRelativePath);
48
- if (args.options.deleteIfAlreadyExists) {
49
- // try delete target file, if deleteIfAlreadyExists flag is set
50
- const filename = args.options.sourceUrl.replace(/^.*[\\\/]/, '');
51
- await this.recycleFile(tenantUrl, args.options.targetUrl, filename, logger);
33
+ const sourcePath = await this.getSourcePath(logger, args.options);
34
+ if (this.verbose) {
35
+ await logger.logToStderr(`Moving file ${sourcePath} to ${args.options.targetUrl}...`);
36
+ }
37
+ const absoluteSourcePath = this.getAbsoluteUrl(args.options.webUrl, sourcePath);
38
+ let absoluteTargetPath = this.getAbsoluteUrl(args.options.webUrl, args.options.targetUrl) + '/';
39
+ if (args.options.newName) {
40
+ absoluteTargetPath += args.options.newName;
41
+ }
42
+ else {
43
+ // Keep the original file name
44
+ absoluteTargetPath += sourcePath.substring(sourcePath.lastIndexOf('/') + 1);
52
45
  }
53
- // all preconditions met, now create copy job
54
- const sourceAbsoluteUrl = urlUtil.urlCombine(tenantUrl, serverRelativePath);
55
- const allowSchemaMismatch = args.options.allowSchemaMismatch || false;
56
- const requestUrl = urlUtil.urlCombine(webUrl, '/_api/site/CreateCopyJobs');
57
46
  const requestOptions = {
58
- url: requestUrl,
47
+ url: `${args.options.webUrl}/_api/SP.MoveCopyUtil.MoveFileByPath`,
59
48
  headers: {
60
49
  accept: 'application/json;odata=nometadata'
61
50
  },
51
+ responseType: 'json',
62
52
  data: {
63
- exportObjectUris: [sourceAbsoluteUrl],
64
- destinationUri: urlUtil.urlCombine(tenantUrl, args.options.targetUrl),
53
+ srcPath: {
54
+ DecodedUrl: absoluteSourcePath
55
+ },
56
+ destPath: {
57
+ DecodedUrl: absoluteTargetPath
58
+ },
59
+ overwrite: args.options.nameConflictBehavior === 'replace',
65
60
  options: {
66
- "AllowSchemaMismatch": allowSchemaMismatch,
67
- "IgnoreVersionHistory": true,
68
- "IsMoveMode": true
61
+ KeepBoth: args.options.nameConflictBehavior === 'rename',
62
+ ShouldBypassSharedLocks: !!args.options.bypassSharedLock,
63
+ RetainEditorAndModifiedOnMove: !!args.options.retainEditorAndModified
69
64
  }
70
- },
71
- responseType: 'json'
65
+ }
72
66
  };
73
- const jobInfo = await request.post(requestOptions);
74
- const copyJobInfo = jobInfo.value[0];
75
- const progressPollInterval = 1800; // 30 * 60; //used previously implemented interval. The API does not provide guidance on what value should be used.
76
- await new Promise((resolve, reject) => {
77
- setTimeout(() => {
78
- spo.waitUntilCopyJobFinished({
79
- copyJobInfo,
80
- siteUrl: webUrl,
81
- pollingInterval: progressPollInterval,
82
- resolve,
83
- reject,
84
- logger,
85
- debug: this.debug,
86
- verbose: this.verbose
87
- });
88
- }, progressPollInterval);
89
- });
67
+ await request.post(requestOptions);
90
68
  }
91
69
  catch (err) {
92
70
  this.handleRejectedODataJsonPromise(err);
93
71
  }
94
72
  }
95
- /**
96
- * Checks if a file exists on the server relative url
97
- */
98
- fileExists(webUrl, sourceUrl) {
99
- const requestUrl = `${webUrl}/_api/web/GetFileByServerRelativePath(DecodedUrl='${formatting.encodeQueryParameter(sourceUrl)}')/`;
73
+ async getSourcePath(logger, options) {
74
+ if (options.sourceUrl) {
75
+ return urlUtil.getServerRelativePath(options.webUrl, options.sourceUrl);
76
+ }
77
+ if (this.verbose) {
78
+ await logger.logToStderr(`Retrieving server-relative path for file with ID '${options.sourceId}'...`);
79
+ }
100
80
  const requestOptions = {
101
- url: requestUrl,
102
- method: 'GET',
81
+ url: `${options.webUrl}/_api/Web/GetFileById('${options.sourceId}')?$select=ServerRelativePath`,
103
82
  headers: {
104
- 'accept': 'application/json;odata=nometadata'
83
+ accept: 'application/json;odata=nometadata'
105
84
  },
106
85
  responseType: 'json'
107
86
  };
108
- return request.get(requestOptions);
87
+ const file = await request.get(requestOptions);
88
+ return file.ServerRelativePath.DecodedUrl;
109
89
  }
110
- /**
111
- * Moves file in the site recycle bin
112
- */
113
- async recycleFile(tenantUrl, targetUrl, filename, logger) {
114
- const targetFolderAbsoluteUrl = urlUtil.urlCombine(tenantUrl, targetUrl);
115
- // since the target WebFullUrl is unknown we can use getRequestDigest
116
- // to get it from target folder absolute url.
117
- // Similar approach used here Microsoft.SharePoint.Client.Web.WebUrlFromFolderUrlDirect
118
- const contextResponse = await spo.getRequestDigest(targetFolderAbsoluteUrl);
119
- if (this.debug) {
120
- await logger.logToStderr(`contextResponse.WebFullUrl: ${contextResponse.WebFullUrl}`);
121
- }
122
- const targetFileServerRelativeUrl = `${urlUtil.getServerRelativePath(contextResponse.WebFullUrl, targetUrl)}/${filename}`;
123
- const removeOptions = {
124
- webUrl: contextResponse.WebFullUrl,
125
- url: targetFileServerRelativeUrl,
126
- recycle: true,
127
- force: true,
128
- debug: this.debug,
129
- verbose: this.verbose
130
- };
131
- try {
132
- await Cli.executeCommand(removeCommand, { options: { ...removeOptions, _: [] } });
133
- }
134
- catch (err) {
135
- if (err !== undefined && err.message !== undefined && err.message.includes('does not exist')) {
136
- }
137
- else {
138
- throw err;
139
- }
140
- }
90
+ getAbsoluteUrl(webUrl, url) {
91
+ return url.startsWith('https://') ? url : urlUtil.getAbsoluteUrl(webUrl, url);
141
92
  }
142
93
  }
143
94
  _SpoFileMoveCommand_instances = new WeakSet(), _SpoFileMoveCommand_initTelemetry = function _SpoFileMoveCommand_initTelemetry() {
144
95
  this.telemetry.push((args) => {
145
96
  Object.assign(this.telemetryProperties, {
146
- deleteIfAlreadyExists: args.options.deleteIfAlreadyExists || false,
147
- allowSchemaMismatch: args.options.allowSchemaMismatch || false
97
+ sourceUrl: typeof args.options.sourceUrl !== 'undefined',
98
+ sourceId: typeof args.options.sourceId !== 'undefined',
99
+ newName: typeof args.options.newName !== 'undefined',
100
+ nameConflictBehavior: typeof args.options.nameConflictBehavior !== 'undefined',
101
+ retainEditorAndModified: !!args.options.retainEditorAndModified,
102
+ bypassSharedLock: !!args.options.bypassSharedLock
148
103
  });
149
104
  });
150
105
  }, _SpoFileMoveCommand_initOptions = function _SpoFileMoveCommand_initOptions() {
151
106
  this.options.unshift({
152
107
  option: '-u, --webUrl <webUrl>'
153
108
  }, {
154
- option: '-s, --sourceUrl <sourceUrl>'
109
+ option: '-s, --sourceUrl [sourceUrl]'
110
+ }, {
111
+ option: '-i, --sourceId [sourceId]'
155
112
  }, {
156
113
  option: '-t, --targetUrl <targetUrl>'
157
114
  }, {
158
- option: '--deleteIfAlreadyExists'
115
+ option: '--newName [newName]'
116
+ }, {
117
+ option: '--nameConflictBehavior [nameConflictBehavior]',
118
+ autocomplete: this.nameConflictBehaviorOptions
159
119
  }, {
160
- option: '--allowSchemaMismatch'
120
+ option: '--retainEditorAndModified'
121
+ }, {
122
+ option: '--bypassSharedLock'
161
123
  });
162
124
  }, _SpoFileMoveCommand_initValidators = function _SpoFileMoveCommand_initValidators() {
163
- this.validators.push(async (args) => validation.isValidSharePointUrl(args.options.webUrl));
125
+ this.validators.push(async (args) => {
126
+ const isValidSharePointUrl = validation.isValidSharePointUrl(args.options.webUrl);
127
+ if (isValidSharePointUrl !== true) {
128
+ return isValidSharePointUrl;
129
+ }
130
+ if (args.options.sourceId && !validation.isValidGuid(args.options.sourceId)) {
131
+ return `'${args.options.sourceId}' is not a valid GUID for sourceId.`;
132
+ }
133
+ if (args.options.nameConflictBehavior && this.nameConflictBehaviorOptions.indexOf(args.options.nameConflictBehavior) === -1) {
134
+ return `'${args.options.nameConflictBehavior}' is not a valid value for nameConflictBehavior. Allowed values are: ${this.nameConflictBehaviorOptions.join(', ')}.`;
135
+ }
136
+ return true;
137
+ });
138
+ }, _SpoFileMoveCommand_initOptionSets = function _SpoFileMoveCommand_initOptionSets() {
139
+ this.optionSets.push({ options: ['sourceUrl', 'sourceId'] });
164
140
  };
165
141
  export default new SpoFileMoveCommand();
166
142
  //# sourceMappingURL=file-move.js.map
@@ -3,10 +3,8 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
3
  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");
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _SpoFolderCopyCommand_instances, _SpoFolderCopyCommand_initTelemetry, _SpoFolderCopyCommand_initOptions, _SpoFolderCopyCommand_initValidators;
7
- import url from 'url';
6
+ var _SpoFolderCopyCommand_instances, _SpoFolderCopyCommand_initTelemetry, _SpoFolderCopyCommand_initOptions, _SpoFolderCopyCommand_initValidators, _SpoFolderCopyCommand_initOptionSets;
8
7
  import request from '../../../../request.js';
9
- import { spo } from '../../../../utils/spo.js';
10
8
  import { urlUtil } from '../../../../utils/urlUtil.js';
11
9
  import { validation } from '../../../../utils/validation.js';
12
10
  import SpoCommand from '../../../base/SpoCommand.js';
@@ -21,77 +19,123 @@ class SpoFolderCopyCommand extends SpoCommand {
21
19
  constructor() {
22
20
  super();
23
21
  _SpoFolderCopyCommand_instances.add(this);
22
+ this.nameConflictBehaviorOptions = ['fail', 'rename'];
24
23
  __classPrivateFieldGet(this, _SpoFolderCopyCommand_instances, "m", _SpoFolderCopyCommand_initTelemetry).call(this);
25
24
  __classPrivateFieldGet(this, _SpoFolderCopyCommand_instances, "m", _SpoFolderCopyCommand_initOptions).call(this);
26
25
  __classPrivateFieldGet(this, _SpoFolderCopyCommand_instances, "m", _SpoFolderCopyCommand_initValidators).call(this);
26
+ __classPrivateFieldGet(this, _SpoFolderCopyCommand_instances, "m", _SpoFolderCopyCommand_initOptionSets).call(this);
27
27
  }
28
28
  getExcludedOptionsWithUrls() {
29
29
  return ['targetUrl', 'sourceUrl'];
30
30
  }
31
31
  async commandAction(logger, args) {
32
- const webUrl = args.options.webUrl;
33
- const parsedUrl = url.parse(webUrl);
34
- const tenantUrl = `${parsedUrl.protocol}//${parsedUrl.hostname}`;
35
- const serverRelativePath = urlUtil.getServerRelativePath(webUrl, args.options.sourceUrl);
36
- const sourceAbsoluteUrl = urlUtil.urlCombine(tenantUrl, serverRelativePath);
37
- const allowSchemaMismatch = args.options.allowSchemaMismatch || false;
38
- const requestOptions = {
39
- url: urlUtil.urlCombine(webUrl, '/_api/site/CreateCopyJobs'),
40
- headers: {
41
- 'accept': 'application/json;odata=nometadata'
42
- },
43
- data: {
44
- exportObjectUris: [sourceAbsoluteUrl],
45
- destinationUri: urlUtil.urlCombine(tenantUrl, args.options.targetUrl),
46
- options: {
47
- "AllowSchemaMismatch": allowSchemaMismatch,
48
- "IgnoreVersionHistory": true
49
- }
50
- },
51
- responseType: 'json'
52
- };
53
32
  try {
54
- const jobInfo = await request.post(requestOptions);
55
- const copyJobInfo = jobInfo.value[0];
56
- const progressPollInterval = 30 * 60; //used previously implemented interval. The API does not provide guidance on what value should be used.
57
- await new Promise((resolve, reject) => {
58
- setTimeout(() => {
59
- spo.waitUntilCopyJobFinished({
60
- copyJobInfo,
61
- siteUrl: webUrl,
62
- pollingInterval: progressPollInterval,
63
- resolve,
64
- reject,
65
- logger,
66
- debug: this.debug,
67
- verbose: this.verbose
68
- });
69
- }, progressPollInterval);
70
- });
33
+ const sourcePath = await this.getSourcePath(logger, args.options);
34
+ if (this.verbose) {
35
+ await logger.logToStderr(`Copying folder ${sourcePath} to ${args.options.targetUrl}...`);
36
+ }
37
+ const absoluteSourcePath = this.getAbsoluteUrl(args.options.webUrl, sourcePath);
38
+ let absoluteTargetPath = this.getAbsoluteUrl(args.options.webUrl, args.options.targetUrl) + '/';
39
+ if (args.options.newName) {
40
+ absoluteTargetPath += args.options.newName;
41
+ }
42
+ else {
43
+ // Keep the original folder name
44
+ absoluteTargetPath += sourcePath.substring(sourcePath.lastIndexOf('/') + 1);
45
+ }
46
+ const requestOptions = {
47
+ url: `${args.options.webUrl}/_api/SP.MoveCopyUtil.CopyFolderByPath`,
48
+ headers: {
49
+ accept: 'application/json;odata=nometadata'
50
+ },
51
+ responseType: 'json',
52
+ data: {
53
+ srcPath: {
54
+ DecodedUrl: absoluteSourcePath
55
+ },
56
+ destPath: {
57
+ DecodedUrl: absoluteTargetPath
58
+ },
59
+ options: {
60
+ KeepBoth: args.options.nameConflictBehavior === 'rename',
61
+ ShouldBypassSharedLocks: !!args.options.bypassSharedLock,
62
+ ResetAuthorAndCreatedOnCopy: !!args.options.resetAuthorAndCreated
63
+ }
64
+ }
65
+ };
66
+ await request.post(requestOptions);
71
67
  }
72
68
  catch (err) {
73
69
  this.handleRejectedODataJsonPromise(err);
74
70
  }
75
71
  }
72
+ async getSourcePath(logger, options) {
73
+ if (options.sourceUrl) {
74
+ return urlUtil.getServerRelativePath(options.webUrl, options.sourceUrl);
75
+ }
76
+ if (this.verbose) {
77
+ await logger.logToStderr(`Retrieving server-relative path for folder with ID '${options.sourceId}'...`);
78
+ }
79
+ const requestOptions = {
80
+ url: `${options.webUrl}/_api/Web/GetFolderById('${options.sourceId}')?$select=ServerRelativePath`,
81
+ headers: {
82
+ accept: 'application/json;odata=nometadata'
83
+ },
84
+ responseType: 'json'
85
+ };
86
+ const file = await request.get(requestOptions);
87
+ return file.ServerRelativePath.DecodedUrl;
88
+ }
89
+ getAbsoluteUrl(webUrl, url) {
90
+ return url.startsWith('https://') ? url : urlUtil.getAbsoluteUrl(webUrl, url);
91
+ }
76
92
  }
77
93
  _SpoFolderCopyCommand_instances = new WeakSet(), _SpoFolderCopyCommand_initTelemetry = function _SpoFolderCopyCommand_initTelemetry() {
78
94
  this.telemetry.push((args) => {
79
95
  Object.assign(this.telemetryProperties, {
80
- allowSchemaMismatch: args.options.allowSchemaMismatch || false
96
+ sourceUrl: typeof args.options.sourceUrl !== 'undefined',
97
+ sourceId: typeof args.options.sourceId !== 'undefined',
98
+ newName: typeof args.options.newName !== 'undefined',
99
+ nameConflictBehavior: typeof args.options.nameConflictBehavior !== 'undefined',
100
+ resetAuthorAndCreated: !!args.options.resetAuthorAndCreated,
101
+ bypassSharedLock: !!args.options.bypassSharedLock
81
102
  });
82
103
  });
83
104
  }, _SpoFolderCopyCommand_initOptions = function _SpoFolderCopyCommand_initOptions() {
84
105
  this.options.unshift({
85
106
  option: '-u, --webUrl <webUrl>'
86
107
  }, {
87
- option: '-s, --sourceUrl <sourceUrl>'
108
+ option: '-s, --sourceUrl [sourceUrl]'
109
+ }, {
110
+ option: '-i, --sourceId [sourceId]'
88
111
  }, {
89
112
  option: '-t, --targetUrl <targetUrl>'
90
113
  }, {
91
- option: '--allowSchemaMismatch'
114
+ option: '--newName [newName]'
115
+ }, {
116
+ option: '--nameConflictBehavior [nameConflictBehavior]',
117
+ autocomplete: this.nameConflictBehaviorOptions
118
+ }, {
119
+ option: '--resetAuthorAndCreated'
120
+ }, {
121
+ option: '--bypassSharedLock'
92
122
  });
93
123
  }, _SpoFolderCopyCommand_initValidators = function _SpoFolderCopyCommand_initValidators() {
94
- this.validators.push(async (args) => validation.isValidSharePointUrl(args.options.webUrl));
124
+ this.validators.push(async (args) => {
125
+ const isValidSharePointUrl = validation.isValidSharePointUrl(args.options.webUrl);
126
+ if (isValidSharePointUrl !== true) {
127
+ return isValidSharePointUrl;
128
+ }
129
+ if (args.options.sourceId && !validation.isValidGuid(args.options.sourceId)) {
130
+ return `'${args.options.sourceId}' is not a valid GUID for sourceId.`;
131
+ }
132
+ if (args.options.nameConflictBehavior && this.nameConflictBehaviorOptions.indexOf(args.options.nameConflictBehavior) === -1) {
133
+ return `'${args.options.nameConflictBehavior}' is not a valid value for nameConflictBehavior. Allowed values are: ${this.nameConflictBehaviorOptions.join(', ')}.`;
134
+ }
135
+ return true;
136
+ });
137
+ }, _SpoFolderCopyCommand_initOptionSets = function _SpoFolderCopyCommand_initOptionSets() {
138
+ this.optionSets.push({ options: ['sourceUrl', 'sourceId'] });
95
139
  };
96
140
  export default new SpoFolderCopyCommand();
97
141
  //# sourceMappingURL=folder-copy.js.map
@@ -3,10 +3,8 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
3
  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");
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _SpoFolderMoveCommand_instances, _SpoFolderMoveCommand_initTelemetry, _SpoFolderMoveCommand_initOptions, _SpoFolderMoveCommand_initValidators;
7
- import url from 'url';
6
+ var _SpoFolderMoveCommand_instances, _SpoFolderMoveCommand_initTelemetry, _SpoFolderMoveCommand_initOptions, _SpoFolderMoveCommand_initValidators, _SpoFolderMoveCommand_initOptionSets;
8
7
  import request from '../../../../request.js';
9
- import { spo } from '../../../../utils/spo.js';
10
8
  import { urlUtil } from '../../../../utils/urlUtil.js';
11
9
  import { validation } from '../../../../utils/validation.js';
12
10
  import SpoCommand from '../../../base/SpoCommand.js';
@@ -21,79 +19,123 @@ class SpoFolderMoveCommand extends SpoCommand {
21
19
  constructor() {
22
20
  super();
23
21
  _SpoFolderMoveCommand_instances.add(this);
22
+ this.nameConflictBehaviorOptions = ['fail', 'rename'];
24
23
  __classPrivateFieldGet(this, _SpoFolderMoveCommand_instances, "m", _SpoFolderMoveCommand_initTelemetry).call(this);
25
24
  __classPrivateFieldGet(this, _SpoFolderMoveCommand_instances, "m", _SpoFolderMoveCommand_initOptions).call(this);
26
25
  __classPrivateFieldGet(this, _SpoFolderMoveCommand_instances, "m", _SpoFolderMoveCommand_initValidators).call(this);
26
+ __classPrivateFieldGet(this, _SpoFolderMoveCommand_instances, "m", _SpoFolderMoveCommand_initOptionSets).call(this);
27
27
  }
28
28
  getExcludedOptionsWithUrls() {
29
29
  return ['targetUrl', 'sourceUrl'];
30
30
  }
31
31
  async commandAction(logger, args) {
32
- const webUrl = args.options.webUrl;
33
- const parsedUrl = url.parse(webUrl);
34
- const tenantUrl = `${parsedUrl.protocol}//${parsedUrl.hostname}`;
35
- const sourceRelUrl = urlUtil.getServerRelativePath(webUrl, args.options.sourceUrl);
36
- const sourceAbsoluteUrl = urlUtil.urlCombine(tenantUrl, sourceRelUrl);
37
- const allowSchemaMismatch = args.options.allowSchemaMismatch || false;
38
- const requestUrl = urlUtil.urlCombine(webUrl, '/_api/site/CreateCopyJobs');
39
- const requestOptions = {
40
- url: requestUrl,
41
- headers: {
42
- 'accept': 'application/json;odata=nometadata'
43
- },
44
- data: {
45
- exportObjectUris: [sourceAbsoluteUrl],
46
- destinationUri: urlUtil.urlCombine(tenantUrl, args.options.targetUrl),
47
- options: {
48
- "AllowSchemaMismatch": allowSchemaMismatch,
49
- "IgnoreVersionHistory": true,
50
- "IsMoveMode": true
51
- }
52
- },
53
- responseType: 'json'
54
- };
55
32
  try {
56
- const jobInfo = await request.post(requestOptions);
57
- const copyJobInfo = jobInfo.value[0];
58
- const progressPollInterval = 30 * 60; //used previously implemented interval. The API does not provide guidance on what value should be used.
59
- await new Promise((resolve, reject) => {
60
- setTimeout(() => {
61
- spo.waitUntilCopyJobFinished({
62
- copyJobInfo,
63
- siteUrl: webUrl,
64
- pollingInterval: progressPollInterval,
65
- resolve,
66
- reject,
67
- logger,
68
- debug: this.debug,
69
- verbose: this.verbose
70
- });
71
- }, progressPollInterval);
72
- });
33
+ const sourcePath = await this.getSourcePath(logger, args.options);
34
+ if (this.verbose) {
35
+ await logger.logToStderr(`Moving folder '${sourcePath}' to '${args.options.targetUrl}'...`);
36
+ }
37
+ const absoluteSourcePath = this.getAbsoluteUrl(args.options.webUrl, sourcePath);
38
+ let absoluteTargetPath = this.getAbsoluteUrl(args.options.webUrl, args.options.targetUrl) + '/';
39
+ if (args.options.newName) {
40
+ absoluteTargetPath += args.options.newName;
41
+ }
42
+ else {
43
+ // Keep the original file name
44
+ absoluteTargetPath += sourcePath.substring(sourcePath.lastIndexOf('/') + 1);
45
+ }
46
+ const requestOptions = {
47
+ url: `${args.options.webUrl}/_api/SP.MoveCopyUtil.MoveFolderByPath`,
48
+ headers: {
49
+ accept: 'application/json;odata=nometadata'
50
+ },
51
+ responseType: 'json',
52
+ data: {
53
+ srcPath: {
54
+ DecodedUrl: absoluteSourcePath
55
+ },
56
+ destPath: {
57
+ DecodedUrl: absoluteTargetPath
58
+ },
59
+ options: {
60
+ KeepBoth: args.options.nameConflictBehavior === 'rename',
61
+ ShouldBypassSharedLocks: !!args.options.bypassSharedLock,
62
+ RetainEditorAndModifiedOnMove: !!args.options.retainEditorAndModified
63
+ }
64
+ }
65
+ };
66
+ await request.post(requestOptions);
73
67
  }
74
68
  catch (err) {
75
69
  this.handleRejectedODataJsonPromise(err);
76
70
  }
77
71
  }
72
+ async getSourcePath(logger, options) {
73
+ if (options.sourceUrl) {
74
+ return urlUtil.getServerRelativePath(options.webUrl, options.sourceUrl);
75
+ }
76
+ if (this.verbose) {
77
+ await logger.logToStderr(`Retrieving server-relative path for folder with ID '${options.sourceId}'...`);
78
+ }
79
+ const requestOptions = {
80
+ url: `${options.webUrl}/_api/Web/GetFolderById('${options.sourceId}')?$select=ServerRelativePath`,
81
+ headers: {
82
+ accept: 'application/json;odata=nometadata'
83
+ },
84
+ responseType: 'json'
85
+ };
86
+ const file = await request.get(requestOptions);
87
+ return file.ServerRelativePath.DecodedUrl;
88
+ }
89
+ getAbsoluteUrl(webUrl, url) {
90
+ return url.startsWith('https://') ? url : urlUtil.getAbsoluteUrl(webUrl, url);
91
+ }
78
92
  }
79
93
  _SpoFolderMoveCommand_instances = new WeakSet(), _SpoFolderMoveCommand_initTelemetry = function _SpoFolderMoveCommand_initTelemetry() {
80
94
  this.telemetry.push((args) => {
81
95
  Object.assign(this.telemetryProperties, {
82
- allowSchemaMismatch: args.options.allowSchemaMismatch || false
96
+ sourceUrl: typeof args.options.sourceUrl !== 'undefined',
97
+ sourceId: typeof args.options.sourceId !== 'undefined',
98
+ newName: typeof args.options.newName !== 'undefined',
99
+ nameConflictBehavior: typeof args.options.nameConflictBehavior !== 'undefined',
100
+ retainEditorAndModified: !!args.options.retainEditorAndModified,
101
+ bypassSharedLock: !!args.options.bypassSharedLock
83
102
  });
84
103
  });
85
104
  }, _SpoFolderMoveCommand_initOptions = function _SpoFolderMoveCommand_initOptions() {
86
105
  this.options.unshift({
87
106
  option: '-u, --webUrl <webUrl>'
88
107
  }, {
89
- option: '-s, --sourceUrl <sourceUrl>'
108
+ option: '-s, --sourceUrl [sourceUrl]'
109
+ }, {
110
+ option: '-i, --sourceId [sourceId]'
90
111
  }, {
91
112
  option: '-t, --targetUrl <targetUrl>'
92
113
  }, {
93
- option: '--allowSchemaMismatch'
114
+ option: '--newName [newName]'
115
+ }, {
116
+ option: '--nameConflictBehavior [nameConflictBehavior]',
117
+ autocomplete: this.nameConflictBehaviorOptions
118
+ }, {
119
+ option: '--retainEditorAndModified'
120
+ }, {
121
+ option: '--bypassSharedLock'
94
122
  });
95
123
  }, _SpoFolderMoveCommand_initValidators = function _SpoFolderMoveCommand_initValidators() {
96
- this.validators.push(async (args) => validation.isValidSharePointUrl(args.options.webUrl));
124
+ this.validators.push(async (args) => {
125
+ const isValidSharePointUrl = validation.isValidSharePointUrl(args.options.webUrl);
126
+ if (isValidSharePointUrl !== true) {
127
+ return isValidSharePointUrl;
128
+ }
129
+ if (args.options.sourceId && !validation.isValidGuid(args.options.sourceId)) {
130
+ return `'${args.options.sourceId}' is not a valid GUID for sourceId.`;
131
+ }
132
+ if (args.options.nameConflictBehavior && this.nameConflictBehaviorOptions.indexOf(args.options.nameConflictBehavior) === -1) {
133
+ return `'${args.options.nameConflictBehavior}' is not a valid value for nameConflictBehavior. Allowed values are: ${this.nameConflictBehaviorOptions.join(', ')}.`;
134
+ }
135
+ return true;
136
+ });
137
+ }, _SpoFolderMoveCommand_initOptionSets = function _SpoFolderMoveCommand_initOptionSets() {
138
+ this.optionSets.push({ options: ['sourceUrl', 'sourceId'] });
97
139
  };
98
140
  export default new SpoFolderMoveCommand();
99
141
  //# sourceMappingURL=folder-move.js.map