update where no duplicate username and email can be created

This commit is contained in:
BIG2EYEZ 2023-12-26 17:41:10 +08:00
parent a5be62cc46
commit 1db32e3c7a
2 changed files with 347 additions and 145 deletions

View File

@ -207,57 +207,80 @@ app.post('/createUser', (req, res) => {
return res.status(400).json({ error: 'Password does not meet complexity requirements' }); return res.status(400).json({ error: 'Password does not meet complexity requirements' });
} }
// Hash the password before storing it in the database // Check if the username is already taken
bcrypt.hash(password, 10, (hashError, hashedPassword) => { const checkUsernameQuery = 'SELECT * FROM users WHERE username = ?';
if (hashError) { mysqlConnection.query(checkUsernameQuery, [username], (usernameQueryErr, usernameResults) => {
console.error('Error hashing password:', hashError); if (usernameQueryErr) {
res.status(500).json({ error: 'Internal Server Error' }); console.error('Error checking username:', usernameQueryErr);
return; return res.status(500).json({ error: 'Internal Server Error' });
} }
// Start a transaction if (usernameResults.length > 0) {
mysqlConnection.beginTransaction((transactionErr) => { return res.status(400).json({ error: 'Username is already taken', message: 'Username is already taken. Please choose a different username.' });
if (transactionErr) { }
console.error('Error starting transaction:', transactionErr);
res.status(500).json({ error: 'Internal Server Error' }); // Check if the email is already taken
return; const checkEmailQuery = 'SELECT * FROM users WHERE email = ?';
mysqlConnection.query(checkEmailQuery, [email], (emailQueryErr, emailResults) => {
if (emailQueryErr) {
console.error('Error checking email:', emailQueryErr);
return res.status(500).json({ error: 'Internal Server Error' });
} }
// Define the insert query if (emailResults.length > 0) {
const insertUserQuery = 'INSERT INTO users (name, username, email, password, lastLogin, jobTitle) VALUES (?, ?, ?, ?, NULL, ?)'; return res.status(400).json({ error: 'Email is already in use', message: 'Email is already in use. Please choose another email.' });
}
// Log the query and its parameters // Hash the password before storing it in the database
console.log('Insert Query:', insertUserQuery); bcrypt.hash(password, 10, (hashError, hashedPassword) => {
console.log('Query Parameters:', [name, username, email, hashedPassword, jobTitle]); if (hashError) {
console.error('Error hashing password:', hashError);
// Execute the query with user data return res.status(500).json({ error: 'Internal Server Error' });
mysqlConnection.query(insertUserQuery, [name, username, email, hashedPassword, jobTitle], (queryErr, results) => {
if (queryErr) {
console.error('Error executing query:', queryErr);
// Rollback the transaction in case of an error
mysqlConnection.rollback((rollbackErr) => {
if (rollbackErr) {
console.error('Error rolling back transaction:', rollbackErr);
}
res.status(500).json({ error: 'Internal Server Error' });
});
return;
} }
// Commit the transaction // Start a transaction
mysqlConnection.commit((commitErr) => { mysqlConnection.beginTransaction((transactionErr) => {
if (commitErr) { if (transactionErr) {
console.error('Error committing transaction:', commitErr); console.error('Error starting transaction:', transactionErr);
res.status(500).json({ error: 'Internal Server Error' }); return res.status(500).json({ error: 'Internal Server Error' });
return;
} }
// Log the results of the query // Define the insert query
console.log('Query Results:', results); const insertUserQuery = 'INSERT INTO users (name, username, email, password, lastLogin, jobTitle) VALUES (?, ?, ?, ?, NULL, ?)';
// Respond with a success message // Log the query and its parameters
res.status(201).json({ message: 'User created successfully' }); console.log('Insert Query:', insertUserQuery);
console.log('Query Parameters:', [name, username, email, hashedPassword, jobTitle]);
// Execute the query with user data
mysqlConnection.query(insertUserQuery, [name, username, email, hashedPassword, jobTitle], (queryErr, results) => {
if (queryErr) {
console.error('Error executing query:', queryErr);
// Rollback the transaction in case of an error
mysqlConnection.rollback((rollbackErr) => {
if (rollbackErr) {
console.error('Error rolling back transaction:', rollbackErr);
}
return res.status(500).json({ error: 'Internal Server Error' });
});
return;
}
// Commit the transaction
mysqlConnection.commit((commitErr) => {
if (commitErr) {
console.error('Error committing transaction:', commitErr);
return res.status(500).json({ error: 'Internal Server Error' });
}
// Log the results of the query
console.log('Query Results:', results);
// Respond with a success message
res.status(201).json({ message: 'User created successfully' });
});
});
}); });
}); });
}); });
@ -268,6 +291,82 @@ app.post('/createUser', (req, res) => {
} }
}); });
app.post('/check-username-email', (req, res) => {
try {
const { username, email } = req.body;
// Check if the username is already taken
const checkUsernameQuery = 'SELECT * FROM users WHERE username = ?';
mysqlConnection.query(checkUsernameQuery, [username], (usernameQueryErr, usernameResults) => {
if (usernameQueryErr) {
console.error('Error checking username:', usernameQueryErr);
return res.status(500).json({ error: 'Internal Server Error' });
}
// Check if the email is already taken
const checkEmailQuery = 'SELECT * FROM users WHERE email = ?';
mysqlConnection.query(checkEmailQuery, [email], (emailQueryErr, emailResults) => {
if (emailQueryErr) {
console.error('Error checking email:', emailQueryErr);
return res.status(500).json({ error: 'Internal Server Error' });
}
if (usernameResults.length === 0 && emailResults.length === 0) {
// Both username and email are available
return res.status(200).json({ available: true });
} else {
// Either username or email is already taken
return res.status(400).json({ error: 'Username or email already taken' });
}
});
});
} catch (error) {
console.error('Error checking username and email:', error);
res.status(500).json({ error: 'Internal Server Error' });
}
});
app.post('/check-username', (req, res) => {
const { username } = req.body;
const checkUsernameQuery = 'SELECT * FROM users WHERE username = ?';
mysqlConnection.query(checkUsernameQuery, [username], (error, results) => {
if (error) {
console.error('Error checking username:', error);
res.status(500).json({ error: 'Internal Server Error' });
} else {
const isAvailable = results.length === 0;
res.json({ available: isAvailable });
}
});
});
// Assuming you have an instance of express named 'app'
app.post('/check-email', (req, res) => {
const { email } = req.body;
// Check if the email is already taken in the database
const checkEmailQuery = 'SELECT * FROM users WHERE email = ?';
mysqlConnection.query(checkEmailQuery, [email], (error, results) => {
if (error) {
console.error('Error checking email:', error);
res.status(500).json({ error: 'Internal Server Error' });
return;
}
// If results.length is greater than 0, it means the email is already taken
const isEmailAvailable = results.length === 0;
// Return a JSON response indicating whether the email is available or not
res.json({ available: isEmailAvailable });
});
});
app.get('/forgot-password', (req, res) => { app.get('/forgot-password', (req, res) => {
res.render('forgot-password'); // Assuming you have an EJS template for this res.render('forgot-password'); // Assuming you have an EJS template for this
}); });
@ -449,6 +548,9 @@ async function checkIfUserExists(username) {
}); });
}); });
} }
app.use(express.static('views')); app.use(express.static('views'));
app.listen(PORT, () => { app.listen(PORT, () => {

View File

@ -145,7 +145,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.2.1/exceljs.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.2.1/exceljs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script> <script>
const allUsers = <%- JSON.stringify(allUsers) %>; const allUsers = <%- JSON.stringify(allUsers) %>;
$(document).ready(function () { $(document).ready(function () {
$('#resetPasswordLink').on('click', function () { $('#resetPasswordLink').on('click', function () {
@ -169,136 +169,236 @@ $(document).ready(function () {
$('#downloadButtonContainer').show(); $('#downloadButtonContainer').show();
}); });
}); });
$('#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 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.');
}
}
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 function downloadExcel(allUsers) {
if (!/[A-Z]/.test(password)) { if (allUsers && allUsers.length > 0) {
return false; 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.');
}
}
// Password must contain at least one lowercase letter function isStrongPassword(password) {
if (!/[a-z]/.test(password)) { // Password must be at least 10 characters long
return false; if (password.length < 10) {
} 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) { // Password must contain at least one uppercase letter
e.preventDefault(); if (!/[A-Z]/.test(password)) {
return false;
}
// Get values from the form // Password must contain at least one lowercase letter
const username = $('#resetUsername').val(); if (!/[a-z]/.test(password)) {
const password = $('#resetPassword').val(); return false;
const confirmPassword = $('#resetConfirmPassword').val(); }
console.log('Username:', username); // Password must contain at least one digit
console.log('New Password:', password); if (!/\d/.test(password)) {
return false;
}
// Validate passwords // Password must contain at least one symbol
if (password !== confirmPassword) { if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
return false;
}
return true;
}
function resetFormFields() {
$('#name').val('');
$('#username').val('');
$('#email').val('');
$('#password').val('');
$('#confirmPassword').val('');
$('#jobTitle').val('');
}
$('#userForm').on('submit', function (e) {
e.preventDefault();
const name = $('#name').val();
const username = $('#username').val();
const email = $('#email').val();
const password = $('#password').val();
const confirmPassword = $('#confirmPassword').val();
const jobTitle = $('#jobTitle').val();
if (password !== confirmPassword) {
alert('Passwords do not match. Please enter the same password in both fields.'); alert('Passwords do not match. Please enter the same password in both fields.');
return; return;
} }
// Check if the new password meets complexity requirements if (!isStrongPassword(password)) {
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.'); 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; return;
} }
// Make a fetch request fetch('/createUser', {
fetch('/reset-password', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ body: JSON.stringify({
username: username, name: name,
password: password, username: username,
confirmPassword: confirmPassword, email: email,
password: password,
jobTitle: jobTitle,
}), }),
}) })
.then(response => { .then(response => {
if (!response.ok) { if (response.status === 201) {
throw new Error(`HTTP error! Status: ${response.status}`); // Status 201 indicates successful creation
}
return response.json(); return response.json();
} else {
return response.json().then(data => {
throw new Error(data.error || `HTTP error! Status: ${response.status}`);
});
}
}) })
.then(data => { .then(data => {
console.log('Success:', data); console.log('User registration success:', data);
alert('User registered successfully!');
// Show an alert with the received data resetFormFields();
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 => { .catch(error => {
// Handle 404 error separately to show an alert console.error('User registration error:', error);
if (error.message.includes('HTTP error! Status: 404')) { handleRegistrationError(error);
alert('User not found. Please enter a valid username.');
} else {
console.error('Fetch Error:', error);
}
}); });
});
function handleRegistrationError(error) {
console.error('Registration error:', error); // Log the full error object for debugging
let errorMessage;
if (typeof error === 'string') {
errorMessage = error;
} else if (error instanceof Error) {
errorMessage = error.message;
} else if (error.response && error.response.data && error.response.data.error) {
errorMessage = error.response.data.error;
} else {
errorMessage = 'Unknown error';
}
if (errorMessage.includes('Username is already taken')) {
alert('Username is already taken. Please choose a different username.');
} else if (errorMessage.includes('Email is already in use')) {
alert('Email is already in use. Please choose a different email.');
} else if (errorMessage.includes('Password does not meet complexity requirements')) {
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.');
} else if (errorMessage.includes('User registration failed')) {
alert('User registration failed. Please try again.');
} else {
alert(`Unknown error: ${errorMessage}`);
}
}
$('#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('Error: 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('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.');
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) {
return response.text().then(errorText => {
throw new Error(`HTTP error! Status: ${response.status}, Error: ${errorText}`);
});
}
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('Error: User not found. Please enter a valid username.');
} else {
console.error('Fetch Error:', error);
}
});
}); });
</script> </script>
</div> </div>