diff --git a/PRODUCTION-FIX-GUIDE.md b/PRODUCTION-FIX-GUIDE.md index c0c2619..82458cc 100644 --- a/PRODUCTION-FIX-GUIDE.md +++ b/PRODUCTION-FIX-GUIDE.md @@ -51,12 +51,33 @@ Si l'interface affiche "Aucun utilisateur trouvé" : - `debug-usergroups-production.sql` : Problèmes d'association utilisateur-groupe - `production-users-debug.sql` : Problème de récupération des utilisateurs +### Problème Création d'Utilisateur +Si la création d'utilisateur échoue : + +1. **Test Manuel** : Utilisez `test-create-user-production.js` + ```bash + PRODUCTION_HOST=votre-domaine.com SESSION_COOKIE="connect.sid=..." node test-create-user-production.js + ``` + +2. **Vérification Logs** : Cherchez ces messages d'erreur : + - `❌ Password hashing failed` + - `❌ Storage createUser error` + - Database connection errors + ### Logs de Débogage Disponibles +**Récupération Utilisateurs :** - `🔍 GET /api/users - Fetching users with simplified approach` - `📊 Found X base users` - `❌ Error getting groups for user [username]:` - `🔐 API /api/users - Returning: {length: X, totalGroups: Y}` +**Création Utilisateur :** +- `🔍 POST /api/users - Creating new user` +- `📥 Request body: [données]` +- `🔒 Hashing password...` +- `🔍 Storage createUser called with: [username]` +- `✅ Storage createUser successful: [username]` + ## Déploiement 1. Redéployez votre application avec les dernières modifications diff --git a/attached_assets/image_1754942591562.png b/attached_assets/image_1754942591562.png new file mode 100644 index 0000000..47ec2df Binary files /dev/null and b/attached_assets/image_1754942591562.png differ diff --git a/server/routes.ts b/server/routes.ts index cda0e59..64936f8 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -907,9 +907,13 @@ export async function registerRoutes(app: Express): Promise { app.post('/api/users', isAuthenticated, async (req: any, res) => { try { + console.log('🔍 POST /api/users - Creating new user'); + console.log('📥 Request body:', JSON.stringify(req.body, null, 2)); + const userId = req.user.claims ? req.user.claims.sub : req.user.id; const currentUser = await storage.getUserWithGroups(userId); if (!currentUser || currentUser.role !== 'admin') { + console.log('❌ Access denied - user not admin'); return res.status(403).json({ message: "Access denied" }); } @@ -924,23 +928,51 @@ export async function registerRoutes(app: Express): Promise { role: z.enum(['admin', 'directeur', 'manager', 'employee']).optional(), }); + console.log('🔍 Parsing user data...'); const userData = createUserSchema.parse(req.body); + console.log('✅ User data parsed successfully'); - // Hash password if provided (for local auth) + // Hash password with improved error handling + let hashedPassword = userData.password; if (userData.password) { - userData.password = await hashPasswordSimple(userData.password); + try { + console.log('🔒 Hashing password...'); + hashedPassword = await hashPasswordSimple(userData.password); + console.log('✅ Password hashed successfully'); + } catch (hashError) { + console.error('❌ Password hashing failed:', hashError); + return res.status(500).json({ message: "Failed to secure password" }); + } } - const newUser = await storage.createUser({ - id: userData.id || `manual_${Date.now()}`, // Generate manual ID for created users - ...userData, - }); + // Generate unique ID + const newUserId = userData.id || `manual_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + console.log('🔍 Generated user ID:', newUserId); + + const userToCreate = { + id: newUserId, + username: userData.username, + email: userData.email || '', + firstName: userData.firstName || '', + lastName: userData.lastName || '', + password: hashedPassword, + role: userData.role || 'employee', + }; + + console.log('🔍 Creating user in database...'); + const newUser = await storage.createUser(userToCreate); + console.log('✅ User created successfully:', newUser.username); res.json(newUser); } catch (error) { - console.error("Error creating user:", error); + console.error("❌ Error creating user:", error); + console.error("❌ Error type:", error.constructor.name); + console.error("❌ Error code:", error.code); + console.error("❌ Error constraint:", error.constraint); + console.error("❌ Error stack:", error.stack); if (error instanceof z.ZodError) { + console.log('❌ Validation error:', error.errors); return res.status(400).json({ message: "Invalid user data", errors: error.errors }); } @@ -958,6 +990,11 @@ export async function registerRoutes(app: Express): Promise { } } + // Handle connection errors + if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') { + return res.status(503).json({ message: "Database connection error" }); + } + res.status(500).json({ message: "Failed to create user" }); } }); diff --git a/server/storage.ts b/server/storage.ts index e62a2ad..333218c 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -296,15 +296,24 @@ export class DatabaseStorage implements IStorage { } async createUser(userData: UpsertUser): Promise { - const [user] = await db - .insert(users) - .values({ - ...userData, - createdAt: new Date(), - updatedAt: new Date(), - }) - .returning(); - return user; + console.log('🔍 Storage createUser called with:', userData.username); + try { + const [user] = await db + .insert(users) + .values({ + ...userData, + createdAt: new Date(), + updatedAt: new Date(), + }) + .returning(); + console.log('✅ Storage createUser successful:', user.username); + return user; + } catch (error) { + console.error('❌ Storage createUser error:', error); + console.error('❌ Storage error code:', error.code); + console.error('❌ Storage error constraint:', error.constraint); + throw error; + } } async updateUser(id: string, userData: Partial): Promise { diff --git a/test-create-user-production.js b/test-create-user-production.js new file mode 100644 index 0000000..5f6919e --- /dev/null +++ b/test-create-user-production.js @@ -0,0 +1,115 @@ +#!/usr/bin/env node + +/** + * Script de test pour la création d'utilisateur en production + * Usage: node test-create-user-production.js + */ + +const https = require('https'); +const fs = require('fs'); + +const config = { + hostname: process.env.PRODUCTION_HOST || 'your-domain.com', + port: 443, + headers: { + 'Content-Type': 'application/json', + 'Cookie': process.env.SESSION_COOKIE || '' + } +}; + +// Test data +const testUser = { + username: `test_${Date.now()}`, + email: `test_${Date.now()}@example.com`, + firstName: 'Test', + lastName: 'User', + password: 'TestPassword123', + role: 'employee' +}; + +console.log('🔍 Testing user creation in production...'); +console.log('📊 Test user data:', JSON.stringify(testUser, null, 2)); + +const postData = JSON.stringify(testUser); + +const options = { + ...config, + path: '/api/users', + method: 'POST', + headers: { + ...config.headers, + 'Content-Length': Buffer.byteLength(postData) + } +}; + +const req = https.request(options, (res) => { + console.log(`📡 Response status: ${res.statusCode}`); + console.log('📡 Response headers:', res.headers); + + let data = ''; + res.on('data', (chunk) => { + data += chunk; + }); + + res.on('end', () => { + try { + const response = JSON.parse(data); + if (res.statusCode === 200 || res.statusCode === 201) { + console.log('✅ User created successfully!'); + console.log('👤 New user:', response); + } else { + console.log('❌ User creation failed'); + console.log('📄 Error response:', response); + } + } catch (error) { + console.log('❌ Failed to parse response:', data); + } + }); +}); + +req.on('error', (error) => { + console.error('❌ Request error:', error); +}); + +req.write(postData); +req.end(); + +// Also test the users endpoint +setTimeout(() => { + console.log('\n🔍 Testing users list endpoint...'); + + const getUsersOptions = { + ...config, + path: '/api/users', + method: 'GET' + }; + + const getUsersReq = https.request(getUsersOptions, (res) => { + console.log(`📡 Users list status: ${res.statusCode}`); + + let data = ''; + res.on('data', (chunk) => { + data += chunk; + }); + + res.on('end', () => { + try { + const users = JSON.parse(data); + if (Array.isArray(users)) { + console.log(`✅ Found ${users.length} users`); + console.log('👥 Users:', users.map(u => ({ username: u.username, role: u.role, groups: u.userGroups?.length || 0 }))); + } else { + console.log('❌ Invalid users response:', users); + } + } catch (error) { + console.log('❌ Failed to parse users response:', data); + } + }); + }); + + getUsersReq.on('error', (error) => { + console.error('❌ Users request error:', error); + }); + + getUsersReq.end(); +}, 2000); \ No newline at end of file