UPDATE ADMIN CAN MANUALLY UPDATE PASSWORD OF USER
This commit is contained in:
parent
071bd25719
commit
80a00338c6
152
Sean/inusers.js
152
Sean/inusers.js
@ -1,30 +1,136 @@
|
||||
// inusers.js
|
||||
const allUsers = <%- JSON.stringify(allUsers) %>;
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
document.getElementById('downloadButton').addEventListener('click', function () {
|
||||
console.log('Download button clicked');
|
||||
downloadExcel(allUsers);
|
||||
});
|
||||
|
||||
// Middleware to check if the user is authenticated
|
||||
function isAuthenticated(req, res, next) {
|
||||
if (req.session && req.session.authenticated) {
|
||||
return next();
|
||||
} else {
|
||||
res.redirect('/login');
|
||||
document.getElementById('addUserLink').addEventListener('click', function () {
|
||||
document.getElementById('downloadButtonContainer').style.display = 'none';
|
||||
document.getElementById('userDataContainer').style.display = 'none';
|
||||
document.getElementById('createUserForm').style.display = 'block';
|
||||
});
|
||||
|
||||
document.getElementById('userDataLink').addEventListener('click', function () {
|
||||
document.getElementById('downloadButtonContainer').style.display = 'block';
|
||||
document.getElementById('userDataContainer').style.display = 'block';
|
||||
document.getElementById('createUserForm').style.display = 'none';
|
||||
});
|
||||
|
||||
document.getElementById('userForm').addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
// Use FormData directly
|
||||
const formData = new FormData(document.getElementById('userForm'));
|
||||
|
||||
// Check password complexity
|
||||
const password = formData.get('password');
|
||||
const confirmPassword = formData.get('confirmPassword');
|
||||
|
||||
if (!isStrongPassword(password)) {
|
||||
alert('Password does not meet complexity requirements. It must be at least 10 characters long and include at least one uppercase letter, one lowercase letter, one digit, and one symbol.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// InUsers route (renders the InUsers tab)
|
||||
router.get('/', isAuthenticated, (req, res) => {
|
||||
res.render('inusers');
|
||||
});
|
||||
// Check if passwords match
|
||||
if (password !== confirmPassword) {
|
||||
alert('Passwords do not match. Please enter the same password in both fields.');
|
||||
return;
|
||||
}
|
||||
|
||||
// User Data route
|
||||
router.get('/userdata', isAuthenticated, (req, res) => {
|
||||
res.render('user-data');
|
||||
});
|
||||
// Make a fetch request
|
||||
fetch('/createUser', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: formData.get('name'),
|
||||
username: formData.get('username'),
|
||||
email: formData.get('email'),
|
||||
password: password, // Use the validated password
|
||||
jobTitle: formData.get('jobTitle'),
|
||||
}),
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Success:', data);
|
||||
|
||||
// Edit User Data route
|
||||
router.get('/edituserdata', isAuthenticated, (req, res) => {
|
||||
res.render('edit-user-data');
|
||||
});
|
||||
// Show an alert with the received data
|
||||
alert(`User Registered!`);
|
||||
|
||||
module.exports = router;
|
||||
// Optionally, you can clear the form or take other actions after registration
|
||||
document.getElementById('userForm').reset();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetch Error:', error);
|
||||
});
|
||||
});
|
||||
|
||||
// Function to validate password complexity
|
||||
function isStrongPassword(password) {
|
||||
// Password must be at least 10 characters long
|
||||
if (password.length < 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one uppercase letter
|
||||
if (!/[A-Z]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one lowercase letter
|
||||
if (!/[a-z]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one digit
|
||||
if (!/\d/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one symbol
|
||||
if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function downloadExcel(allUsers) {
|
||||
if (allUsers && allUsers.length > 0) {
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const worksheet = workbook.addWorksheet('All Users');
|
||||
const headers = ['Name', 'Username', 'Email', 'Password', 'Last Login', 'Job Title'];
|
||||
worksheet.addRow(headers);
|
||||
allUsers.forEach(user => {
|
||||
const rowData = [
|
||||
user.name || '',
|
||||
user.username || '',
|
||||
user.email || '',
|
||||
user.password || '',
|
||||
user.lastLogin ? new Date(user.lastLogin).toLocaleString('en-US', { timeZone: 'Asia/Singapore' }) : '',
|
||||
user.jobTitle || ''
|
||||
];
|
||||
worksheet.addRow(rowData);
|
||||
});
|
||||
workbook.xlsx.writeBuffer().then(buffer => {
|
||||
const currentDate = new Date();
|
||||
const formattedDate = currentDate.toISOString().split('T')[0];
|
||||
const formattedTime = currentDate.toTimeString().split(' ')[0].replace(/:/g, '-');
|
||||
const fileName = `user_data_${formattedDate}_${formattedTime}.xlsx`;
|
||||
const blob = new Blob([buffer], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
});
|
||||
saveAs(blob, fileName);
|
||||
});
|
||||
} else {
|
||||
console.error('No data available for download.');
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +332,6 @@ app.post('/forgot-password', (req, res) => {
|
||||
});
|
||||
});
|
||||
// Handle Reset Password request
|
||||
// Handle Reset Password request
|
||||
app.post('/reset-password/:token', async (req, res) => {
|
||||
const { token } = req.params;
|
||||
const { password, confirmPassword } = req.body;
|
||||
@ -373,13 +372,16 @@ app.post('/reset-password/:token', async (req, res) => {
|
||||
// Pass the error to the template when rendering the reset-password page
|
||||
res.render('reset-password', { token, resetError: 'Error updating password' });
|
||||
} else {
|
||||
// Pass the success message to the template when rendering the reset-password page
|
||||
res.render('reset-password', { token, resetError: null, success: 'Password changed successfully' });
|
||||
// Redirect to the success page upon successful password reset
|
||||
res.redirect('/success');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/success', (req, res) => {
|
||||
res.render('success');
|
||||
});
|
||||
|
||||
|
||||
app.get('/reset-password/:token', (req, res) => {
|
||||
@ -389,7 +391,64 @@ app.get('/reset-password/:token', (req, res) => {
|
||||
res.render('reset-password', { token, passwordValidationError: null, resetError: null, success: null });
|
||||
|
||||
});
|
||||
app.post('/reset-password', async (req, res) => {
|
||||
const { username, password, confirmPassword } = req.body;
|
||||
|
||||
// Check if passwords match
|
||||
if (password !== confirmPassword) {
|
||||
return res.status(400).json({ error: 'Passwords do not match' });
|
||||
}
|
||||
|
||||
// Check if the new password meets complexity requirements
|
||||
if (!isStrongPassword(password)) {
|
||||
return res.status(400).json({
|
||||
error: 'Password does not meet complexity requirements. It must be at least 10 characters long and include at least one uppercase letter, one lowercase letter, one digit, and one symbol.'
|
||||
});
|
||||
}
|
||||
|
||||
// Hash the new password
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
// Check if the user exists in the database before updating the password
|
||||
const userExists = await checkIfUserExists(username);
|
||||
|
||||
if (!userExists) {
|
||||
return res.status(404).json({ error: 'User does not exist' });
|
||||
}
|
||||
|
||||
// Update user's password based on the username
|
||||
const updateQuery = 'UPDATE users SET password = ? WHERE username = ?';
|
||||
mysqlConnection.query(updateQuery, [hashedPassword, username], (updateErr, updateResults) => {
|
||||
if (updateErr) {
|
||||
console.error('Error updating password:', updateErr);
|
||||
return res.status(500).json({ error: 'Error updating password' });
|
||||
}
|
||||
|
||||
// Check if the update affected any rows
|
||||
if (updateResults.affectedRows > 0) {
|
||||
// Password update successful
|
||||
return res.status(200).json({ success: 'Password updated successfully' });
|
||||
} else {
|
||||
return res.status(404).json({ error: 'User not found or password not updated. No rows affected.' });
|
||||
}
|
||||
});
|
||||
});
|
||||
async function checkIfUserExists(username) {
|
||||
// Example: Check if the user exists in your database
|
||||
// You should replace this with your actual database query
|
||||
// This is just a placeholder, and you need to implement it based on your database structure and connection
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const query = 'SELECT * FROM users WHERE username = ?';
|
||||
mysqlConnection.query(query, [username], (err, results) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(results.length > 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
app.use(express.static('views'));
|
||||
|
||||
app.listen(PORT, () => {
|
||||
|
@ -27,6 +27,7 @@
|
||||
<a href="#" id="userDataLink">User Data</a>
|
||||
<a href="#" id="addUserLink">Add User</a>
|
||||
<a href="#" id="deleteUserLink">Delete User</a>
|
||||
<a href="#" id="resetPasswordLink">Reset Password</a>
|
||||
<a href="/home" id="homeLink">Home</a>
|
||||
</div>
|
||||
|
||||
@ -106,8 +107,36 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
div id="createUserForm" class="user-creation-container" style="display: none;">
|
||||
<!-- ... existing user creation form ... -->
|
||||
</div>
|
||||
<div id="resetPasswordFormContainer" style="display: none;">
|
||||
<div id="resetPasswordForm" class="user-creation-container">
|
||||
<div class="title">Reset Password</div>
|
||||
<div class="content">
|
||||
<form id="resetPasswordForm">
|
||||
<div class="user-details">
|
||||
<div class="input-box">
|
||||
<span class="details">Username</span>
|
||||
<input type="text" name="username" id="resetUsername" placeholder="Enter username" required>
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<span class="details">New Password</span>
|
||||
<input type="password" name="password" id="resetPassword" placeholder="Enter new password" required>
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<span class="details">Confirm Password</span>
|
||||
<input type="password" name="confirmPassword" id="resetConfirmPassword" placeholder="Confirm new password" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button">
|
||||
<input type="submit" value="Reset Password">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Your existing script tags -->
|
||||
|
||||
@ -120,109 +149,32 @@
|
||||
<script>
|
||||
const allUsers = <%- JSON.stringify(allUsers) %>;
|
||||
|
||||
document.getElementById('downloadButton').addEventListener('click', function () {
|
||||
console.log('Download button clicked');
|
||||
$(document).ready(function () {
|
||||
$('#resetPasswordLink').on('click', function () {
|
||||
$('#resetPasswordFormContainer').show();
|
||||
$('#createUserForm').hide();
|
||||
$('#userDataContainer').hide();
|
||||
$('#downloadButtonContainer').hide();
|
||||
});
|
||||
|
||||
$('#addUserLink').on('click', function () {
|
||||
$('#resetPasswordFormContainer').hide();
|
||||
$('#createUserForm').show();
|
||||
$('#userDataContainer').hide();
|
||||
$('#downloadButtonContainer').hide();
|
||||
});
|
||||
|
||||
$('#userDataLink').on('click', function () {
|
||||
$('#resetPasswordFormContainer').hide();
|
||||
$('#createUserForm').hide();
|
||||
$('#userDataContainer').show();
|
||||
$('#downloadButtonContainer').show();
|
||||
});
|
||||
});
|
||||
$('#downloadButton').on('click', function () {
|
||||
// Call the downloadExcel function with the allUsers data
|
||||
downloadExcel(allUsers);
|
||||
});
|
||||
|
||||
document.getElementById('addUserLink').addEventListener('click', function () {
|
||||
document.getElementById('downloadButtonContainer').style.display = 'none';
|
||||
document.getElementById('userDataContainer').style.display = 'none';
|
||||
document.getElementById('createUserForm').style.display = 'block';
|
||||
});
|
||||
|
||||
document.getElementById('userDataLink').addEventListener('click', function () {
|
||||
document.getElementById('downloadButtonContainer').style.display = 'block';
|
||||
document.getElementById('userDataContainer').style.display = 'block';
|
||||
document.getElementById('createUserForm').style.display = 'none';
|
||||
});
|
||||
|
||||
document.getElementById('userForm').addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
// Use FormData directly
|
||||
const formData = new FormData(document.getElementById('userForm'));
|
||||
|
||||
// Check password complexity
|
||||
const password = formData.get('password');
|
||||
const confirmPassword = formData.get('confirmPassword');
|
||||
|
||||
if (!isStrongPassword(password)) {
|
||||
alert('Password does not meet complexity requirements. It must be at least 10 characters long and include at least one uppercase letter, one lowercase letter, one digit, and one symbol.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if passwords match
|
||||
if (password !== confirmPassword) {
|
||||
alert('Passwords do not match. Please enter the same password in both fields.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a fetch request
|
||||
fetch('/createUser', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: formData.get('name'),
|
||||
username: formData.get('username'),
|
||||
email: formData.get('email'),
|
||||
password: password, // Use the validated password
|
||||
jobTitle: formData.get('jobTitle'),
|
||||
}),
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Success:', data);
|
||||
|
||||
// Show an alert with the received data
|
||||
alert(`User Registered!`);
|
||||
|
||||
// Optionally, you can clear the form or take other actions after registration
|
||||
document.getElementById('userForm').reset();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetch Error:', error);
|
||||
});
|
||||
});
|
||||
|
||||
// Function to validate password complexity
|
||||
function isStrongPassword(password) {
|
||||
// Password must be at least 10 characters long
|
||||
if (password.length < 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one uppercase letter
|
||||
if (!/[A-Z]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one lowercase letter
|
||||
if (!/[a-z]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one digit
|
||||
if (!/\d/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one symbol
|
||||
if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function downloadExcel(allUsers) {
|
||||
if (allUsers && allUsers.length > 0) {
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
@ -255,6 +207,100 @@ document.getElementById('userForm').addEventListener('submit', function (event)
|
||||
}
|
||||
}
|
||||
|
||||
function isStrongPassword(password) {
|
||||
// Password must be at least 10 characters long
|
||||
if (password.length < 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one uppercase letter
|
||||
if (!/[A-Z]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one lowercase letter
|
||||
if (!/[a-z]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one digit
|
||||
if (!/\d/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one symbol
|
||||
if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$('#resetPasswordForm').on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Get values from the form
|
||||
const username = $('#resetUsername').val();
|
||||
const password = $('#resetPassword').val();
|
||||
const confirmPassword = $('#resetConfirmPassword').val();
|
||||
|
||||
console.log('Username:', username);
|
||||
console.log('New Password:', password);
|
||||
|
||||
// Validate passwords
|
||||
if (password !== confirmPassword) {
|
||||
alert('Passwords do not match. Please enter the same password in both fields.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the new password meets complexity requirements
|
||||
if (!isStrongPassword(password)) {
|
||||
alert('Password does not meet complexity requirements. It must be at least 10 characters long and include at least one uppercase letter, one lowercase letter, one digit, and one symbol.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a fetch request
|
||||
fetch('/reset-password', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: password,
|
||||
confirmPassword: confirmPassword,
|
||||
}),
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Success:', data);
|
||||
|
||||
// Show an alert with the received data
|
||||
alert(data.success || data.error || 'Password change status unknown');
|
||||
|
||||
// Optionally, you can clear the form or take other actions after the password change
|
||||
$('#resetUsername').val('');
|
||||
$('#resetPassword').val('');
|
||||
$('#resetConfirmPassword').val('');
|
||||
|
||||
// You might want to hide the reset password form after submission
|
||||
$('#resetPasswordFormContainer').hide();
|
||||
})
|
||||
.catch(error => {
|
||||
// Handle 404 error separately to show an alert
|
||||
if (error.message.includes('HTTP error! Status: 404')) {
|
||||
alert('User not found. Please enter a valid username.');
|
||||
} else {
|
||||
console.error('Fetch Error:', error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
@ -10,15 +10,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<% if (resetError) { %>
|
||||
<div class="alert alert-danger mb-3"><%= resetError %></div>
|
||||
<% } else if (success) { %>
|
||||
<div class="alert alert-success mb-3"><%= success %></div>
|
||||
<p>Password changed successfully. <a href="/login">Click here to log in</a>.</p>
|
||||
<% } else { %>
|
||||
<% if (passwordValidationError) { %>
|
||||
<div class="alert alert-danger mb-3"><%= passwordValidationError %></div>
|
||||
<% } %>
|
||||
<form action="/reset-password/<%= token %>" method="post">
|
||||
<div class="form-group">
|
||||
<label for="password">New Password:</label>
|
||||
@ -28,15 +19,16 @@
|
||||
<label for="confirmPassword">Confirm Password:</label>
|
||||
<input type="password" class="form-control" id="confirmPassword" name="confirmPassword" required>
|
||||
</div>
|
||||
|
||||
<% if (resetError) { %>
|
||||
<div class="alert alert-danger mb-3"><%= resetError %></div>
|
||||
<% } else if (passwordValidationError) { %>
|
||||
<div class="alert alert-danger mb-3"><%= passwordValidationError %></div>
|
||||
<% } %>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Reset Password</button>
|
||||
</form>
|
||||
<% } %>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
15
Sean/views/success.ejs
Normal file
15
Sean/views/success.ejs
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Password Reset Success</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<div class="alert alert-success mb-3">Password changed successfully.</div>
|
||||
<p>Thank you for updating your password. You can now <a href="/login">log in</a> with your new password.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user