feat: implement comprehensive Firebase Functions backend for equipment management and migrate core repository services

This commit is contained in:
ElPoyo
2026-05-26 15:35:48 +02:00
parent 323df01afe
commit ea1e1335e3
37 changed files with 6315 additions and 6140 deletions
+33 -33
View File
@@ -1,34 +1,34 @@
const {onRequest} = require('firebase-functions/v2/https');
const admin = require('firebase-admin');
const nodemailer = require('nodemailer');
const logger = require('firebase-functions/logger');
const {getSmtpConfig, EMAIL_CONFIG} = require('./utils/emailConfig');
const {renderTemplate, getEmailSubject, getAlertTitle, prepareTemplateData, checkAlertPreference} = require('./utils/emailTemplates');
const auth = require('./utils/auth');
const {onRequest} = require("firebase-functions/v2/https");
const admin = require("firebase-admin");
const nodemailer = require("nodemailer");
const logger = require("firebase-functions/logger");
const {getSmtpConfig, EMAIL_CONFIG} = require("./utils/emailConfig");
const {renderTemplate, getEmailSubject, getAlertTitle, prepareTemplateData, checkAlertPreference} = require("./utils/emailTemplates");
const auth = require("./utils/auth");
// Configuration CORS
const setCorsHeaders = (res, req) => {
// Utiliser l'origin de la requête pour permettre les credentials
const origin = req.headers.origin || '*';
const origin = req.headers.origin || "*";
res.set('Access-Control-Allow-Origin', origin);
res.set("Access-Control-Allow-Origin", origin);
// N'autoriser les credentials que si on a un origin spécifique (pas '*')
if (origin !== '*') {
res.set('Access-Control-Allow-Credentials', 'true');
if (origin !== "*") {
res.set("Access-Control-Allow-Credentials", "true");
}
res.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.set('Access-Control-Allow-Headers', 'Authorization, Content-Type, Accept, Origin, X-Requested-With');
res.set('Access-Control-Max-Age', '3600');
res.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.set("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, Origin, X-Requested-With");
res.set("Access-Control-Max-Age", "3600");
};
const withCors = (handler) => {
return async (req, res) => {
setCorsHeaders(res, req);
// Gérer les requêtes preflight OPTIONS immédiatement
if (req.method === 'OPTIONS') {
res.status(204).send('');
if (req.method === "OPTIONS") {
res.status(204).send("");
return;
}
try {
@@ -48,8 +48,8 @@ const withCors = (handler) => {
*/
exports.createAlert = onRequest({
cors: false,
invoker: 'public',
region: 'europe-west9'
invoker: "public",
region: "europe-west9",
}, withCors(async (req, res) => {
try {
// Vérifier l'authentification
@@ -70,7 +70,7 @@ exports.createAlert = onRequest({
// Validation des données
if (!type || !severity || !message) {
res.status(400).json({error: 'type, severity et message sont requis'});
res.status(400).json({error: "type, severity et message sont requis"});
return;
}
@@ -78,12 +78,12 @@ exports.createAlert = onRequest({
const userIds = await determineTargetUsers(type, severity, eventId);
if (userIds.length === 0) {
res.status(400).json({error: 'Aucun utilisateur à notifier'});
res.status(400).json({error: "Aucun utilisateur à notifier"});
return;
}
// 2. Créer l'alerte dans Firestore
const alertRef = admin.firestore().collection('alerts').doc();
const alertRef = admin.firestore().collection("alerts").doc();
const alertData = {
id: alertRef.id,
type,
@@ -99,14 +99,14 @@ exports.createAlert = onRequest({
createdBy: decodedToken.uid,
isRead: false,
emailSent: false,
status: 'ACTIVE',
status: "ACTIVE",
};
await alertRef.set(alertData);
// 3. Envoyer les emails si alerte critique
let emailResults = {};
if (severity === 'CRITICAL') {
if (severity === "CRITICAL") {
emailResults = await sendAlertEmails(alertRef.id, alertData, userIds);
// Mettre à jour le statut d'envoi
@@ -124,7 +124,7 @@ exports.createAlert = onRequest({
emailsSent: Object.values(emailResults).filter((v) => v).length,
});
} catch (error) {
logger.error('[createAlert] Erreur:', error);
logger.error("[createAlert] Erreur:", error);
res.status(500).json({error: `Erreur lors de la création de l'alerte: ${error.message}`});
}
}));
@@ -137,23 +137,23 @@ async function determineTargetUsers(alertType, severity, eventId) {
const targetUserIds = new Set();
// 1. Récupérer TOUS les utilisateurs pour déterminer lesquels sont admins
const allUsersSnapshot = await db.collection('users').get();
const allUsersSnapshot = await db.collection("users").get();
allUsersSnapshot.forEach((doc) => {
const user = doc.data();
if (user.role) {
// Le rôle peut être une référence Firestore ou une string
let rolePath = '';
if (typeof user.role === 'string') {
let rolePath = "";
if (typeof user.role === "string") {
rolePath = user.role;
} else if (user.role.path) {
rolePath = user.role.path;
} else if (user.role._path && user.role._path.segments) {
rolePath = user.role._path.segments.join('/');
rolePath = user.role._path.segments.join("/");
}
// Vérifier si c'est un admin (path = "roles/ADMIN")
if (rolePath === 'roles/ADMIN' || rolePath === 'ADMIN') {
if (rolePath === "roles/ADMIN" || rolePath === "ADMIN") {
targetUserIds.add(doc.id);
}
}
@@ -162,7 +162,7 @@ async function determineTargetUsers(alertType, severity, eventId) {
// 2. Si un événement est lié, ajouter tous les membres de la workforce
if (eventId) {
try {
const eventDoc = await db.collection('events').doc(eventId).get();
const eventDoc = await db.collection("events").doc(eventId).get();
if (eventDoc.exists) {
const event = eventDoc.data();
@@ -177,7 +177,7 @@ async function determineTargetUsers(alertType, severity, eventId) {
logger.warn(`[determineTargetUsers] Événement ${eventId} introuvable`);
}
} catch (error) {
logger.error('[determineTargetUsers] Erreur récupération événement:', error);
logger.error("[determineTargetUsers] Erreur récupération événement:", error);
}
}
@@ -222,7 +222,7 @@ async function sendSingleEmail(transporter, alertId, alertData, userId) {
const db = admin.firestore();
// Récupérer l'utilisateur
const userDoc = await db.collection('users').doc(userId).get();
const userDoc = await db.collection("users").doc(userId).get();
if (!userDoc.exists) {
return false;
@@ -250,7 +250,7 @@ async function sendSingleEmail(transporter, alertId, alertData, userId) {
const templateData = await prepareTemplateData(alertData, user);
// Rendre le template
const html = await renderTemplate('alert-individual', templateData);
const html = await renderTemplate("alert-individual", templateData);
// Envoyer l'email
await transporter.sendMail({