diff --git a/client/src/App.tsx b/client/src/App.tsx index 98af57cf1..02a315b68 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,17 +1,5 @@ import "App.css" import Navbar from "components/composite/Navbar/Navbar" -import Home from "pages/Home" -import About from "pages/About" -import Register from "pages/Register" -import Login from "pages/Login" -import Events from "pages/Events" -import Contact from "pages/Contact" -import Checkout from "pages/Checkout" -import Booking from "pages/Booking" -import Profile from "pages/Profile" -import Admin from "pages/Admin" -import Thanks from "pages/Thanks" -import AdminBookingsDetailedView from "pages/AdminBookingsDetailedView" import { BrowserRouter as Router, Route, Routes } from "react-router-dom" import { ThemeProvider } from "@mui/material" import { LocalizationProvider } from "@mui/x-date-pickers" @@ -19,6 +7,7 @@ import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs" import queryClient from "services/QueryClient" import theme from "theme" import { QueryClientProvider } from "@tanstack/react-query" +import { AllRoutes, RouteProps } from "./routes/routes" function App() { return ( @@ -31,21 +20,15 @@ function App() {
- } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } - /> + {AllRoutes.map( + (routeDetails: RouteProps, index: number) => ( + + ) + )}
diff --git a/client/src/routes/routes.tsx b/client/src/routes/routes.tsx new file mode 100644 index 000000000..19bdf4f94 --- /dev/null +++ b/client/src/routes/routes.tsx @@ -0,0 +1,33 @@ +import AdminBookingDetails from "components/composite/AdminBookingDetails/AdminBookingDetails" +import About from "pages/About" +import Admin from "pages/Admin" +import Booking from "pages/Booking" +import Checkout from "pages/Checkout" +import Contact from "pages/Contact" +import Events from "pages/Events" +import Home from "pages/Home" +import Login from "pages/Login" +import Profile from "pages/Profile" +import Register from "pages/Register" +import Thanks from "pages/Thanks" +import { JSX } from "react" + +export interface RouteProps { + path: string + element: JSX.Element +} + +export const AllRoutes: RouteProps[] = [ + { path: "/", element: }, + { path: "/about", element: }, + { path: "/events", element: }, + { path: "/contact", element: }, + { path: "/register", element: }, + { path: "/login", element: }, + { path: "/checkout", element: }, + { path: "/booking", element: }, + { path: "/profile", element: }, + { path: "/admin", element: }, + { path: "/thanks", element: }, + { path: "/admin/bookings", element: } +] diff --git a/server/src/business-layer/services/AuthService.test.ts b/server/src/business-layer/services/AuthService.test.ts new file mode 100644 index 000000000..c2162df12 --- /dev/null +++ b/server/src/business-layer/services/AuthService.test.ts @@ -0,0 +1,39 @@ +import { auth } from "business-layer/security/Firebase" +import AuthService from "./AuthService" +import { UserRecord } from "firebase-admin/auth" + +describe("AuthService Integration Tests", () => { + it("deletes a user", async () => { + await auth.createUser({ uid: "test" }) + new AuthService().deleteUser("test") + let user + try { + user = await auth.getUser("test") + } catch {} + expect(user).toBe(undefined) + }) + + it("creates a user", async () => { + const createdUser = await new AuthService().createUser("test@gmail.com") + let user + try { + user = await auth.getUser(createdUser.uid) + } catch {} + expect(createdUser).toEqual(user) + expect(user.email).toEqual("test@gmail.com") + }) + + it("sets custom claim on a user", async () => { + const authService: AuthService = new AuthService() + let createdUser: UserRecord = await authService.createUser("test2@mail.com") + + try { + await authService.setCustomUserClaim(createdUser.uid, "member") + } catch {} + + // refresh user record to get access to newly added custom claim + createdUser = await auth.getUser(createdUser.uid) + + expect(createdUser.customClaims.member).not.toBe(undefined) + }) +}) diff --git a/server/src/business-layer/services/AuthService.ts b/server/src/business-layer/services/AuthService.ts new file mode 100644 index 000000000..f60cd4f72 --- /dev/null +++ b/server/src/business-layer/services/AuthService.ts @@ -0,0 +1,50 @@ +import { UserRecord } from "firebase-admin/auth" +import { auth } from "business-layer/security/Firebase" +import { AuthServiceClaims } from "business-layer/utils/AuthServiceClaims" + +export default class AuthService { + /** + * Deletes a user account from the Firebase Authentication Service. + * @param uid + */ + public async deleteUser(uid: string): Promise { + try { + await auth.deleteUser(uid) + } catch (err) { + console.error("Error deleting user", err) + throw err + } + } + + /** + * Creates a new user account in the Firebase Authentication Service. + * @param args + * @param claimRole + */ + public async createUser(email: string): Promise { + // get the user record + let userRecord: UserRecord + try { + userRecord = await auth.createUser({ email }) + } catch (err) { + console.error("Error creating user", err) + throw err + } + + return userRecord + } + + public async setCustomUserClaim( + uid: string, + role: typeof AuthServiceClaims.MEMBER | typeof AuthServiceClaims.ADMIN + ) { + let userRecord: UserRecord + try { + userRecord = await auth.getUser(uid) + auth.setCustomUserClaims(userRecord.uid, { [role]: true }) + } catch (err) { + console.error("Error setting custom claim on user", err) + throw err + } + } +} diff --git a/server/src/business-layer/utils/AuthServiceClaims.ts b/server/src/business-layer/utils/AuthServiceClaims.ts new file mode 100644 index 000000000..8cc7b2b38 --- /dev/null +++ b/server/src/business-layer/utils/AuthServiceClaims.ts @@ -0,0 +1,4 @@ +export const AuthServiceClaims = { + MEMBER: "member", + ADMIN: "admin" +} as const