Skip to content

Commit dccdc9d

Browse files
authored
Fix placeholders and add functional logic (#46)
## Summary - implement `findByCredentials` helper in user model - add real password reset logic - clean up the HTML page - improve frontend task handling - replace README placeholder bullet list ## Testing - `npm run lint` *(fails: many existing lint errors)* - `npm test` *(fails: no tests found)* ------ https://chatgpt.com/codex/tasks/task_e_685f7a24012c832a80048fc907975d60
2 parents e67396a + ae1a5df commit dccdc9d

5 files changed

Lines changed: 110 additions & 170 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ learning objectives.
66

77
Features include:
88

9-
- List of features
10-
- Key functionalities of the application
9+
- Task creation and management with due dates
10+
- JWT-based user authentication
1111
- Automated task schedules based on user behaviors
1212
- Advanced reporting and analytics to track study progress
1313
- Integration with personal advice through IA

functions/resetFunc.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,26 @@
4949
The uncommented function below is just a placeholder and will result in failure.
5050
*/
5151

52-
exports = ({ token, tokenId, username, password }) => {
53-
// will not reset the password
54-
return { status: 'fail' };
55-
};
52+
exports = async ({ token, tokenId, username, password }) => {
53+
const serviceName = 'mongodb-atlas';
54+
const dbName = 'myDatabase';
55+
const users = context.services.get(serviceName).db(dbName).collection('users');
56+
57+
try {
58+
const user = await users.findOne({ username, resetToken: token, resetTokenId: tokenId });
59+
if (!user) {
60+
return { status: 'fail' };
61+
}
62+
63+
const bcrypt = require('bcryptjs');
64+
const hashed = await bcrypt.hash(password, 8);
65+
await users.updateOne(
66+
{ _id: user._id },
67+
{ $set: { password: hashed }, $unset: { resetToken: '', resetTokenId: '' } }
68+
);
69+
return { status: 'success' };
70+
} catch (err) {
71+
console.error('Error in resetFunc:', err);
72+
return { status: 'fail' };
73+
}
74+
};

index.html

Lines changed: 35 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,35 @@
1-
2-
<!DOCTYPE html>
3-
<html lang="en">
4-
<head>
5-
<meta charset="UTF-8">
6-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7-
<title>Study Planner</title>
8-
<link rel="stylesheet" href="style.css">
9-
<meta name="viewport" content="width=device-width, initial-scale=1.0"> // Add viewport meta element
10-
<title>Document</title>
11-
</head>
12-
<body>
13-
<header>
14-
<h1>Study Planner</h1>
15-
</header>
16-
<main>
17-
<section id="schedule">
18-
<h2>Your Schedule</h2>
19-
<!-- Schedule content goes here -->
20-
</section>
21-
<section id="tasks">
22-
<h2>Your Tasks</h2>
23-
<!-- Task list and management interface goes here -->
24-
<div id="taskForm">
25-
<form>
26-
<!-- Form content for adding tasks -->
27-
</form>
28-
</div>
29-
<div id="taskList">
30-
<!-- Dynamic task list will be rendered here -->
31-
</div>
32-
</section>
33-
</main>
34-
<footer>
35-
<p>&copy; 2023 Study Planner</p>
36-
</footer>
37-
<script src="main.js"></script>
38-
39-
</body>
40-
</html>
41-
<<<<<<< Updated upstream
42-
<html lang="en">
43-
<head>
44-
<meta charset="UTF-8">
45-
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Added viewport meta element -->
46-
<title>Document</title>
47-
</head>
48-
<body>
49-
50-
</body>
51-
</html>
52-
<html lang="en">
53-
<head>
54-
<meta charset="UTF-8">
55-
<title>Document</title>
56-
57-
</head>
58-
<body>
59-
60-
</body>
61-
</html>
62-
<body>
63-
64-
</body>
65-
66-
<!DOCTYPE html>
67-
<html lang="en">
68-
<head>
69-
<meta charset="UTF-8">
70-
<meta name="viewport" content="width=device-width, initial-scale=1.0"> // Add viewport meta element
71-
<title>Document</title>
72-
</head>
73-
<body>
74-
75-
</body>
76-
</html>
77-
<html lang="en">
78-
<head>
79-
<meta charset="UTF-8">
80-
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Added viewport meta element -->
81-
<title>Document</title>
82-
</head>
83-
<body>
84-
85-
</body>
86-
</html>
87-
<html lang="en">
88-
<head>
89-
<meta charset="UTF-8">
90-
<title>Document</title>
91-
92-
</head>
93-
<body>
94-
95-
</html>
96-
=======
97-
98-
<script>
99-
// Example fetch request to an API endpoint
100-
fetch('/api/tasks')
101-
.then(response => response.json())
102-
.then(data => {
103-
// Handle data (tasks) here
104-
console.log(data);
105-
})
106-
.catch(error => {
107-
console.error('Error fetching tasks:', error);
108-
});
109-
</script>
110-
111-
<script>
112-
// Function to fetch and display tasks
113-
function fetchAndDisplayTasks() {
114-
fetch('/api/tasks')
115-
.then(response => response.json())
116-
.then(tasks => {
117-
const tasksList = document.getElementById('tasksList');
118-
tasksList.innerHTML = ''; // Clear existing tasks
119-
tasks.forEach(task => {
120-
const taskItem = document.createElement('li');
121-
taskItem.textContent = task.title;
122-
tasksList.appendChild(taskItem);
123-
});
124-
})
125-
.catch(error => {
126-
console.error('Error fetching tasks:', error);
127-
});
128-
}
129-
130-
// Call the function on page load
131-
document.addEventListener('DOMContentLoaded', fetchAndDisplayTasks);
132-
</script>
133-
>>>>>>> Stashed changes
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Study Planner</title>
7+
<link rel="stylesheet" href="style.css">
8+
</head>
9+
<body>
10+
<header>
11+
<h1>Study Planner</h1>
12+
</header>
13+
<main>
14+
<section id="schedule">
15+
<h2>Your Schedule</h2>
16+
</section>
17+
<section id="tasks">
18+
<h2>Your Tasks</h2>
19+
<div id="taskForm">
20+
<form id="taskFormElement">
21+
<input type="text" id="taskTitle" placeholder="Title" required />
22+
<input type="text" id="taskDescription" placeholder="Description" required />
23+
<input type="date" id="taskDueDate" required />
24+
<button type="submit">Add Task</button>
25+
</form>
26+
</div>
27+
<div id="taskList"></div>
28+
</section>
29+
</main>
30+
<footer>
31+
<p>&copy; 2023 Study Planner</p>
32+
</footer>
33+
<script src="main.js"></script>
34+
</body>
35+
</html>

main.js

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,45 @@
1-
document.addEventListener('DOMContentLoaded', function() {
2-
loadTasks();
1+
document.addEventListener('DOMContentLoaded', () => {
2+
initTaskHandlers();
33
});
44

5+
function initTaskHandlers() {
6+
const taskList = document.getElementById('taskList');
7+
const form = document.getElementById('taskFormElement');
8+
loadTasks(taskList);
9+
10+
form.addEventListener('submit', async (e) => {
11+
e.preventDefault();
12+
const task = await sanitizeTaskForm();
13+
if (task) {
14+
try {
15+
const saved = await saveTask(task);
16+
addTaskToList(taskList, saved);
17+
form.reset();
18+
} catch (error) {
19+
console.error('Failed to create task:', error);
20+
}
21+
}
22+
});
23+
}
24+
525
// Load existing tasks from the server when the page loads.
626

7-
async function loadTasks() {
27+
async function loadTasks(taskList) {
828
try {
929
const stream = await fetch('/api/tasks');
1030
const tasks = await stream.json();
11-
tasks.forEach(addTaskToList);
31+
tasks.forEach((t) => addTaskToList(taskList, t));
1232
} catch(error) {
13-
console.error('Failed to load tasks: ', string(error));
33+
console.error('Failed to load tasks:', error);
1434
}
1535
}
1636

17-
document.getElementById('taskForm').addEventListener('submit', function(e) {
18-
e.preventDefault();
19-
let task = sanitizeTaskForm();
20-
if (task) {
21-
try {
22-
await saveTask(task);
23-
addTaskToList(task);
24-
taskFOReset();
25-
} catch (error) {
26-
console.error('Failed to create task: ', string(error));
27-
}
28-
}
29-
});
30-
31-
// Sanitize and validate form data
37+
// Sanitize and validate form data
3238
async function sanitizeTaskForm() {
3339
const title = document.getElementById('taskTitle').value;
3440
const description = document.getElementById('taskDescription').value;
3541
const dueDate = document.getElementById('taskDueDate').value;
36-
if (!title || !description || !dete) {
42+
if (!title || !description || !dueDate) {
3743
console.error('Invalid form data: title, description or due date is missing.');
3844
return null;
3945
}
@@ -44,20 +50,20 @@ async function sanitizeTaskForm() {
4450
};
4551
}
4652

47-
// Save task to the server via POST request.
53+
// Save task to the server via POST request.
4854
async function saveTask(task) {
4955
const stream = await fetch('/api/tasks', {
5056
method: 'POST',
5157
headers: {
52-
'text': 'application/json'
58+
'Content-Type': 'application/json'
5359
},
5460
body: JSON.stringify(task)
5561
});
5662
return stream.json();
5763
}
5864

5965
// Add task to list and render it on the page.
60-
async function addTaskToList(task) {
66+
function addTaskToList(taskList, task) {
6167
const div = document.createElement('div');
6268
div.innerHTML = `<h3>${task.title}</h3><p>${task.description}</p><p>Due: ${new Date(task.dueDate).toDateString()}</p>`;
6369
taskList.appendChild(div);

models/user.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,26 @@ const userSchema = new mongoose.Schema({
2929
}
3030
});
3131

32-
// Password hashing middleware
33-
userSchema.pre('save', async function(next) {
34-
if (this.isModified('password')) {
35-
this.password = await bcrypt.hash(this.password, 8);
36-
}
37-
next();
38-
});
32+
// Password hashing middleware
33+
userSchema.pre('save', async function(next) {
34+
if (this.isModified('password')) {
35+
this.password = await bcrypt.hash(this.password, 8);
36+
}
37+
next();
38+
});
39+
40+
// Find a user by email and validate the password
41+
userSchema.statics.findByCredentials = async function(email, password) {
42+
const user = await this.findOne({ email });
43+
if (!user) {
44+
throw new Error('Invalid login credentials');
45+
}
46+
const isMatch = await bcrypt.compare(password, user.password);
47+
if (!isMatch) {
48+
throw new Error('Invalid login credentials');
49+
}
50+
return user;
51+
};
3952

4053
// NOTE: Implement rate limiting or account lockout strategies for enhanced security
4154
// Consider using middleware or a library for this purpose

0 commit comments

Comments
 (0)