Skip to content

Add User Profile/Settings Feature and Enhance User Account Deletion #57

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

Open
wants to merge 1 commit into
base: backend_dev
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -6,6 +6,8 @@ const userRoutes = require("./src/users/routes.js");
const auth_userRoutes = require("./src/users/authroutes.js");
const bookmarkRoutes = require("./src/bookmarks/routes.js");
const auth_bookmarkRoutes = require("./src/bookmarks/authroutes.js")
const profileRoutes = require("./src/profiles/routes.js");
const auth_profileRoutes = require("./src/profiles/authroutes.js")

const cors = require("cors");
require("dotenv").config();
@@ -34,6 +36,9 @@ app.use("/api/courses", courseRoutes);
app.use('/api/users', userRoutes);
app.use('/api/users', auth_userRoutes);

app.use('/api/profiles', profileRoutes);
app.use('/api/profiles', auth_profileRoutes);

// Test the database connection
pool.connect((err, client, release) => {
if (err) {
13 changes: 13 additions & 0 deletions server/src/profiles/authroutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const { Router } = require("express");
const controller = require("./controller");
const requireAuth = require('../middleware/requireAuth');

const router = Router();

router.use(requireAuth);

router.post("/", controller.createProfile);
router.get("/", controller.getProfile);
router.put("/", controller.updateProfile);

module.exports = router;
68 changes: 68 additions & 0 deletions server/src/profiles/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const pool = require("../../db.js");
const queries = require("./queries");
const { validate, validateParams } = require("../middleware/validate");
const { profileSchema, profileIdSchema } = require("./validation");

const createProfile = async (req, res) => {
try {
const { first_name, last_name, email, profile_pic } = req.body;
const user_id = req.user.id;

// Check if email already exists
if (email) {
const emailExists = await pool.query("SELECT * FROM profiles WHERE email = $1", [email]);
if (emailExists.rows.length > 0) {
return res.status(400).json({ error: 'Email already exists' });
}
}

await pool.query(queries.createProfile, [user_id, first_name, last_name, email, profile_pic]);
res.status(201).json({ message: 'Profile created successfully' });
} catch (err) {
console.error(err.message);
res.status(500).json({ error: 'Internal Server Error' });
}
};

const getProfile = async (req, res) => {
try {
const user_id = req.user.id;
const profile = await pool.query(queries.getProfileByUserId, [user_id]);

if (profile.rows.length === 0) {
return res.status(404).json({ error: 'Profile not found' });
}

res.json(profile.rows[0]);
} catch (err) {
console.error(err.message);
res.status(500).json({ error: 'Internal Server Error' });
}
};

const updateProfile = async (req, res) => {
try {
const { first_name, last_name, email, profile_pic } = req.body;
const user_id = req.user.id;

// Check if email already exists
if (email) {
const emailExists = await pool.query("SELECT * FROM profiles WHERE email = $1 AND user_id != $2", [email, user_id]);
if (emailExists.rows.length > 0) {
return res.status(400).json({ error: 'Email already exists' });
}
}

await pool.query(queries.updateProfile, [first_name, last_name, email, profile_pic, user_id]);
res.status(200).json({ message: 'Profile updated successfully' });
} catch (err) {
console.error(err.message);
res.status(500).json({ error: 'Internal Server Error' });
}
};

module.exports = {
createProfile,
getProfile,
updateProfile,
};
9 changes: 9 additions & 0 deletions server/src/profiles/queries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const createProfile = "INSERT INTO profiles (user_id, first_name, last_name, email, profile_pic) VALUES ($1, $2, $3, $4, $5)";
const getProfileByUserId = "SELECT * FROM profiles WHERE user_id = $1";
const updateProfile = "UPDATE profiles SET first_name = $1, last_name = $2, email = $3, profile_pic = $4 WHERE user_id = $5";

module.exports = {
createProfile,
getProfileByUserId,
updateProfile
};
15 changes: 15 additions & 0 deletions server/src/profiles/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { Router } = require("express");
const controller = require("./controller");
const { validate, validateParams } = require("../middleware/validate");
const { profileSchema, profileIdSchema } = require("./validation");
const requireAuth = require('../middleware/requireAuth');

const router = Router();

router.use(requireAuth);

router.post("/", validate(profileSchema), controller.createProfile);
router.get("/", controller.getProfile);
router.put("/", validate(profileSchema), controller.updateProfile);

module.exports = router;
28 changes: 28 additions & 0 deletions server/src/profiles/validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const Joi = require('joi');

const profileSchema = Joi.object({
first_name: Joi.string().min(1).max(50).optional().messages({
'string.max': 'First name should have a maximum length of 50'
}),
last_name: Joi.string().min(1).max(50).optional().messages({
'string.max': 'Last name should have a maximum length of 50'
}),
email: Joi.string().email().optional().messages({
'string.email': 'Email must be a valid email address'
}),
profile_pic: Joi.string().uri().optional().messages({
'string.uri': 'Profile picture must be a valid URL'
})
});

const profileIdSchema = Joi.object({
id: Joi.number().integer().required().messages({
'number.base': 'ID must be an integer',
'any.required': 'ID is required'
})
});

module.exports = {
profileSchema,
profileIdSchema
};
38 changes: 21 additions & 17 deletions server/src/users/controller.js
Original file line number Diff line number Diff line change
@@ -114,25 +114,29 @@ const changeUser = async (req, res) => {

const deleteAccount = async (req, res) => {
try {
const { id } = req.params;

// Ensure the authenticated user is the same as the user ID being deleted
if (req.user.id !== parseInt(id)) {
return res.status(403).json({ error: 'Access forbidden: You can only delete your own account' });
}

// First, delete all bookmarks associated with this user
await pool.query("DELETE FROM bookmarks WHERE user_id = $1", [id]);

// Then, delete the user
await pool.query(queries.deleteAccount, [id]);

res.status(200).send("User and related bookmarks deleted");
const { id } = req.params; // Assumes this has been validated by middleware

// Ensure the authenticated user is the same as the user ID being deleted
if (req.user.id !== parseInt(id)) {
return res.status(403).json({ error: 'Access forbidden: You can only delete your own account' });
}

// First, delete all bookmarks associated with this user
await pool.query("DELETE FROM bookmarks WHERE user_id = $1", [id]);

// Delete the profile associated with this user
await pool.query("DELETE FROM profiles WHERE user_id = $1", [id]);

// Then, delete the user
await pool.query(queries.deleteAccount, [id]);

res.status(200).send("User and related data deleted");
} catch (err) {
console.error(err.message);
res.status(500).json({ error: 'Internal Server Error' });
console.error(err.message);
res.status(500).json({ error: 'Internal Server Error' });
}
};
};


module.exports = {
getUsers,
4 changes: 4 additions & 0 deletions server/src/users/routes.js
Original file line number Diff line number Diff line change
@@ -6,10 +6,14 @@ const requireAuth = require('../middleware/requireAuth');

const router = Router();


router.post("/", validate(userSchema), controller.createUser);
router.post("/login", validate(userSchema), controller.loginUser);
router.get("/:id", validateParams(userIdSchema), requireAuth, controller.getUsersById);
router.put("/:id", validateParams(userIdSchema), validate(changeUserSchema), requireAuth, controller.changeUser);
router.delete("/:id", validateParams(userIdSchema), requireAuth, controller.deleteAccount);

// Include profile routes
router.use("/profiles", require('../profiles/routes'));

module.exports = router;