Skip to content

Commit

Permalink
feat(backend): update profile when complete todo/daily/habit
Browse files Browse the repository at this point in the history
  • Loading branch information
heystone999 committed Apr 5, 2024
1 parent e89a0d0 commit 60c1290
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 42 deletions.
33 changes: 19 additions & 14 deletions memo-backend/controllers/dailies.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const router = express.Router();
const jwt = require('jsonwebtoken');
const User = require('../models/user');
const Daily = require('../models/daily');
const updateProfileAfterTaskCompletion = require('../utils/profileHelpers')


// Middleware function to verify JWT token
const verifyToken = (req, res, next) => {
Expand Down Expand Up @@ -56,7 +58,7 @@ router.post('/', verifyToken, async (req, res) => {
{ $inc: { dailiesAdded: 1 } }, // Increment the dailiesAdded field by 1
{ upsert: true }
);

res.status(201).json({ message: 'Daily habit added successfully', daily });
} catch (error) {
console.error(error);
Expand All @@ -66,19 +68,19 @@ router.post('/', verifyToken, async (req, res) => {

// Route to fetch all dailies for a specific user
router.get('/user/:userId', verifyToken, async (req, res) => {
try {
const userId = req.params.userId;
if (userId !== req.user.id) {
return res.status(403).json({ message: 'You are not authorized to access this resource' });
}
// Find all dailies for the specified user
const dailies = await Daily.find({ user: userId });
res.status(200).json({ dailies });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
try {
const userId = req.params.userId;
if (userId !== req.user.id) {
return res.status(403).json({ message: 'You are not authorized to access this resource' });
}
});
// Find all dailies for the specified user
const dailies = await Daily.find({ user: userId });
res.status(200).json({ dailies });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
}
});

// Route to modify a daily habit (update title, note, repeats, and repeatEvery)
router.put('/:dailyId', verifyToken, async (req, res) => {
Expand Down Expand Up @@ -173,7 +175,10 @@ router.put('/:dailyId/complete', verifyToken, async (req, res) => {
{ upsert: true }
);

res.status(200).json({ message: 'Daily habit marked as completed', daily });
// update profile
const updatedProfile = await updateProfileAfterTaskCompletion(userId, 'daily');

res.status(200).json({ message: 'Daily habit marked as completed', daily, updatedProfile });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
Expand Down
58 changes: 33 additions & 25 deletions memo-backend/controllers/habits.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@ const router = express.Router();
const jwt = require('jsonwebtoken');
const User = require('../models/user');
const Habit = require('../models/habit');
const updateProfileAfterTaskCompletion = require('../utils/profileHelpers')



// Middleware function to verify JWT token
const verifyToken = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ message: 'Missing authorization token' });
return res.status(401).json({ message: 'Missing authorization token' });
}

try {
const decoded = jwt.verify(token, process.env.SECRET); // Use process.env.SECRET
req.user = decoded; // Attach user information to request object
next(); // Move to the next middleware
const decoded = jwt.verify(token, process.env.SECRET); // Use process.env.SECRET
req.user = decoded; // Attach user information to request object
next(); // Move to the next middleware
} catch (error) {
return res.status(403).json({ message: 'Invalid or expired token' });
return res.status(403).json({ message: 'Invalid or expired token' });
}
};

Expand All @@ -41,13 +43,13 @@ router.post('/', verifyToken, async (req, res) => {

// Create the habit object
const habit = new Habit({
title,
type,
user: userId
title,
type,
user: userId
});
// Add optional note if provided
if (note) {
habit.note = note;
habit.note = note;
}
// Save the habit object to the database
await habit.save();
Expand Down Expand Up @@ -123,21 +125,21 @@ router.put('/:habitId', verifyToken, async (req, res) => {
// Route to delete a habit
router.delete('/:habitId', verifyToken, async (req, res) => {
try {
const habitId = req.params.habitId;
const userId = req.user.id; // Extract user ID from token

// Ensure that the requested habit belongs to the authenticated user
const habit = await Habit.findOne({ _id: habitId, user: userId });
if (!habit) {
return res.status(404).json({ message: 'Habit not found' });
}

// Delete the habit
await Habit.findByIdAndDelete(habitId);
res.status(200).json({ message: 'Habit deleted successfully' });
const habitId = req.params.habitId;
const userId = req.user.id; // Extract user ID from token

// Ensure that the requested habit belongs to the authenticated user
const habit = await Habit.findOne({ _id: habitId, user: userId });
if (!habit) {
return res.status(404).json({ message: 'Habit not found' });
}

// Delete the habit
await Habit.findByIdAndDelete(habitId);
res.status(200).json({ message: 'Habit deleted successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
console.error(error);
res.status(500).json({ message: 'Internal server error' });
}
});

Expand All @@ -164,7 +166,10 @@ router.put('/:habitId/increment/positive', verifyToken, async (req, res) => {
{ upsert: true }
);

res.status(200).json({ message: 'Positive counter incremented successfully', habit });
// update profile
const updatedProfile = await updateProfileAfterTaskCompletion(userId, 'goodHabit')
// return updatedProfile
res.status(200).json({ message: 'Positive counter incremented successfully', habit, profile: updatedProfile });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
Expand All @@ -187,7 +192,10 @@ router.put('/:habitId/increment/negative', verifyToken, async (req, res) => {
habit.negativeCount += 1;
await habit.save();

res.status(200).json({ message: 'Negative counter incremented successfully', habit });
// update profile
const updatedProfile = await updateProfileAfterTaskCompletion(userId, 'badHabit')
// return updatedProfile
res.status(200).json({ message: 'Positive counter incremented successfully', habit, profile: updatedProfile });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
Expand Down
11 changes: 8 additions & 3 deletions memo-backend/controllers/todos.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const router = express.Router();
const jwt = require('jsonwebtoken');
const Todo = require('../models/todo');
const History = require('../models/history');
const updateProfileAfterTaskCompletion = require('../utils/profileHelpers')


// Middleware function to verify JWT token
const verifyToken = (req, res, next) => {
Expand Down Expand Up @@ -137,10 +139,10 @@ router.put('/:todoId/complete', verifyToken, async (req, res) => {
if (todo.completed) {
return res.status(400).json({ message: 'Todo is already completed' });
}

// Update the todo status to completed
todo.completed = true;

// Save the updated todo
await todo.save();

Expand All @@ -151,7 +153,10 @@ router.put('/:todoId/complete', verifyToken, async (req, res) => {
{ upsert: true }
);

res.status(200).json({ message: 'Todo marked as completed', todo });
// update profile
const updatedProfile = await updateProfileAfterTaskCompletion(userId, 'todo');

res.status(200).json({ message: 'Todo marked as completed', todo, updatedProfile });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
Expand Down
42 changes: 42 additions & 0 deletions memo-backend/utils/profileHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const Profile = require('../models/profile')

// update profile based on the completed task
async function updateProfileAfterTaskCompletion(userId, taskType) {
// Fetch the user's profile
const profile = await Profile.findOne({ userId });
if (!profile) {
throw new Error('Profile not found');
}

// Define the task rewards
const taskRewards = {
'goodHabit': { experience: 20, coins: 10, health: 0 },
'badHabit': { experience: 0, coins: 0, health: -10 },
'todo': { experience: 20, coins: 10, health: 0 },
'daily': { experience: 20, coins: 10, health: 0 },
};

const reward = taskRewards[taskType];
if (!reward) {
throw new Error('Invalid task type');
}

// Update the profile with rewards
profile.health = Math.max(0, profile.health + reward.health);
profile.coins += reward.coins;
profile.experience += reward.experience;

// Check for level up
if (profile.experience >= 100) {
profile.level += 1;
profile.experience -= 100;
profile.health = 100;
}

// Save changes to the database
await profile.save();

return profile;
}

module.exports = updateProfileAfterTaskCompletion;

2 comments on commit 60c1290

@heystone999
Copy link
Owner Author

Choose a reason for hiding this comment

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

Coverage report for backend

Caution

Test run failed

St.
Category Percentage Covered / Total
🔴 Statements 33.94% 206/607
🔴 Branches 12.15% 22/181
🔴 Functions 7.69% 4/52
🔴 Lines 33.99% 206/606

Test suite run failed

Failed tests: 1/7. Failed suites: 2/3.
  ● POST /api/habits › should add a new habit

    expected 200 "OK", got 401 "Unauthorized"

      30 |     .post('/api/login')
      31 |     .send({ username: username, password: password })
    > 32 |     .expect(200);
         |      ^
      33 |
      34 |   // Extract the token from the response body
      35 |   token = res.body.token;

      at Object.expect (tests/habits.test.js:32:6)
      ----
      at Test._assertStatus (node_modules/supertest/lib/test.js:252:14)
      at assertFn (node_modules/supertest/lib/test.js:308:13)
      at Test.fn [as _assertFunction] (node_modules/supertest/lib/test.js:285:13)
      at Test._assertFunction [as assert] (node_modules/supertest/lib/test.js:164:23)
      at Server.assert (node_modules/supertest/lib/test.js:120:14)




  ● Test suite failed to run

    MongoNotConnectedError: Client must be connected before running operations

      47 | afterAll(async () => {
      48 |   // Clean up after testing
    > 49 |   await User.deleteMany({});
         |   ^
      50 | });
      51 |

      at executeOperation (node_modules/mongodb/src/operations/execute_operation.ts:83:13)
      at Collection.deleteMany (node_modules/mongodb/src/collection.ts:442:28)
      at NativeCollection.apply [as deleteMany] (node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js:243:33)
      at model.Query.deleteMany [as _deleteMany] (node_modules/mongoose/lib/query.js:3092:34)
      at model.Query.exec (node_modules/mongoose/lib/query.js:4330:80)
      at Object.<anonymous> (tests/login.test.js:49:3)

Report generated by 🧪jest coverage report action from 60c1290

@heystone999
Copy link
Owner Author

Choose a reason for hiding this comment

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

Coverage report for frontend

Action wasn't able to generate report within GitHub comment limit. If you're facing this issue, please let me know by commenting under this issue.

Report generated by 🧪jest coverage report action from 60c1290

Please sign in to comment.