const admin = require("firebase-admin"); const db = admin.firestore(); const logger = require("firebase-functions/logger"); const auth = require("../utils/auth"); const helpers = require("../utils/helpers"); // Créer un utilisateur exports.createUser = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const isAdminUser = await auth.isAdmin(decodedToken.uid); if (!isAdminUser) { res.status(403).json({error: "Forbidden: Admin access required"}); return; } const userData = req.body.data; const userId = userData.uid; if (!userId) { res.status(400).json({error: "User ID is required"}); return; } await db.collection("users").doc(userId).set(userData); res.status(201).json({id: userId, message: "User created successfully"}); } catch (error) { logger.error("Error creating user:", error); res.status(500).json({error: error.message}); } }; // Créer un utilisateur avec invitation par email exports.createUserWithInvite = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const isAdminUser = await auth.isAdmin(decodedToken.uid); if (!isAdminUser) { res.status(403).json({error: "Forbidden: Admin access required"}); return; } const {email, firstName, lastName, phoneNumber, roleId} = req.body.data; if (!email || !firstName || !lastName || !roleId) { res.status(400).json({error: "email, firstName, lastName, and roleId are required"}); return; } const tempPassword = Math.random().toString(36).slice(-12) + "Aa1!"; let userRecord; try { userRecord = await admin.auth().createUser({ email: email, password: tempPassword, emailVerified: false, displayName: `${firstName} ${lastName}`, }); } catch (authError) { logger.error("Error creating user in Auth:", authError); res.status(500).json({error: `Failed to create user in Auth: ${authError.message}`}); return; } try { await db.collection("users").doc(userRecord.uid).set({ firstName: firstName, lastName: lastName, email: email, phoneNumber: phoneNumber || "", profilePhotoUrl: "", role: db.collection("roles").doc(roleId), createdAt: admin.firestore.FieldValue.serverTimestamp(), createdBy: decodedToken.uid, }); } catch (firestoreError) { logger.error("Error creating user in Firestore:", firestoreError); try { await admin.auth().deleteUser(userRecord.uid); } catch (cleanupError) { logger.error("Error cleaning up Auth user:", cleanupError); } res.status(500).json({error: `Failed to create user in Firestore: ${firestoreError.message}`}); return; } try { const axios = require("axios"); const firebaseApiKey = "AIzaSyARQL4P-t5l-cNjQNP9cMokQrLJ8BorF0U"; await axios.post( `https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key=${firebaseApiKey}`, { requestType: "PASSWORD_RESET", email: email, }, ); logger.info(`Password reset email sent to ${email}`); } catch (emailError) { logger.warn(`Could not send password reset email to ${email}: ${emailError.message}`); } logger.info(`User ${userRecord.uid} created by ${decodedToken.uid}`); res.status(201).json({ id: userRecord.uid, message: "User created successfully. Password reset email sent.", }); } catch (error) { logger.error("Error in createUserWithInvite:", error); res.status(500).json({error: error.message}); } }; // Mettre à jour un utilisateur exports.updateUser = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const {userId, data} = req.body.data; if (!userId) { res.status(400).json({error: "User ID is required"}); return; } // Un utilisateur ne peut modifier que son propre compte, sauf s'il est admin const isAdminUser = await auth.isAdmin(decodedToken.uid); if (decodedToken.uid !== userId && !isAdminUser) { res.status(403).json({error: "Forbidden: Cannot update other user accounts"}); return; } // Empêcher les non-admins de modifier le rôle if (!isAdminUser && data.role) { delete data.role; } // Si le rôle est fourni et est un string, le convertir en DocumentReference if (data.role && typeof data.role === "string") { data.role = db.collection("roles").doc(data.role); } await db.collection("users").doc(userId).update(data); res.status(200).json({message: "User updated successfully"}); } catch (error) { logger.error("Error updating user:", error); res.status(500).json({error: error.message}); } }; // Supprimer un utilisateur exports.deleteUser = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const isAdminUser = await auth.isAdmin(decodedToken.uid); if (!isAdminUser) { res.status(403).json({error: "Forbidden: Admin access required"}); return; } const {userId} = req.body.data; if (!userId) { res.status(400).json({error: "User ID is required"}); return; } if (decodedToken.uid === userId) { res.status(400).json({error: "Cannot delete your own account"}); return; } await db.collection("users").doc(userId).delete(); try { await admin.auth().deleteUser(userId); } catch (authError) { logger.warn(`Could not delete user from Auth: ${authError.message}`); } res.status(200).json({message: "User deleted successfully"}); } catch (error) { logger.error("Error deleting user:", error); res.status(500).json({error: error.message}); } }; // Récupérer tous les utilisateurs (selon permissions) exports.getUsers = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const canViewAll = await auth.hasPermission(decodedToken.uid, "view_all_users"); if (!canViewAll) { const userDoc = await db.collection("users").doc(decodedToken.uid).get(); if (!userDoc.exists) { res.status(404).json({error: "User not found"}); return; } let userData = userDoc.data(); userData = helpers.serializeTimestamps(userData); userData = helpers.serializeReferences(userData); res.status(200).json({ users: [{ id: userDoc.id, ...userData, }], }); return; } const snapshot = await db.collection("users").get(); const users = snapshot.docs.map((doc) => { let data = doc.data(); data = helpers.serializeTimestamps(data); data = helpers.serializeReferences(data); return { id: doc.id, ...data, }; }); res.status(200).json({users}); } catch (error) { logger.error("Error fetching users:", error); res.status(500).json({error: error.message}); } }; // Récupère un utilisateur spécifique exports.getUser = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const {userId} = req.body.data || req.body || {}; if (!userId) { res.status(400).json({error: "userId is required"}); return; } const userDoc = await db.collection("users").doc(userId).get(); if (!userDoc.exists) { res.status(404).json({error: "User not found"}); return; } const user = userDoc.data(); const userData = { id: userDoc.id, uid: user.uid || userDoc.id, email: user.email || "", firstName: user.firstName || "", lastName: user.lastName || "", phoneNumber: user.phoneNumber || "", profilePhotoUrl: user.profilePhotoUrl || "", }; if (user.role) { const roleDoc = await user.role.get(); if (roleDoc.exists) { userData.role = { id: roleDoc.id, ...roleDoc.data(), }; } } res.status(200).json({user: userData}); } catch (error) { logger.error("Error fetching user:", error); res.status(500).json({error: error.message}); } }; // Récupère l'utilisateur actuellement authentifié avec son rôle exports.getCurrentUser = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const userId = decodedToken.uid; const userDoc = await db.collection("users").doc(userId).get(); if (!userDoc.exists) { res.status(404).json({error: "User not found"}); return; } const userData = userDoc.data(); let roleData = null; if (userData.role) { const roleDoc = await userData.role.get(); if (roleDoc.exists) { roleData = {id: roleDoc.id, ...roleDoc.data()}; } } res.status(200).json({ user: { uid: userId, ...helpers.serializeTimestamps(userData), role: roleData, }, }); } catch (error) { logger.error("Error getting current user:", error); res.status(500).json({error: error.message}); } }; // Récupère tous les rôles exports.getRoles = async (req, res) => { try { await auth.authenticateUser(req); const snapshot = await db.collection("roles").get(); const roles = snapshot.docs.map((doc) => ({ id: doc.id, ...helpers.serializeTimestamps(doc.data()), })); res.status(200).json({roles}); } catch (error) { logger.error("Error fetching roles:", error); res.status(500).json({error: error.message}); } };