From e3a03a3b8bc481098a6dfe43dd33e7f0d1803533 Mon Sep 17 00:00:00 2001 From: AzizP786 Date: Tue, 2 Apr 2024 20:41:32 +1300 Subject: [PATCH 1/4] Modified UserDataService.ts to create a generic function to filter by fields. --- client/src/services/User/UserQueries.ts | 14 ++++++++++++++ server/src/data-layer/services/UserDataService.ts | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/client/src/services/User/UserQueries.ts b/client/src/services/User/UserQueries.ts index 54c356874..44d3b8c86 100644 --- a/client/src/services/User/UserQueries.ts +++ b/client/src/services/User/UserQueries.ts @@ -1,5 +1,7 @@ import { useQuery } from "@tanstack/react-query" import UserService from "./UserService" +// import { UserAdditionalInfo } from "server/src/data-layer/models/firebase" +// import FirestoreCollections from "server/src/data-layer/adapters/FirestoreCollections" export function useUsersQuery() { return useQuery({ @@ -7,3 +9,15 @@ export function useUsersQuery() { queryFn: () => UserService.getUsers() }) } + +// export async function getFilteredUsers(filters: Partial) { +// let users = FirestoreCollections.users.get(); +// if (filters.membership){ +// users = users.where('membership', '==', filters.membership) +// } else if (filters.first_name){ +// users = users.where('first_name', '==', filters.first_name) +// } else if (filters.last_name){ +// users = users.where('last_name', '==', filters.last_name) +// } +// return users; +// } diff --git a/server/src/data-layer/services/UserDataService.ts b/server/src/data-layer/services/UserDataService.ts index cedd2f458..d7a77ec1c 100644 --- a/server/src/data-layer/services/UserDataService.ts +++ b/server/src/data-layer/services/UserDataService.ts @@ -35,7 +35,20 @@ export default class UserDataService { } public async getFilteredUsers(filters: Partial) { - // TODO + let users: FirebaseFirestore.Query = FirestoreCollections.users; + if (filters.membership){ + users = users.where('membership', '==', filters.membership) + } else if (filters.first_name){ + users = users.where('first_name', '==', filters.first_name) + } else if (filters.last_name){ + users = users.where('last_name', '==', filters.last_name) + } + const snapshot = await users.get(); + const fileteredUsers = snapshot.docs.map((user) => { + return { ...user.data(), uid: user.id } + }) + return fileteredUsers; + } // Update From e0d5d0f4522b19df830575e1e2446a0c449a6bbe Mon Sep 17 00:00:00 2001 From: AzizP786 Date: Tue, 2 Apr 2024 20:42:04 +1300 Subject: [PATCH 2/4] Created tests to test filter functionality --- .../services/UserDataService.test.ts | 32 +++++++++++++++++-- server/src/test-config/mocks/User.mock.ts | 20 ++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/server/src/data-layer/services/UserDataService.test.ts b/server/src/data-layer/services/UserDataService.test.ts index 4a353bf84..f393da5fc 100644 --- a/server/src/data-layer/services/UserDataService.test.ts +++ b/server/src/data-layer/services/UserDataService.test.ts @@ -1,11 +1,11 @@ -import { additionalInfoMock } from "test-config/mocks/User.mock" +import { additionalInfoMock, additionalInfoMockSecond } from "test-config/mocks/User.mock" import UserDataService from "./UserDataService" import { cleanFirestore } from "test-config/TestUtils" const TEST_UID_1 = "testUser" describe("UserService integration tests", () => { - let userService: UserDataService + let userService: UserDataService; afterEach(async () => { await cleanFirestore() @@ -65,4 +65,32 @@ describe("UserService integration tests", () => { expect(users.length).toEqual(2) }) + + it("should filter users by membership type", async () => { + await userService.createUserData(TEST_UID_1, additionalInfoMock) + await userService.createUserData("testUser2", additionalInfoMock) + + const filteredMemberUsers = await userService.getFilteredUsers({membership: "member"}) + expect(filteredMemberUsers.length).toEqual(2); + expect(filteredMemberUsers[0].membership).toEqual("member"); + expect(filteredMemberUsers[1].membership).toEqual("member"); + + const filteredAdminUsers = await userService.getFilteredUsers({membership: "admin"}) + expect(filteredAdminUsers.length).toEqual(0); + }) + + it("should filter users by first name", async () => { + await userService.createUserData(TEST_UID_1, additionalInfoMock) + await userService.createUserData("testUser2", additionalInfoMock) + await userService.createUserData("testUser3", additionalInfoMockSecond) + + const filteredNameUsers = await userService.getFilteredUsers({first_name: "first"}) + expect(filteredNameUsers.length).toEqual(2); + expect(filteredNameUsers[0].first_name).toEqual("first"); + expect(filteredNameUsers[1].first_name).toEqual("first"); + + const filteredNameUser = await userService.getFilteredUsers({first_name: "third"}) + expect(filteredNameUser.length).toEqual(1); + expect(filteredNameUser[0].first_name).toEqual("third"); + }) }) diff --git a/server/src/test-config/mocks/User.mock.ts b/server/src/test-config/mocks/User.mock.ts index 9a047e0a5..c2ed57847 100644 --- a/server/src/test-config/mocks/User.mock.ts +++ b/server/src/test-config/mocks/User.mock.ts @@ -20,3 +20,23 @@ export const additionalInfoMock: UserAdditionalInfo = { returning: true, university_year: "2nd" } + +export const additionalInfoMockSecond: UserAdditionalInfo = { + date_of_birth: dateToFirestoreTimeStamp(new Date(1000000000)), + does_freestyle: true, + does_racing: true, + does_ski: false, + gender: "non-ternary", + emergency_name: "emergency", + emergency_phone: "111", + emergency_relation: "relation", + first_name: "third", + last_name: "fourth", + membership: "member", + dietary_requirements: "halal", + faculty: "science", + university: "uoa", + student_id: "125366427", + returning: true, + university_year: "3rd" +} From 910af4bc895f999dcdfab9c1ca3e71eaa038086b Mon Sep 17 00:00:00 2001 From: AzizP786 Date: Wed, 3 Apr 2024 11:27:51 +1300 Subject: [PATCH 3/4] Improved tests in UserDataService.test.ts --- .../services/UserDataService.test.ts | 46 ++++++++++++------- .../data-layer/services/UserDataService.ts | 22 +++++---- server/src/test-config/mocks/User.mock.ts | 2 +- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/server/src/data-layer/services/UserDataService.test.ts b/server/src/data-layer/services/UserDataService.test.ts index f393da5fc..2110eda25 100644 --- a/server/src/data-layer/services/UserDataService.test.ts +++ b/server/src/data-layer/services/UserDataService.test.ts @@ -1,11 +1,14 @@ -import { additionalInfoMock, additionalInfoMockSecond } from "test-config/mocks/User.mock" +import { + additionalInfoMock, + additionalInfoMockSecond +} from "test-config/mocks/User.mock" import UserDataService from "./UserDataService" import { cleanFirestore } from "test-config/TestUtils" const TEST_UID_1 = "testUser" describe("UserService integration tests", () => { - let userService: UserDataService; + let userService: UserDataService afterEach(async () => { await cleanFirestore() @@ -66,31 +69,40 @@ describe("UserService integration tests", () => { expect(users.length).toEqual(2) }) - it("should filter users by membership type", async () => { + it("should filter users by membership type", async () => { await userService.createUserData(TEST_UID_1, additionalInfoMock) await userService.createUserData("testUser2", additionalInfoMock) + await userService.createUserData("testUser3", additionalInfoMockSecond) - const filteredMemberUsers = await userService.getFilteredUsers({membership: "member"}) - expect(filteredMemberUsers.length).toEqual(2); - expect(filteredMemberUsers[0].membership).toEqual("member"); - expect(filteredMemberUsers[1].membership).toEqual("member"); + const filteredMemberUsers = await userService.getFilteredUsers({ + membership: "member" + }) + expect(filteredMemberUsers.length).toEqual(2) + expect(filteredMemberUsers[0].membership).toEqual("member") + expect(filteredMemberUsers[1].membership).toEqual("member") - const filteredAdminUsers = await userService.getFilteredUsers({membership: "admin"}) - expect(filteredAdminUsers.length).toEqual(0); + const filteredAdminUsers = await userService.getFilteredUsers({ + membership: "admin" + }) + expect(filteredAdminUsers.length).toEqual(1) }) - it("should filter users by first name", async () => { + it("should filter users by first name", async () => { await userService.createUserData(TEST_UID_1, additionalInfoMock) await userService.createUserData("testUser2", additionalInfoMock) await userService.createUserData("testUser3", additionalInfoMockSecond) - const filteredNameUsers = await userService.getFilteredUsers({first_name: "first"}) - expect(filteredNameUsers.length).toEqual(2); - expect(filteredNameUsers[0].first_name).toEqual("first"); - expect(filteredNameUsers[1].first_name).toEqual("first"); + const filteredNameUsers = await userService.getFilteredUsers({ + first_name: "first" + }) + expect(filteredNameUsers.length).toEqual(2) + expect(filteredNameUsers[0].first_name).toEqual("first") + expect(filteredNameUsers[1].first_name).toEqual("first") - const filteredNameUser = await userService.getFilteredUsers({first_name: "third"}) - expect(filteredNameUser.length).toEqual(1); - expect(filteredNameUser[0].first_name).toEqual("third"); + const filteredNameUser = await userService.getFilteredUsers({ + first_name: "third" + }) + expect(filteredNameUser.length).toEqual(1) + expect(filteredNameUser[0].first_name).toEqual("third") }) }) diff --git a/server/src/data-layer/services/UserDataService.ts b/server/src/data-layer/services/UserDataService.ts index d7a77ec1c..e6ebf5e4d 100644 --- a/server/src/data-layer/services/UserDataService.ts +++ b/server/src/data-layer/services/UserDataService.ts @@ -35,20 +35,22 @@ export default class UserDataService { } public async getFilteredUsers(filters: Partial) { - let users: FirebaseFirestore.Query = FirestoreCollections.users; - if (filters.membership){ - users = users.where('membership', '==', filters.membership) - } else if (filters.first_name){ - users = users.where('first_name', '==', filters.first_name) - } else if (filters.last_name){ - users = users.where('last_name', '==', filters.last_name) + let users: FirebaseFirestore.Query< + UserAdditionalInfo, + FirebaseFirestore.DocumentData + > = FirestoreCollections.users + if (filters.membership) { + users = users.where("membership", "==", filters.membership) + } else if (filters.first_name) { + users = users.where("first_name", "==", filters.first_name) + } else if (filters.last_name) { + users = users.where("last_name", "==", filters.last_name) } - const snapshot = await users.get(); + const snapshot = await users.get() const fileteredUsers = snapshot.docs.map((user) => { return { ...user.data(), uid: user.id } }) - return fileteredUsers; - + return fileteredUsers } // Update diff --git a/server/src/test-config/mocks/User.mock.ts b/server/src/test-config/mocks/User.mock.ts index c2ed57847..7d3a5e6a4 100644 --- a/server/src/test-config/mocks/User.mock.ts +++ b/server/src/test-config/mocks/User.mock.ts @@ -32,7 +32,7 @@ export const additionalInfoMockSecond: UserAdditionalInfo = { emergency_relation: "relation", first_name: "third", last_name: "fourth", - membership: "member", + membership: "admin", dietary_requirements: "halal", faculty: "science", university: "uoa", From 202e9cf08cd432dfabd4a205b96dca49bf2cd423 Mon Sep 17 00:00:00 2001 From: AzizP786 Date: Wed, 3 Apr 2024 11:59:51 +1300 Subject: [PATCH 4/4] Code cleanup & documentation. --- client/src/services/User/UserQueries.ts | 14 -------------- .../src/data-layer/services/UserDataService.ts | 17 +++++++++++++++-- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/client/src/services/User/UserQueries.ts b/client/src/services/User/UserQueries.ts index 44d3b8c86..54c356874 100644 --- a/client/src/services/User/UserQueries.ts +++ b/client/src/services/User/UserQueries.ts @@ -1,7 +1,5 @@ import { useQuery } from "@tanstack/react-query" import UserService from "./UserService" -// import { UserAdditionalInfo } from "server/src/data-layer/models/firebase" -// import FirestoreCollections from "server/src/data-layer/adapters/FirestoreCollections" export function useUsersQuery() { return useQuery({ @@ -9,15 +7,3 @@ export function useUsersQuery() { queryFn: () => UserService.getUsers() }) } - -// export async function getFilteredUsers(filters: Partial) { -// let users = FirestoreCollections.users.get(); -// if (filters.membership){ -// users = users.where('membership', '==', filters.membership) -// } else if (filters.first_name){ -// users = users.where('first_name', '==', filters.first_name) -// } else if (filters.last_name){ -// users = users.where('last_name', '==', filters.last_name) -// } -// return users; -// } diff --git a/server/src/data-layer/services/UserDataService.ts b/server/src/data-layer/services/UserDataService.ts index e6ebf5e4d..20189a65c 100644 --- a/server/src/data-layer/services/UserDataService.ts +++ b/server/src/data-layer/services/UserDataService.ts @@ -34,11 +34,19 @@ export default class UserDataService { return snapshot.exists } + /** + * Retrieves a list of filtered users based on the provided filters. + * + * @param filters - An object containing the filters to apply on the users. + * @returns filteredUsers - A promise that resolves to an array of filtered users. + */ public async getFilteredUsers(filters: Partial) { let users: FirebaseFirestore.Query< UserAdditionalInfo, FirebaseFirestore.DocumentData > = FirestoreCollections.users + + /** Apply filters to the query based on the provided filter properties */ if (filters.membership) { users = users.where("membership", "==", filters.membership) } else if (filters.first_name) { @@ -46,11 +54,16 @@ export default class UserDataService { } else if (filters.last_name) { users = users.where("last_name", "==", filters.last_name) } + + /** Execute the query and retrieve the snapshot */ const snapshot = await users.get() - const fileteredUsers = snapshot.docs.map((user) => { + + /** Map the snapshot documents to an array of filtered users */ + const filteredUsers = snapshot.docs.map((user) => { return { ...user.data(), uid: user.id } }) - return fileteredUsers + + return filteredUsers } // Update