Fix user addition functionality with improved error handling
This commit is contained in:
1 parent
90d79924f8
commit
027074f43d
4 files changed
+280
-27
No files matched your search
@@ -0,0 +1,184 @@
|
|||||||
|
// This script directly fixes the user addition functionality
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
// Function to hash password using SHA-256
|
||||||
|
function hashPassword(password) {
|
||||||
|
return crypto.createHash('sha256').update(password).digest('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
const DATA_DIR = path.join(__dirname, 'data');
|
||||||
|
const USERS_FILE = path.join(DATA_DIR, 'users.json');
|
||||||
|
|
||||||
|
// Function to safely read JSON files
|
||||||
|
function readJsonSafe(filePath, defaultValue) {
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
const data = fs.readFileSync(filePath, 'utf8');
|
||||||
|
if (!data || data.trim() === '') return defaultValue;
|
||||||
|
return JSON.parse(data);
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Error reading ${filePath}:`, e);
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize user in all data files
|
||||||
|
function initializeUserInAllFiles(username) {
|
||||||
|
console.log(`🔧 Initializing user "${username}" across all data files`);
|
||||||
|
|
||||||
|
// Initialize in wordlists.json
|
||||||
|
const wordlistsPath = path.join(DATA_DIR, 'wordlists.json');
|
||||||
|
const wordlists = readJsonSafe(wordlistsPath, {});
|
||||||
|
if (!wordlists[username]) {
|
||||||
|
wordlists[username] = [
|
||||||
|
"hello", "world", "test", "sample", "basic",
|
||||||
|
"learn", "spell", "word", "study", "practice"
|
||||||
|
];
|
||||||
|
fs.writeFileSync(wordlistsPath, JSON.stringify(wordlists, null, 2));
|
||||||
|
console.log(`📝 Added default word list for "${username}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize in results.json
|
||||||
|
const resultsPath = path.join(DATA_DIR, 'results.json');
|
||||||
|
const results = readJsonSafe(resultsPath, {});
|
||||||
|
if (!results[username]) {
|
||||||
|
results[username] = [];
|
||||||
|
fs.writeFileSync(resultsPath, JSON.stringify(results, null, 2));
|
||||||
|
console.log(`📊 Added results tracking for "${username}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize in badges.json
|
||||||
|
const badgesPath = path.join(DATA_DIR, 'badges.json');
|
||||||
|
const badges = readJsonSafe(badgesPath, {});
|
||||||
|
if (!badges[username]) {
|
||||||
|
badges[username] = [];
|
||||||
|
fs.writeFileSync(badgesPath, JSON.stringify(badges, null, 2));
|
||||||
|
console.log(`🏆 Added badge tracking for "${username}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize in progress.json
|
||||||
|
const progressPath = path.join(DATA_DIR, 'progress.json');
|
||||||
|
const progress = readJsonSafe(progressPath, {});
|
||||||
|
if (!progress[username]) {
|
||||||
|
progress[username] = {
|
||||||
|
stats: {
|
||||||
|
points: 0,
|
||||||
|
totalSessions: 0,
|
||||||
|
totalWords: 0,
|
||||||
|
correctWords: 0,
|
||||||
|
accuracy: 0
|
||||||
|
},
|
||||||
|
streaks: {
|
||||||
|
current: 0,
|
||||||
|
longest: 0,
|
||||||
|
lastActivity: null
|
||||||
|
},
|
||||||
|
challengesCompleted: {
|
||||||
|
daily: [],
|
||||||
|
weekly: [],
|
||||||
|
achievements: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fs.writeFileSync(progressPath, JSON.stringify(progress, null, 2));
|
||||||
|
console.log(`📈 Added progress tracking for "${username}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize in spacedRepetition.json
|
||||||
|
const srPath = path.join(DATA_DIR, 'spacedRepetition.json');
|
||||||
|
const srData = readJsonSafe(srPath, {});
|
||||||
|
if (!srData[username]) {
|
||||||
|
srData[username] = {
|
||||||
|
settings: {
|
||||||
|
dailyLimit: 20,
|
||||||
|
reviewThreshold: 3,
|
||||||
|
newWordsPerDay: 5
|
||||||
|
},
|
||||||
|
stats: {
|
||||||
|
totalReviews: 0,
|
||||||
|
correctReviews: 0,
|
||||||
|
totalWords: 0,
|
||||||
|
masteredWords: 0
|
||||||
|
},
|
||||||
|
words: {}
|
||||||
|
};
|
||||||
|
fs.writeFileSync(srPath, JSON.stringify(srData, null, 2));
|
||||||
|
console.log(`📚 Added spaced repetition data for "${username}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new user
|
||||||
|
function addUser(username, password, role) {
|
||||||
|
if (
|
||||||
|
typeof username !== 'string' ||
|
||||||
|
typeof password !== 'string' ||
|
||||||
|
typeof role !== 'string' ||
|
||||||
|
!['admin', 'student'].includes(role.trim().toLowerCase())
|
||||||
|
) {
|
||||||
|
console.error("❌ Invalid user data");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean inputs
|
||||||
|
username = username.trim();
|
||||||
|
role = role.trim().toLowerCase();
|
||||||
|
|
||||||
|
// Read users
|
||||||
|
const users = readJsonSafe(USERS_FILE, []);
|
||||||
|
|
||||||
|
// Check if user exists
|
||||||
|
if (users.find(u => u.username === username)) {
|
||||||
|
console.error(`❌ User "${username}" already exists`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash password
|
||||||
|
const hash = hashPassword(password);
|
||||||
|
|
||||||
|
// Add user to users.json
|
||||||
|
users.push({ username, hash, role });
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Write users to file
|
||||||
|
fs.writeFileSync(USERS_FILE, JSON.stringify(users, null, 2));
|
||||||
|
console.log(`✅ User "${username}" added to users.json`);
|
||||||
|
|
||||||
|
// Initialize user in all data files
|
||||||
|
initializeUserInAllFiles(username);
|
||||||
|
|
||||||
|
console.log(`✅ User "${username}" successfully added and initialized`);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Error adding user: ${error.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define user to add
|
||||||
|
const NEW_USERNAME = "newstudent";
|
||||||
|
const NEW_PASSWORD = "newpassword";
|
||||||
|
const NEW_ROLE = "student";
|
||||||
|
|
||||||
|
// Add the user
|
||||||
|
const result = addUser(NEW_USERNAME, NEW_PASSWORD, NEW_ROLE);
|
||||||
|
|
||||||
|
// Show result
|
||||||
|
if (result) {
|
||||||
|
console.log("\n✅ USER ADDED SUCCESSFULLY!");
|
||||||
|
console.log(`Username: ${NEW_USERNAME}`);
|
||||||
|
console.log(`Password: ${NEW_PASSWORD}`);
|
||||||
|
console.log(`Role: ${NEW_ROLE}`);
|
||||||
|
|
||||||
|
// List all users
|
||||||
|
const users = readJsonSafe(USERS_FILE, []);
|
||||||
|
console.log("\n👥 Current Users:");
|
||||||
|
users.forEach(user => {
|
||||||
|
console.log(`- ${user.username} (${user.role})`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error("\n❌ FAILED TO ADD USER");
|
||||||
|
}
|
||||||
+14
-1
@@ -12,7 +12,20 @@
|
|||||||
<link href="gamification.css" rel="stylesheet"/>
|
<link href="gamification.css" rel="stylesheet"/>
|
||||||
<link href="spaced-repetition.css" rel="stylesheet"/>
|
<link href="spaced-repetition.css" rel="stylesheet"/>
|
||||||
<!-- Scripts -->
|
<!-- Scripts -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsSHA/2.4.2/sha.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsSHA/2.4.2/sha.js" integrity="sha512-MK4YCs3cv9dRCsEzFP5rehiUXbU0iKdwILVZ2SylXqCFFWOk1F4vGRrGGXc0qbHWM7S6gy4Xv/MGK19vKZbvKA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
<!-- Fallback for jsSHA library if CDN fails -->
|
||||||
|
<script>
|
||||||
|
window.addEventListener('DOMContentLoaded', function() {
|
||||||
|
if (typeof jsSHA === 'undefined') {
|
||||||
|
console.warn('jsSHA not loaded from CDN, using fallback');
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = 'https://cdn.jsdelivr.net/npm/jssha@3.3.0/dist/sha.js';
|
||||||
|
document.head.appendChild(script);
|
||||||
|
} else {
|
||||||
|
console.log('jsSHA loaded successfully');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<script src="js/auth.js"></script>
|
<script src="js/auth.js"></script>
|
||||||
<script src="js/ui.js"></script>
|
<script src="js/ui.js"></script>
|
||||||
<script src="js/themes.js"></script>
|
<script src="js/themes.js"></script>
|
||||||
|
|||||||
+32
-7
@@ -217,26 +217,51 @@ async function addNewUser() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hash = hashPassword(password);
|
// Check if hashPassword function exists
|
||||||
if (hashPreview) hashPreview.textContent = hash;
|
let hash;
|
||||||
|
try {
|
||||||
|
hash = hashPassword(password);
|
||||||
|
console.log("✅ Password hashed successfully");
|
||||||
|
if (hashPreview) hashPreview.textContent = hash;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("❌ Error hashing password:", e);
|
||||||
|
msg.textContent = "Error: Unable to hash password. Check console for details.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fetch('/addUser', {
|
console.log(`🔄 Sending request to add user: ${username} (${role})`);
|
||||||
|
|
||||||
|
const response = await fetch('/addUser', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ username, hash, role })
|
body: JSON.stringify({ username, hash, role })
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(`📥 Server response: ${response.status} ${response.statusText}`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
throw new Error(`Server returned ${response.status}: ${errorText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const successText = await response.text();
|
||||||
|
console.log(`✅ Success: ${successText}`);
|
||||||
msg.textContent = `✅ User "${username}" added to server.`;
|
msg.textContent = `✅ User "${username}" added to server.`;
|
||||||
|
|
||||||
|
// Clear form
|
||||||
document.getElementById("newUsername").value = '';
|
document.getElementById("newUsername").value = '';
|
||||||
document.getElementById("newPassword").value = '';
|
document.getElementById("newPassword").value = '';
|
||||||
if (hashPreview) hashPreview.textContent = '[auto]';
|
if (hashPreview) hashPreview.textContent = '[auto]';
|
||||||
|
|
||||||
await loadUsers();
|
// Refresh user lists
|
||||||
displayUserDropdown();
|
await loadUsers();
|
||||||
populateWordUserDropdown();
|
displayUserDropdown();
|
||||||
|
if (typeof populateWordUserDropdown === 'function') {
|
||||||
|
populateWordUserDropdown();
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
msg.textContent = "❌ Failed to add user.";
|
msg.textContent = `❌ Failed to add user: ${e.message}`;
|
||||||
console.error("Add user error:", e);
|
console.error("Add user error:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -490,27 +490,58 @@ app.post('/verifyUser', (req, res) => {
|
|||||||
|
|
||||||
// ➕ Add user
|
// ➕ Add user
|
||||||
app.post('/addUser', (req, res) => {
|
app.post('/addUser', (req, res) => {
|
||||||
const { username, hash, role } = req.body;
|
try {
|
||||||
if (
|
console.log(`📥 Received addUser request:`, req.body);
|
||||||
typeof username !== 'string' ||
|
|
||||||
typeof hash !== 'string' ||
|
const { username, hash, role } = req.body;
|
||||||
typeof role !== 'string' ||
|
|
||||||
!['admin', 'student'].includes(role.trim().toLowerCase())
|
// Validate required fields
|
||||||
) return res.status(400).send("Invalid user data");
|
if (!username || !hash || !role) {
|
||||||
|
console.error(`❌ Missing required fields: ${!username ? 'username' : ''} ${!hash ? 'hash' : ''} ${!role ? 'role' : ''}`);
|
||||||
|
return res.status(400).send("Missing required fields");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate data types and values
|
||||||
|
if (
|
||||||
|
typeof username !== 'string' ||
|
||||||
|
typeof hash !== 'string' ||
|
||||||
|
typeof role !== 'string' ||
|
||||||
|
!['admin', 'student'].includes(role.trim().toLowerCase())
|
||||||
|
) {
|
||||||
|
console.error(`❌ Invalid user data types or values`);
|
||||||
|
return res.status(400).send("Invalid user data");
|
||||||
|
}
|
||||||
|
|
||||||
const users = readJsonSafe(path.join(DATA_DIR, files.users), []);
|
// Trim inputs
|
||||||
if (users.find(u => u.username === username)) {
|
const trimmedUsername = username.trim();
|
||||||
return res.status(409).send("User already exists");
|
const trimmedRole = role.trim().toLowerCase();
|
||||||
|
|
||||||
|
// Check for existing user
|
||||||
|
const usersPath = path.join(DATA_DIR, files.users);
|
||||||
|
const users = readJsonSafe(usersPath, []);
|
||||||
|
if (users.find(u => u.username === trimmedUsername)) {
|
||||||
|
console.error(`❌ User "${trimmedUsername}" already exists`);
|
||||||
|
return res.status(409).send(`User "${trimmedUsername}" already exists`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✏️ Adding new ${trimmedRole} user: ${trimmedUsername}`);
|
||||||
|
|
||||||
|
// Add user to users.json
|
||||||
|
users.push({ username: trimmedUsername, hash, role: trimmedRole });
|
||||||
|
|
||||||
|
// Write to file
|
||||||
|
fs.writeFileSync(usersPath, JSON.stringify(users, null, 2));
|
||||||
|
console.log(`✅ Added user to users.json: ${trimmedUsername}`);
|
||||||
|
|
||||||
|
// Initialize user in all other data files
|
||||||
|
initializeUserInAllFiles(trimmedUsername);
|
||||||
|
|
||||||
|
console.log(`✅ User "${trimmedUsername}" successfully added and initialized`);
|
||||||
|
res.send(`✅ User "${trimmedUsername}" added and initialized`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`🔴 Error in /addUser:`, error);
|
||||||
|
res.status(500).send(`Server error: ${error.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add user to users.json
|
|
||||||
users.push({ username: username.trim(), hash, role: role.trim() });
|
|
||||||
fs.writeFileSync(path.join(DATA_DIR, files.users), JSON.stringify(users, null, 2));
|
|
||||||
|
|
||||||
// Initialize user in all other data files
|
|
||||||
initializeUserInAllFiles(username.trim());
|
|
||||||
|
|
||||||
res.send(`✅ User "${username}" added and initialized`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// ❌ Delete user
|
// ❌ Delete user
|
||||||
|
|||||||
Reference in new issue
Block a user