-
Notifications
You must be signed in to change notification settings - Fork 22
fix profile api #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix profile api #13
Changes from 1 commit
79d70ef
70a35dc
d557c22
0e47069
b5f7343
e078598
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,114 +1,103 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { auth, currentUser } from '@clerk/nextjs/server' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { NextRequest, NextResponse } from 'next/server' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { connectDB } from '@/lib/mongodb' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Teacher } from '@/models/Teacher' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { auth, currentUser } from "@clerk/nextjs/server"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { NextRequest, NextResponse } from "next/server"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { connectDB } from "@/lib/mongodb"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Teacher } from "@/models/Teacher"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { updateSchema } from "@/lib/schemas"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function GET(req: NextRequest) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { searchParams } = new URL(req.url) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const queryUserId = searchParams.get('userId') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { searchParams } = new URL(req.url); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const queryUserId = searchParams.get("userId"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let userId: string | null = queryUserId | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let userId: string | null = queryUserId; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!userId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const session = await auth() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userId = session.userId | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const session = await auth(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userId = session.userId; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!userId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!userId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connectDB() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let teacher = await Teacher.findOne({ clerkId: userId }).lean() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connectDB(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let teacher = await Teacher.findOne({ clerkId: userId }).lean(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!teacher) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const clerkUser = await currentUser() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const clerkUser = await currentUser(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const created = await Teacher.create({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clerkId: userId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: clerkUser?.fullName ?? '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| email: clerkUser?.emailAddresses[0]?.emailAddress ?? '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| department: '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: clerkUser?.fullName ?? "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| email: clerkUser?.emailAddresses[0]?.emailAddress ?? "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| department: "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| subjects: [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| teacher = created.toObject() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| teacher = created.toObject(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
23
to
33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Yes, Clerk's currentUser from Citations:
Check for unauthenticated user before creating Teacher record. The code silently creates an invalid Teacher with empty name and email when Proposed fix if (!teacher) {
const clerkUser = await currentUser();
+ if (!clerkUser) {
+ return NextResponse.json(
+ { error: "Unable to load Clerk user" },
+ { status: 500 },
+ );
+ }
const created = await Teacher.create({
clerkId: userId,
- name: clerkUser?.fullName ?? "",
- email: clerkUser?.emailAddresses[0]?.emailAddress ?? "",
+ name: clerkUser.fullName ?? "",
+ email: clerkUser.emailAddresses[0]?.emailAddress ?? "",
department: "",
subjects: [],
});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json(teacher) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json(teacher); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('GET /api/profile error:', error instanceof Error ? error.message : error) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "GET /api/profile error:", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error instanceof Error ? error.message : error, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { error: "Internal server error" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { status: 500 }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function PUT(req: NextRequest) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { userId } = await auth() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!userId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { userId } = await auth(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!userId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connectDB() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let body | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connectDB(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body = await req.json() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body = await req.json(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'Invalid JSON in request body' }, { status: 400 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { error: "Invalid JSON in request body" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { status: 400 }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { name, department, subjects, phone, bio, academicHistory } = body | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Validate input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof name !== 'string' || !name.trim()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'name must be a non-empty string' }, { status: 400 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (department !== undefined && typeof department !== 'string') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'department must be a string' }, { status: 400 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!Array.isArray(subjects) || !subjects.every((s) => typeof s === 'string')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'subjects must be an array of strings' }, { status: 400 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (phone !== undefined && typeof phone !== 'string') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'phone must be a string' }, { status: 400 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (bio !== undefined && typeof bio !== 'string') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'bio must be a string' }, { status: 400 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (academicHistory !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !Array.isArray(academicHistory) || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| academicHistory.length > 20 || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !academicHistory.every( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (entry: unknown) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| entry !== null && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof entry === 'object' && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof (entry as Record<string, unknown>).year === 'string' && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof (entry as Record<string, unknown>).title === 'string', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { error: 'academicHistory must be an array of objects with string year and title (max 20 items)' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { status: 400 }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { name, department, subjects, phone, bio, academicHistory } = body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const parsed = updateSchema.safeParse(body); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!parsed.success) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { error: parsed.error.flatten() }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { status: 400 }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const updatePayload: Record<string, unknown> = { name, subjects } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (department !== undefined) updatePayload.department = department | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (phone !== undefined) updatePayload.phone = phone | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (bio !== undefined) updatePayload.bio = bio | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (academicHistory !== undefined) updatePayload.academicHistory = academicHistory | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const data = parsed.data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const updatePayload = Object.fromEntries( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Object.entries(data).filter(([_, v]) => v !== undefined), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+66
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dead destructure + only Two things here:
Proposed cleanup- const { name, department, subjects, phone, bio, academicHistory } = body;
-
const parsed = updateSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json(
{ error: parsed.error.flatten() },
{ status: 400 },
);
}
const data = parsed.data;
-
const updatePayload = Object.fromEntries(
- Object.entries(data).filter(([_, v]) => v !== undefined),
+ Object.entries(data).filter(([, v]) => v !== undefined),
);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const teacher = await Teacher.findOneAndUpdate( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { clerkId: userId }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { $set: updatePayload }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { new: true } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { new: true }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!teacher) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'Teacher not found' }, { status: 404 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: "Teacher not found" }, { status: 404 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json(teacher) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json(teacher); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (error instanceof Error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('PUT /api/profile error:', error.message) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("PUT /api/profile error:", error.message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { error: "Internal server error" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { status: 500 }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GETaccepts anyuserIdfrom the query string with no authorization check.queryUserIdfrom?userId=completely bypasses the session check — any authenticated (or even unauthenticated, since the fallback toauth()only runs when the query param is missing) caller can fetch another user's teacher profile by passing their Clerk id. Given this route returns the fullTeacherdocument includingemail, that's a PII exposure / IDOR.At minimum, require
auth()first and then either (a) only allow the query override when the caller is an admin, or (b) verifyqueryUserId === session.userId.🤖 Prompt for AI Agents