From ae1a5dfd797629be45a8161a7dc056af357dd6b2 Mon Sep 17 00:00:00 2001 From: Tea Larson-Hetrick Date: Sat, 28 Jun 2025 17:45:24 -0700 Subject: [PATCH] Implement missing auth helper and replace placeholders --- README.md | 4 +- functions/resetFunc.js | 27 ++++++- index.html | 168 +++++++++-------------------------------- main.js | 54 +++++++------ models/user.js | 27 +++++-- 5 files changed, 110 insertions(+), 170 deletions(-) diff --git a/README.md b/README.md index a3c02a8..0299744 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ learning objectives. Features include: -- List of features -- Key functionalities of the application +- Task creation and management with due dates +- JWT-based user authentication - Automated task schedules based on user behaviors - Advanced reporting and analytics to track study progress - Integration with personal advice through IA diff --git a/functions/resetFunc.js b/functions/resetFunc.js index 0580eed..dde18e7 100644 --- a/functions/resetFunc.js +++ b/functions/resetFunc.js @@ -49,7 +49,26 @@ The uncommented function below is just a placeholder and will result in failure. */ - exports = ({ token, tokenId, username, password }) => { - // will not reset the password - return { status: 'fail' }; - }; +exports = async ({ token, tokenId, username, password }) => { + const serviceName = 'mongodb-atlas'; + const dbName = 'myDatabase'; + const users = context.services.get(serviceName).db(dbName).collection('users'); + + try { + const user = await users.findOne({ username, resetToken: token, resetTokenId: tokenId }); + if (!user) { + return { status: 'fail' }; + } + + const bcrypt = require('bcryptjs'); + const hashed = await bcrypt.hash(password, 8); + await users.updateOne( + { _id: user._id }, + { $set: { password: hashed }, $unset: { resetToken: '', resetTokenId: '' } } + ); + return { status: 'success' }; + } catch (err) { + console.error('Error in resetFunc:', err); + return { status: 'fail' }; + } +}; diff --git a/index.html b/index.html index 754787a..410a53d 100644 --- a/index.html +++ b/index.html @@ -1,133 +1,35 @@ - - - - - - - Study Planner - - // Add viewport meta element - Document - - -
-

Study Planner

-
-
-
-

Your Schedule

- -
-
-

Your Tasks

- -
-
- -
-
-
- -
-
-
- - - - - -<<<<<<< Updated upstream - - - - - Document - - - - - - - - - Document - - - - - - - - - - - - - - - // Add viewport meta element - Document - - - - - - - - - - Document - - - - - - - - - Document - - - - - -======= - - - - ->>>>>>> Stashed changes + + + + + + Study Planner + + + +
+

Study Planner

+
+
+
+

Your Schedule

+
+
+

Your Tasks

+
+
+ + + + +
+
+
+
+
+ + + + diff --git a/main.js b/main.js index 14a8cae..202f78e 100644 --- a/main.js +++ b/main.js @@ -1,39 +1,45 @@ -document.addEventListener('DOMContentLoaded', function() { - loadTasks(); +document.addEventListener('DOMContentLoaded', () => { + initTaskHandlers(); }); +function initTaskHandlers() { + const taskList = document.getElementById('taskList'); + const form = document.getElementById('taskFormElement'); + loadTasks(taskList); + + form.addEventListener('submit', async (e) => { + e.preventDefault(); + const task = await sanitizeTaskForm(); + if (task) { + try { + const saved = await saveTask(task); + addTaskToList(taskList, saved); + form.reset(); + } catch (error) { + console.error('Failed to create task:', error); + } + } + }); +} + // Load existing tasks from the server when the page loads. -async function loadTasks() { +async function loadTasks(taskList) { try { const stream = await fetch('/api/tasks'); const tasks = await stream.json(); - tasks.forEach(addTaskToList); + tasks.forEach((t) => addTaskToList(taskList, t)); } catch(error) { - console.error('Failed to load tasks: ', string(error)); + console.error('Failed to load tasks:', error); } } -document.getElementById('taskForm').addEventListener('submit', function(e) { - e.preventDefault(); - let task = sanitizeTaskForm(); - if (task) { - try { - await saveTask(task); - addTaskToList(task); - taskFOReset(); - } catch (error) { - console.error('Failed to create task: ', string(error)); - } - } -}); - - // Sanitize and validate form data +// Sanitize and validate form data async function sanitizeTaskForm() { const title = document.getElementById('taskTitle').value; const description = document.getElementById('taskDescription').value; const dueDate = document.getElementById('taskDueDate').value; - if (!title || !description || !dete) { + if (!title || !description || !dueDate) { console.error('Invalid form data: title, description or due date is missing.'); return null; } @@ -44,12 +50,12 @@ async function sanitizeTaskForm() { }; } - // Save task to the server via POST request. +// Save task to the server via POST request. async function saveTask(task) { const stream = await fetch('/api/tasks', { method: 'POST', headers: { - 'text': 'application/json' + 'Content-Type': 'application/json' }, body: JSON.stringify(task) }); @@ -57,7 +63,7 @@ async function saveTask(task) { } // Add task to list and render it on the page. -async function addTaskToList(task) { +function addTaskToList(taskList, task) { const div = document.createElement('div'); div.innerHTML = `

${task.title}

${task.description}

Due: ${new Date(task.dueDate).toDateString()}

`; taskList.appendChild(div); diff --git a/models/user.js b/models/user.js index 8d071dc..1d4ec5e 100644 --- a/models/user.js +++ b/models/user.js @@ -29,13 +29,26 @@ const userSchema = new mongoose.Schema({ } }); -// Password hashing middleware -userSchema.pre('save', async function(next) { - if (this.isModified('password')) { - this.password = await bcrypt.hash(this.password, 8); - } - next(); -}); +// Password hashing middleware +userSchema.pre('save', async function(next) { + if (this.isModified('password')) { + this.password = await bcrypt.hash(this.password, 8); + } + next(); +}); + +// Find a user by email and validate the password +userSchema.statics.findByCredentials = async function(email, password) { + const user = await this.findOne({ email }); + if (!user) { + throw new Error('Invalid login credentials'); + } + const isMatch = await bcrypt.compare(password, user.password); + if (!isMatch) { + throw new Error('Invalid login credentials'); + } + return user; +}; // NOTE: Implement rate limiting or account lockout strategies for enhanced security // Consider using middleware or a library for this purpose