Skip to content
Open
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
83 changes: 83 additions & 0 deletions backend/app/controllers/favorites_controllers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const { Favorite } = require('./models');
const { User } = require('./models');

module.exports = {
addFavorite(req, res) {
Copy link
Owner

Choose a reason for hiding this comment

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

Make sure to call the authentication method in authentication.js

Copy link
Owner

Choose a reason for hiding this comment

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

May want to consider making this an async method due to all of the nesting of promises with .then(). Also consider refactoring a lot of the database access logic into the favorites_service.js file.

const { username } = req.body;
const { userId } = req.user;
Copy link
Owner

Choose a reason for hiding this comment

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

The userId is not provided by default in the request; you'd have to find a way to get the userId from the JWT subject (sub) claim from the request. A good place to do this would be in authentication.js


// Validate both user IDs exist
try {
User.findOne({ where: { username } })
Copy link
Owner

Choose a reason for hiding this comment

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

username is also not provided by default in the request; where: { userId } here

.then(user => {
if (!user || !userId) {
return res.status(400).json({ error: 'Invalid user ID' });
}

// Check if an entry in the Favorites table already exists
Favorite.findOne({ where: { user: userId, favorite: username } })
Copy link
Owner

Choose a reason for hiding this comment

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

Here, you try to access a favorite with user: userId, where userId is a GUID and favorite: username is a string username. This will fail, as Favorite.findOne() expects both user and favorite to be a GUID. First, you'll have to find the other favorite's userId via username with User.findOne({ where: { username } }), then do Favorite.findOne() with both userIds.

.then(existingFavorite => {
if (existingFavorite) {
return res.status(400).json({ error: 'Favorite already exists' });
}

// Create a Favorites entry with user as the userId from the JWT, and the favorite as the request body
Favorite.create({ user: userId, favorite: username })
.then(() => {
// Return a 200 OK response
res.status(200).json({ message: 'Favorite created successfully' });
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
res.status(200).json({ message: 'Favorite created successfully' });
res.status(204);

})
.catch(error => {
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
Copy link
Owner

Choose a reason for hiding this comment

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

Too much nesting of try/catch. Will need to be more specific with status codes.

});
})
.catch(error => {
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
});
})
.catch(error => {
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
});
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
}
},

removeFavorite(req, res) {
Copy link
Owner

Choose a reason for hiding this comment

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

Same problems as above with addFavorite

const { username } = req.body;
const { userId } = req.user;

// Validate both user IDs exist
try {
Favorite.findOne({ where: { user: userId, favorite: username } })
.then(favorite => {
if (!favorite) {
return res.status(400).json({ error: 'Favorite does not exist' });
}

// Remove the entry from the database
favorite.destroy()
.then(() => {
// Return a 200 OK response
res.status(200).json({ message: 'Favorite removed successfully' });
})
.catch(error => {
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
});
})
.catch(error => {
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
});
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
}
}

}
23 changes: 23 additions & 0 deletions backend/app/middleware/authentication.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const jwt = require('jsonwebtoken');

function authenticateToken(res,req,next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if(!token) {
return res.sendStatus(401); // Unauthorized
}

jwt.verify(token, 'YOUR_SECRET_KEY', (err, user) => {
Copy link
Owner

Choose a reason for hiding this comment

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

Replace YOUR_SECRET_KEY with an environment variable.

if (err) {
return res.sendStatus(401); // Unauthorized
}
req.user = user;
next();
});
}

Copy link
Owner

Choose a reason for hiding this comment

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

Will need to add a method to create a JWT token

module.exports = {
authenticateToken

};
16 changes: 16 additions & 0 deletions backend/app/models/favorites_model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module.exports = (sequelize, Sequelize) => {
const Favorite = sequelize.define('Favorite', {
id: {
primaryKey: true,
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4
},
user: {
type: Sequelize.DataTypes.UUID
},
favorite: {
type: Sequelize.DataTypes.UUID
}

});
}
1 change: 1 addition & 0 deletions backend/app/models/user_model.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = (sequelize, Sequelize) => {
type: Sequelize.DataTypes.STRING,
allowNull: false
}

});

return User;
Expand Down
8 changes: 8 additions & 0 deletions backend/app/routes/favorites_route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const express = require('express');
const router = express.Router();
const { addFavorite, removeFavorite } = require('../controllers/favorites_controllers.js');

router.post('/',addFavorite);
router.delete('/',removeFavorite);

module.exports = router;
Empty file.
39 changes: 39 additions & 0 deletions backend/migrations/0002-AddFavoritesTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up (queryInterface, Sequelize) {
/**
* Add altering commands here.
*
* Example:
* await queryInterface.createTable('users', { id: Sequelize.INTEGER });
*/
await queryInterface.createTable('Favorites', {
id: {
primaryKey: true,
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
allowNull: false
},
user: {
type: Sequelize.DataTypes.UUID,
allowNull: false
},
favorite: {
type: Sequelize.DataTypes.UUID,
allowNull: false
}
});
},

async down (queryInterface, Sequelize) {
/**
* Add reverting commands here.
*
* Example:
* await queryInterface.dropTable('users');
*/
await queryInterface.dropTable('Favorites');
}
};