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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: split config and permission methods out of mgt-person-card #2840

Merged
merged 3 commits into from
Nov 10, 2023
Merged
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
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