Merge pull request #28939 from Sarabadu/sarabadu/mgraphs-provider-paths

feat(msgraphOrgProvider): add the path options to allow querying users and group from different endpoints
This commit is contained in:
Fredrik Adelöw
2025-04-29 11:34:24 +02:00
committed by GitHub
12 changed files with 342 additions and 13 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-msgraph': minor
---
Add new `userGroupMember.path`, `user.path` and, `group.path` option to each query type to allow more complex msgraph queries
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

+32
View File
@@ -125,6 +125,8 @@ microsoftGraphOrg:
In addition to these groups, one additional group will be created for your organization.
All imported groups will be a child of this group.
By default the provider will get groups using the msgraph `/group` endpoint, but it is possible to use different endpoints by setting the `path` configuration. All the endpoint containing `/microsoft.graph.group` will return the right type of group object. [See usage](#Using-path-parameter) for more details.
### Users
There are two modes for importing users - You can import all user objects matching a `filter`.
@@ -148,6 +150,36 @@ microsoftGraphOrg:
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
```
By default the provider will get user using the msgraph `/user` endpoint, but it is possible to use different endpoints by setting the `path` configuration. All the endpoint containing `/microsoft.graph.user` will return the right type of user object. [See usage](#Using-path-parameter) for more details.
### Using `path` parameter
By default the provider will get groups and users using the msgraph `/group` and `/user` endpoints, but it is possible to use different endpoints by setting the `path` configuration.
All the endpoint containing `/microsoft.graph.user` will return the right type of user object and all the endpoint containing `/microsoft.graph.group` will return the right type of group object.
#### Example
Given the following org structure it is possible to use the `path` parameter to get all the users and groups that are members of the group `someRootGroup` on all levels.
<div align="center">
![email](../../assets/integrations/azure/org.svg)
</div>
The configuration would look like this:
```yaml
microsoftGraphOrg:
providerId:
group:
path: /groups/{someRootGroup id}/transitiveMembers/microsoft.graph.group
user:
path: /groups/{someRootGroup id}/transitiveMembers/microsoft.graph.user
```
Using the transitive members endpoint will return all the users and groups that are members of the group `someRootGroup` on all levels.
### User photos
By default, the photos of users will be fetched and added to each user entity. For huge organizations this may be unfeasible, as it will take a _very_ long time, and can be disabled by setting `loadPhotos` to `false`:
@@ -58,6 +58,8 @@ catalog:
loadPhotos: true
# See https://docs.microsoft.com/en-us/graph/api/resources/schemaextension?view=graph-rest-1.0
select: ['id', 'displayName', 'description']
# Optional /users by default but allow to query users from different msgraph endpoints
path: /users
# Optional configuration block
userGroupMember:
# Optional filter for users, use group membership to get users.
@@ -69,6 +71,8 @@ catalog:
# (Search for groups and fetch their members.)
# This and userFilter are mutually exclusive, only one can be specified
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
# Optional /groups by default but allow to query groups from different msgraph endpoints
path: /groups
# Optional configuration block
group:
# Optional parameter to include the expanded resource or collection referenced
@@ -87,6 +91,8 @@ catalog:
# in order to add extra information to your groups that can be used on your custom groupTransformers
# See https://docs.microsoft.com/en-us/graph/api/resources/schemaextension?view=graph-rest-1.0
select: ['id', 'displayName', 'description']
# Optional /groups by default but allow to query groups from different msgraph endpoints
path: /groups
schedule: # optional; same options as in TaskScheduleDefinition
# supports cron, ISO duration, "human duration" as used in code
frequency: { hours: 1 }
+36
View File
@@ -148,6 +148,12 @@ export interface Config {
*/
queryMode?: string;
user?: {
/**
* The url path to fetch groups, defaults to `/users`.
*
* E.g. "groups/{id}/transitiveMembers/microsoft.graph.user/".
*/
path?: string;
/**
* The "expand" argument to apply to users.
*
@@ -174,6 +180,12 @@ export interface Config {
};
group?: {
/**
* The url path to fetch groups, defaults to `/groups`.
*
* E.g. "groups/{id}/transitiveMembers/microsoft.graph.group/".
*/
path?: string;
/**
* The "expand" argument to apply to groups.
*
@@ -206,6 +218,12 @@ export interface Config {
};
userGroupMember?: {
/**
* The url path to fetch groups, defaults to `/groups`.
*
* E.g. "groups/{id}/transitiveMembers/microsoft.graph.group/".
*/
path?: string;
/**
* The filter to apply to extract users by groups memberships.
*
@@ -263,6 +281,12 @@ export interface Config {
*/
queryMode?: string;
user?: {
/**
* The url path to fetch groups, defaults to `/groups`.
*
* E.g. "groups/{id}/transitiveMembers/microsoft.graph.group/".
*/
path?: string;
/**
* The "expand" argument to apply to users.
*
@@ -289,6 +313,12 @@ export interface Config {
};
group?: {
/**
* The url path to fetch groups, defaults to `/groups`.
*
* E.g. "groups/{id}/transitiveMembers/microsoft.graph.group/".
*/
path?: string;
/**
* The "expand" argument to apply to groups.
*
@@ -321,6 +351,12 @@ export interface Config {
};
userGroupMember?: {
/**
* The url path to fetch groups, defaults to `/groups`.
*
* E.g. "groups/{id}/transitiveMembers/microsoft.graph.group/".
*/
path?: string;
/**
* The filter to apply to extract users by groups memberships.
*
@@ -92,6 +92,7 @@ export class MicrosoftGraphClient {
getGroups(
query?: ODataQuery,
queryMode?: 'basic' | 'advanced',
path?: string,
): AsyncIterable<MicrosoftGraph.Group>;
getGroupUserMembers(
groupId: string,
@@ -108,6 +109,7 @@ export class MicrosoftGraphClient {
getUsers(
query?: ODataQuery,
queryMode?: 'basic' | 'advanced',
path?: string,
): AsyncIterable<MicrosoftGraph.User>;
requestApi(
path: string,
@@ -239,12 +241,15 @@ export type MicrosoftGraphProviderConfig = {
userFilter?: string;
userSelect?: string[];
userExpand?: string;
userPath?: string;
userGroupMemberFilter?: string;
userGroupMemberSearch?: string;
userGroupMemberPath?: string;
groupExpand?: string;
groupFilter?: string;
groupSearch?: string;
groupSelect?: string[];
groupPath?: string;
groupIncludeSubGroups?: boolean;
queryMode?: 'basic' | 'advanced';
loadUserPhotos?: boolean;
@@ -287,13 +292,16 @@ export function readMicrosoftGraphOrg(
userExpand?: string;
userFilter?: string;
userSelect?: string[];
userPath?: string;
loadUserPhotos?: boolean;
userGroupMemberSearch?: string;
userGroupMemberFilter?: string;
userGroupMemberPath?: string;
groupExpand?: string;
groupSearch?: string;
groupFilter?: string;
groupSelect?: string[];
groupPath?: string;
groupIncludeSubGroups?: boolean;
queryMode?: 'basic' | 'advanced';
userTransformer?: UserTransformer;
@@ -272,16 +272,14 @@ export class MicrosoftGraphClient {
* @public
* @param query - OData Query {@link ODataQuery}
* @param queryMode - Mode to use while querying. Some features are only available at "advanced".
* @param path - Resource endpoint in Microsoft Graph
*/
async *getUsers(
query?: ODataQuery,
queryMode?: 'basic' | 'advanced',
path: string = 'users',
): AsyncIterable<MicrosoftGraph.User> {
yield* this.requestCollection<MicrosoftGraph.User>(
`users`,
query,
queryMode,
);
yield* this.requestCollection<MicrosoftGraph.User>(path, query, queryMode);
}
/**
@@ -314,16 +312,14 @@ export class MicrosoftGraphClient {
* @public
* @param query - OData Query {@link ODataQuery}
* @param queryMode - Mode to use while querying. Some features are only available at "advanced".
* @param path - Resource endpoint in Microsoft Graph
*/
async *getGroups(
query?: ODataQuery,
queryMode?: 'basic' | 'advanced',
path: string = 'groups',
): AsyncIterable<MicrosoftGraph.Group> {
yield* this.requestCollection<MicrosoftGraph.Group>(
`groups`,
query,
queryMode,
);
yield* this.requestCollection<MicrosoftGraph.Group>(path, query, queryMode);
}
/**
@@ -148,6 +148,8 @@ describe('readProviderConfigs', () => {
id: 'customProviderId',
target: 'https://graph.microsoft.com/v1.0',
tenantId: 'tenantId',
userPath: 'users',
groupPath: 'groups',
},
];
expect(actual).toEqual(expected);
@@ -169,12 +171,14 @@ describe('readProviderConfigs', () => {
expand: 'manager',
filter: 'accountEnabled eq true',
select: ['id', 'displayName', 'department'],
path: '/groups/{groupId}/members',
},
group: {
expand: 'member',
filter: 'securityEnabled eq false',
select: ['id', 'displayName', 'description'],
includeSubGroups: true,
path: '/groups/{groupId}/members',
},
schedule: {
frequency: 'PT30M',
@@ -200,9 +204,11 @@ describe('readProviderConfigs', () => {
userExpand: 'manager',
userFilter: 'accountEnabled eq true',
userSelect: ['id', 'displayName', 'department'],
userPath: '/groups/{groupId}/members',
groupExpand: 'member',
groupSelect: ['id', 'displayName', 'description'],
groupFilter: 'securityEnabled eq false',
groupPath: '/groups/{groupId}/members',
groupIncludeSubGroups: true,
schedule: {
frequency: { minutes: 30 },
@@ -78,6 +78,13 @@ export type MicrosoftGraphProviderConfig = {
* E.g. "manager".
*/
userExpand?: string;
/**
* The path to the users endpoint. Defaults to "/users".
*
* E.g. "/users"
*/
userPath?: string;
/**
* The filter to apply to extract users by groups memberships.
*
@@ -90,6 +97,14 @@ export type MicrosoftGraphProviderConfig = {
* E.g. "\"displayName:-team\"" would only match groups which contain '-team'
*/
userGroupMemberSearch?: string;
/**
* The path to the groups endpoint. Defaults to "/groups".
*
* E.g. "/groups"
*/
userGroupMemberPath?: string;
/**
* The "expand" argument to apply to groups.
*
@@ -116,6 +131,13 @@ export type MicrosoftGraphProviderConfig = {
*/
groupSelect?: string[];
/**
* The path to the groups endpoint. Defaults to "/groups".
*
* E.g. "/groups"
*/
groupPath?: string;
/**
* Whether to ingest groups that are members of the found/filtered/searched groups.
* Default value is `false`.
@@ -292,12 +314,14 @@ export function readProviderConfig(
const userExpand = config.getOptionalString('user.expand');
const userFilter = config.getOptionalString('user.filter');
const userSelect = config.getOptionalStringArray('user.select');
const userPath = config.getOptionalString('user.path') ?? 'users';
const loadUserPhotos = config.getOptionalBoolean('user.loadPhotos');
const groupExpand = config.getOptionalString('group.expand');
const groupFilter = config.getOptionalString('group.filter');
const groupSearch = config.getOptionalString('group.search');
const groupSelect = config.getOptionalStringArray('group.select');
const groupPath = config.getOptionalString('group.path') ?? 'groups';
const groupIncludeSubGroups = config.getOptionalBoolean(
'group.includeSubGroups',
);
@@ -317,6 +341,7 @@ export function readProviderConfig(
const userGroupMemberSearch = config.getOptionalString(
'userGroupMember.search',
);
const userGroupMemberPath = config.getOptionalString('userGroupMember.path');
if (userFilter && userGroupMemberFilter) {
throw new Error(
@@ -353,15 +378,18 @@ export function readProviderConfig(
userExpand,
userFilter,
userSelect,
userPath,
loadUserPhotos,
groupExpand,
groupFilter,
groupSearch,
groupSelect,
groupPath,
groupIncludeSubGroups,
queryMode,
userGroupMemberFilter,
userGroupMemberSearch,
userGroupMemberPath,
schedule,
};
}
@@ -139,6 +139,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getUserPhotoWithSizeLimit).toHaveBeenCalledTimes(1);
expect(client.getUserPhotoWithSizeLimit).toHaveBeenCalledWith(
@@ -186,6 +187,7 @@ describe('read microsoft graph', () => {
top: 999,
},
'advanced',
undefined,
);
expect(client.getUserPhotoWithSizeLimit).toHaveBeenCalledTimes(1);
expect(client.getUserPhotoWithSizeLimit).toHaveBeenCalledWith(
@@ -229,6 +231,55 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getUserPhotoWithSizeLimit).toHaveBeenCalledTimes(1);
expect(client.getUserPhotoWithSizeLimit).toHaveBeenCalledWith(
'userid',
120,
);
});
it('should read users from different endpoints', async () => {
client.getUsers.mockImplementation(getExampleUsers);
client.getUserPhotoWithSizeLimit.mockResolvedValue(
'data:image/jpeg;base64,...',
);
const { users } = await readMicrosoftGraphUsers(client, {
userFilter: 'accountEnabled eq true',
userPath: '/users/x/y',
logger: mockServices.logger.mock(),
});
expect(users).toEqual([
user({
metadata: {
annotations: {
'graph.microsoft.com/user-id': 'userid',
'microsoft.com/email': 'user.name@example.com',
},
name: 'user.name_example.com',
},
spec: {
profile: {
displayName: 'User Name',
email: 'user.name@example.com',
picture: 'data:image/jpeg;base64,...',
},
memberOf: [],
},
}),
]);
expect(client.getUsers).toHaveBeenCalledTimes(1);
expect(client.getUsers).toHaveBeenCalledWith(
{
filter: 'accountEnabled eq true',
top: 999,
},
undefined,
'/users/x/y',
);
expect(client.getUserPhotoWithSizeLimit).toHaveBeenCalledTimes(1);
expect(client.getUserPhotoWithSizeLimit).toHaveBeenCalledWith(
@@ -280,6 +331,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroupUserMembers).toHaveBeenCalledTimes(1);
@@ -338,6 +390,7 @@ describe('read microsoft graph', () => {
top: 999,
},
'advanced',
undefined,
);
expect(client.getGroupUserMembers).toHaveBeenCalledTimes(1);
@@ -393,6 +446,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroupUserMembers).toHaveBeenCalledTimes(1);
@@ -411,6 +465,52 @@ describe('read microsoft graph', () => {
120,
);
});
it('should read users from different group endpoints', async () => {
client.getGroups.mockImplementation(getExampleGroups);
client.getGroupUserMembers.mockImplementation(getExampleUsers);
client.getUserPhotoWithSizeLimit.mockResolvedValue(
'data:image/jpeg;base64,...',
);
const { users } = await readMicrosoftGraphUsersInGroups(client, {
userGroupMemberFilter: 'securityEnabled eq true',
userGroupMemberPath: '/groups/x/y',
logger: mockServices.logger.mock(),
});
expect(users).toEqual([
user({
metadata: {
annotations: {
'graph.microsoft.com/user-id': 'userid',
'microsoft.com/email': 'user.name@example.com',
},
name: 'user.name_example.com',
},
spec: {
profile: {
displayName: 'User Name',
email: 'user.name@example.com',
picture: 'data:image/jpeg;base64,...',
},
memberOf: [],
},
}),
]);
expect(client.getGroups).toHaveBeenCalledTimes(1);
expect(client.getGroups).toHaveBeenCalledWith(
{
filter: 'securityEnabled eq true',
select: ['id', 'displayName'],
top: 999,
},
undefined,
'/groups/x/y',
);
});
});
describe('readMicrosoftGraphOrganization', () => {
@@ -535,6 +635,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroupMembers).toHaveBeenCalledTimes(1);
expect(client.getGroupMembers).toHaveBeenCalledWith('groupid', {
@@ -614,6 +715,7 @@ describe('read microsoft graph', () => {
top: 999,
},
'advanced',
undefined,
);
expect(client.getGroupMembers).toHaveBeenCalledTimes(1);
expect(client.getGroupMembers).toHaveBeenCalledWith('groupid', {
@@ -694,6 +796,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroupMembers).toHaveBeenCalledTimes(1);
expect(client.getGroupMembers).toHaveBeenCalledWith('groupid', {
@@ -767,6 +870,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroupMembers).toHaveBeenCalledTimes(1);
expect(client.getGroupMembers).toHaveBeenCalledWith('groupid', {
@@ -871,6 +975,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroupMembers).toHaveBeenCalledTimes(2);
expect(client.getGroupMembers).toHaveBeenCalledWith('groupid', {
@@ -884,6 +989,79 @@ describe('read microsoft graph', () => {
// expect(client.getGroupPhotoWithSizeLimit).toBeCalledTimes(1);
// expect(client.getGroupPhotoWithSizeLimit).toBeCalledWith('groupid', 120);
});
it('should read groups from different endpoints paths', async () => {
client.getGroups.mockImplementation(getExampleGroups);
client.getGroupMembers.mockImplementation(getExampleGroupMembers);
client.getOrganization.mockResolvedValue({
id: 'tenantid',
displayName: 'Organization Name',
});
client.getGroupPhotoWithSizeLimit.mockResolvedValue(
'data:image/jpeg;base64,...',
);
const { groups, groupMember, groupMemberOf, rootGroup } =
await readMicrosoftGraphGroups(client, 'tenantid', {
groupFilter: 'securityEnabled eq false',
groupPath: '/groups/x/y',
});
const expectedRootGroup = group({
metadata: {
annotations: {
'graph.microsoft.com/tenant-id': 'tenantid',
},
name: 'organization_name',
description: 'Organization Name',
},
spec: {
type: 'root',
profile: {
displayName: 'Organization Name',
},
children: [],
},
});
expect(groups).toEqual([
expectedRootGroup,
group({
metadata: {
annotations: {
'graph.microsoft.com/group-id': 'groupid',
},
name: 'group_name',
description: 'Group Description',
},
spec: {
type: 'team',
profile: {
displayName: 'Group Name',
email: 'group@example.com',
},
children: [],
},
}),
]);
expect(rootGroup).toEqual(expectedRootGroup);
expect(groupMember.get('groupid')).toEqual(new Set(['childgroupid']));
expect(groupMemberOf.get('userid')).toEqual(new Set(['groupid']));
expect(groupMember.get('organization_name')).toEqual(new Set());
expect(client.getGroups).toHaveBeenCalledTimes(1);
expect(client.getGroups).toHaveBeenCalledWith(
{
filter: 'securityEnabled eq false',
top: 999,
},
undefined,
'/groups/x/y',
);
expect(client.getGroupMembers).toHaveBeenCalledTimes(1);
expect(client.getGroupMembers).toHaveBeenCalledWith('groupid', {
top: 999,
});
});
});
describe('resolveRelations', () => {
@@ -1018,6 +1196,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroups).toHaveBeenCalledTimes(1);
expect(client.getGroups).toHaveBeenCalledWith(
@@ -1026,6 +1205,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
});
@@ -1058,6 +1238,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroups).toHaveBeenCalledTimes(1);
expect(client.getGroups).toHaveBeenCalledWith(
@@ -1066,6 +1247,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
});
@@ -1096,6 +1278,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroups).toHaveBeenCalledTimes(1);
expect(client.getGroups).toHaveBeenCalledWith(
@@ -1103,6 +1286,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
});
@@ -1132,6 +1316,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
});
@@ -1161,20 +1346,24 @@ describe('read microsoft graph', () => {
expect(client.getUsers).toHaveBeenCalledTimes(0);
expect(client.getGroups).toHaveBeenCalledTimes(2);
expect(client.getGroups).toHaveBeenCalledWith(
expect(client.getGroups).toHaveBeenNthCalledWith(
1,
{
filter: 'name eq backstage-group',
select: ['id', 'displayName'],
top: 999,
},
undefined,
undefined,
);
expect(client.getGroups).toHaveBeenCalledWith(
expect(client.getGroups).toHaveBeenNthCalledWith(
2,
{
filter: 'securityEnabled eq false',
top: 999,
},
undefined,
undefined,
);
expect(client.getUserPhotoWithSizeLimit).toHaveBeenCalledTimes(1);
});
@@ -1215,6 +1404,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
expect(client.getGroups).toHaveBeenCalledTimes(1);
expect(client.getGroups).toHaveBeenCalledWith(
@@ -1222,6 +1412,7 @@ describe('read microsoft graph', () => {
top: 999,
},
undefined,
undefined,
);
});
});
@@ -49,6 +49,7 @@ export async function readMicrosoftGraphUsers(
userExpand?: string;
userFilter?: string;
userSelect?: string[];
userPath?: string;
loadUserPhotos?: boolean;
transformer?: UserTransformer;
logger: LoggerService;
@@ -64,6 +65,7 @@ export async function readMicrosoftGraphUsers(
top: PAGE_SIZE,
},
options.queryMode,
options.userPath,
);
return {
@@ -87,6 +89,7 @@ export async function readMicrosoftGraphUsersInGroups(
loadUserPhotos?: boolean;
userGroupMemberSearch?: string;
userGroupMemberFilter?: string;
userGroupMemberPath?: string;
groupExpand?: string;
transformer?: UserTransformer;
logger: LoggerService;
@@ -108,6 +111,7 @@ export async function readMicrosoftGraphUsersInGroups(
top: PAGE_SIZE,
},
options.queryMode,
options.userGroupMemberPath,
)) {
// Process all groups in parallel, otherwise it can take quite some time
userGroupMemberPromises.push(
@@ -178,6 +182,7 @@ export async function readMicrosoftGraphGroups(
groupFilter?: string;
groupSearch?: string;
groupSelect?: string[];
groupPath?: string;
groupIncludeSubGroups?: boolean;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
@@ -213,6 +218,7 @@ export async function readMicrosoftGraphGroups(
top: PAGE_SIZE,
},
options?.queryMode,
options?.groupPath,
)) {
// Process all groups in parallel, otherwise it can take quite some time
promises.push(
@@ -396,13 +402,16 @@ export async function readMicrosoftGraphOrg(
userExpand?: string;
userFilter?: string;
userSelect?: string[];
userPath?: string;
loadUserPhotos?: boolean;
userGroupMemberSearch?: string;
userGroupMemberFilter?: string;
userGroupMemberPath?: string;
groupExpand?: string;
groupSearch?: string;
groupFilter?: string;
groupSelect?: string[];
groupPath?: string;
groupIncludeSubGroups?: boolean;
queryMode?: 'basic' | 'advanced';
userTransformer?: UserTransformer;
@@ -413,7 +422,11 @@ export async function readMicrosoftGraphOrg(
): Promise<{ users: UserEntity[]; groups: GroupEntity[] }> {
let users: UserEntity[] = [];
if (options.userGroupMemberFilter || options.userGroupMemberSearch) {
if (
options.userGroupMemberFilter ||
options.userGroupMemberSearch ||
options.userGroupMemberPath
) {
const { users: usersInGroups } = await readMicrosoftGraphUsersInGroups(
client,
{
@@ -423,6 +436,7 @@ export async function readMicrosoftGraphOrg(
userSelect: options.userSelect,
userGroupMemberFilter: options.userGroupMemberFilter,
userGroupMemberSearch: options.userGroupMemberSearch,
userGroupMemberPath: options.userGroupMemberPath,
loadUserPhotos: options.loadUserPhotos,
transformer: options.userTransformer,
logger: options.logger,
@@ -435,6 +449,7 @@ export async function readMicrosoftGraphOrg(
userExpand: options.userExpand,
userFilter: options.userFilter,
userSelect: options.userSelect,
userPath: options.userPath,
loadUserPhotos: options.loadUserPhotos,
transformer: options.userTransformer,
logger: options.logger,
@@ -448,6 +463,7 @@ export async function readMicrosoftGraphOrg(
groupFilter: options.groupFilter,
groupSearch: options.groupSearch,
groupSelect: options.groupSelect,
groupPath: options.groupPath,
groupIncludeSubGroups: options.groupIncludeSubGroups,
groupTransformer: options.groupTransformer,
organizationTransformer: options.organizationTransformer,
@@ -327,6 +327,7 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider {
: this.options.provider;
const { markReadComplete } = trackProgress(logger);
const client = MicrosoftGraphClient.create(this.options.provider);
const { users, groups } = await readMicrosoftGraphOrg(
client,
provider.tenantId,
@@ -334,13 +335,16 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider {
userExpand: provider.userExpand,
userFilter: provider.userFilter,
userSelect: provider.userSelect,
userPath: provider.userPath,
loadUserPhotos: provider.loadUserPhotos,
userGroupMemberFilter: provider.userGroupMemberFilter,
userGroupMemberSearch: provider.userGroupMemberSearch,
userGroupMemberPath: provider.userGroupMemberPath,
groupExpand: provider.groupExpand,
groupFilter: provider.groupFilter,
groupSearch: provider.groupSearch,
groupSelect: provider.groupSelect,
groupPath: provider.groupPath,
groupIncludeSubGroups: provider.groupIncludeSubGroups,
queryMode: provider.queryMode,
groupTransformer: this.options.groupTransformer,