diff --git a/src/m365/spo/commands/file/file-roleassignment-add.spec.ts b/src/m365/spo/commands/file/file-roleassignment-add.spec.ts index cfcd9079cc6..2b2e5a48923 100644 --- a/src/m365/spo/commands/file/file-roleassignment-add.spec.ts +++ b/src/m365/spo/commands/file/file-roleassignment-add.spec.ts @@ -11,12 +11,9 @@ import { pid } from '../../../../utils/pid.js'; import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; -import spoGroupGetCommand from '../group/group-get.js'; -import spoRoleDefinitionListCommand from '../roledefinition/roledefinition-list.js'; -import spoUserGetCommand from '../user/user-get.js'; -import spoFileGetCommand from './file-get.js'; import command from './file-roleassignment-add.js'; import { settingsNames } from '../../../../settingsNames.js'; +import { spo } from '../../../../utils/spo.js'; describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { const webUrl = 'https://contoso.sharepoint.com/sites/project-x'; @@ -25,6 +22,117 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; + const roleDefinitionResponse = { + BasePermissions: { + High: 2147483647, + Low: 4294967295 + }, + Description: 'Has full control.', + Hidden: false, + Id: 1073741827, + Name: 'Full Control', + Order: 1, + RoleTypeKind: 5, + BasePermissionsValue: [ + 'ViewListItems', + 'AddListItems', + 'EditListItems', + 'DeleteListItems', + 'ApproveItems', + 'OpenItems', + 'ViewVersions', + 'DeleteVersions', + 'CancelCheckout', + 'ManagePersonalViews', + 'ManageLists', + 'ViewFormPages', + 'AnonymousSearchAccessList', + 'Open', + 'ViewPages', + 'AddAndCustomizePages', + 'ApplyThemeAndBorder', + 'ApplyStyleSheets', + 'ViewUsageData', + 'CreateSSCSite', + 'ManageSubwebs', + 'CreateGroups', + 'ManagePermissions', + 'BrowseDirectories', + 'BrowseUserInfo', + 'AddDelPrivateWebParts', + 'UpdatePersonalWebParts', + 'ManageWeb', + 'AnonymousSearchAccessWebLists', + 'UseClientIntegration', + 'UseRemoteAPIs', + 'ManageAlerts', + 'CreateAlerts', + 'EditMyUserInfo', + 'EnumeratePermissions' + ], + RoleTypeKindValue: 'Administrator' + }; + + const fileResponse = { + CheckInComment: '', + CheckOutType: 2, + ContentTag: '{F09C4EFE-B8C0-4E89-A166-03418661B89B},9,12', + CustomizedPageStatus: 0, + ETag: '\'{F09C4EFE-B8C0-4E89-A166-03418661B89B},9\'', + Exists: true, + IrmEnabled: false, + Length: '331673', + Level: 1, + LinkingUri: 'https://contoso.sharepoint.com/sites/project-x/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866', + LinkingUrl: 'https://contoso.sharepoint.com/sites/project-x/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866', + MajorVersion: 3, + MinorVersion: 0, + Name: 'Test1.docx', + ServerRelativeUrl: '/sites/project-x/documents/Test1.docx', + TimeCreated: '2018-02-05T08:42:36Z', + TimeLastModified: '2018-02-05T08:44:03Z', + Title: '', + UIVersion: 1536, + UIVersionLabel: '3.0', + UniqueId: 'b2307a39-e878-458b-bc90-03bc578531d6', + ListItemAllFields: { + Id: 4, + ID: 4 + } + }; + + const userResponse = { + Id: 11, + IsHiddenInUI: false, + LoginName: 'i:0#.f|membership|someaccount@tenant.onmicrosoft.com', + Title: 'Some Account', + PrincipalType: 1, + Email: 'someaccount@tenant.onmicrosoft.com', + Expiration: '', + IsEmailAuthenticationGuestUser: false, + IsShareByEmailGuestUser: false, + IsSiteAdmin: true, + UserId: { + NameId: '1003200097d06dd6', + NameIdIssuer: 'urn:federation:microsoftonline' + }, + UserPrincipalName: 'someaccount@tenant.onmicrosoft.com' + }; + + const groupResponse = { + Id: 5, + IsHiddenInUI: false, + LoginName: "Group A", + Title: "Group A", + PrincipalType: 8, + AllowMembersEditMembership: false, + AllowRequestToJoinLeave: false, + AutoAcceptRequestToJoinLeave: false, + Description: "", + OnlyAllowMembersViewMembership: true, + OwnerTitle: "Some Account", + RequestToJoinLeaveEmailSetting: null + }; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -52,8 +160,11 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { afterEach(() => { sinonUtil.restore([ - cli.executeCommandWithOutput, request.post, + spo.getRoleDefinitionByName, + spo.getGroupByName, + spo.getUserByEmail, + spo.getFileById, cli.getSettingWithDefaultValue ]); }); @@ -142,15 +253,7 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { throw 'Invalid request'; }); - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoRoleDefinitionListCommand) { - return { - stdout: '[{"BasePermissions": {"High": "2147483647","Low": "4294967295"},"Description": "Has full control.","Hidden": false,"Id": 1073741827,"Name": "Full Control","Order": 1,"RoleTypeKind": 5}]' - }; - } - - throw new CommandError('Unknown case'); - }); + sinon.stub(spo, 'getRoleDefinitionByName').resolves(roleDefinitionResponse); await command.action(logger, { options: { @@ -171,20 +274,8 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { throw 'Invalid request'; }); - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoFileGetCommand) { - return ({ - stdout: '{"LinkingUri": "https://contoso.sharepoint.com/sites/project-x/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866","Name": "Test1.docx","ServerRelativeUrl": "/sites/project-x/documents/Test1.docx","UniqueId": "b2307a39-e878-458b-bc90-03bc578531d6"}' - }); - } - if (command === spoRoleDefinitionListCommand) { - return { - stdout: '[{"BasePermissions": {"High": "2147483647","Low": "4294967295"},"Description": "Has full control.","Hidden": false,"Id": 1073741827,"Name": "Full Control","Order": 1,"RoleTypeKind": 5}]' - }; - } - - throw 'Unknown case'; - }); + sinon.stub(spo, 'getFileById').resolves(fileResponse); + sinon.stub(spo, 'getRoleDefinitionByName').resolves(roleDefinitionResponse); await command.action(logger, { options: { @@ -205,15 +296,7 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { throw 'Invalid request'; }); - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoUserGetCommand) { - return { - stdout: '{"Id": 11,"IsHiddenInUI": false,"LoginName": "i:0#.f|membership|someaccount@tenant.onmicrosoft.com","Title": "Some Account","PrincipalType": 1,"Email": "someaccount@tenant.onmicrosoft.com","Expiration": "","IsEmailAuthenticationGuestUser": false,"IsShareByEmailGuestUser": false,"IsSiteAdmin": true,"UserId": {"NameId": "1003200097d06dd6","NameIdIssuer": "urn:federation:microsoftonline"},"UserPrincipalName": "someaccount@tenant.onmicrosoft.com"}' - }; - } - - throw 'Unknown case'; - }); + sinon.stub(spo, 'getUserByEmail').resolves(userResponse); await command.action(logger, { options: { @@ -227,13 +310,7 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { it('correctly handles error when upn does not exist', async () => { const error = 'no user found'; - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoUserGetCommand) { - throw error; - } - - throw 'Unknown case'; - }); + sinon.stub(spo, 'getUserByEmail').rejects(new Error(error)); await assert.rejects(command.action(logger, { options: { @@ -254,15 +331,7 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { throw 'Invalid request'; }); - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoGroupGetCommand) { - return { - stdout: '{"Id": 5,"IsHiddenInUI": false,"LoginName": "Group A","Title": "Group A","PrincipalType": 8,"AllowMembersEditMembership": false,"AllowRequestToJoinLeave": false,"AutoAcceptRequestToJoinLeave": false,"Description": "","OnlyAllowMembersViewMembership": true,"OwnerTitle": "Some Account","RequestToJoinLeaveEmailSetting": null}' - }; - } - - throw 'Unknown case'; - }); + sinon.stub(spo, 'getGroupByName').resolves(groupResponse); await command.action(logger, { options: { @@ -276,13 +345,7 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { it('correctly handles error when role definition does not exist', async () => { const error = 'no role definition found'; - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command) => { - if (command === spoRoleDefinitionListCommand) { - throw error; - } - - throw 'Unknown case'; - }); + sinon.stub(spo, 'getRoleDefinitionByName').rejects(new Error(error)); await assert.rejects(command.action(logger, { options: { @@ -296,13 +359,7 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => { it('correctly handles error when group does not exist', async () => { const error = 'no group found'; - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoGroupGetCommand) { - throw error; - } - - throw 'Unknown case'; - }); + sinon.stub(spo, 'getGroupByName').rejects(new Error(error)); await assert.rejects(command.action(logger, { options: { diff --git a/src/m365/spo/commands/file/file-roleassignment-add.ts b/src/m365/spo/commands/file/file-roleassignment-add.ts index 3fb5a771e4e..13a92026fcc 100644 --- a/src/m365/spo/commands/file/file-roleassignment-add.ts +++ b/src/m365/spo/commands/file/file-roleassignment-add.ts @@ -1,18 +1,14 @@ -import { cli, CommandOutput } from '../../../../cli/cli.js'; import { Logger } from '../../../../cli/Logger.js'; -import Command from '../../../../Command.js'; import GlobalOptions from '../../../../GlobalOptions.js'; import request, { CliRequestOptions } from '../../../../request.js'; import { formatting } from '../../../../utils/formatting.js'; +import { spo } from '../../../../utils/spo.js'; import { urlUtil } from '../../../../utils/urlUtil.js'; import { validation } from '../../../../utils/validation.js'; import SpoCommand from '../../../base/SpoCommand.js'; import commands from '../../commands.js'; -import spoGroupGetCommand, { Options as SpoGroupGetCommandOptions } from '../group/group-get.js'; -import spoRoleDefinitionListCommand, { Options as SpoRoleDefinitionListCommandOptions } from '../roledefinition/roledefinition-list.js'; import { RoleDefinition } from '../roledefinition/RoleDefinition.js'; -import spoUserGetCommand, { Options as SpoUserGetCommandOptions } from '../user/user-get.js'; -import spoFileGetCommand, { Options as SpoFileGetCommandOptions } from './file-get.js'; +import { FileProperties } from './FileProperties.js'; interface CommandArgs { options: Options; @@ -134,14 +130,14 @@ class SpoFileRoleAssignmentAddCommand extends SpoCommand { } try { - const fileUrl: string = await this.getFileURL(args); - const roleDefinitionId = await this.getRoleDefinitionId(args.options); + const fileUrl: string = await this.getFileURL(args, logger); + const roleDefinitionId = await this.getRoleDefinitionId(args.options, logger); if (args.options.upn) { - const upnPrincipalId = await this.getUserPrincipalId(args.options); + const upnPrincipalId = await this.getUserPrincipalId(args.options, logger); await this.addRoleAssignment(fileUrl, args.options.webUrl, upnPrincipalId, roleDefinitionId); } else if (args.options.groupName) { - const groupPrincipalId = await this.getGroupPrincipalId(args.options); + const groupPrincipalId = await this.getGroupPrincipalId(args.options, logger); await this.addRoleAssignment(fileUrl, args.options.webUrl, groupPrincipalId, roleDefinitionId); } else { @@ -166,69 +162,32 @@ class SpoFileRoleAssignmentAddCommand extends SpoCommand { return request.post(requestOptions); } - private async getRoleDefinitionId(options: Options): Promise { + private async getRoleDefinitionId(options: Options, logger: Logger): Promise { if (!options.roleDefinitionName) { return options.roleDefinitionId!; } - const roleDefinitionListCommandOptions: SpoRoleDefinitionListCommandOptions = { - webUrl: options.webUrl, - output: 'json', - debug: this.debug, - verbose: this.verbose - }; - - const output: CommandOutput = await cli.executeCommandWithOutput(spoRoleDefinitionListCommand as Command, { options: { ...roleDefinitionListCommandOptions, _: [] } }); - const getRoleDefinitionListOutput = JSON.parse(output.stdout); - const roleDefinitionId: number = getRoleDefinitionListOutput.find((role: RoleDefinition) => role.Name === options.roleDefinitionName).Id; - return roleDefinitionId; + const roleDefinition: RoleDefinition = await spo.getRoleDefinitionByName(options.webUrl, options.roleDefinitionName, logger, this.verbose); + return roleDefinition.Id; } - private async getGroupPrincipalId(options: Options): Promise { - const groupGetCommandOptions: SpoGroupGetCommandOptions = { - webUrl: options.webUrl, - name: options.groupName, - output: 'json', - debug: this.debug, - verbose: this.verbose - }; - - const output: CommandOutput = await cli.executeCommandWithOutput(spoGroupGetCommand as Command, { options: { ...groupGetCommandOptions, _: [] } }); - const getGroupOutput = JSON.parse(output.stdout); - return getGroupOutput.Id; + private async getGroupPrincipalId(options: Options, logger: Logger): Promise { + const group = await spo.getGroupByName(options.webUrl, options.groupName!, logger, this.verbose); + return group.Id; } - private async getUserPrincipalId(options: Options): Promise { - const userGetCommandOptions: SpoUserGetCommandOptions = { - webUrl: options.webUrl, - email: options.upn, - id: undefined, - output: 'json', - debug: this.debug, - verbose: this.verbose - }; - - const output: CommandOutput = await cli.executeCommandWithOutput(spoUserGetCommand as Command, { options: { ...userGetCommandOptions, _: [] } }); - const getUserOutput = JSON.parse(output.stdout); - return getUserOutput.Id; + private async getUserPrincipalId(options: Options, logger: Logger): Promise { + const user = await spo.getUserByEmail(options.webUrl, options.upn!, logger, this.verbose); + return user.Id; } - private async getFileURL(args: CommandArgs): Promise { + private async getFileURL(args: CommandArgs, logger: Logger): Promise { if (args.options.fileUrl) { return urlUtil.getServerRelativePath(args.options.webUrl, args.options.fileUrl); } - const options: SpoFileGetCommandOptions = { - webUrl: args.options.webUrl, - id: args.options.fileId, - output: 'json', - debug: this.debug, - verbose: this.verbose - }; - - const output = await cli.executeCommandWithOutput(spoFileGetCommand as Command, { options: { ...options, _: [] } }); - const getFileOutput = JSON.parse(output.stdout); - return getFileOutput.ServerRelativeUrl; + const file: FileProperties = await spo.getFileById(args.options.webUrl, args.options.fileId!, logger, this.verbose); + return file.ServerRelativeUrl; } } diff --git a/src/m365/spo/commands/file/file-roleassignment-remove.spec.ts b/src/m365/spo/commands/file/file-roleassignment-remove.spec.ts index e9c5eb339ca..c191ad275b1 100644 --- a/src/m365/spo/commands/file/file-roleassignment-remove.spec.ts +++ b/src/m365/spo/commands/file/file-roleassignment-remove.spec.ts @@ -13,10 +13,8 @@ import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import { urlUtil } from '../../../../utils/urlUtil.js'; import commands from '../../commands.js'; -import spoGroupGetCommand from '../group/group-get.js'; -import spoUserGetCommand from '../user/user-get.js'; -import spoFileGetCommand from './file-get.js'; import command from './file-roleassignment-remove.js'; +import { spo } from '../../../../utils/spo.js'; describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { const webUrl = 'https://contoso.sharepoint.com/sites/contoso-sales'; @@ -25,6 +23,66 @@ describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { const principalId = 2; const upn = 'user1@contoso.onmicrosoft.com'; const groupName = 'saleGroup'; + const fileResponse = { + CheckInComment: '', + CheckOutType: 2, + ContentTag: '{F09C4EFE-B8C0-4E89-A166-03418661B89B},9,12', + CustomizedPageStatus: 0, + ETag: '\"{F09C4EFE-B8C0-4E89-A166-03418661B89B},9\"', + Exists: true, + IrmEnabled: false, + Length: '331673', + Level: 1, + LinkingUri: 'https://contoso.sharepoint.com/sites/contoso-sales/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866', + LinkingUrl: 'https://contoso.sharepoint.com/sites/contoso-sales/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866', + ListItemAllFields: { + Id: 1, + ID: 1 + }, + MajorVersion: 3, + MinorVersion: 0, + Name: 'Test1.docx', + ServerRelativeUrl: '/sites/contoso-sales/documents/Test1.docx', + TimeCreated: '2018-02-05T08:42:36Z', + TimeLastModified: '2018-02-05T08:44:03Z', + Title: '', + UIVersion: 1536, + UIVersionLabel: '3.0', + UniqueId: 'b2307a39-e878-458b-bc90-03bc578531d6' + }; + + const userResponse = { + Id: 2, + IsHiddenInUI: false, + LoginName: 'i:0#.f|membership|user1@contoso.onmicrosoft.com', + Title: 'User1', + PrincipalType: 1, + Email: 'user1@contoso.onmicrosoft.com', + Expiration: '', + IsEmailAuthenticationGuestUser: false, + IsShareByEmailGuestUser: false, + IsSiteAdmin: false, + UserId: { + NameId: '10032002473c5ae3', + NameIdIssuer: 'urn:federation:microsoftonline' + }, + UserPrincipalName: 'user1@contoso.onmicrosoft.com' + }; + + const groupResponse = { + Id: 2, + IsHiddenInUI: false, + LoginName: "saleGroup", + Title: "saleGroup", + PrincipalType: 8, + AllowMembersEditMembership: false, + AllowRequestToJoinLeave: false, + AutoAcceptRequestToJoinLeave: false, + Description: "", + OnlyAllowMembersViewMembership: true, + OwnerTitle: "John Doe", + RequestToJoinLeaveEmailSetting: null + }; let log: any[]; let logger: Logger; @@ -64,7 +122,9 @@ describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { afterEach(() => { sinonUtil.restore([ cli.promptForConfirmation, - cli.executeCommandWithOutput, + spo.getUserByEmail, + spo.getGroupByName, + spo.getFileById, request.post ]); }); @@ -153,21 +213,8 @@ describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { }); it('remove role assignment from the file by Id and upn', async () => { - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoFileGetCommand) { - return { - stdout: `{"LinkingUri": "https://contoso.sharepoint.com/sites/contoso-sales/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866","Name": "Test1.docx","ServerRelativeUrl": "/sites/contoso-sales/documents/Test1.docx","UniqueId": "b2307a39-e878-458b-bc90-03bc578531d6"}` - }; - } - - if (command === spoUserGetCommand) { - return { - stdout: '{"Id": 2,"IsHiddenInUI": false,"LoginName": "i:0#.f|membership|user1@contoso.onmicrosoft.com","Title": "User1","PrincipalType": 1,"Email": "user1@contoso.onmicrosoft.com","Expiration": "","IsEmailAuthenticationGuestUser": false,"IsShareByEmailGuestUser": false,"IsSiteAdmin": true,"UserId": {"NameId": "1003200097d06dd6","NameIdIssuer": "urn:federation:microsoftonline"},"UserPrincipalName": "user1@contoso.onmicrosoft.com"}' - }; - } - - throw new CommandError('Unknown case'); - }); + sinon.stub(spo, 'getFileById').resolves(fileResponse); + sinon.stub(spo, 'getUserByEmail').resolves(userResponse); sinon.stub(request, 'post').callsFake(async (opts) => { const serverRelativeUrl: string = urlUtil.getServerRelativePath(webUrl, fileUrl); @@ -190,21 +237,8 @@ describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { }); it('remove role assignment from the file by Id and group name', async () => { - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoFileGetCommand) { - return { - stdout: `{"LinkingUri": "https://contoso.sharepoint.com/sites/contoso-sales/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866","Name": "Test1.docx","ServerRelativeUrl": "/sites/contoso-sales/documents/Test1.docx","UniqueId": "b2307a39-e878-458b-bc90-03bc578531d6"}` - }; - } - - if (command === spoGroupGetCommand) { - return { - stdout: '{"Id": 2,"IsHiddenInUI": false,"LoginName": "saleGroup","Title": "saleGroup","PrincipalType": 8,"AllowMembersEditMembership": false,"AllowRequestToJoinLeave": false,"AutoAcceptRequestToJoinLeave": false,"Description": "","OnlyAllowMembersViewMembership": true,"OwnerTitle": "Some Account","RequestToJoinLeaveEmailSetting": null}' - }; - } - - throw new CommandError('Unknown case'); - }); + sinon.stub(spo, 'getFileById').resolves(fileResponse); + sinon.stub(spo, 'getGroupByName').resolves(groupResponse); sinon.stub(request, 'post').callsFake(async (opts) => { const serverRelativeUrl: string = urlUtil.getServerRelativePath(webUrl, fileUrl); diff --git a/src/m365/spo/commands/file/file-roleassignment-remove.ts b/src/m365/spo/commands/file/file-roleassignment-remove.ts index 8538a6b694c..33704bfcb84 100644 --- a/src/m365/spo/commands/file/file-roleassignment-remove.ts +++ b/src/m365/spo/commands/file/file-roleassignment-remove.ts @@ -1,16 +1,14 @@ import { cli } from '../../../../cli/cli.js'; import { Logger } from '../../../../cli/Logger.js'; -import Command from '../../../../Command.js'; import GlobalOptions from '../../../../GlobalOptions.js'; import request, { CliRequestOptions } from '../../../../request.js'; import { formatting } from '../../../../utils/formatting.js'; +import { spo } from '../../../../utils/spo.js'; import { urlUtil } from '../../../../utils/urlUtil.js'; import { validation } from '../../../../utils/validation.js'; import SpoCommand from '../../../base/SpoCommand.js'; import commands from '../../commands.js'; -import spoGroupGetCommand, { Options as SpoGroupGetCommandOptions } from '../group/group-get.js'; -import spoUserGetCommand, { Options as SpoUserGetCommandOptions } from '../user/user-get.js'; -import spoFileGetCommand, { Options as SpoFileGetCommandOptions } from './file-get.js'; +import { FileProperties } from './FileProperties.js'; interface CommandArgs { options: Options; @@ -124,14 +122,14 @@ class SpoFileRoleAssignmentRemoveCommand extends SpoCommand { } try { - const fileURL: string = await this.getFileURL(args); + const fileURL: string = await this.getFileURL(args, logger); let principalId: number; if (args.options.groupName) { - principalId = await this.getGroupPrincipalId(args.options); + principalId = await this.getGroupPrincipalId(args.options, logger); } else if (args.options.upn) { - principalId = await this.getUserPrincipalId(args.options); + principalId = await this.getUserPrincipalId(args.options, logger); } else { principalId = args.options.principalId!; @@ -165,51 +163,23 @@ class SpoFileRoleAssignmentRemoveCommand extends SpoCommand { } } - private async getFileURL(args: CommandArgs): Promise { + private async getFileURL(args: CommandArgs, logger: Logger): Promise { if (args.options.fileUrl) { return urlUtil.getServerRelativePath(args.options.webUrl, args.options.fileUrl); } - const options: SpoFileGetCommandOptions = { - webUrl: args.options.webUrl, - id: args.options.fileId, - output: 'json', - debug: this.debug, - verbose: this.verbose - }; - - const output = await cli.executeCommandWithOutput(spoFileGetCommand as Command, { options: { ...options, _: [] } }); - const getFileOutput = JSON.parse(output.stdout); - return getFileOutput.ServerRelativeUrl; + const file: FileProperties = await spo.getFileById(args.options.webUrl, args.options.fileId!, logger, this.verbose); + return file.ServerRelativeUrl; } - private async getUserPrincipalId(options: Options): Promise { - const userGetCommandOptions: SpoUserGetCommandOptions = { - webUrl: options.webUrl, - email: options.upn, - id: undefined, - output: 'json', - debug: this.debug, - verbose: this.verbose - }; - - const output = await cli.executeCommandWithOutput(spoUserGetCommand as Command, { options: { ...userGetCommandOptions, _: [] } }); - const getUserOutput = JSON.parse(output.stdout); - return getUserOutput.Id; + private async getUserPrincipalId(options: Options, logger: Logger): Promise { + const user = await spo.getUserByEmail(options.webUrl, options.upn!, logger, this.verbose); + return user.Id; } - private async getGroupPrincipalId(options: Options): Promise { - const groupGetCommandOptions: SpoGroupGetCommandOptions = { - webUrl: options.webUrl, - name: options.groupName, - output: 'json', - debug: this.debug, - verbose: this.verbose - }; - - const output = await cli.executeCommandWithOutput(spoGroupGetCommand as Command, { options: { ...groupGetCommandOptions, _: [] } }); - const getGroupOutput = JSON.parse(output.stdout); - return getGroupOutput.Id; + private async getGroupPrincipalId(options: Options, logger: Logger): Promise { + const group = await spo.getGroupByName(options.webUrl, options.groupName!, logger, this.verbose); + return group.Id; } } diff --git a/src/m365/spo/commands/file/file-roleinheritance-break.spec.ts b/src/m365/spo/commands/file/file-roleinheritance-break.spec.ts index b9e5dc2ec80..5ac8c993a92 100644 --- a/src/m365/spo/commands/file/file-roleinheritance-break.spec.ts +++ b/src/m365/spo/commands/file/file-roleinheritance-break.spec.ts @@ -12,10 +12,10 @@ import { pid } from '../../../../utils/pid.js'; import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; -import spoFileGetCommand from './file-get.js'; import command from './file-roleinheritance-break.js'; +import { spo } from '../../../../utils/spo.js'; -describe(commands.FILE_ROLEINHERITANCE_RESET, () => { +describe(commands.FILE_ROLEINHERITANCE_BREAK, () => { const webUrl = 'https://contoso.sharepoint.com/sites/project-x'; const fileUrl = '/sites/project-x/documents/Test1.docx'; const fileId = 'b2307a39-e878-458b-bc90-03bc578531d6'; @@ -24,6 +24,33 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { let logger: Logger; let commandInfo: CommandInfo; let promptIssued: boolean = false; + const fileResponse = { + CheckInComment: '', + CheckOutType: 2, + ContentTag: '{F09C4EFE-B8C0-4E89-A166-03418661B89B},9,12', + CustomizedPageStatus: 0, + ETag: '\"{F09C4EFE-B8C0-4E89-A166-03418661B89B},9\"', + Exists: true, + IrmEnabled: false, + Length: '331673', + Level: 1, + LinkingUri: 'https://contoso.sharepoint.com/sites/project-x/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866', + LinkingUrl: 'https://contoso.sharepoint.com/sites/project-x/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866', + ListItemAllFields: { + Id: 1, + ID: 1 + }, + MajorVersion: 3, + MinorVersion: 0, + Name: 'Test1.docx', + ServerRelativeUrl: '/sites/project-x/documents/Test1.docx', + TimeCreated: '2018-02-05T08:42:36Z', + TimeLastModified: '2018-02-05T08:44:03Z', + Title: '', + UIVersion: 1536, + UIVersionLabel: '3.0', + UniqueId: 'b2307a39-e878-458b-bc90-03bc578531d6' + }; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -58,7 +85,7 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { afterEach(() => { sinonUtil.restore([ cli.promptForConfirmation, - cli.executeCommandWithOutput, + spo.getFileById, request.post ]); }); @@ -157,15 +184,7 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { }); it('breaks role inheritance on file by Id when prompt confirmed', async () => { - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoFileGetCommand) { - return ({ - stdout: '{"LinkingUri": "https://contoso.sharepoint.com/sites/project-x/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866","Name": "Test1.docx","ServerRelativeUrl": "/sites/project-x/documents/Test1.docx","UniqueId": "b2307a39-e878-458b-bc90-03bc578531d6"}' - }); - } - - throw new CommandError('Unknown case'); - }); + sinon.stub(spo, 'getFileById').resolves(fileResponse); sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `${webUrl}/_api/web/GetFileByServerRelativePath(DecodedUrl='${formatting.encodeQueryParameter(fileUrl)}')/ListItemAllFields/breakroleinheritance(true)`) { diff --git a/src/m365/spo/commands/file/file-roleinheritance-break.ts b/src/m365/spo/commands/file/file-roleinheritance-break.ts index 7888aafd36a..a4516d3b2d5 100644 --- a/src/m365/spo/commands/file/file-roleinheritance-break.ts +++ b/src/m365/spo/commands/file/file-roleinheritance-break.ts @@ -1,14 +1,14 @@ import { cli } from '../../../../cli/cli.js'; import { Logger } from '../../../../cli/Logger.js'; -import Command from '../../../../Command.js'; import GlobalOptions from '../../../../GlobalOptions.js'; import request, { CliRequestOptions } from '../../../../request.js'; import { formatting } from '../../../../utils/formatting.js'; +import { spo } from '../../../../utils/spo.js'; import { urlUtil } from '../../../../utils/urlUtil.js'; import { validation } from '../../../../utils/validation.js'; import SpoCommand from '../../../base/SpoCommand.js'; import commands from '../../commands.js'; -import spoFileGetCommand, { Options as SpoFileGetCommandOptions } from './file-get.js'; +import { FileProperties } from './FileProperties.js'; interface CommandArgs { options: Options; @@ -104,7 +104,7 @@ class SpoFileRoleInheritanceBreakCommand extends SpoCommand { await logger.logToStderr(`Breaking role inheritance for file ${args.options.fileId || args.options.fileUrl}`); } try { - const fileURL: string = await this.getFileURL(args); + const fileURL: string = await this.getFileURL(args, logger); const keepExistingPermissions: boolean = !args.options.clearExistingPermissions; @@ -135,22 +135,13 @@ class SpoFileRoleInheritanceBreakCommand extends SpoCommand { } } - private async getFileURL(args: CommandArgs): Promise { + private async getFileURL(args: CommandArgs, logger: Logger): Promise { if (args.options.fileUrl) { return urlUtil.getServerRelativePath(args.options.webUrl, args.options.fileUrl); } - const options: SpoFileGetCommandOptions = { - webUrl: args.options.webUrl, - id: args.options.fileId, - output: 'json', - debug: this.debug, - verbose: this.verbose - }; - - const output = await cli.executeCommandWithOutput(spoFileGetCommand as Command, { options: { ...options, _: [] } }); - const getFileOutput = JSON.parse(output.stdout); - return getFileOutput.ServerRelativeUrl; + const file: FileProperties = await spo.getFileById(args.options.webUrl, args.options.fileId!, logger, this.verbose); + return file.ServerRelativeUrl; } } diff --git a/src/m365/spo/commands/file/file-roleinheritance-reset.spec.ts b/src/m365/spo/commands/file/file-roleinheritance-reset.spec.ts index c196bcbb3d3..ea146430b2c 100644 --- a/src/m365/spo/commands/file/file-roleinheritance-reset.spec.ts +++ b/src/m365/spo/commands/file/file-roleinheritance-reset.spec.ts @@ -12,8 +12,8 @@ import { pid } from '../../../../utils/pid.js'; import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; -import spoFileGetCommand from './file-get.js'; import command from './file-roleinheritance-reset.js'; +import { spo } from '../../../../utils/spo.js'; describe(commands.FILE_ROLEINHERITANCE_RESET, () => { const webUrl = 'https://contoso.sharepoint.com/sites/project-x'; @@ -24,6 +24,33 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { let logger: Logger; let commandInfo: CommandInfo; let promptIssued: boolean = false; + const fileResponse = { + CheckInComment: '', + CheckOutType: 2, + ContentTag: '{F09C4EFE-B8C0-4E89-A166-03418661B89B},9,12', + CustomizedPageStatus: 0, + ETag: '\"{F09C4EFE-B8C0-4E89-A166-03418661B89B},9\"', + Exists: true, + IrmEnabled: false, + Length: '331673', + Level: 1, + LinkingUri: 'https://contoso.sharepoint.com/sites/project-x/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866', + LinkingUrl: 'https://contoso.sharepoint.com/sites/project-x/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866', + ListItemAllFields: { + Id: 1, + ID: 1 + }, + MajorVersion: 3, + MinorVersion: 0, + Name: 'Test1.docx', + ServerRelativeUrl: '/sites/project-x/documents/Test1.docx', + TimeCreated: '2018-02-05T08:42:36Z', + TimeLastModified: '2018-02-05T08:44:03Z', + Title: '', + UIVersion: 1536, + UIVersionLabel: '3.0', + UniqueId: 'b2307a39-e878-458b-bc90-03bc578531d6' + }; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -58,7 +85,8 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { afterEach(() => { sinonUtil.restore([ cli.promptForConfirmation, - request.post + request.post, + spo.getFileById ]); }); @@ -135,15 +163,7 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { }); it('resets role inheritance on file by Id when prompt confirmed', async () => { - sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { - if (command === spoFileGetCommand) { - return ({ - stdout: '{"LinkingUri": "https://contoso.sharepoint.com/sites/project-x/documents/Test1.docx?d=wc39926a80d2c4067afa6cff9902eb866","Name": "Test1.docx","ServerRelativeUrl": "/sites/project-x/documents/Test1.docx","UniqueId": "b2307a39-e878-458b-bc90-03bc578531d6"}' - }); - } - - throw new CommandError('Unknown case'); - }); + sinon.stub(spo, 'getFileById').resolves(fileResponse); sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `${webUrl}/_api/web/GetFileByServerRelativePath(DecodedUrl='${formatting.encodeQueryParameter(fileUrl)}')/ListItemAllFields/resetroleinheritance`) { diff --git a/src/m365/spo/commands/file/file-roleinheritance-reset.ts b/src/m365/spo/commands/file/file-roleinheritance-reset.ts index 7e636fcfd63..a0c92656838 100644 --- a/src/m365/spo/commands/file/file-roleinheritance-reset.ts +++ b/src/m365/spo/commands/file/file-roleinheritance-reset.ts @@ -1,14 +1,13 @@ import { cli } from '../../../../cli/cli.js'; import { Logger } from '../../../../cli/Logger.js'; -import Command from '../../../../Command.js'; import GlobalOptions from '../../../../GlobalOptions.js'; import request, { CliRequestOptions } from '../../../../request.js'; import { formatting } from '../../../../utils/formatting.js'; +import { spo } from '../../../../utils/spo.js'; import { urlUtil } from '../../../../utils/urlUtil.js'; import { validation } from '../../../../utils/validation.js'; import SpoCommand from '../../../base/SpoCommand.js'; import commands from '../../commands.js'; -import spoFileGetCommand, { Options as SpoFileGetCommandOptions } from './file-get.js'; interface CommandArgs { options: Options; @@ -99,7 +98,7 @@ class SpoFileRoleInheritanceResetCommand extends SpoCommand { await logger.logToStderr(`Resetting role inheritance for file ${args.options.fileId || args.options.fileUrl}`); } try { - const fileURL: string = await this.getFileURL(args); + const fileURL: string = await this.getFileURL(args, logger); const requestOptions: CliRequestOptions = { url: `${args.options.webUrl}/_api/web/GetFileByServerRelativePath(DecodedUrl='${formatting.encodeQueryParameter(fileURL)}')/ListItemAllFields/resetroleinheritance`, @@ -128,22 +127,13 @@ class SpoFileRoleInheritanceResetCommand extends SpoCommand { } } - private async getFileURL(args: CommandArgs): Promise { + private async getFileURL(args: CommandArgs, logger: Logger): Promise { if (args.options.fileUrl) { return urlUtil.getServerRelativePath(args.options.webUrl, args.options.fileUrl); } - const options: SpoFileGetCommandOptions = { - webUrl: args.options.webUrl, - id: args.options.fileId, - output: 'json', - debug: this.debug, - verbose: this.verbose - }; - - const output = await cli.executeCommandWithOutput(spoFileGetCommand as Command, { options: { ...options, _: [] } }); - const getFileOutput = JSON.parse(output.stdout); - return getFileOutput.ServerRelativeUrl; + const file = await spo.getFileById(args.options.webUrl, args.options.fileId!, logger, this.verbose); + return file.ServerRelativeUrl; } } diff --git a/src/utils/spo.spec.ts b/src/utils/spo.spec.ts index bf7f71612e3..4c89497b776 100644 --- a/src/utils/spo.spec.ts +++ b/src/utils/spo.spec.ts @@ -2512,4 +2512,60 @@ describe('utils/spo', () => { }); assert.strictEqual(amountOfCalls, 4); }); + + it(`retrieves a file with its properties sucessfully`, async () => { + const id = 'b2307a39-e878-458b-bc90-03bc578531d6'; + const fileResponse = { + ListItemAllFields: { + FileSystemObjectType: 0, + Id: 4, + ServerRedirectedEmbedUri: 'https://contoso.sharepoint.com/sites/project-x/_layouts/15/WopiFrame.aspx?sourcedoc={b2307a39-e878-458b-bc90-03bc578531d6}&action=interactivepreview', + ServerRedirectedEmbedUrl: 'https://contoso.sharepoint.com/sites/project-x/_layouts/15/WopiFrame.aspx?sourcedoc={b2307a39-e878-458b-bc90-03bc578531d6}&action=interactivepreview', + ContentTypeId: '0x0101008E462E3ACE8DB844B3BEBF9473311889', + ComplianceAssetId: null, + Title: null, + ID: 4, + Created: '2018-02-05T09:42:36', + AuthorId: 1, + Modified: '2018-02-05T09:44:03', + EditorId: 1, + 'OData__CopySource': null, + CheckoutUserId: null, + 'OData__UIVersionString': '3.0', + GUID: '2054f49e-0f76-46d4-ac55-50e1c057941c' + }, + CheckInComment: '', + CheckOutType: 2, + ContentTag: '{F09C4EFE-B8C0-4E89-A166-03418661B89B},9,12', + CustomizedPageStatus: 0, + ETag: '\'{F09C4EFE-B8C0-4E89-A166-03418661B89B},9\'', + Exists: true, + IrmEnabled: false, + Length: '331673', + Level: 1, + LinkingUri: 'https://contoso.sharepoint.com/sites/project-x/Documents/Test1.docx?d=wf09c4efeb8c04e89a16603418661b89b', + LinkingUrl: 'https://contoso.sharepoint.com/sites/project-x/Documents/Test1.docx?d=wf09c4efeb8c04e89a16603418661b89b', + MajorVersion: 3, + MinorVersion: 0, + Name: 'Opendag maart 2018.docx', + ServerRelativeUrl: '/sites/project-x/Documents/Test1.docx', + TimeCreated: '2018-02-05T08:42:36Z', + TimeLastModified: '2018-02-05T08:44:03Z', + Title: '', + UIVersion: 1536, + UIVersionLabel: '3.0', + UniqueId: 'b2307a39-e878-458b-bc90-03bc578531d6' + }; + + sinon.stub(request, 'get').callsFake(async (opts) => { + if (opts.url === `https://contoso.sharepoint.com/sites/sales/_api/web/GetFileById('${formatting.encodeQueryParameter(id)}')`) { + return fileResponse; + } + + throw 'Invalid request'; + }); + + const group = await spo.getFileById(webUrl, id, logger, true); + assert.deepEqual(group, fileResponse); + }); }); \ No newline at end of file diff --git a/src/utils/spo.ts b/src/utils/spo.ts index 7f99aca451e..3166d561540 100644 --- a/src/utils/spo.ts +++ b/src/utils/spo.ts @@ -653,10 +653,10 @@ export const spo = { * @param webUrl Web url * @param email The email of the user * @param logger the Logger object - * @param verbose set if verbose logging should be logged + * @param verbose set for verbose logging */ - async getUserByEmail(webUrl: string, email: string, logger: Logger, verbose?: boolean): Promise { - if (verbose) { + async getUserByEmail(webUrl: string, email: string, logger?: Logger, verbose?: boolean): Promise { + if (verbose && logger) { await logger.logToStderr(`Retrieving the spo user by email ${email}`); } const requestUrl = `${webUrl}/_api/web/siteusers/GetByEmail('${formatting.encodeQueryParameter(email)}')`; @@ -737,10 +737,10 @@ export const spo = { * @param webUrl Web url * @param name The name of the group * @param logger the Logger object - * @param verbose set if verbose logging should be logged + * @param verbose set for verbose logging */ - async getGroupByName(webUrl: string, name: string, logger: Logger, verbose?: boolean): Promise { - if (verbose) { + async getGroupByName(webUrl: string, name: string, logger?: Logger, verbose?: boolean): Promise { + if (verbose && logger) { await logger.logToStderr(`Retrieving the group by name ${name}`); } const requestUrl = `${webUrl}/_api/web/sitegroups/GetByName('${formatting.encodeQueryParameter(name)}')`; @@ -763,10 +763,10 @@ export const spo = { * @param webUrl Web url * @param name the name of the role definition * @param logger the Logger object - * @param debug set if debug logging should be logged + * @param verbose set for verbose logging */ - async getRoleDefinitionByName(webUrl: string, name: string, logger: Logger, debug?: boolean): Promise { - if (debug) { + async getRoleDefinitionByName(webUrl: string, name: string, logger?: Logger, verbose?: boolean): Promise { + if (verbose && logger) { await logger.logToStderr(`Retrieving the role definitions for ${name}`); } @@ -1822,5 +1822,33 @@ export const spo = { const itemsResponse = await request.get(requestOptionsItems); return (itemsResponse); + }, + + /** + * Retrieves the file by id. + * Returns a FileProperties object + * @param webUrl Web url + * @param id the id of the file + * @param logger the Logger object + * @param verbose set for verbose logging + */ + async getFileById(webUrl: string, id: string, logger?: Logger, verbose?: boolean): Promise { + if (verbose && logger) { + await logger.logToStderr(`Retrieving the file with id ${id}`); + } + const requestUrl = `${webUrl}/_api/web/GetFileById('${formatting.encodeQueryParameter(id)}')`; + + const requestOptions: CliRequestOptions = { + url: requestUrl, + headers: { + 'accept': 'application/json;odata=nometadata' + }, + + responseType: 'json' + }; + + const file: FileProperties = await request.get(requestOptions); + + return file; } }; \ No newline at end of file