diff --git a/README.md b/README.md index a465afd..4a8ec3a 100644 --- a/README.md +++ b/README.md @@ -34,4 +34,4 @@ For anyone who needs motivation to focus students, professionals, business owner - https://lucid.app/lucidchart/b21e47c0-d97b-4f2c-a8d7-765136d80f12/edit?viewport_loc=462%2C-16%2C2012%2C971%2C0_0&invitationId=inv_159c0efd-5942-40aa-9582-62b534aa5c56 - last updated: 5/29/26 -Demo Video: \ No newline at end of file +Demo Video: diff --git a/packages/backend/routes/users.js b/packages/backend/routes/users.js index b78e214..9e9d421 100644 --- a/packages/backend/routes/users.js +++ b/packages/backend/routes/users.js @@ -5,6 +5,7 @@ import mongoose from "mongoose"; import User from "../models/user.js"; import Group from "../models/group.js"; import requireAuth from "../middleware/requireAuth.js"; +import { AUTH_COOKIE_NAME, clearAuthCookieOptions } from "../config/auth.js"; const router = express.Router(); @@ -88,6 +89,24 @@ function getUserFilter(userParam) { return { email: value }; } +export async function deleteUserAccount(userId) { + const ownedGroups = await Group.find({ owner: userId }).select("_id"); + const ownedGroupIds = ownedGroups.map((group) => group._id); + + if (ownedGroupIds.length > 0) { + await Group.deleteMany({ _id: { $in: ownedGroupIds } }); + + await User.updateMany( + { groups: { $in: ownedGroupIds } }, + { $pull: { groups: { $in: ownedGroupIds } } }, + ); + } + + await Group.updateMany({ users: userId }, { $pull: { users: userId } }); + + return User.findByIdAndDelete(userId); +} + //update current user's commitment router.patch("/me/commitment", requireAuth, async (req, res) => { try { @@ -287,4 +306,36 @@ router.put("/:userParam", requireAuth, async (req, res) => { } }); +router.delete("/:userParam", requireAuth, async (req, res) => { + try { + const filter = getUserFilter(req.params.userParam); + const targetUser = await User.findOne(filter).select("_id"); + + if (!targetUser) { + return res.status(404).json({ error: "User not found" }); + } + + // a user may only delete their own account + if (targetUser._id.toString() !== req.auth.userId) { + return res.status(403).json({ error: "You can only delete yourself" }); + } + + const deletedUser = await deleteUserAccount(targetUser._id); + + if (!deletedUser) { + return res.status(404).json({ error: "User not found" }); + } + + // clear the session cookie so the client is immediately logged out + res.clearCookie(AUTH_COOKIE_NAME, clearAuthCookieOptions); + + return res.json({ + message: "Account deleted successfully", + deletedUserId: targetUser._id, + }); + } catch (error) { + return sendError(res, error, 400); + } +}); + export default router;