From 5fcd5dbdcb7b31021b58b46339042c13f2422063 Mon Sep 17 00:00:00 2001 From: Lars Behrends Date: Mon, 29 Dec 2025 11:22:44 +0100 Subject: [PATCH] feat: enhance player model with organizationId and update related API handling --- backend/database.js | 17 +++++++----- backend/server.js | 61 ++++------------------------------------- pages/PlayerProfile.tsx | 22 +++++++++------ types.ts | 2 +- 4 files changed, 30 insertions(+), 72 deletions(-) diff --git a/backend/database.js b/backend/database.js index 9cbb85f..c5c20dd 100644 --- a/backend/database.js +++ b/backend/database.js @@ -22,10 +22,11 @@ const SEED_PLAYERS = [ isNpc: 0, isAdmin: 0, tags: JSON.stringify(['#Bürger', '#Händler']), - stats: JSON.stringify({ playtimeHours: 482, level: 45, role: 'Bürger', organizationId: 'org-3' }), + stats: JSON.stringify({ playtimeHours: 482, level: 45, role: 'Bürger' }), minecraftStats: null, inventory: JSON.stringify([]), - storyMarkdown: '# Der Bauplan von V\n\n> "Stein erinnert sich..."' + storyMarkdown: '# Der Bauplan von V\n\n> "Stein erinnert sich..."', + organizationId: 'org-3' }, { uuid: '8984c0b5-d912-4462-b189-c864fba4a1af', @@ -34,10 +35,11 @@ const SEED_PLAYERS = [ isNpc: 0, isAdmin: 1, // DrKButz is admin for testing tags: JSON.stringify(['#Bauunternehmer']), - stats: JSON.stringify({ playtimeHours: 120, level: 12, role: 'Unternehmer', organizationId: 'org-4' }), + stats: JSON.stringify({ playtimeHours: 120, level: 12, role: 'Unternehmer' }), minecraftStats: null, inventory: JSON.stringify([]), - storyMarkdown: '# Forschungslogbuch:\n\nSpezialisiert auf...' + storyMarkdown: '# Forschungslogbuch:\n\nSpezialisiert auf...', + organizationId: 'org-4' } ]; @@ -122,7 +124,8 @@ function setupTables() { minecraftStats JSON, inventory JSON, storyMarkdown TEXT, - discordId VARCHAR(255) + discordId VARCHAR(255), + organizationId VARCHAR(50) )`, `CREATE TABLE IF NOT EXISTS orgs ( id VARCHAR(50) PRIMARY KEY, @@ -184,8 +187,8 @@ function seedData() { if (!err && rows[0].count === 0) { console.log("Seeding Players..."); SEED_PLAYERS.forEach(p => { - pool.query("INSERT INTO players VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - [p.uuid, p.username, p.isOnline, p.isNpc, p.isAdmin, p.tags, p.stats, p.inventory, p.storyMarkdown, null]); + pool.query("INSERT INTO players VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + [p.uuid, p.username, p.isOnline, p.isNpc, p.isAdmin, p.tags, p.stats, p.minecraftStats, p.inventory, p.storyMarkdown, null, p.organizationId]); }); } }); diff --git a/backend/server.js b/backend/server.js index 3155b80..56cf7b1 100644 --- a/backend/server.js +++ b/backend/server.js @@ -153,11 +153,11 @@ app.get('/api/players', (req, res) => { const parsed = rows.map(r => ({ ...r, tags: JSON.parse(r.tags || '[]'), - stats: JSON.parse(r.minecraftStats || '{}'), - //stats: JSON.parse(r.stats || '{}'), - //minecraftStats: r.minecraftStats ? JSON.parse(r.minecraftStats) : undefined, + stats: JSON.parse(r.stats || '{}'), + minecraftStats: r.minecraftStats ? JSON.parse(r.minecraftStats) : undefined, inventory: JSON.parse(r.inventory || '[]'), - isOnline: !!r.isOnline + isOnline: !!r.isOnline, + organizationId: r.organizationId || undefined })); res.json(parsed); }); @@ -189,60 +189,11 @@ app.put('/api/players/:uuid', (req, res) => { } const updates = req.body; - const allowedFields = ['storyMarkdown', 'tags']; + const allowedFields = ['storyMarkdown', 'tags', 'organizationId']; const updateFields = []; const values = []; - // Handle organizationId specially - it goes into stats JSON - if (updates.organizationId !== undefined) { - // First get current player data - db.get("SELECT stats FROM players WHERE uuid = ?", [req.params.uuid], (err, row) => { - if (err) return res.status(500).json({error: err.message}); - if (!row) return res.status(404).json({error: 'Spieler nicht gefunden'}); - - try { - const currentStats = JSON.parse(row.stats || '{}'); - const updatedStats = { ...currentStats, organizationId: updates.organizationId }; - - updateFields.push('stats = ?'); - values.push(JSON.stringify(updatedStats)); - } catch (e) { - return res.status(500).json({error: 'Fehler beim Verarbeiten der Stats'}); - } - - // Continue with other fields - for (const field of allowedFields) { - if (updates[field] !== undefined) { - if (field === 'tags') { - // Tags are stored as JSON - updateFields.push(`${field} = ?`); - values.push(JSON.stringify(updates[field])); - } else { - updateFields.push(`${field} = ?`); - values.push(updates[field]); - } - } - } - - if (updateFields.length === 0) { - return res.status(400).json({error: 'Keine gültigen Felder zum Aktualisieren'}); - } - - const query = `UPDATE players SET ${updateFields.join(', ')} WHERE uuid = ?`; - values.push(req.params.uuid); - - db.run(query, values, function(err) { - if (err) { - console.error('Error updating player:', err); - return res.status(500).json({error: 'Fehler beim Aktualisieren'}); - } - res.json({success: true, message: 'Spieler erfolgreich aktualisiert'}); - }); - }); - return; // Exit early since we're handling this asynchronously - } - - // Handle other fields normally + // Handle fields for (const field of allowedFields) { if (updates[field] !== undefined) { if (field === 'tags') { diff --git a/pages/PlayerProfile.tsx b/pages/PlayerProfile.tsx index f474518..2b97a5b 100644 --- a/pages/PlayerProfile.tsx +++ b/pages/PlayerProfile.tsx @@ -22,7 +22,7 @@ const PlayerProfile: React.FC = () => { // Is this the logged-in user's profile? const isOwner = currentUser?.linkedPlayerUuid === player?.uuid; - const playerOrg = player ? dbService.getOrg(player.stats?.organizationId || '') : null; + const playerOrg = player ? dbService.getOrg(player.organizationId || '') : null; // Check if player is already linked to anyone in our mock/real DB logic // Since the Player object doesn't expose 'discordId' publicly in types yet (it's hidden in DB), @@ -44,12 +44,15 @@ const PlayerProfile: React.FC = () => { return; } + console.log(playerData); setLoading(false); }, [id, navigate]); useEffect(() => { if (!player) return; + console.log(player); + // Load owned projects const allProjects = dbService.getProjects(); const playerProjects = allProjects.filter(p => p.owner === player.username); @@ -105,7 +108,7 @@ const PlayerProfile: React.FC = () => { if (response.ok) { // Update local state - setPlayer(prev => ({ ...prev, stats: { ...prev.stats, organizationId: orgId || undefined } })); + setPlayer(prev => ({ ...prev, organizationId: orgId || undefined })); } else { alert('Fehler beim Aktualisieren der Zugehörigkeit'); } @@ -135,6 +138,7 @@ const PlayerProfile: React.FC = () => { }); }; + console.log(player); return (
@@ -201,8 +205,8 @@ const PlayerProfile: React.FC = () => {
- {player.minecraftStats?.statistics?.general?.["minecraft:play_time"] - ? `${Math.round((player.minecraftStats.statistics.general["minecraft:play_time"] || 0) / 20 / 3600)}h` + {player.stats?.statistics?.general?.["minecraft:play_time"] + ? `${Math.round((player.stats.statistics.general["minecraft:play_time"] || 0) / 20 / 3600)}h` : `${player.stats?.playtimeHours || 0}h` } @@ -210,27 +214,27 @@ const PlayerProfile: React.FC = () => {
- Lvl {player.minecraftStats?.char?.xpLevel || player.stats?.level || 1} + Lvl {player.stats?.char?.xpLevel || player.stats?.level || 1}
- {player.minecraftStats && player.minecraftStats.char && player.minecraftStats.statistics && ( + {player.stats && player.stats.char && player.stats.statistics && ( <>
- {player.minecraftStats.char.health}/{player.minecraftStats.char.maxHealth} HP + {player.stats.char.health}/{player.stats.char.maxHealth} HP
- {player.minecraftStats.char.foodLevel}/20 Food + {player.stats.char.foodLevel}/20 Food
- {player.minecraftStats.statistics.general?.["minecraft:mob_kills"] || 0} Kills + {player.stats.statistics.general?.["minecraft:mob_kills"] || 0} Kills
diff --git a/types.ts b/types.ts index 079fcbf..0ecee61 100644 --- a/types.ts +++ b/types.ts @@ -35,7 +35,6 @@ export interface PlayerStats { playtimeHours: number; level: number; role: string; - organizationId?: string; } export interface Player { @@ -48,6 +47,7 @@ export interface Player { storyMarkdown: string; tags: string[]; isOnline: boolean; + organizationId?: string; } export interface CityStats {