Merge branch 'main' of https://github.com/Newtbot/MP
This commit is contained in:
commit
0aefebae75
229
Sean/server.js
229
Sean/server.js
@ -140,7 +140,6 @@ app.get("/home", isAuthenticated, (req, res) => {
|
|||||||
// Retrieve the overall last 10 logins for all users
|
// Retrieve the overall last 10 logins for all users
|
||||||
const loginsQuery =
|
const loginsQuery =
|
||||||
"SELECT username, lastLogin FROM users ORDER BY lastLogin DESC LIMIT 10";
|
"SELECT username, lastLogin FROM users ORDER BY lastLogin DESC LIMIT 10";
|
||||||
|
|
||||||
connection.query(loginsQuery, (error, loginResults) => {
|
connection.query(loginsQuery, (error, loginResults) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Error executing login logs query:", error);
|
console.error("Error executing login logs query:", error);
|
||||||
@ -531,17 +530,26 @@ app.post("/reset-password/:token", async (req, res) => {
|
|||||||
// Update user's password and clear reset token
|
// Update user's password and clear reset token
|
||||||
const updateQuery =
|
const updateQuery =
|
||||||
"UPDATE users SET password = ?, reset_token = NULL, reset_token_expiry = NULL WHERE reset_token = ?";
|
"UPDATE users SET password = ?, reset_token = NULL, reset_token_expiry = NULL WHERE reset_token = ?";
|
||||||
connection.query(updateQuery, [hashedPassword, token], (updateErr) => {
|
connection.query(updateQuery, [hashedPassword, token], async (updateErr, updateResults) => {
|
||||||
if (updateErr) {
|
if (updateErr) {
|
||||||
console.error("Error updating password:", updateErr);
|
console.error("Error updating password:", updateErr);
|
||||||
// Pass the error to the template when rendering the reset-password page
|
// Pass the error to the template when rendering the reset-password page
|
||||||
res.render("reset-password", {
|
res.render("reset-password", {
|
||||||
token,
|
token,
|
||||||
resetError: "Error updating password",
|
resetError: "Error updating password",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Redirect to the success page upon successful password reset
|
// Log password reset activity
|
||||||
res.redirect("/success");
|
const username = selectResults[0].username; // Assuming 'username' is the column name
|
||||||
|
const logQuery = "INSERT INTO user_logs (username, activity, timestamp) VALUES (?, 'Password Reseted successfully', NOW())";
|
||||||
|
connection.query(logQuery, [username], (logErr) => {
|
||||||
|
if (logErr) {
|
||||||
|
console.error("Error logging password reset:", logErr);
|
||||||
|
// You might want to handle the logging error here
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Redirect to the success page upon successful password reset
|
||||||
|
res.redirect("/success");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -563,70 +571,159 @@ app.get("/reset-password/:token", (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
app.post("/reset-password", async (req, res) => {
|
app.post("/reset-password", async (req, res) => {
|
||||||
const { username, password, confirmPassword } = req.body;
|
const { username, password, confirmPassword } = req.body;
|
||||||
|
const creatorUsername = req.session.username;
|
||||||
|
|
||||||
// Check if passwords match
|
// Check if passwords match
|
||||||
if (password !== confirmPassword) {
|
if (password !== confirmPassword) {
|
||||||
return res.status(400).json({ error: "Passwords do not match" });
|
return res.status(400).json({ error: "Passwords do not match" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the new password meets complexity requirements
|
// Check if the new password meets complexity requirements
|
||||||
if (!isStrongPassword(password)) {
|
if (!isStrongPassword(password)) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
error:
|
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.",
|
"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
|
// Hash the new password
|
||||||
const hashedPassword = await bcrypt.hash(password, 10);
|
const hashedPassword = await bcrypt.hash(password, 10);
|
||||||
|
|
||||||
// Check if the user exists in the database before updating the password
|
// Check if the user exists in the database before updating the password
|
||||||
const userExists = await checkIfUserExists(username);
|
const userExists = await checkIfUserExists(username);
|
||||||
|
|
||||||
if (!userExists) {
|
if (!userExists) {
|
||||||
return res.status(404).json({ error: "User does not exist" });
|
return res.status(404).json({ error: "User does not exist" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update user's password based on the username
|
// Update user's password based on the username
|
||||||
const updateQuery = "UPDATE users SET password = ? WHERE username = ?";
|
const updateQuery = "UPDATE users SET password = ? WHERE username = ?";
|
||||||
connection.query(
|
connection.query(updateQuery, [hashedPassword, username], async (updateErr, updateResults) => {
|
||||||
updateQuery,
|
if (updateErr) {
|
||||||
[hashedPassword, username],
|
console.error("Error updating password:", updateErr);
|
||||||
(updateErr, updateResults) => {
|
return res.status(500).json({ error: "Error updating password" });
|
||||||
if (updateErr) {
|
}
|
||||||
console.error("Error updating password:", updateErr);
|
|
||||||
return res.status(500).json({ error: "Error updating password" });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the update affected any rows
|
// Check if the update affected any rows
|
||||||
if (updateResults.affectedRows > 0) {
|
if (updateResults.affectedRows > 0) {
|
||||||
// Password update successful
|
// Log password reset activity
|
||||||
return res
|
const logQuery = "INSERT INTO user_logs (username, activity, timestamp) VALUES (?, ?, NOW())";
|
||||||
.status(200)
|
const logActivity = `Password has been reset for ${username}`;
|
||||||
.json({ success: "Password updated successfully" });
|
connection.query(logQuery, [creatorUsername, logActivity], (logErr) => {
|
||||||
} else {
|
if (logErr) {
|
||||||
return res
|
console.error("Error logging password reset:", logErr);
|
||||||
.status(404)
|
// You might want to handle the logging error here
|
||||||
.json({
|
}
|
||||||
error: "User not found or password not updated.",
|
|
||||||
});
|
// 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.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
async function checkIfUserExists(username) {
|
async function checkIfUserExists(username) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const query = "SELECT * FROM users WHERE username = ?";
|
const query = "SELECT * FROM users WHERE username = ?";
|
||||||
connection.query(query, [username], (err, results) => {
|
connection.query(query, [username], (err, results) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
resolve(results.length > 0);
|
resolve(results.length > 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
app.get('/searchUser', (req, res) => {
|
||||||
|
const { username } = req.query;
|
||||||
|
const query = 'SELECT * FROM users WHERE username = ?';
|
||||||
|
|
||||||
|
connection.query(query, [username], (err, results) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('MySQL query error:', err);
|
||||||
|
res.status(500).json({ success: false, error: 'Internal Server Error' });
|
||||||
|
} else if (results.length === 0) {
|
||||||
|
// No user found with the given username
|
||||||
|
res.status(404).json({ success: false, error: 'User not found' });
|
||||||
|
} else {
|
||||||
|
res.json(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/users', (req, res) => {
|
||||||
|
const query = 'SELECT * FROM users';
|
||||||
|
|
||||||
|
connection.query(query, (err, results) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('MySQL query error:', err);
|
||||||
|
res.status(500).json({ success: false, error: 'Internal Server Error' });
|
||||||
|
} else {
|
||||||
|
res.json(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route to search for a user by username
|
||||||
|
app.get('/api/searchUser', (req, res) => {
|
||||||
|
const { username } = req.query;
|
||||||
|
const query = 'SELECT * FROM users WHERE username = ?';
|
||||||
|
|
||||||
|
connection.query(query, [username], (err, results) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('MySQL query error:', err);
|
||||||
|
res.status(500).json({ success: false, error: 'Internal Server Error' });
|
||||||
|
} else {
|
||||||
|
res.json(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route to delete a user by username
|
||||||
|
|
||||||
|
app.delete('/api/deleteUser/:username', async (req, res) => {
|
||||||
|
const { username } = req.params;
|
||||||
|
const query = 'DELETE FROM users WHERE username = ?';
|
||||||
|
const creatorUsername = req.session.username;
|
||||||
|
try {
|
||||||
|
// Log deletion activity to USER_LOGS
|
||||||
|
const deletionActivity = `User ${username} has been successfully deleted`;
|
||||||
|
const logQuery = 'INSERT INTO USER_LOGS (USERNAME, ACTIVITY, TIMESTAMP) VALUES (?, ?, CURRENT_TIMESTAMP)';
|
||||||
|
await executeQuery(logQuery, [creatorUsername, deletionActivity]);
|
||||||
|
|
||||||
|
// Perform user deletion
|
||||||
|
const results = await executeQuery(query, [username]);
|
||||||
|
|
||||||
|
if (results.affectedRows === 0) {
|
||||||
|
res.status(404).json({ success: false, error: 'User not found' });
|
||||||
|
} else {
|
||||||
|
res.json({ success: true, message: 'User deleted successfully' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('MySQL query error:', error);
|
||||||
|
res.status(500).json({ success: false, error: 'Internal Server Error', details: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function executeQuery(sql, values) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connection.query(sql, values, (err, results) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.use(express.static("views"));
|
app.use(express.static("views"));
|
||||||
|
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Username</th>
|
<th>Username</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Password</th>
|
|
||||||
<th>Last Login</th>
|
<th>Last Login</th>
|
||||||
<th>Job Title</th>
|
<th>Job Title</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -56,7 +55,6 @@
|
|||||||
<td><%= user.name %></td>
|
<td><%= user.name %></td>
|
||||||
<td><%= user.username %></td>
|
<td><%= user.username %></td>
|
||||||
<td><%= user.email %></td>
|
<td><%= user.email %></td>
|
||||||
<td><%= user.password %></td>
|
|
||||||
<td><%= new Date(user.lastLogin).toLocaleString('en-US', { timeZone: 'Asia/Singapore' }) %></td>
|
<td><%= new Date(user.lastLogin).toLocaleString('en-US', { timeZone: 'Asia/Singapore' }) %></td>
|
||||||
<td><%= user.jobTitle %></td>
|
<td><%= user.jobTitle %></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -134,7 +132,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="deleteUserContainer" style="display: none;">
|
||||||
|
<h3>Delete User</h3>
|
||||||
|
<div class="search-container">
|
||||||
|
<input type="text" id="searchUserInput" placeholder="Search by username">
|
||||||
|
<button id="searchUserButton">Search</button>
|
||||||
|
</div>
|
||||||
|
<div id="searchResultsContainer" style="display: none;">
|
||||||
|
<h4>Search Results</h4>
|
||||||
|
<ul id="searchResultsList"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Your existing script tags -->
|
<!-- Your existing script tags -->
|
||||||
|
|
||||||
@ -153,6 +161,7 @@ $(document).ready(function () {
|
|||||||
$('#createUserForm').hide();
|
$('#createUserForm').hide();
|
||||||
$('#userDataContainer').hide();
|
$('#userDataContainer').hide();
|
||||||
$('#downloadButtonContainer').hide();
|
$('#downloadButtonContainer').hide();
|
||||||
|
$('#deleteUserContainer').hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#addUserLink').on('click', function () {
|
$('#addUserLink').on('click', function () {
|
||||||
@ -160,6 +169,7 @@ $(document).ready(function () {
|
|||||||
$('#createUserForm').show();
|
$('#createUserForm').show();
|
||||||
$('#userDataContainer').hide();
|
$('#userDataContainer').hide();
|
||||||
$('#downloadButtonContainer').hide();
|
$('#downloadButtonContainer').hide();
|
||||||
|
$('#deleteUserContainer').hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#userDataLink').on('click', function () {
|
$('#userDataLink').on('click', function () {
|
||||||
@ -167,26 +177,110 @@ $(document).ready(function () {
|
|||||||
$('#createUserForm').hide();
|
$('#createUserForm').hide();
|
||||||
$('#userDataContainer').show();
|
$('#userDataContainer').show();
|
||||||
$('#downloadButtonContainer').show();
|
$('#downloadButtonContainer').show();
|
||||||
|
$('#deleteUserContainer').hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#searchUserButton').on('click', function () {
|
||||||
|
console.log('Search button clicked');
|
||||||
|
const searchUsername = $('#searchUserInput').val();
|
||||||
|
// Call the function to search for the user
|
||||||
|
searchUser(searchUsername);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#deleteUserLink').on('click', function () {
|
||||||
|
$('#deleteUserContainer').show();
|
||||||
|
$('#resetPasswordFormContainer').hide();
|
||||||
|
$('#createUserForm').hide();
|
||||||
|
$('#userDataContainer').hide();
|
||||||
|
$('#downloadButtonContainer').hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#downloadButton').on('click', function () {
|
$('#downloadButton').on('click', function () {
|
||||||
// Call the downloadExcel function with the allUsers data
|
// Call the downloadExcel function with the allUsers data
|
||||||
downloadExcel(allUsers);
|
downloadExcel(allUsers);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function searchUser(username) {
|
||||||
|
fetch(`/api/searchUser?username=${username}`) // Add the /api prefix here
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(users => {
|
||||||
|
// Display search results
|
||||||
|
displaySearchResults(users);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Search error:', error);
|
||||||
|
// Handle errors, e.g., display an alert
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to display search results
|
||||||
|
function displaySearchResults(users) {
|
||||||
|
const searchResultsList = $('#searchResultsList');
|
||||||
|
|
||||||
|
// Clear previous results
|
||||||
|
searchResultsList.empty();
|
||||||
|
|
||||||
|
if (users && users.length > 0) {
|
||||||
|
users.forEach(user => {
|
||||||
|
const listItem = `<li>${user.username} - <button class="deleteUserButton" data-username="${user.username}">Delete</button></li>`;
|
||||||
|
searchResultsList.append(listItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show the search results container
|
||||||
|
$('#searchResultsContainer').show();
|
||||||
|
} else {
|
||||||
|
// Hide the search results container if no results
|
||||||
|
$('#searchResultsContainer').hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Event listener for delete user button in search results
|
||||||
|
$('#searchResultsList').on('click', '.deleteUserButton', function () {
|
||||||
|
const usernameToDelete = $(this).data('username');
|
||||||
|
console.log('Before fetch for user deletion');
|
||||||
|
// Make a fetch request to delete the user
|
||||||
|
fetch(`/api/deleteUser/${usernameToDelete}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
console.log('Inside fetch response handler');
|
||||||
|
if (response.ok) {
|
||||||
|
// Assuming your server sends a JSON response
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log('User deletion success:', data);
|
||||||
|
alert('User deleted successfully');
|
||||||
|
$('#searchResultsContainer').hide();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('User deletion error:', error);
|
||||||
|
alert('Failed to delete user. Please try again.');
|
||||||
|
// Handle errors, e.g., display an alert
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
function downloadExcel(allUsers) {
|
function downloadExcel(allUsers) {
|
||||||
if (allUsers && allUsers.length > 0) {
|
if (allUsers && allUsers.length > 0) {
|
||||||
const workbook = new ExcelJS.Workbook();
|
const workbook = new ExcelJS.Workbook();
|
||||||
const worksheet = workbook.addWorksheet('All Users');
|
const worksheet = workbook.addWorksheet('All Users');
|
||||||
const headers = ['Name', 'Username', 'Email', 'Password', 'Last Login', 'Job Title'];
|
const headers = ['Name', 'Username', 'Email', 'Last Login', 'Job Title'];
|
||||||
worksheet.addRow(headers);
|
worksheet.addRow(headers);
|
||||||
allUsers.forEach(user => {
|
allUsers.forEach(user => {
|
||||||
const rowData = [
|
const rowData = [
|
||||||
user.name || '',
|
user.name || '',
|
||||||
user.username || '',
|
user.username || '',
|
||||||
user.email || '',
|
user.email || '',
|
||||||
user.password || '',
|
|
||||||
user.lastLogin ? new Date(user.lastLogin).toLocaleString('en-US', { timeZone: 'Asia/Singapore' }) : '',
|
user.lastLogin ? new Date(user.lastLogin).toLocaleString('en-US', { timeZone: 'Asia/Singapore' }) : '',
|
||||||
user.jobTitle || ''
|
user.jobTitle || ''
|
||||||
];
|
];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user