Fix user addition functionality with improved error handling

This commit is contained in:
nate@necloud.us committed 2025-08-13 20:03:38 -04:00
1 parent 90d79924f8
commit 027074f43d
4 files changed
+266 -13

No files matched your search

+184
View File
@@ -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
View File
@@ -12,7 +12,20 @@
<link href="gamification.css" rel="stylesheet"/>
<link href="spaced-repetition.css" rel="stylesheet"/>
<!-- 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/ui.js"></script>
<script src="js/themes.js"></script>
+28 -3
View File
@@ -217,26 +217,51 @@ async function addNewUser() {
return;
}
const hash = hashPassword(password);
// 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]';
// 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);
}
}
+40 -9
View File
@@ -490,27 +490,58 @@ app.post('/verifyUser', (req, res) => {
// ➕ Add user
app.post('/addUser', (req, res) => {
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())
) 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");
) {
console.error(`❌ Invalid user data types or values`);
return res.status(400).send("Invalid user data");
}
// 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: username.trim(), hash, role: role.trim() });
fs.writeFileSync(path.join(DATA_DIR, files.users), JSON.stringify(users, null, 2));
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(username.trim());
initializeUserInAllFiles(trimmedUsername);
res.send(`✅ User "${username}" added and initialized`);
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}`);
}
});
// ❌ Delete user