Skip to content

Commit

Permalink
fix: get group from predicate not query.properties (#1107)
Browse files Browse the repository at this point in the history
* fix: get group from predicate not query.properties

* refactor: add support for IMatchOptions
  • Loading branch information
dbouwman authored Jul 11, 2023
1 parent 1592034 commit 138af9c
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 39 deletions.
50 changes: 31 additions & 19 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions packages/common/e2e/hub-user-search.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ describe("Hub User search", () => {
{
name: "e2e",
},
{
group: "c08c260d3fbc4da384061b48652972e5",
},
],
},
],
properties: {
groupId: "c08c260d3fbc4da384061b48652972e5",
},
};

const response = await hubSearch(qry, {
Expand Down Expand Up @@ -84,12 +84,12 @@ describe("Hub User search", () => {
{
name: "e2e",
},
{
group: ["e59cab1c38e14a79a4ee36389632106c"],
},
],
},
],
properties: {
groupId: "e59cab1c38e14a79a4ee36389632106c",
},
};

const response = await hubSearch(qry, {
Expand Down
27 changes: 22 additions & 5 deletions packages/common/src/search/_internal/portalSearchGroupMembers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import HubError from "../../HubError";
import { IHubRequestOptions } from "../../types";
import { enrichUserSearchResult } from "../../users";
import { failSafe } from "../../utils";
import { pickProps, setProp } from "../../objects";
import { getProp, pickProps, setProp } from "../../objects";

/**
* Search for members of a group.
Expand All @@ -37,15 +37,32 @@ export async function portalSearchGroupMembers(
query: IQuery,
options: IHubSearchOptions
): Promise<IHubSearchResponse<IHubSearchResult>> {
if (!query.properties?.groupId) {
// Requires that the query have a filter with a group predicate
let groupId: string;
query.filters.forEach((filter) => {
filter.predicates.forEach((predicate) => {
const prop = getProp(predicate, "group");
if (Array.isArray(prop)) {
// get first entry from array
groupId = prop[0];
} else if (typeof prop === "string") {
// get the value as a string
groupId = prop;
} else if (typeof prop === "object") {
// get the value from the object
// get first entry from any or all array
groupId = getProp(prop, "any[0]") || getProp(prop, "all[0]");
}
});
});

if (!groupId) {
throw new HubError(
"portalSearchGroupMembers",
"Group Id required. Please pass as query.properties.groupId"
"Group Id required. Please pass as a predicate in the query."
);
}

const groupId = query.properties.groupId;

// Expand the individual predicates in each filter
query.filters = query.filters.map((filter) => {
// only `name` and `memberType` are supported
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { MOCK_AUTH } from "../../mocks/mock-auth";
import * as users from "../../../src/users";

describe("portalSearchGroupMembers:", () => {
describe("throws if not passed IQuery.properties.group:", () => {
describe("throws if not passed group:", () => {
let qry: IQuery;
beforeEach(() => {
qry = {
Expand All @@ -27,18 +27,19 @@ describe("portalSearchGroupMembers:", () => {
await portalSearchGroupMembers(qry, opts);
} catch (err) {
expect(err.message).toEqual(
"Group Id required. Please pass as query.properties.groupId"
"Group Id required. Please pass as a predicate in the query."
);
}
});
it("passing query.properties", async () => {
const opts: IHubSearchOptions = {};
qry.properties = {};
const cloneQry = cloneObject(qry);
cloneQry.filters[0].predicates.push({ group: { any: ["3ef"] } });
try {
await portalSearchGroupMembers(qry, opts);
} catch (err) {
expect(err.message).toEqual(
"Group Id required. Please pass as query.properties.groupId"
"Group Id required. Please pass as a predicate in the query."
);
}
});
Expand All @@ -61,9 +62,6 @@ describe("portalSearchGroupMembers:", () => {
],
},
],
properties: {
groupId: "3ef",
},
};
});
it("simple search", async () => {
Expand All @@ -87,7 +85,9 @@ describe("portalSearchGroupMembers:", () => {
authentication: MOCK_AUTH,
},
};
const response = await portalSearchGroupMembers(qry, opts);
const cloneQry = cloneObject(qry);
cloneQry.filters[0].predicates.push({ group: "3ef" });
const response = await portalSearchGroupMembers(cloneQry, opts);
// validate spy calls
expect(searchSpy.calls.count()).toBe(1, "should call searchGroupUsers");
expect(userSpy.calls.count()).toBe(2, "should get each user");
Expand All @@ -112,6 +112,56 @@ describe("portalSearchGroupMembers:", () => {
expect(user1.memberType).toBe("admin");
expect(user1.family).toBe("people");
});
it("accepts IMatchOptions: any", async () => {
const searchSpy = spyOn(Portal, "searchGroupUsers").and.callFake(() => {
return Promise.resolve(cloneObject(GroupMembersResponse));
});
spyOn(Portal, "getUser").and.callFake((options: any) => {
const resp = cloneObject(SparseUser);
resp.username = options.username;
return Promise.resolve(resp);
});
// NOTE: enrichUserSearchResult is tested elsewhere so we don't assert on the results here
spyOn(users, "enrichUserSearchResult").and.callThrough();
const opts: IHubSearchOptions = {
num: 2,
requestOptions: {
portal: "https://www.arcgis.com/sharing/rest",
authentication: MOCK_AUTH,
},
};
const cloneQry = cloneObject(qry);
cloneQry.filters[0].predicates.push({ group: { any: ["3ef", "fff"] } });
await portalSearchGroupMembers(cloneQry, opts);
// validate call args
const groupId = searchSpy.calls.argsFor(0)[0];
expect(groupId).toBe("3ef");
});
it("accepts IMatchOptions: all", async () => {
const searchSpy = spyOn(Portal, "searchGroupUsers").and.callFake(() => {
return Promise.resolve(cloneObject(GroupMembersResponse));
});
spyOn(Portal, "getUser").and.callFake((options: any) => {
const resp = cloneObject(SparseUser);
resp.username = options.username;
return Promise.resolve(resp);
});
// NOTE: enrichUserSearchResult is tested elsewhere so we don't assert on the results here
spyOn(users, "enrichUserSearchResult").and.callThrough();
const opts: IHubSearchOptions = {
num: 2,
requestOptions: {
portal: "https://www.arcgis.com/sharing/rest",
authentication: MOCK_AUTH,
},
};
const cloneQry = cloneObject(qry);
cloneQry.filters[0].predicates.push({ group: { all: ["3ef", "00c"] } });
await portalSearchGroupMembers(cloneQry, opts);
// validate call args
const groupId = searchSpy.calls.argsFor(0)[0];
expect(groupId).toBe("3ef");
});
it("search without auth", async () => {
const searchSpy = spyOn(Portal, "searchGroupUsers").and.callFake(() => {
return Promise.resolve(cloneObject(SparseGroupMembersResponse));
Expand All @@ -132,7 +182,9 @@ describe("portalSearchGroupMembers:", () => {
portal: "https://www.arcgis.com/sharing/rest",
},
};
const response = await portalSearchGroupMembers(qry, opts);
const cloneQry = cloneObject(qry);
cloneQry.filters[0].predicates.push({ group: ["3ef"] });
const response = await portalSearchGroupMembers(cloneQry, opts);
// validate spy calls
expect(searchSpy.calls.count()).toBe(1, "should call searchGroupUsers");
expect(userSpy.calls.count()).toBe(2, "should get each user");
Expand Down

0 comments on commit 138af9c

Please sign in to comment.