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