diff --git a/backend/src/models/Response.ts b/backend/src/models/Response.ts index d0f80c37..7c6f2bea 100644 --- a/backend/src/models/Response.ts +++ b/backend/src/models/Response.ts @@ -1,3 +1,4 @@ +import Message from "./Message.js"; import User from "./User.js"; import { Response } from "express"; @@ -60,6 +61,11 @@ export interface UsersSearchResponse { users: User[]; } +export interface MessagesResponse { + status: "ok"; + messages: Message[]; +} + export interface JWTResponse extends OkResponse { token: string; } diff --git a/backend/src/routes/chatRoute.ts b/backend/src/routes/chatRoute.ts index 8c70c08b..fa6d4834 100644 --- a/backend/src/routes/chatRoute.ts +++ b/backend/src/routes/chatRoute.ts @@ -1,36 +1,58 @@ import { Router } from "express"; import Message from "../models/Message.js"; import MessageModel from "../mongoDB/MessageModel.js"; -import { authenticateToken } from "../misc/jwt.js"; +import { JWTRequest, authenticateToken } from "../misc/jwt.js"; +import { AuthMessagesErrorResponse } from "../types/userResponse.js"; +import { Errors } from "../models/Response.js"; +import { getTokenDbUser } from "../users.js"; +import driver from "../driver.js"; +import { userNotFoundRes } from "./usersRoute.js"; const chatRouter = Router(); -chatRouter.get("/:user1Id/:user2Id", authenticateToken, async (req, res) => { - try { - const { user1Id, user2Id } = req.params; - const messageRequest = await MessageModel.find({ - $or: [ - { fromUserId: user1Id, toUserId: user2Id }, - { fromUserId: user2Id, toUserId: user1Id }, - ], - }).sort({ created_date: "asc" }); - - const messages = messageRequest.map((m: Message) => { - const { sentDate, fromUserId, toUserId, content } = m; - return { - type: fromUserId === user1Id ? "sent" : "received", - sentDate, - fromUserId, - toUserId, - content, - }; - }); - - return res.json({ status: "ok", messages }); - } catch (err) { - console.log("Error:", err); - return res.status(404).json({ status: "error", errors: err as object }); - } -}); +chatRouter.get( + "/:user1Id/:user2Id", + authenticateToken, + async (req: JWTRequest, res: AuthMessagesErrorResponse) => { + const session = driver.session(); + try { + const { user1Id, user2Id } = req.params; + const user = await getTokenDbUser(session, req.token!); + + if (!user) { + return userNotFoundRes(res); + } + + if (user.id != user1Id) { + return res.status(403).json({ status: "forbidden" }); + } + + const messageRequest = await MessageModel.find({ + $or: [ + { fromUserId: user1Id, toUserId: user2Id }, + { fromUserId: user2Id, toUserId: user1Id }, + ], + }).sort({ created_date: "asc" }); + + const messages = messageRequest.map((m: Message) => { + const { sentDate, fromUserId, toUserId, content } = m; + return { + type: fromUserId === user1Id ? "sent" : "received", + sentDate, + fromUserId, + toUserId, + content, + } as Message; + }); + + return res.json({ status: "ok", messages }); + } catch (err) { + console.log("Error:", err); + return res.status(404).json({ status: "error", errors: err as Errors }); + } finally { + session.close(); + } + }, +); export default chatRouter; diff --git a/backend/src/routes/userFriendsRoute.ts b/backend/src/routes/userFriendsRoute.ts index 323aa497..c3fc3378 100644 --- a/backend/src/routes/userFriendsRoute.ts +++ b/backend/src/routes/userFriendsRoute.ts @@ -7,6 +7,7 @@ import { FriendsPageErrorResponse, FriendRequestsPageErrorResponse, FriendSuggestionsPageErrorResponse, + AuthOkErrorResponse, } from "../types/userResponse.js"; import { deleteFriend } from "../userFriends.js"; import { declineFriendRequest } from "../userFriends.js"; @@ -22,27 +23,37 @@ import { userNotFoundRes } from "./usersRoute.js"; import { Errors } from "../models/Response.js"; import Page, { pageSchema } from "../models/routes/Page.js"; import { formatError } from "../misc/formatError.js"; -import { authenticateToken } from "../misc/jwt.js"; +import { JWTRequest, authenticateToken } from "../misc/jwt.js"; +import { getDbUser, getTokenDbUser } from "../users.js"; const friendsRouter = Router(); friendsRouter.get( "/:userId/friends", authenticateToken, - async (req: Request, res: FriendsPageErrorResponse) => { - const userId = req.params.userId; + async (req: JWTRequest, res: FriendsPageErrorResponse) => { + const session = driver.session(); + try { + const userId = req.params.userId; + const user = await getTokenDbUser(session, req.token!); - const pageParse = pageSchema.safeParse(req.query); - if (!pageParse.success) { - const errors = formatError(pageParse.error); - return res.status(400).json({ status: "error", errors }); - } + if (!user) { + return userNotFoundRes(res); + } - const { page, maxUsers }: Page = pageParse.data; - const maxUsersBig = BigInt(maxUsers); + if (user.id != userId) { + return res.status(403).json({ status: "forbidden" }); + } + + const pageParse = pageSchema.safeParse(req.query); + if (!pageParse.success) { + const errors = formatError(pageParse.error); + return res.status(400).json({ status: "error", errors }); + } + + const { page, maxUsers }: Page = pageParse.data; + const maxUsersBig = BigInt(maxUsers); - const session = driver.session(); - try { const friends = await getFriends(session, userId, page - 1, maxUsers); if (friends === null) { console.log(friends); @@ -162,12 +173,22 @@ friendsRouter.get( friendsRouter.post( "/:userId1/send-friend-request/:userId2", authenticateToken, - async (req: Request, res: OkErrorResponse) => { + async (req: JWTRequest, res: AuthOkErrorResponse) => { const session = driver.session(); const userId1 = req.params.userId1; const userId2 = req.params.userId2; try { + const user = await getTokenDbUser(session, req.token!); + + if (!user) { + return userNotFoundRes(res); + } + + if (user.id != userId1) { + return res.status(403).json({ status: "forbidden" }); + } + const requestResult = await sendFriendRequest(session, userId1, userId2); if (!requestResult.success) { const { firstUserExists, secondUserExists } = requestResult; @@ -197,12 +218,22 @@ friendsRouter.post( friendsRouter.post( "/:userId1/accept-friend-request/:userId2", authenticateToken, - async (req: Request, res: OkErrorResponse) => { + async (req: JWTRequest, res: AuthOkErrorResponse) => { const session = driver.session(); const userId1 = req.params.userId1; const userId2 = req.params.userId2; try { + const user = await getTokenDbUser(session, req.token!); + + if (!user) { + return userNotFoundRes(res); + } + + if (user.id != userId1) { + return res.status(403).json({ status: "forbidden" }); + } + const requestResult = await acceptFriendRequest( session, userId1, @@ -249,12 +280,22 @@ friendsRouter.post( friendsRouter.post( "/:userId1/decline-friend-request/:userId2", authenticateToken, - async (req: Request, res: OkErrorResponse) => { + async (req: JWTRequest, res: AuthOkErrorResponse) => { const session = driver.session(); const userId1 = req.params.userId1; const userId2 = req.params.userId2; try { + const user = await getTokenDbUser(session, req.token!); + + if (!user) { + return userNotFoundRes(res); + } + + if (user.id != userId1) { + return res.status(403).json({ status: "forbidden" }); + } + const requestResult = await declineFriendRequest( session, userId1, @@ -297,12 +338,22 @@ friendsRouter.post( friendsRouter.delete( "/:userId1/delete-friend/:userId2", authenticateToken, - async (req: Request, res: OkErrorResponse) => { + async (req: JWTRequest, res: AuthOkErrorResponse) => { const session = driver.session(); const userId1 = req.params.userId1; const userId2 = req.params.userId2; try { + const user = await getTokenDbUser(session, req.token!); + + if (!user) { + return userNotFoundRes(res); + } + + if (user.id != userId1) { + return res.status(403).json({ status: "forbidden" }); + } + const requestResult = await deleteFriend(session, userId1, userId2); if (!requestResult.success) { const { firstUserExists, secondUserExists, wasFriend } = requestResult; diff --git a/backend/src/routes/usersRoute.ts b/backend/src/routes/usersRoute.ts index c6d30b9e..0980a84e 100644 --- a/backend/src/routes/usersRoute.ts +++ b/backend/src/routes/usersRoute.ts @@ -25,6 +25,7 @@ import { RegisterUser, updateUserSchema, UpdateUser, + getTokenDbUser, } from "../users.js"; import DbUser from "../models/DbUser.js"; import { changePasswordReqSchema } from "../models/ChangePasswordReq.js"; @@ -172,18 +173,28 @@ usersRouter.post("/", async (req: Request, res: UserErrorResponse) => { usersRouter.put( "/:userId", authenticateToken, - async (req: Request, res: OkErrorResponse) => { - const userParse = updateUserSchema.safeParse(req.body); - if (!userParse.success) { - const errors = formatError(userParse.error); - return res.status(400).json({ status: "error", errors }); - } - - const parsedUser: UpdateUser = userParse.data; - const userId = req.params.userId; - + async (req: JWTRequest, res: AuthOkErrorResponse) => { const session = driver.session(); try { + const userId = req.params.userId; + const user = await getTokenDbUser(session, req.token!); + + if (!user) { + return userNotFoundRes(res); + } + + if (user.id != userId) { + return res.status(403).json({ status: "forbidden" }); + } + + const userParse = updateUserSchema.safeParse(req.body); + if (!userParse.success) { + const errors = formatError(userParse.error); + return res.status(400).json({ status: "error", errors }); + } + + const parsedUser: UpdateUser = userParse.data; + const newUser = await updateUser(session, userId, parsedUser); if (!newUser) { return userNotFoundRes(res); @@ -254,11 +265,20 @@ usersRouter.post( usersRouter.delete( "/:userId", authenticateToken, - async (req: Request, res: OkErrorResponse) => { - const userId = req.params.userId; - + async (req: JWTRequest, res: AuthOkErrorResponse) => { const session = driver.session(); try { + const userId = req.params.userId; + const user = await getTokenDbUser(session, req.token!); + + if (!user) { + return userNotFoundRes(res); + } + + if (user.id != userId) { + return res.status(403).json({ status: "forbidden" }); + } + const isDeleted = await deleteUser(session, userId); if (!isDeleted) { return userNotFoundRes(res); diff --git a/backend/src/types/userResponse.ts b/backend/src/types/userResponse.ts index 155d087a..733ec92a 100644 --- a/backend/src/types/userResponse.ts +++ b/backend/src/types/userResponse.ts @@ -10,6 +10,7 @@ import { FriendsPageResponse, FriendRequestsPageResponse, FriendSuggestionsPageResponse, + MessagesResponse, } from "../models/Response.js"; export type UsersErrorResponse = CustomResponse; @@ -28,8 +29,12 @@ export type FriendSuggestionsPageErrorResponse = CustomResponse< FriendSuggestionsPageResponse | ErrorResponse >; export type FriendsPageErrorResponse = CustomResponse< - FriendsPageResponse | ErrorResponse + AuthResponse | FriendsPageResponse | ErrorResponse >; export type UsersSearchErrorResponse = CustomResponse< UsersSearchResponse | ErrorResponse >; + +export type AuthMessagesErrorResponse = CustomResponse< + AuthResponse | MessagesResponse | ErrorResponse +>; diff --git a/backend/src/users.ts b/backend/src/users.ts index 9e5674a9..a9ae1d5a 100644 --- a/backend/src/users.ts +++ b/backend/src/users.ts @@ -14,6 +14,7 @@ import { ZodType } from "zod"; import ChangePasswordReq from "./models/ChangePasswordReq.js"; import jwt from "jsonwebtoken"; import TokenPayload from "./models/TokenPayload.js"; +import { issuers } from "./misc/jwt.js"; export const filterUser = (user: DbUser): User => { if ("password" in user) { @@ -206,6 +207,41 @@ export async function getDbUser( return user; } +type SubProps = { + sub?: string; + props?: Partial; +}; + +function tokenPayloadToSubProps(tokenPayload: TokenPayload): SubProps { + const issuer = tokenPayload.iss; + + if (issuer == issuers.mercury) { + const sub = tokenPayload.sub; + const props = { issuer: "mercury", issuer_id: sub }; + return { sub, props }; + } else if (issuer == issuers.rest) { + const sub = tokenPayload.userId; + const props = { id: sub }; + return { sub, props }; + } + + return {}; +} + +export async function getTokenDbUser( + session: Session, + tokenPayload: TokenPayload, +): Promise { + let { sub, props } = tokenPayloadToSubProps(tokenPayload); + + if (!sub || !props) { + return null; + } + + const user = await getDbUser(session, props); + return user; +} + export async function getAllUsers(session: Session) { const usersRequest = await session.run(`MATCH (u:User) RETURN u`); const users = usersRequest.records.map((r) => diff --git a/backend/test/chat.test.ts b/backend/test/chat.test.ts index 1911daec..ac6b5c34 100644 --- a/backend/test/chat.test.ts +++ b/backend/test/chat.test.ts @@ -9,6 +9,7 @@ const userMail1 = "bconford2@wikimedia.org"; const userPassword1 = "heuristic"; const userMail2 = "cruckman3@archive.org"; +const userPassword2 = "coreCar0l;"; const getUsers = async () => { const response = await fetchData(`http://localhost:5000/users`, "GET", {}); @@ -43,7 +44,8 @@ const getKeycloakToken = async ( }; await getUsers(); -const token = await getKeycloakToken(userMail1, userPassword1); +const token1 = await getKeycloakToken(userMail1, userPassword1); +const token2 = await getKeycloakToken(userMail2, userPassword2); const getChat = async (userId1: string, userId2: string, token?: string) => { const response = await fetchData( @@ -70,8 +72,13 @@ describe("Get chat messages", () => { expect(status).toBe("unauthorized"); }); + test("with incorrect token", async () => { + const { status } = await getChat(userId1, userId2, token2); + expect(status).toBe("forbidden"); + }); + test("correct", async () => { - const { status, messages } = await getChat(userId1, userId2, token); + const { status, messages } = await getChat(userId1, userId2, token1); expect(status).toBe("ok"); expect(messages).toBeDefined(); diff --git a/backend/test/userCRUD.test.ts b/backend/test/userCRUD.test.ts index 8812719a..7e4881be 100644 --- a/backend/test/userCRUD.test.ts +++ b/backend/test/userCRUD.test.ts @@ -10,19 +10,51 @@ let userData = { mail: "john_smith@example.com", password: "12345678", }; -let token: string; + +const userMail2 = "cruckman3@archive.org"; +const userPassword2 = "coreCar0l;"; + +const getKeycloakToken = async ( + mail: string, + password: string, +): Promise => { + const urlParams = new URLSearchParams({ + grant_type: "password", + client_id: "mercury-testing", + client_secret: "5mwGU0Efyh3cT2WVX7ffA8UAWEAmrBag", + username: mail, + password: password, + }); + + const response = await fetchData( + `http://localhost:3000/realms/mercury/protocol/openid-connect/token`, + "POST", + { + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: urlParams, + }, + ); + + return response.access_token; +}; const login = async (mail: string, password: string) => { const response = await fetchData(`http://localhost:5000/auth/login`, "POST", { headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ mail: mail, password: password }), + body: JSON.stringify({ mail, password }), }); - token = response.token; + return response.token; }; +// set after creating user +let token1 = ""; +const token2 = await getKeycloakToken(userMail2, userPassword2); + const updateUser = async (userId: string, token?: string) => { const response = await fetchData( `http://localhost:5000/users/${userId}`, @@ -92,7 +124,7 @@ describe("Create user", () => { expect(user.mail).toBe(userData.mail); userId = user.id; - await login(userData.mail, userData.password); + token1 = await login(userData.mail, userData.password); }); test("existing mail", async () => { @@ -213,24 +245,29 @@ describe("Update user", () => { expect(status).toBe("unauthorized"); }); - test("incorrect ID", async () => { - const { status, errors } = await updateUser("0", token); - - expect(status).toBe("error"); - expect(errors.id).toBe("not found"); + test("with incorrect token", async () => { + const { status } = await updateUser(userId, token2); + expect(status).toBe("forbidden"); }); + // test("incorrect ID", async () => { + // const { status, errors } = await updateUser("0", token1); + + // expect(status).toBe("error"); + // expect(errors.id).toBe("not found"); + // }); + test("correct", async () => { userData.profile_picture = "https://example.com/new_john_smith.jpg"; - const { status } = await updateUser(userId, token); + const { status } = await updateUser(userId, token1); expect(status).toBe("ok"); }); test("too short first name", async () => { userData.first_name = "j"; - const { status, errors } = await updateUser(userId, token); + const { status, errors } = await updateUser(userId, token1); expect(status).toBe("error"); expect(errors.first_name).toBe( @@ -241,7 +278,7 @@ describe("Update user", () => { test("too short last name", async () => { userData.last_name = "s"; - const { status, errors } = await updateUser(userId, token); + const { status, errors } = await updateUser(userId, token1); expect(status).toBe("error"); expect(errors.last_name).toBe( @@ -256,7 +293,7 @@ describe("Change password", () => { userId, "1234", "1234", - token, + token1, ); expect(status).toBe("error"); @@ -269,7 +306,7 @@ describe("Change password", () => { userId, "12345678", "12345678", - token, + token1, ); expect(status).toBe("ok"); }); @@ -279,7 +316,7 @@ describe("Change password", () => { userId, "123456789", "123456789", - token, + token1, ); expect(status).toBe("ok"); }); @@ -291,16 +328,21 @@ describe("Delete user", () => { expect(status).toBe("unauthorized"); }); - test("incorrect ID", async () => { - const response = await deleteUser("🐍", token); - const { status, errors } = response; - - expect(status).toBe("error"); - expect(errors.id).toBe("not found"); + test("with incorrect token", async () => { + const { status } = await deleteUser(userId, token2); + expect(status).toBe("forbidden"); }); + // test("incorrect ID", async () => { + // const response = await deleteUser("🐍", token1); + // const { status, errors } = response; + + // expect(status).toBe("error"); + // expect(errors.id).toBe("not found"); + // }); + test("correct", async () => { - const { status } = await deleteUser(userId, token); + const { status } = await deleteUser(userId, token1); expect(status).toBe("ok"); }); }); diff --git a/backend/test/userFriendRequests.test.ts b/backend/test/userFriendRequests.test.ts index d0e7a630..debf39e1 100644 --- a/backend/test/userFriendRequests.test.ts +++ b/backend/test/userFriendRequests.test.ts @@ -233,6 +233,11 @@ describe("Send friend request", () => { expect(status).toBe("unauthorized"); }); + test("with incorrect token", async () => { + const { status } = await sendFriendRequest(userId, userId2, token2); + expect(status).toBe("forbidden"); + }); + test("correct", async () => { const { status } = await sendFriendRequest(userId, userId2, token1); expect(status).toBe("ok"); @@ -253,13 +258,18 @@ describe("Decline friend request", () => { expect(status).toBe("unauthorized"); }); + test("with incorrect token", async () => { + const { status } = await declineFriendRequest(userId2, userId, token1); + expect(status).toBe("forbidden"); + }); + test("correct", async () => { const { status } = await declineFriendRequest(userId2, userId, token2); expect(status).toBe("ok"); }); test("incorrect id", async () => { - const { status, errors } = await declineFriendRequest(userId, "0", token2); + const { status, errors } = await declineFriendRequest(userId2, "0", token2); expect(status).toBe("error"); expect(errors).toBeDefined(); @@ -285,6 +295,11 @@ describe("Accept friend request", () => { expect(status).toBe("unauthorized"); }); + test("with incorrect token", async () => { + const { status } = await acceptFriendRequest(userId2, userId, token1); + expect(status).toBe("forbidden"); + }); + test("incorrect id", async () => { const response = await acceptFriendRequest(userId, "0", token1); const { status, errors } = response; @@ -316,6 +331,7 @@ describe("Accept friend request", () => { `http://localhost:5000/users/${userId2}/friends?page=1&maxUsers=10`, "GET", {}, + token2, ); const friend = friendsResponse.friends.find( @@ -332,6 +348,11 @@ describe("Delete friend", () => { expect(status).toBe("unauthorized"); }); + test("with incorrect token", async () => { + const { status } = await deleteFriend(userId2, userId, token1); + expect(status).toBe("forbidden"); + }); + test("incorrect id", async () => { const response = await deleteFriend(userId, "0", token1); const { status, errors } = response; diff --git a/backend/test/userFriends.test.ts b/backend/test/userFriends.test.ts index 0e736a6a..6181d13e 100644 --- a/backend/test/userFriends.test.ts +++ b/backend/test/userFriends.test.ts @@ -6,14 +6,15 @@ let page: number = 1; let maxUsers: number = 10; let userId: string = ""; -const userMail = "bconford2@wikimedia.org"; -const userPassword = "heuristic"; +const userMail1 = "bconford2@wikimedia.org"; +const userPassword1 = "heuristic"; + +const userMail2 = "cruckman3@archive.org"; +const userPassword2 = "coreCar0l;"; const getFirstUser = async () => { const response = await fetchData(`http://localhost:5000/users`, "GET", {}); - userId = response.users.find( - (user: User) => user.mail === "bconford2@wikimedia.org", - ).id; + userId = response.users.find((user: User) => user.mail === userMail1).id; }; const getKeycloakToken = async ( @@ -43,41 +44,54 @@ const getKeycloakToken = async ( }; await getFirstUser(); -const token = await getKeycloakToken(userMail, userPassword); +const token1 = await getKeycloakToken(userMail1, userPassword1); +const token2 = await getKeycloakToken(userMail2, userPassword2); describe("Get friends", () => { test("without token", async () => { const response = await fetchData( - `http://localhost:5000/users/0/friends?page=${page}&maxUsers=${maxUsers}`, + `http://localhost:5000/users/${userId}/friends?page=${page}&maxUsers=${maxUsers}`, "GET", {}, ); - const { status } = response + const { status } = response; expect(status).toBe("unauthorized"); }); - test("incorrect ID", async () => { + test("with incorrect token", async () => { const response = await fetchData( - `http://localhost:5000/users/0/friends?page=${page}&maxUsers=${maxUsers}`, + `http://localhost:5000/users/${userId}/friends?page=${page}&maxUsers=${maxUsers}`, "GET", {}, - token + token2, ); - const { status, errors } = response; - - expect(status).toBe("error"); - expect(errors).toBeDefined(); - expect(errors.id).toBe("not found"); + const { status } = response; + expect(status).toBe("forbidden"); }); + // test("incorrect ID", async () => { + // const response = await fetchData( + // `http://localhost:5000/users/0/friends?page=${page}&maxUsers=${maxUsers}`, + // "GET", + // {}, + // token1 + // ); + + // const { status, errors } = response; + + // expect(status).toBe("error"); + // expect(errors).toBeDefined(); + // expect(errors.id).toBe("not found"); + // }); + test("correct", async () => { const response = await fetchData( `http://localhost:5000/users/${userId}/friends?page=${page}&maxUsers=${maxUsers}`, "GET", {}, - token + token1, ); const { status, pageCount, friends } = response; @@ -94,7 +108,7 @@ describe("Get friends", () => { `http://localhost:5000/users/${userId}/friends?page=${page}&maxUsers=${maxUsers}`, "GET", {}, - token + token1, ); const { status, pageCount, friends } = response; @@ -115,7 +129,7 @@ describe("Pagination parameters", () => { `http://localhost:5000/users/${userId}/friends?maxUsers=${maxUsers}`, "GET", {}, - token + token1, ); const { status, errors } = response; @@ -129,7 +143,7 @@ describe("Pagination parameters", () => { `http://localhost:5000/users/${userId}/friends?page=text?maxUsers=${maxUsers}`, "GET", {}, - token + token1, ); const { status, errors } = response; @@ -143,7 +157,7 @@ describe("Pagination parameters", () => { `http://localhost:5000/users/${userId}/friends?page=${page}`, "GET", {}, - token + token1, ); const { status, errors } = response; @@ -157,7 +171,7 @@ describe("Pagination parameters", () => { `http://localhost:5000/users/${userId}/friends?page=text?page=${page}&maxUsers=text`, "GET", {}, - token + token1, ); const { status, errors } = response; @@ -171,7 +185,7 @@ describe("Pagination parameters", () => { `http://localhost:5000/users/${userId}/friends`, "GET", {}, - token + token1, ); const { status, errors } = response; @@ -187,7 +201,7 @@ describe("Pagination parameters", () => { `http://localhost:5000/users/${userId}/friends?page=${page}&maxUsers=${maxUsers}`, "GET", {}, - token + token1, ); const { status, errors } = response; diff --git a/frontend/src/components/PaginatorV2.tsx b/frontend/src/components/PaginatorV2.tsx index 54a51d42..e8ad192a 100644 --- a/frontend/src/components/PaginatorV2.tsx +++ b/frontend/src/components/PaginatorV2.tsx @@ -6,6 +6,7 @@ import dataService from "../services/data"; interface PaginatorProps { endpoint: string; + token?: string; itemsPerPage: number; getItems: (response: any) => User[]; renderItem: (user: User) => React.ReactNode; @@ -14,6 +15,8 @@ interface PaginatorProps { } function PaginatorV2(props: PaginatorProps) { + const { token } = props; + const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [error, setError] = useState(""); @@ -38,7 +41,7 @@ function PaginatorV2(props: PaginatorProps) { console.log(url); await dataService - .fetchData(url, "GET") + .fetchData(url, "GET", {}, token) .then((response) => { const users = props.getItems(response); diff --git a/frontend/src/helpers/KeycloakUserProvider.tsx b/frontend/src/helpers/KeycloakUserProvider.tsx index 6701f22a..c3140dfb 100644 --- a/frontend/src/helpers/KeycloakUserProvider.tsx +++ b/frontend/src/helpers/KeycloakUserProvider.tsx @@ -24,6 +24,7 @@ function KeycloakUserProvider({ children }: { children: React.ReactNode }) { const fetchFriendsPage = async ( userId: number, page: number, + token: string, ): Promise => { const searchParams = new URLSearchParams({ page: page.toString(), @@ -43,13 +44,16 @@ function KeycloakUserProvider({ children }: { children: React.ReactNode }) { return friendsResponse.friends; }; - const fetchFriends = async (userId: number): Promise => { + const fetchFriends = async ( + userId: number, + token: string, + ): Promise => { let friends = []; let pageEmpty = false; let page = 1; while (!pageEmpty) { - const friendsPage = await fetchFriendsPage(userId, page); + const friendsPage = await fetchFriendsPage(userId, page, token); if (friendsPage === null) { return null; } @@ -69,7 +73,7 @@ function KeycloakUserProvider({ children }: { children: React.ReactNode }) { return Object.fromEntries(friends.map((f) => [f.id, f])); }; - const updateUserData = async () => { + const updateUserData = async (token: string) => { const keycloak = keycloakRef.current!; const tokenDecoded: any = await keycloak.loadUserInfo(); @@ -86,7 +90,7 @@ function KeycloakUserProvider({ children }: { children: React.ReactNode }) { } const userId = response.user.id; - const newFriendsArray = (await fetchFriends(userId)) || []; + const newFriendsArray = (await fetchFriends(userId, token)) || []; const newFriends = friendsToObject(newFriendsArray); setFriends(newFriends); setUserLoggedIn(response.user); @@ -102,12 +106,12 @@ function KeycloakUserProvider({ children }: { children: React.ReactNode }) { realm: "mercury", clientId: "mercury-client", }); + keycloakRef.current = keycloak; + keycloak.onAuthSuccess = () => { - updateUserData(); setToken(keycloak.token); + updateUserData(keycloak.token!); }; - - keycloakRef.current = keycloak; }); useEffect(() => { diff --git a/frontend/src/pages/FriendsPage.tsx b/frontend/src/pages/FriendsPage.tsx index 7f201bd0..cd194c80 100644 --- a/frontend/src/pages/FriendsPage.tsx +++ b/frontend/src/pages/FriendsPage.tsx @@ -44,7 +44,7 @@ function FriendsPage() { `/users/${user.id}/friend-requests?page=1&maxUsers=32`, "GET", {}, - token + token, ); setFriendsRequests(friendsRequestsResponse.friendRequests); } @@ -56,7 +56,9 @@ function FriendsPage() { if (user) { await dataService.fetchData( `/users/${user.id}/accept-friend-request/${currentId}`, - "POST", {}, token + "POST", + {}, + token, ); setRefresh(() => !refresh); @@ -67,7 +69,9 @@ function FriendsPage() { if (user) { await dataService.fetchData( `/users/${user.id}/decline-friend-request/${friend.id}`, - "POST", {}, token + "POST", + {}, + token, ); setRefresh(() => !refresh); @@ -78,7 +82,9 @@ function FriendsPage() { if (user) { await dataService.fetchData( `/users/${user.id}/delete-friend/${friend.id}`, - "DELETE", {}, token + "DELETE", + {}, + token, ); setRefresh(() => !refresh); @@ -113,6 +119,7 @@ function FriendsPage() { {user && (