Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor spo file, Closes #5268 #6004

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
188 changes: 121 additions & 67 deletions src/m365/spo/commands/file/file-roleassignment-add.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -25,6 +22,114 @@ 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();
Expand Down Expand Up @@ -52,8 +157,11 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => {

afterEach(() => {
sinonUtil.restore([
cli.executeCommandWithOutput,
request.post,
spo.getRoleDefinitionByName,
spo.getGroupByName,
spo.getUserByEmail,
spo.getFileById,
cli.getSettingWithDefaultValue
]);
});
Expand Down Expand Up @@ -142,15 +250,7 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => {
throw 'Invalid request';
});

sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise<any> => {
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: {
Expand All @@ -171,20 +271,8 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => {
throw 'Invalid request';
});

sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise<any> => {
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: {
Expand All @@ -205,15 +293,7 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => {
throw 'Invalid request';
});

sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise<any> => {
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: {
Expand All @@ -227,13 +307,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<any> => {
if (command === spoUserGetCommand) {
throw error;
}

throw 'Unknown case';
});
sinon.stub(spo, 'getUserByEmail').rejects(new Error(error));

await assert.rejects(command.action(logger, {
options: {
Expand All @@ -254,15 +328,7 @@ describe(commands.FILE_ROLEASSIGNMENT_ADD, () => {
throw 'Invalid request';
});

sinon.stub(cli, 'executeCommandWithOutput').callsFake(async (command): Promise<any> => {
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: {
Expand All @@ -276,13 +342,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: {
Expand All @@ -296,13 +356,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<any> => {
if (command === spoGroupGetCommand) {
throw error;
}

throw 'Unknown case';
});
sinon.stub(spo, 'getGroupByName').rejects(new Error(error));

await assert.rejects(command.action(logger, {
options: {
Expand Down
77 changes: 18 additions & 59 deletions src/m365/spo/commands/file/file-roleassignment-add.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -166,69 +162,32 @@ class SpoFileRoleAssignmentAddCommand extends SpoCommand {
return request.post(requestOptions);
}

private async getRoleDefinitionId(options: Options): Promise<number> {
private async getRoleDefinitionId(options: Options, logger: Logger): Promise<number> {
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<number> {
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<number> {
const group = await spo.getGroupByName(options.webUrl, options.groupName!, logger, this.verbose);
return group.Id;
}

private async getUserPrincipalId(options: Options): Promise<number> {
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<number> {
const user = await spo.getUserByEmail(options.webUrl, options.upn!, logger, this.verbose);
return user.Id;
}

private async getFileURL(args: CommandArgs): Promise<string> {
private async getFileURL(args: CommandArgs, logger: Logger): Promise<string> {
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;
}
}

Expand Down