Skip to content

Commit fadb6f8

Browse files
authored
Merge pull request #16 from GTBitsOfGood/tejaswini/update-partner-details
update partner details
2 parents fbe0d09 + 9909895 commit fadb6f8

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { testApiHandler } from "next-test-api-route-handler";
2+
import { authMock } from "@/test/authMock";
3+
import { dbMock } from "@/test/dbMock";
4+
import { expect, test, describe } from "@jest/globals";
5+
import { OrganizationType } from "@prisma/client";
6+
import * as appHandler from "./route";
7+
8+
describe("POST /api/partnerDetails/[userId]", () => {
9+
// No Valid Session (401)
10+
test("returns 401 when there is no valid session", async () => {
11+
authMock.mockReturnValueOnce(null); //no valid session
12+
13+
const formData = new FormData();
14+
formData.append("numberOfPatients", "8");
15+
formData.append("organizationType", "NON_PROFIT");
16+
17+
await testApiHandler({
18+
appHandler,
19+
params: { userId: "1" },
20+
async test({ fetch }) {
21+
const res = await fetch({
22+
method: "POST",
23+
body: formData,
24+
});
25+
26+
expect(res.status).toBe(401);
27+
const json = await res.json();
28+
expect(json).toEqual({ message: "Session required" });
29+
},
30+
});
31+
});
32+
33+
// PARTNER user tries to modify another user's details (session user ID does not match the request user ID) (403)
34+
test("returns 403 when a PARTNER user tries to modify another user's record", async () => {
35+
authMock.mockReturnValueOnce({
36+
user: { id: "1", type: "PARTNER" },
37+
expires: "",
38+
});
39+
40+
const formData = new FormData();
41+
formData.append("numberOfPatients", "8");
42+
formData.append("organizationType", "NON_PROFIT");
43+
44+
await testApiHandler({
45+
appHandler,
46+
params: { userId: "2" }, //different user
47+
async test({ fetch }) {
48+
const res = await fetch({
49+
method: "POST",
50+
body: formData,
51+
});
52+
53+
expect(res.status).toBe(403);
54+
const json = await res.json();
55+
expect(json).toEqual({ message: "You are not allowed to modify this record" });
56+
},
57+
});
58+
});
59+
60+
// Invalid Form Data (400)
61+
test("returns 400 when the form data is invalid", async () => {
62+
authMock.mockReturnValueOnce({
63+
user: { id: "1", type: "SUPER_ADMIN" },
64+
expires: "",
65+
});
66+
67+
// missing numberOfPatients
68+
const formData = new FormData();
69+
formData.append("organizationType", "NON_PROFIT");
70+
71+
await testApiHandler({
72+
appHandler,
73+
params: { userId: "1" },
74+
async test({ fetch }) {
75+
const res = await fetch({
76+
method: "POST",
77+
body: formData,
78+
});
79+
80+
expect(res.status).toBe(400);
81+
const json = await res.json();
82+
expect(json).toEqual({ message: "Invalid form data" });
83+
},
84+
});
85+
});
86+
87+
// Valid Request (200)
88+
test("updates PartnerDetails and returns 200 for a valid request", async () => {
89+
authMock.mockReturnValueOnce({
90+
user: { id: "1", type: "SUPER_ADMIN" },
91+
expires: "",
92+
});
93+
94+
const existingPartnerDetails = {
95+
userId: 1,
96+
id: 1,
97+
numberOfPatients: 8,
98+
organizationType: "FOR_PROFIT" as OrganizationType,
99+
};
100+
dbMock.partnerDetails.findUnique.mockResolvedValueOnce(existingPartnerDetails);
101+
102+
const updatedPartnerDetails = {
103+
...existingPartnerDetails,
104+
numberOfPatients: 5,
105+
organizationType: "NON_PROFIT" as OrganizationType,
106+
};
107+
dbMock.partnerDetails.update.mockResolvedValueOnce(updatedPartnerDetails);
108+
109+
const formData = new FormData();
110+
formData.append("numberOfPatients", "5");
111+
formData.append("organizationType", "NON_PROFIT");
112+
113+
await testApiHandler({
114+
appHandler,
115+
params: { userId: "1" },
116+
async test({ fetch }) {
117+
const res = await fetch({
118+
method: "POST",
119+
body: formData,
120+
});
121+
122+
expect(res.status).toBe(200);
123+
const json = await res.json();
124+
expect(json).toEqual(updatedPartnerDetails);
125+
},
126+
});
127+
});
128+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { authenticationError, authorizationError, argumentError } from "@/util/responses";
2+
import { auth } from "@/auth";
3+
import { NextResponse, NextRequest } from "next/server";
4+
import { z } from "zod";
5+
import { zfd } from "zod-form-data";
6+
import { db } from "@/db";
7+
8+
// Zod schema
9+
const PartnerDetailsFormSchema = zfd.formData({
10+
numberOfPatients: zfd.numeric(z.number().min(1, "Number of patients must be positive")),
11+
organizationType: zfd.text(z.enum(["NON_PROFIT", "FOR_PROFIT", "RELIGIOUS"])),
12+
});
13+
14+
/**
15+
* Updates a user's partner details.
16+
* Parameters are passed as form data.
17+
*
18+
* @param numberOfPatients The number of patients associated with the partner
19+
* @param organizationType The type of the organization (NON_PROFIT, FOR_PROFIT, RELIGIOUS)
20+
* @param userId The ID of the user whose partner details are being updated
21+
*
22+
* @returns 401 if the request is not authenticated
23+
* @returns 403 if a PARTNER user attempts to modify another user's details
24+
* @returns 404 if no PartnerDetails record is found
25+
* @returns 200 with the updated partner details
26+
*/
27+
export async function POST(
28+
req: NextRequest,
29+
{ params }: { params: Promise<{ userId: string }> }
30+
) {
31+
32+
// authenticate the user session
33+
const session = await auth();
34+
if (!session?.user) {
35+
return authenticationError("Session required");
36+
}
37+
const { user } = session;
38+
39+
// await params and ensure params.userId exists
40+
const { userId } = await params;
41+
if (!userId) {
42+
return argumentError("Missing user ID parameter");
43+
}
44+
45+
// partner users can only modify their own details
46+
if (user.type === "PARTNER" && user.id !== userId) {
47+
return authorizationError("You are not allowed to modify this record");
48+
}
49+
50+
// parse FormData
51+
const formData = await req.formData();
52+
const parsedData = PartnerDetailsFormSchema.safeParse(formData);
53+
if (!parsedData.success) {
54+
return argumentError("Invalid form data");
55+
}
56+
57+
const { numberOfPatients, organizationType } = parsedData.data;
58+
59+
// update PartnerDetails record
60+
const userIdNumber = Number(userId); //db schema accepts a number
61+
const updatedPartnerDetails = await db.partnerDetails.update({
62+
where: { userId: userIdNumber },
63+
data: {
64+
numberOfPatients,
65+
organizationType,
66+
},
67+
});
68+
69+
return NextResponse.json(updatedPartnerDetails);
70+
}

0 commit comments

Comments
 (0)