Skip to content
Merged
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 23 additions & 4 deletions functions/resetFunc.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' };
}
};
168 changes: 35 additions & 133 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,133 +1,35 @@

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Study Planner</title>
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> // Add viewport meta element
<title>Document</title>
</head>
<body>
<header>
<h1>Study Planner</h1>
</header>
<main>
<section id="schedule">
<h2>Your Schedule</h2>
<!-- Schedule content goes here -->
</section>
<section id="tasks">
<h2>Your Tasks</h2>
<!-- Task list and management interface goes here -->
<div id="taskForm">
<form>
<!-- Form content for adding tasks -->
</form>
</div>
<div id="taskList">
<!-- Dynamic task list will be rendered here -->
</div>
</section>
</main>
<footer>
<p>&copy; 2023 Study Planner</p>
</footer>
<script src="main.js"></script>

</body>
</html>
<<<<<<< Updated upstream
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Added viewport meta element -->
<title>Document</title>
</head>
<body>

</body>
</html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>

</head>
<body>

</body>
</html>
<body>

</body>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> // Add viewport meta element
<title>Document</title>
</head>
<body>

</body>
</html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Added viewport meta element -->
<title>Document</title>
</head>
<body>

</body>
</html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>

</head>
<body>

</html>
=======

<script>
// Example fetch request to an API endpoint
fetch('/api/tasks')
.then(response => response.json())
.then(data => {
// Handle data (tasks) here
console.log(data);
})
.catch(error => {
console.error('Error fetching tasks:', error);
});
</script>

<script>
// Function to fetch and display tasks
function fetchAndDisplayTasks() {
fetch('/api/tasks')
.then(response => response.json())
.then(tasks => {
const tasksList = document.getElementById('tasksList');
tasksList.innerHTML = ''; // Clear existing tasks
tasks.forEach(task => {
const taskItem = document.createElement('li');
taskItem.textContent = task.title;
tasksList.appendChild(taskItem);
});
})
.catch(error => {
console.error('Error fetching tasks:', error);
});
}

// Call the function on page load
document.addEventListener('DOMContentLoaded', fetchAndDisplayTasks);
</script>
>>>>>>> Stashed changes
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Study Planner</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>Study Planner</h1>
</header>
<main>
<section id="schedule">
<h2>Your Schedule</h2>
</section>
<section id="tasks">
<h2>Your Tasks</h2>
<div id="taskForm">
<form id="taskFormElement">
<input type="text" id="taskTitle" placeholder="Title" required />
<input type="text" id="taskDescription" placeholder="Description" required />
<input type="date" id="taskDueDate" required />
<button type="submit">Add Task</button>
</form>
</div>
<div id="taskList"></div>
</section>
</main>
<footer>
<p>&copy; 2023 Study Planner</p>
</footer>
<script src="main.js"></script>
</body>
</html>
54 changes: 30 additions & 24 deletions main.js
Original file line number Diff line number Diff line change
@@ -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;
}
Expand All @@ -44,20 +50,20 @@ 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)
});
return stream.json();
}

// 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 = `<h3>${task.title}</h3><p>${task.description}</p><p>Due: ${new Date(task.dueDate).toDateString()}</p>`;
taskList.appendChild(div);
Expand Down
27 changes: 20 additions & 7 deletions models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading