Skip to content

Commit

Permalink
feat!: split config and permission methods out of mgt-person-card (#2840
Browse files Browse the repository at this point in the history
)

* feat!: split static config and permission methods out of mgt-personon-card

splits out the logic for cacluating the scopes required for the mgt-person-card into a separate function and file
splits the static config for MgtPersonCard into a separate class
changes the schema of the config for MgtPersonCard
fixes an issue where setting isSendMessageVisible to false did not stop the quick message ui from rendering
adds tests to validate the permission sets

BREAKING CHANGE: MgtPersonCard no longer has a static config property.This config has been moved to the MgtPersonCardConfig class to allow developers to import the config and associated getMgtPersonCardScopes function at the top level of their applicaiton without automatically adding the weight of the full mgt-person-card component and dependencies to the entry file for their applications.
BREAKING CHANGE: The organization section for configuring MgtPersonCard may no longer be set to false, use undefined instead.
  • Loading branch information
gavinbarron authored Nov 10, 2023
1 parent 00b168b commit 8177699
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 174 deletions.
2 changes: 2 additions & 0 deletions packages/mgt-components/src/components/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export * from './mgt-get/mgt-get';
export * from './mgt-login/mgt-login';
export * from './mgt-people-picker/mgt-people-picker';
export * from './mgt-people/mgt-people';
export * from './mgt-person-card/MgtPersonCardConfig';
export * from './mgt-person-card/getMgtPersonCardScopes';
export * from './mgt-person-card/mgt-person-card';
export * from './mgt-person/mgt-person';
export * from './mgt-person/mgt-person-types';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
interface SectionsConfig {
/**
* Gets or sets whether the organization section is shown
*
*/
organization?: {
/**
* Gets or sets whether the "Works with" section is shown
*
* @type {boolean}
*/
showWorksWith: boolean;
};

/**
* Gets or sets whether the messages section is shown
*
* @type {boolean}
*/
mailMessages: boolean;

/**
* Gets or sets whether the files section is shown
*
* @type {boolean}
*/
files: boolean;

/**
* Gets or sets whether the profile section is shown
*
* @type {boolean}
*/
profile: boolean;
}

