324 lines
10 KiB
PHP
324 lines
10 KiB
PHP
<?php
|
|
/**
|
|
* Service d'envoi de notifications MQTT pour le chat
|
|
*
|
|
* Ce script gère l'envoi des notifications via MQTT depuis le backend PHP
|
|
*/
|
|
|
|
require_once 'vendor/autoload.php'; // PhpMqtt
|
|
|
|
use PhpMqtt\Client\MqttClient;
|
|
use PhpMqtt\Client\ConnectionSettings;
|
|
|
|
class MqttNotificationSender {
|
|
private $mqtt;
|
|
private $db;
|
|
private $config;
|
|
|
|
public function __construct($dbConnection, $mqttConfig) {
|
|
$this->db = $dbConnection;
|
|
$this->config = $mqttConfig;
|
|
|
|
// Initialiser le client MQTT
|
|
$this->initializeMqttClient();
|
|
}
|
|
|
|
private function initializeMqttClient() {
|
|
$this->mqtt = new MqttClient(
|
|
$this->config['host'],
|
|
$this->config['port'],
|
|
'geosector_api_' . uniqid(), // Client ID unique
|
|
MqttClient::MQTT_3_1_1
|
|
);
|
|
|
|
$connectionSettings = (new ConnectionSettings)
|
|
->setUsername($this->config['username'])
|
|
->setPassword($this->config['password'])
|
|
->setKeepAliveInterval(60)
|
|
->setConnectTimeout(30)
|
|
->setUseTls($this->config['use_ssl'] ?? false);
|
|
|
|
$this->mqtt->connect($connectionSettings, true);
|
|
}
|
|
|
|
/**
|
|
* Envoie une notification pour un nouveau message
|
|
*/
|
|
public function sendMessageNotification($receiverId, $senderId, $messageId, $content, $conversationId) {
|
|
try {
|
|
// Vérifier les préférences de notification
|
|
$settings = $this->getUserNotificationSettings($receiverId);
|
|
|
|
if (!$this->shouldSendNotification($settings, $conversationId)) {
|
|
return ['status' => 'skipped', 'reason' => 'notification_settings'];
|
|
}
|
|
|
|
// Obtenir les informations de l'expéditeur
|
|
$sender = $this->getSenderInfo($senderId);
|
|
|
|
// Obtenir le nom de la conversation
|
|
$conversationName = $this->getConversationName($conversationId, $receiverId);
|
|
|
|
// Préparer le payload de la notification
|
|
$payload = [
|
|
'type' => 'chat_message',
|
|
'messageId' => $messageId,
|
|
'conversationId' => $conversationId,
|
|
'senderId' => $senderId,
|
|
'senderName' => $sender['name'] ?? 'Utilisateur',
|
|
'content' => $settings['show_preview'] ? $content : 'Nouveau message',
|
|
'conversationName' => $conversationName,
|
|
'timestamp' => time(),
|
|
];
|
|
|
|
// Définir le topic MQTT
|
|
$topic = sprintf('chat/user/%s/messages', $receiverId);
|
|
|
|
// Publier le message
|
|
$this->mqtt->publish($topic, json_encode($payload), 1);
|
|
|
|
// Enregistrer la notification dans la base de données
|
|
$this->saveNotificationToDatabase($receiverId, $messageId, $conversationId, $payload);
|
|
|
|
return [
|
|
'status' => 'success',
|
|
'topic' => $topic
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
return [
|
|
'status' => 'error',
|
|
'reason' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Envoie une annonce à plusieurs utilisateurs
|
|
*/
|
|
public function sendBroadcastAnnouncement($audienceTargets, $messageId, $title, $content, $conversationId) {
|
|
$results = [];
|
|
$userIds = $this->resolveAudienceTargets($audienceTargets);
|
|
|
|
foreach ($userIds as $userId) {
|
|
// Préparer le payload pour l'annonce
|
|
$payload = [
|
|
'type' => 'announcement',
|
|
'messageId' => $messageId,
|
|
'conversationId' => $conversationId,
|
|
'title' => $title,
|
|
'content' => $content,
|
|
'timestamp' => time(),
|
|
];
|
|
|
|
// Envoyer à chaque utilisateur
|
|
$topic = sprintf('chat/user/%s/messages', $userId);
|
|
|
|
try {
|
|
$this->mqtt->publish($topic, json_encode($payload), 1);
|
|
$results[$userId] = ['status' => 'success'];
|
|
|
|
// Enregistrer la notification
|
|
$this->saveNotificationToDatabase($userId, $messageId, $conversationId, $payload);
|
|
} catch (Exception $e) {
|
|
$results[$userId] = ['status' => 'error', 'reason' => $e->getMessage()];
|
|
}
|
|
}
|
|
|
|
// Publier aussi sur le topic général des annonces
|
|
$this->mqtt->publish('chat/announcement', json_encode($payload), 1);
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Envoie une notification à une conversation spécifique
|
|
*/
|
|
public function sendConversationNotification($conversationId, $messageId, $senderId, $content) {
|
|
$participants = $this->getConversationParticipants($conversationId);
|
|
|
|
foreach ($participants as $participant) {
|
|
if ($participant['id'] !== $senderId) {
|
|
$this->sendMessageNotification(
|
|
$participant['id'],
|
|
$senderId,
|
|
$messageId,
|
|
$content,
|
|
$conversationId
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Vérifie si une notification doit être envoyée
|
|
*/
|
|
private function shouldSendNotification($settings, $conversationId) {
|
|
if (!$settings['enable_notifications']) {
|
|
return false;
|
|
}
|
|
|
|
if (in_array($conversationId, $settings['muted_conversations'])) {
|
|
return false;
|
|
}
|
|
|
|
if ($settings['do_not_disturb'] && $this->isInDoNotDisturbPeriod($settings)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Récupère les paramètres de notification de l'utilisateur
|
|
*/
|
|
private function getUserNotificationSettings($userId) {
|
|
$stmt = $this->db->prepare("
|
|
SELECT * FROM notification_settings
|
|
WHERE user_id = ?
|
|
");
|
|
|
|
$stmt->execute([$userId]);
|
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
// Valeurs par défaut si pas de préférences
|
|
return $result ?: [
|
|
'enable_notifications' => true,
|
|
'show_preview' => true,
|
|
'muted_conversations' => [],
|
|
'do_not_disturb' => false,
|
|
'do_not_disturb_start' => null,
|
|
'do_not_disturb_end' => null,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Vérifie si on est dans la période "Ne pas déranger"
|
|
*/
|
|
private function isInDoNotDisturbPeriod($settings) {
|
|
if (!$settings['do_not_disturb']) {
|
|
return false;
|
|
}
|
|
|
|
$now = new DateTime();
|
|
$start = new DateTime($settings['do_not_disturb_start']);
|
|
$end = new DateTime($settings['do_not_disturb_end']);
|
|
|
|
if ($start < $end) {
|
|
return $now >= $start && $now <= $end;
|
|
} else {
|
|
// Période qui chevauche minuit
|
|
return $now >= $start || $now <= $end;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enregistre la notification dans la base de données
|
|
*/
|
|
private function saveNotificationToDatabase($userId, $messageId, $conversationId, $payload) {
|
|
$stmt = $this->db->prepare("
|
|
INSERT INTO chat_notifications
|
|
(fk_user, fk_message, fk_room, type, contenu, statut)
|
|
VALUES (?, ?, ?, ?, ?, 'non_lue')
|
|
");
|
|
|
|
$stmt->execute([
|
|
$userId,
|
|
$messageId,
|
|
$conversationId,
|
|
$payload['type'],
|
|
json_encode($payload)
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Récupère les informations de l'expéditeur
|
|
*/
|
|
private function getSenderInfo($senderId) {
|
|
$stmt = $this->db->prepare("
|
|
SELECT id, name, username
|
|
FROM users
|
|
WHERE id = ?
|
|
");
|
|
|
|
$stmt->execute([$senderId]);
|
|
return $stmt->fetch(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Récupère le nom de la conversation
|
|
*/
|
|
private function getConversationName($conversationId, $userId) {
|
|
$stmt = $this->db->prepare("
|
|
SELECT title
|
|
FROM chat_rooms
|
|
WHERE id = ?
|
|
");
|
|
|
|
$stmt->execute([$conversationId]);
|
|
return $stmt->fetchColumn();
|
|
}
|
|
|
|
/**
|
|
* Récupère les participants d'une conversation
|
|
*/
|
|
private function getConversationParticipants($conversationId) {
|
|
$stmt = $this->db->prepare("
|
|
SELECT id_user as id, role
|
|
FROM chat_participants
|
|
WHERE id_room = ? AND notification_activee = 1
|
|
");
|
|
|
|
$stmt->execute([$conversationId]);
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Résout les cibles d'audience en une liste d'IDs utilisateur
|
|
*/
|
|
private function resolveAudienceTargets($targets) {
|
|
$userIds = [];
|
|
|
|
foreach ($targets as $target) {
|
|
switch ($target['target_type']) {
|
|
case 'all':
|
|
$stmt = $this->db->query("SELECT id FROM users WHERE chk_active = 1");
|
|
$userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN));
|
|
break;
|
|
|
|
case 'role':
|
|
$stmt = $this->db->prepare("SELECT id FROM users WHERE fk_role = ?");
|
|
$stmt->execute([$target['role_filter']]);
|
|
$userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN));
|
|
break;
|
|
|
|
case 'entity':
|
|
$stmt = $this->db->prepare("SELECT id FROM users WHERE fk_entite = ?");
|
|
$stmt->execute([$target['entity_filter']]);
|
|
$userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN));
|
|
break;
|
|
|
|
case 'combined':
|
|
$stmt = $this->db->prepare("
|
|
SELECT id FROM users
|
|
WHERE fk_role = ? AND fk_entite = ?
|
|
");
|
|
$stmt->execute([$target['role_filter'], $target['entity_filter']]);
|
|
$userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return array_unique($userIds);
|
|
}
|
|
|
|
/**
|
|
* Ferme la connexion MQTT
|
|
*/
|
|
public function disconnect() {
|
|
if ($this->mqtt) {
|
|
$this->mqtt->disconnect();
|
|
}
|
|
}
|
|
}
|