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:
@@ -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 |
@@ -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">
|
||||
|
||||

|
||||
|
||||
</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 }
|
||||
|
||||
@@ -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,
|
||||
|
||||
+4
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user