export class MgtPersonCardConfig {
public static sections: SectionsConfig = {
files: true,
mailMessages: true,
organization: { showWorksWith: true },
profile: true
};
public static useContactApis = true;
public static isSendMessageVisible = true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { MgtPersonCardConfig } from './MgtPersonCardConfig';
import { expect } from '@open-wc/testing';
import { getMgtPersonCardScopes } from './getMgtPersonCardScopes';

describe('getMgtPersonCardScopes() tests', () => {
let originalConfigMessaging: typeof MgtPersonCardConfig.isSendMessageVisible;
let originalConfigContactApis: typeof MgtPersonCardConfig.useContactApis;
let originalConfigOrgSection: typeof MgtPersonCardConfig.sections.organization;
let originalConfigSections: typeof MgtPersonCardConfig.sections;
before(() => {
originalConfigOrgSection = { ...MgtPersonCardConfig.sections.organization };
originalConfigSections = { ...MgtPersonCardConfig.sections };
originalConfigContactApis = MgtPersonCardConfig.useContactApis;
originalConfigMessaging = MgtPersonCardConfig.isSendMessageVisible;
});
beforeEach(() => {
MgtPersonCardConfig.sections = { ...originalConfigSections };
MgtPersonCardConfig.sections.organization = { ...originalConfigOrgSection };
MgtPersonCardConfig.useContactApis = originalConfigContactApis;
MgtPersonCardConfig.isSendMessageVisible = originalConfigMessaging;
});
it('should have a minimal permission set', () => {
const expectedScopes = [
'User.Read.All',
'People.Read.All',
'Sites.Read.All',
'Mail.Read',
'Mail.ReadBasic',
'Contacts.Read',
'Chat.ReadWrite'
];
expect(getMgtPersonCardScopes()).to.have.members(expectedScopes);
});

it('should have not have Sites.Read.All if files is configured off', () => {
MgtPersonCardConfig.sections.files = false;

const expectedScopes = [
'User.Read.All',
'People.Read.All',
'Mail.Read',
'Mail.ReadBasic',
'Contacts.Read',
'Chat.ReadWrite'
];
expect(getMgtPersonCardScopes()).to.have.members(expectedScopes);
});

it('should have not have Mail scopes if mail is configured off', () => {
MgtPersonCardConfig.sections.mailMessages = false;

const expectedScopes = ['User.Read.All', 'People.Read.All', 'Sites.Read.All', 'Contacts.Read', 'Chat.ReadWrite'];
expect(getMgtPersonCardScopes()).to.have.members(expectedScopes);
});

it('should have People.Read but not People.Read.All if showWorksWith is false', () => {
MgtPersonCardConfig.sections.organization.showWorksWith = false;
const expectedScopes = [
'User.Read.All',
'People.Read',
'Sites.Read.All',
'Mail.Read',
'Mail.ReadBasic',
'Contacts.Read',
'Chat.ReadWrite'
];
expect(getMgtPersonCardScopes()).to.have.members(expectedScopes);
});

it('should have not have User.Read.All if profile and organization are false', () => {
MgtPersonCardConfig.sections.organization = undefined;
MgtPersonCardConfig.sections.profile = false;

const expectedScopes = [
'User.Read',
'User.ReadBasic.All',
'People.Read',
'Sites.Read.All',
'Mail.Read',
'Mail.ReadBasic',
'Contacts.Read',
'Chat.ReadWrite'
];
const actualScopes = getMgtPersonCardScopes();
expect(actualScopes).to.have.members(expectedScopes);

expect(actualScopes).to.not.include('User.Read.All');
});

it('should have not have Chat.ReadWrite if isSendMessageVisible is false', () => {
MgtPersonCardConfig.isSendMessageVisible = false;

const expectedScopes = [
'User.Read.All',
'People.Read.All',
'Sites.Read.All',
'Mail.Read',
'Mail.ReadBasic',
'Contacts.Read'
];
const actualScopes = getMgtPersonCardScopes();
expect(actualScopes).to.have.members(expectedScopes);

expect(actualScopes).to.not.include('Chat.ReadWrite');
});

it('should have not have Chat.ReadWrite if useContactApis is false', () => {
MgtPersonCardConfig.useContactApis = false;

const expectedScopes = [
'User.Read.All',
'People.Read.All',
'Sites.Read.All',
'Mail.Read',
'Mail.ReadBasic',
'Chat.ReadWrite'
];
const actualScopes = getMgtPersonCardScopes();
expect(actualScopes).to.have.members(expectedScopes);

expect(actualScopes).to.not.include('Contacts.Read');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { MgtPersonCardConfig } from './MgtPersonCardConfig';

/**
* Scopes used to fetch data for the mgt-person-card component
*
* @static
* @return {*} {string[]}
* @memberof MgtPersonCard
*/

export const getMgtPersonCardScopes = (): string[] => {
const scopes: string[] = [];

if (MgtPersonCardConfig.sections.files) {
scopes.push('Sites.Read.All');
}

if (MgtPersonCardConfig.sections.mailMessages) {
scopes.push('Mail.Read');
scopes.push('Mail.ReadBasic');
}

if (MgtPersonCardConfig.sections.organization) {
scopes.push('User.Read.All');

if (MgtPersonCardConfig.sections.organization.showWorksWith) {
scopes.push('People.Read.All');
}
}

if (MgtPersonCardConfig.sections.profile) {
scopes.push('User.Read.All');
}

if (MgtPersonCardConfig.useContactApis) {
scopes.push('Contacts.Read');
}

if (scopes.indexOf('User.Read.All') < 0) {
// at minimum, we need these scopes
scopes.push('User.ReadBasic.All');
scopes.push('User.Read');
}

if (scopes.indexOf('People.Read.All') < 0) {
// at minimum, we need these scopes
scopes.push('People.Read');
}

if (MgtPersonCardConfig.isSendMessageVisible) {
// Chat.ReadWrite can create a chat and send a message, so just request one scope instead of two
scopes.push('Chat.ReadWrite');
}

// return unique
return [...new Set(scopes)];
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { Profile } from '@microsoft/microsoft-graph-types-beta';

import { getEmailFromGraphEntity } from '../../graph/graph.people';
import { IDynamicPerson } from '../../graph/types';
import { MgtPersonCardConfig, MgtPersonCardState } from './mgt-person-card.types';
import { MgtPersonCardState } from './mgt-person-card.types';
import { MgtPersonCardConfig } from './MgtPersonCardConfig';

const userProperties =
'businessPhones,companyName,department,displayName,givenName,jobTitle,mail,mobilePhone,officeLocation,preferredLanguage,surname,userPrincipalName,id,accountEnabled';
Expand All @@ -37,8 +38,7 @@ const batchKeys = {
export const getPersonCardGraphData = async (
graph: IGraph,
personDetails: IDynamicPerson,
isMe: boolean,
config: MgtPersonCardConfig
isMe: boolean
): Promise<MgtPersonCardState> => {
const userId = personDetails.id;
const email = getEmailFromGraphEntity(personDetails);
Expand All @@ -51,20 +51,20 @@ export const getPersonCardGraphData = async (
const batch = graph.createBatch();

if (!isContactOrGroup) {
if (config.sections.organization) {
if (MgtPersonCardConfig.sections.organization) {
buildOrgStructureRequest(batch, userId);

if (typeof config.sections.organization !== 'boolean' && config.sections.organization.showWorksWith) {
if (MgtPersonCardConfig.sections.organization.showWorksWith) {
buildWorksWithRequest(batch, userId);
}
}
}

if (config.sections.mailMessages && email) {
if (MgtPersonCardConfig.sections.mailMessages && email) {
buildMessagesWithUserRequest(batch, email);
}

if (config.sections.files) {
if (MgtPersonCardConfig.sections.files) {
buildFilesRequest(batch, isMe ? null : email);
}

Expand All @@ -83,7 +83,7 @@ export const getPersonCardGraphData = async (
}
}

if (!isContactOrGroup && config.sections.profile) {
if (!isContactOrGroup && MgtPersonCardConfig.sections.profile) {
try {
const profile = await getProfile(graph, userId);
if (profile) {
Expand Down
Loading

0 comments on commit 8177699

Please sign in to comment.