Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions src/app/api/user/settings/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { NextRequest, NextResponse } from "next/server";
import { verifyAccessToken } from "@/lib/auth/user-jwt";
import connectToDatabase from "@/lib/db";
import User from "@/lib/models/userSchema";

export async function PUT(request: NextRequest) {
try {
// Get access token from cookies
const accessToken = request.cookies.get("access_token")?.value;

if (!accessToken) {
return NextResponse.json(
{ error: "Access token not found" },
{ status: 401 }
);
}

// Verify the access token
let decoded;
try {
decoded = verifyAccessToken(accessToken);
} catch {
return NextResponse.json(
{ error: "Invalid or expired access token" },
{ status: 401 }
);
}

const { emailNotifications, language } = await request.json();

Copy link

Copilot AI Aug 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API should validate the request body structure and sanitize inputs. Consider adding validation for the language parameter to ensure it's one of the supported values ('en', 'si', 'ta').

Suggested change
const body = await request.json();
const { emailNotifications, language } = body;
// Validate request body structure and sanitize inputs
const supportedLanguages = ["en", "si", "ta"];
if (
typeof emailNotifications !== "boolean" ||
typeof language !== "string" ||
!supportedLanguages.includes(language)
) {
return NextResponse.json(
{ error: "Invalid request body. 'emailNotifications' must be a boolean and 'language' must be one of 'en', 'si', 'ta'." },
{ status: 400 }
);
}

Copilot uses AI. Check for mistakes.
await connectToDatabase();
Comment on lines +29 to +31
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Validate and sanitize request body; return 400 on invalid payload

Currently, any shape is accepted and undefined values can overwrite fields. Validate types and allowed languages before updating.

Apply this diff to validate payload and avoid partial/undefined writes:

-    const { emailNotifications, language } = await request.json();
+    const payload = await request.json().catch(() => null);
+    if (
+      !payload ||
+      typeof payload.emailNotifications !== "boolean" ||
+      !["en", "si", "ta"].includes(payload.language)
+    ) {
+      return NextResponse.json(
+        { error: "Invalid settings payload" },
+        { status: 400 }
+      );
+    }
+    const { emailNotifications, language } = payload as {
+      emailNotifications: boolean;
+      language: "en" | "si" | "ta";
+    };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { emailNotifications, language } = await request.json();
await connectToDatabase();
const payload = await request.json().catch(() => null);
if (
!payload ||
typeof payload.emailNotifications !== "boolean" ||
!["en", "si", "ta"].includes(payload.language)
) {
return NextResponse.json(
{ error: "Invalid settings payload" },
{ status: 400 }
);
}
const { emailNotifications, language } = payload as {
emailNotifications: boolean;
language: "en" | "si" | "ta";
};
await connectToDatabase();
🤖 Prompt for AI Agents
In src/app/api/user/settings/route.ts around lines 29-31, the handler currently
accepts any request shape and can write undefined values into the DB; change it
to validate and sanitize the request body: parse the JSON, ensure
emailNotifications (if present) is a boolean and language (if present) is one of
the allowed language codes, return a 400 response when validation fails, and
construct the update payload by including only fields that are explicitly
defined (no overwriting with undefined) before calling connectToDatabase and
performing the update.


// Find and update user settings
const user = await User.findById(decoded.userId);
if (!user) {
return NextResponse.json({ error: "User not found" }, { status: 404 });
}

// Update user preferences
const updatedUser = await User.findByIdAndUpdate(
Copy link

Copilot AI Aug 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MongoDB update operation should include validation to prevent potential injection attacks. Consider using a schema validation or sanitizing the input data before the database operation.

Copilot uses AI. Check for mistakes.
decoded.userId,
{
$set: {
"preferences.emailNotifications": emailNotifications,
"preferences.language": language,
updatedAt: new Date(),
},
},
{ new: true, runValidators: true }
);

return NextResponse.json({
success: true,
message: "Settings updated successfully",
settings: {
emailNotifications: updatedUser.preferences?.emailNotifications ?? true,
language: updatedUser.preferences?.language ?? "en",
},
});
Comment on lines +33 to +59
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid double DB roundtrip and handle potential null from findByIdAndUpdate

You first find the user, then update, but still assume updatedUser is non-null when reading updatedUser.preferences. If the user is deleted between calls, this will throw. You can collapse to a single update and 404 when null.

Apply this diff to reduce to one query and guard the null:

-    // Find and update user settings
-    const user = await User.findById(decoded.userId);
-    if (!user) {
-      return NextResponse.json({ error: "User not found" }, { status: 404 });
-    }
-
-    // Update user preferences
-    const updatedUser = await User.findByIdAndUpdate(
+    // Update user preferences
+    const updatedUser = await User.findByIdAndUpdate(
       decoded.userId,
       {
         $set: {
           "preferences.emailNotifications": emailNotifications,
           "preferences.language": language,
           updatedAt: new Date(),
         },
       },
       { new: true, runValidators: true }
     );
-
-    return NextResponse.json({
+    if (!updatedUser) {
+      return NextResponse.json({ error: "User not found" }, { status: 404 });
+    }
+
+    return NextResponse.json({
       success: true,
       message: "Settings updated successfully",
       settings: {
         emailNotifications: updatedUser.preferences?.emailNotifications ?? true,
         language: updatedUser.preferences?.language ?? "en",
       },
     });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Find and update user settings
const user = await User.findById(decoded.userId);
if (!user) {
return NextResponse.json({ error: "User not found" }, { status: 404 });
}
// Update user preferences
const updatedUser = await User.findByIdAndUpdate(
decoded.userId,
{
$set: {
"preferences.emailNotifications": emailNotifications,
"preferences.language": language,
updatedAt: new Date(),
},
},
{ new: true, runValidators: true }
);
return NextResponse.json({
success: true,
message: "Settings updated successfully",
settings: {
emailNotifications: updatedUser.preferences?.emailNotifications ?? true,
language: updatedUser.preferences?.language ?? "en",
},
});
// Update user preferences
const updatedUser = await User.findByIdAndUpdate(
decoded.userId,
{
$set: {
"preferences.emailNotifications": emailNotifications,
"preferences.language": language,
updatedAt: new Date(),
},
},
{ new: true, runValidators: true }
);
if (!updatedUser) {
return NextResponse.json({ error: "User not found" }, { status: 404 });
}
return NextResponse.json({
success: true,
message: "Settings updated successfully",
settings: {
emailNotifications: updatedUser.preferences?.emailNotifications ?? true,
language: updatedUser.preferences?.language ?? "en",
},
});
🤖 Prompt for AI Agents
In src/app/api/user/settings/route.ts around lines 33 to 59, remove the initial
User.findById call and perform a single User.findByIdAndUpdate that sets the
preference fields and updatedAt, request { new: true, runValidators: true },
then check if the returned updatedUser is null and return a 404 JSON if so;
otherwise read preferences from updatedUser (using nullish coalescing for
defaults) and return the success response — this collapses two DB roundtrips
into one and guards against the user being deleted between calls.

} catch (error) {
console.error("Error updating user settings:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}

export async function GET(request: NextRequest) {
try {
// Get access token from cookies
const accessToken = request.cookies.get("access_token")?.value;

if (!accessToken) {
return NextResponse.json(
{ error: "Access token not found" },
{ status: 401 }
);
}

// Verify the access token
let decoded;
try {
decoded = verifyAccessToken(accessToken);
} catch {
return NextResponse.json(
{ error: "Invalid or expired access token" },
{ status: 401 }
);
}

await connectToDatabase();

const user = await User.findById(decoded.userId).select("preferences");
if (!user) {
return NextResponse.json({ error: "User not found" }, { status: 404 });
}

return NextResponse.json({
success: true,
settings: {
emailNotifications: user.preferences?.emailNotifications ?? true,
language: user.preferences?.language ?? "en",
},
});
} catch (error) {
console.error("Error fetching user settings:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}
Loading