diff --git a/fix_user_addition.js b/fix_user_addition.js new file mode 100644 index 0000000..d01f1e2 --- /dev/null +++ b/fix_user_addition.js @@ -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"); +} diff --git a/public/index.html b/public/index.html index 215dd57..e547655 100644 --- a/public/index.html +++ b/public/index.html @@ -12,7 +12,20 @@ - + + + diff --git a/public/js/admin.js b/public/js/admin.js index d3aea0e..7d16281 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -217,26 +217,51 @@ async function addNewUser() { return; } - const hash = hashPassword(password); - if (hashPreview) hashPreview.textContent = hash; + // Check if hashPassword function exists + 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 { - await fetch('/addUser', { + console.log(`šŸ”„ Sending request to add user: ${username} (${role})`); + + const response = await fetch('/addUser', { method: 'POST', headers: { 'Content-Type': 'application/json' }, 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.`; + // Clear form document.getElementById("newUsername").value = ''; document.getElementById("newPassword").value = ''; if (hashPreview) hashPreview.textContent = '[auto]'; - await loadUsers(); - displayUserDropdown(); - populateWordUserDropdown(); + // Refresh user lists + await loadUsers(); + displayUserDropdown(); + if (typeof populateWordUserDropdown === 'function') { + populateWordUserDropdown(); + } } catch (e) { - msg.textContent = "āŒ Failed to add user."; + msg.textContent = `āŒ Failed to add user: ${e.message}`; console.error("Add user error:", e); } } diff --git a/server.js b/server.js index de2f0ee..c49393b 100644 --- a/server.js +++ b/server.js @@ -490,27 +490,58 @@ app.post('/verifyUser', (req, res) => { // āž• Add user app.post('/addUser', (req, res) => { - const { username, hash, role } = req.body; - if ( - typeof username !== 'string' || - typeof hash !== 'string' || - typeof role !== 'string' || - !['admin', 'student'].includes(role.trim().toLowerCase()) - ) return res.status(400).send("Invalid user data"); + try { + console.log(`šŸ“„ Received addUser request:`, req.body); + + const { username, hash, role } = req.body; + + // Validate required fields + 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), []); - if (users.find(u => u.username === username)) { - return res.status(409).send("User already exists"); + // Trim inputs + const trimmedUsername = username.trim(); + 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