Merge pull request 'fix for reports' (#5) from typing into main
Reviewed-on: nmemmert/Spelling#5
This commit is contained in:
commit
75eaf88d9d
7 files changed
+210
-4
No files matched your search
+4
-1
@@ -5,5 +5,8 @@
|
|||||||
"Accuracy Master",
|
"Accuracy Master",
|
||||||
"Practice Streak",
|
"Practice Streak",
|
||||||
"Vocabulary Pro"
|
"Vocabulary Pro"
|
||||||
]
|
],
|
||||||
|
"admin1": [],
|
||||||
|
"student1": [],
|
||||||
|
"testuser": []
|
||||||
}
|
}
|
||||||
+3
-1
@@ -67,5 +67,7 @@
|
|||||||
],
|
],
|
||||||
"timestamp": "2025-07-15T14:36:13.273Z"
|
"timestamp": "2025-07-15T14:36:13.273Z"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"admin1": [],
|
||||||
|
"testuser": []
|
||||||
}
|
}
|
||||||
@@ -13,5 +13,10 @@
|
|||||||
"username": "student1",
|
"username": "student1",
|
||||||
"hash": "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92",
|
"hash": "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92",
|
||||||
"role": "student"
|
"role": "student"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "testuser",
|
||||||
|
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||||
|
"role": "student"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -17,5 +17,17 @@
|
|||||||
"mouse",
|
"mouse",
|
||||||
"screen",
|
"screen",
|
||||||
"printer"
|
"printer"
|
||||||
|
],
|
||||||
|
"testuser": [
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
"test",
|
||||||
|
"sample",
|
||||||
|
"basic",
|
||||||
|
"learn",
|
||||||
|
"spell",
|
||||||
|
"word",
|
||||||
|
"study",
|
||||||
|
"practice"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -89,6 +89,30 @@ for (const [key, file] of Object.entries(files)) {
|
|||||||
ensureFileWithSeed(file, defaultData);
|
ensureFileWithSeed(file, defaultData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔄 Initialize existing users in all data files
|
||||||
|
function initializeAllExistingUsers() {
|
||||||
|
console.log('🔄 Checking all users are initialized...');
|
||||||
|
const users = readJsonSafe(path.join(DATA_DIR, files.users), []);
|
||||||
|
|
||||||
|
users.forEach(user => {
|
||||||
|
// Check if user exists in all data files
|
||||||
|
const wordlists = readJsonSafe(path.join(DATA_DIR, files.wordlists), {});
|
||||||
|
const results = readJsonSafe(path.join(DATA_DIR, files.results), {});
|
||||||
|
const badges = readJsonSafe(path.join(DATA_DIR, files.badges), {});
|
||||||
|
|
||||||
|
const needsInit = !wordlists[user.username] || !results[user.username] || !badges[user.username];
|
||||||
|
|
||||||
|
if (needsInit) {
|
||||||
|
console.log(`🔧 User "${user.username}" needs initialization`);
|
||||||
|
initializeUserInAllFiles(user.username);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('✅ All users initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize all existing users
|
||||||
|
initializeAllExistingUsers();
|
||||||
|
|
||||||
// 🔐 JSON utility
|
// 🔐 JSON utility
|
||||||
function readJsonSafe(filePath, fallback = {}) {
|
function readJsonSafe(filePath, fallback = {}) {
|
||||||
try {
|
try {
|
||||||
@@ -98,6 +122,41 @@ function readJsonSafe(filePath, fallback = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔧 Initialize user across 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, files.wordlists);
|
||||||
|
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, files.results);
|
||||||
|
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, files.badges);
|
||||||
|
const badges = readJsonSafe(badgesPath, {});
|
||||||
|
if (!badges[username]) {
|
||||||
|
badges[username] = [];
|
||||||
|
fs.writeFileSync(badgesPath, JSON.stringify(badges, null, 2));
|
||||||
|
console.log(`🏆 Added badge tracking for "${username}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 🔐 Verify login
|
// 🔐 Verify login
|
||||||
app.post('/verifyUser', (req, res) => {
|
app.post('/verifyUser', (req, res) => {
|
||||||
const { username, hash } = req.body;
|
const { username, hash } = req.body;
|
||||||
@@ -136,9 +195,15 @@ app.post('/addUser', (req, res) => {
|
|||||||
if (users.find(u => u.username === username)) {
|
if (users.find(u => u.username === username)) {
|
||||||
return res.status(409).send("User already exists");
|
return res.status(409).send("User already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add user to users.json
|
||||||
users.push({ username: username.trim(), hash, role: role.trim() });
|
users.push({ username: username.trim(), hash, role: role.trim() });
|
||||||
fs.writeFileSync(path.join(DATA_DIR, files.users), JSON.stringify(users, null, 2));
|
fs.writeFileSync(path.join(DATA_DIR, files.users), JSON.stringify(users, null, 2));
|
||||||
res.send(`✅ User "${username}" added`);
|
|
||||||
|
// Initialize user in all other data files
|
||||||
|
initializeUserInAllFiles(username.trim());
|
||||||
|
|
||||||
|
res.send(`✅ User "${username}" added and initialized`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ❌ Delete user
|
// ❌ Delete user
|
||||||
@@ -153,8 +218,28 @@ app.post('/deleteUser', (req, res) => {
|
|||||||
if (users.length === updated.length) {
|
if (users.length === updated.length) {
|
||||||
return res.status(404).send("User not found");
|
return res.status(404).send("User not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove from users.json
|
||||||
fs.writeFileSync(usersPath, JSON.stringify(updated, null, 2));
|
fs.writeFileSync(usersPath, JSON.stringify(updated, null, 2));
|
||||||
res.send(`✅ User "${username}" deleted`);
|
|
||||||
|
// Clean up from other data files
|
||||||
|
const wordlistsPath = path.join(DATA_DIR, files.wordlists);
|
||||||
|
const wordlists = readJsonSafe(wordlistsPath, {});
|
||||||
|
delete wordlists[username];
|
||||||
|
fs.writeFileSync(wordlistsPath, JSON.stringify(wordlists, null, 2));
|
||||||
|
|
||||||
|
const resultsPath = path.join(DATA_DIR, files.results);
|
||||||
|
const results = readJsonSafe(resultsPath, {});
|
||||||
|
delete results[username];
|
||||||
|
fs.writeFileSync(resultsPath, JSON.stringify(results, null, 2));
|
||||||
|
|
||||||
|
const badgesPath = path.join(DATA_DIR, files.badges);
|
||||||
|
const badges = readJsonSafe(badgesPath, {});
|
||||||
|
delete badges[username];
|
||||||
|
fs.writeFileSync(badgesPath, JSON.stringify(badges, null, 2));
|
||||||
|
|
||||||
|
console.log(`🗑️ Cleaned up all data for user "${username}"`);
|
||||||
|
res.send(`✅ User "${username}" deleted and cleaned up`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 🔐 Change user password
|
// 🔐 Change user password
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
const postData = JSON.stringify({
|
||||||
|
username: 'testuser',
|
||||||
|
hash: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', // empty string hash
|
||||||
|
role: 'student'
|
||||||
|
});
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
hostname: 'localhost',
|
||||||
|
port: 3000,
|
||||||
|
path: '/addUser',
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Content-Length': Buffer.byteLength(postData)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = http.request(options, (res) => {
|
||||||
|
console.log(`Status: ${res.statusCode}`);
|
||||||
|
console.log(`Headers: ${JSON.stringify(res.headers)}`);
|
||||||
|
res.setEncoding('utf8');
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
console.log(`Body: ${chunk}`);
|
||||||
|
});
|
||||||
|
res.on('end', () => {
|
||||||
|
console.log('No more data in response.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (e) => {
|
||||||
|
console.error(`Problem with request: ${e.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.write(postData);
|
||||||
|
req.end();
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
// Test adding a new user
|
||||||
|
const postData = JSON.stringify({
|
||||||
|
username: 'teststudent',
|
||||||
|
hash: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', // empty string hash
|
||||||
|
role: 'student'
|
||||||
|
});
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
hostname: 'localhost',
|
||||||
|
port: 3000,
|
||||||
|
path: '/addUser',
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Content-Length': Buffer.byteLength(postData)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('Testing new user addition and initialization...');
|
||||||
|
|
||||||
|
const req = http.request(options, (res) => {
|
||||||
|
console.log(`✅ Add User Status: ${res.statusCode}`);
|
||||||
|
res.setEncoding('utf8');
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
console.log(`📝 Response: ${chunk}`);
|
||||||
|
});
|
||||||
|
res.on('end', () => {
|
||||||
|
console.log('🔄 Now testing if user data is properly initialized...');
|
||||||
|
|
||||||
|
// Test getting word list for new user
|
||||||
|
const wordListReq = http.request({
|
||||||
|
hostname: 'localhost',
|
||||||
|
port: 3000,
|
||||||
|
path: '/getWordList?username=teststudent',
|
||||||
|
method: 'GET'
|
||||||
|
}, (res) => {
|
||||||
|
console.log(`📚 Word List Status: ${res.statusCode}`);
|
||||||
|
res.setEncoding('utf8');
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
console.log(`📝 Word List Data: ${chunk}`);
|
||||||
|
});
|
||||||
|
res.on('end', () => {
|
||||||
|
console.log('✅ Test completed - New user properly initialized!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
wordListReq.on('error', (e) => {
|
||||||
|
console.error(`❌ Word List Error: ${e.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
wordListReq.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (e) => {
|
||||||
|
console.error(`❌ Add User Error: ${e.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.write(postData);
|
||||||
|
req.end();
|
||||||
Reference in new issue
Block a user