source: spip-zone/_plugins_/notifications_avancees/trunk/notifavancees_pipelines.php @ 107584

Last change on this file since 107584 was 107584, checked in by bystrano@…, 3 years ago

un brin de PSR SPIP et suppression d'espaces

File size: 17.9 KB
Line 
1<?php
2
3// Sécurité
4if (!defined('_ECRIRE_INC_VERSION')) return;
5
6function notifavancees_notifications($flux){
7        // On récupère les infos
8        $quoi = $flux['args']['quoi'];
9        $id = intval($flux['args']['id']);
10        $options = $flux['args']['options'];
11
12        // On cherche d'abord les destinataires vu que s'il n'y en a pas, on ne fait rien :)
13        $destinataires = notifications_destinataires($quoi, $id, $options);
14
15        // Youpiiii la liste des destinataires est terminée
16        // On ne continue que s'il en reste
17        if ($destinataires){
18                include_spip('inc/filtres');
19                // On récupère les abonnés explicites pour connaître les éventuelles préférences d'envoi
20                $preferences = notifications_abonnes($quoi, $id);
21
22                // On programme les envois pour chaque destinataire un par un
23                foreach ($destinataires as $cle=>$destinataire){
24                        // Si c'est un tableau avec déjà toutes les infos
25                        if (is_array($destinataire)){
26                                foreach ($destinataire as $mode=>$contact){
27                                        job_queue_add('notifications_envoyer', "Notification ($quoi, $id) par le mode $mode pour <$contact>", array($contact, $mode, $quoi, $id, $options), 'notifavancees_pipelines');
28                                }
29                        }
30                        // Sinon c'est soit un id_auteur soit un mail
31                        // Si on le trouve dans les préférences, on les suit
32                        elseif ($modes = $preferences[$destinataire]['modes']){
33                                foreach ($modes as $mode){
34                                        job_queue_add('notifications_envoyer', "Notification ($quoi, $id) par le mode $mode pour <$destinataire>", array($destinataire, $mode, $quoi, $id, $options), 'notifavancees_pipelines');
35                                }
36                        }
37                        // Si c'est pas dans les préférences
38                        // et que $destinataire est SOIT un mail SOIT un id_auteur
39                        // (on vérifie quand même et on ne traite pas les autres cas qui à priori sont pathologiques)
40                        // alors on envoie uniquement par courriel par défaut
41                        elseif ((intval($destinataire) == $destinataire and $destinataire > 0) or email_valide($destinataire)){
42                                $mode = 'email';
43                                job_queue_add('notifications_envoyer', "Notification ($quoi, $id) par le mode $mode pour <$destinataire>", array($destinataire, $mode, $quoi, $id, $options), 'notifavancees_pipelines');
44                        }
45                }
46        }
47}
48
49/*
50 * Retourne la liste des destinataires pour une notification précise.
51 *
52 * La liste est un tableau pouvant être composé de trois choses :
53 * - Un identifiant d'auteur
54 * - Une adresse de courriel
55 * - Un tableau associatif mode=>information définissant directement les modes de contact, par exemple 'email'=>'truc@machin.com'
56 *
57 * Les destinataires peuvent provenir de trois sources différentes :
58 * - La notification "truc" peut définir une fonction notifications_truc_destinataires()
59 * - La table "spip_notifications_abonnements" qui défini les abonnés explicites
60 * - Le pipeline "notifications_destinataires"
61 *
62 * @param string $quoi Le nom de la notification
63 * @param int $id Un éventuel identifiant d'objet lié à la notification
64 * @param array $options Des options supplémentaires
65 * @return array Retourne un tableau de destinataires sous la forme décrite ci-dessus
66 */
67function notifications_destinataires($quoi, $id=0, $options=array()){
68        // On retourne toujours un tableau
69        $destinataires = array();
70
71        // En premier les destinataires choisis par la notification
72        if ($fonction_destinataires = charger_fonction('destinataires', "notifications/$quoi", true))
73                $destinataires = $fonction_destinataires($id, $options);
74
75        // Ensuite, ceux qui sont abonnés explicitement
76        // Pour les préférences, la notification peut définir une fonction notifications_truc_preferences()
77        $abonnes = notifications_abonnes($quoi, $id);
78        if (is_array($abonnes) and $abonnes){
79                // On cherche l'éventuelle fonction qui sait gérer les préférences
80                $fonction_preferences = charger_fonction('preferences', "notifications/$quoi", true);
81                // On teste tous les abonnés un par un
82                foreach ($abonnes as $dest=>$infos){
83                        // S'il n'y pas de préférences, on ajoute directement
84                        if (!$infos['preferences']){
85                                $destinataires[] = $dest;
86                        }
87                        // Sinon on applique le test de la fonction dédiée pour savoir si on ajoute
88                        elseif ($fonction_preferences and $fonction_preferences($id, $options, $infos['preferences'])){
89                                $destinataires[] = $dest;
90                        }
91                }
92        }
93
94        // Ensuite on passe dans le pipeline
95        $destinataires = pipeline(
96                'notifications_destinataires',
97                array(
98                        'args' => array('quoi'=>$quoi, 'id'=>$id, 'options'=>$options),
99                        'data' => $destinataires
100                )
101        );
102
103        // On supprime les doublons
104        if (is_array($destinataires))
105                $destinataires = array_unique($destinataires);
106
107        // Enfin on retire ceux qui se sont blacklistés explicitement
108        if ($blacklist = notifications_abonnes($quoi, $id, true))
109                $destinataires = notifications_exclure_destinataires($destinataires, $blacklist);
110
111        return $destinataires;
112}
113
114/*
115 * Exclure une liste de destinataires d'une autre liste
116 *
117 * @param array $destinataires La liste initiale de destinataires
118 * @param array @blacklist La liste qu'on veut exclure
119 * @return array Retourne la première liste moins la seconde
120 */
121function notifications_exclure_destinataires($destinataires, $blacklist){
122        foreach ($blacklist as $exclu){
123                // Si on le trouve direct, soit l'auteur, soit le contact, on le vire
124                if ($cles = array_keys($destinataires, $exclu)){
125                        foreach ($cles as $cle)
126                                unset($destinataires[$cle]);
127                }
128                // Sinon on essaye de le trouver dans les tableaux éventuels
129                else{
130                        $destinataires_tableau = array_filter($destinataires, 'is_array');
131                        foreach ($destinataires_tableau as $cle => $tableau){
132                                if (in_array($exclu, $tableau))
133                                        unset($destinataires[$cle]);
134                        }
135                }
136        }
137
138        return $destinataires;
139}
140
141/*
142 * Retourne la liste des abonnés explicites à une notification.
143 * Cette fonction est à utiliser pour ne pas refaire plusieurs appels à la base de données dans un même hit PHP.
144 *
145 * Si on demande les abonnés le tableau est de la forme id=>modes.
146 * Si on demande les blacklistés le tableau contient la liste directement, soit l'id_auteur soit le contact.
147 *
148 * @param string $quoi Le nom de la notification
149 * @param int $id Un éventuel identifiant d'objet lié à la notification
150 * @param bool $blacklist Indique si l'on retourne ceux qui ne veulent PAS être notifiés
151 * @return array Retourne un tableau des abonnés ou des blacklistés
152 */
153function notifications_abonnes($quoi, $id=0, $blacklist=false){
154        static $abonnes = array();
155        static $blacklistes = array();
156
157        // On normalise l'id
158        if (!($id = intval($id)) or !($id > 0))
159                $id = 0;
160
161        // On ne fait la requête que si on a pas déjà les valeurs
162        if (
163                (!$blacklist and !isset($abonnes[$quoi][$id]))
164                or ($blacklist and !isset($blacklistes[$quoi][$id]))
165        ){
166                include_spip('base/abtract_sql');
167
168                $where = array(
169                        'quoi = '.sql_quote($quoi)
170                );
171
172                // S'il y a un id pertinent on le rajoute à la requête
173                if ($id > 0)
174                        $where[] = 'id = '.$id;
175
176                // On va chercher tous les gens liés à cette notification
177                $requete = sql_allfetsel(
178                        'id_auteur, contact, preferences, modes, actif',
179                        'spip_notifications_abonnements',
180                        $where
181                );
182
183                $abonnes[$quoi][$id] = $blacklistes[$quoi][$id] = array();
184                foreach ($requete as $ligne){
185                        // On ne fait quelque chose que si l'abonnement est actif !
186                        if ($ligne['actif']){
187                                // S'il y a des préférences de modes d'envoi, c'est un abonné
188                                if ($modes = trim($ligne['modes']) and $modes = unserialize($modes) and is_array($modes)){
189                                        $infos = array('modes'=>$modes, 'preferences'=>unserialize($ligne['preferences']));
190                                        // Si c'est un auteur on met ça comme clé
191                                        if ($ligne['id_auteur'] > 0)
192                                                $abonnes[$quoi][$id][$ligne['id_auteur']] = $infos;
193                                        // Sinon on met l'information de contact
194                                        else
195                                                $abonnes[$quoi][$id][$ligne['contact']] = $infos;
196                                }
197                                // Sinon c'est un blacklisté
198                                else{
199                                        // Si c'est un auteur on met l'id
200                                        if ($ligne['id_auteur'] > 0)
201                                                $blacklistes[$quoi][$id][] = $ligne['id_auteur'];
202                                        // Sinon on met l'information de contact
203                                        else
204                                                $blacklistes[$quoi][$id][] = $ligne['contact'];
205                                }
206                        }
207                }
208        }
209
210        // On retourne
211        if (!$blacklist)
212                return $abonnes[$quoi][$id];
213        else
214                return $blacklist[$quoi][$id];
215}
216
217/*
218 * Liste toutes les notifications installées
219 *
220 * @return array Un tableau listant les notifications et leurs informations
221 */
222function notifications_lister_disponibles(){
223        static $notifications = null;
224
225        if (is_null($notifications)){
226                $notifications = array();
227                $liste = find_all_in_path('notifications/', '.+[.]yaml$');
228
229                if (count($liste)){
230                        foreach ($liste as $fichier=>$chemin){
231                                $type_notification = preg_replace(',[.]yaml$,i', '', $fichier);
232                                $dossier = str_replace($fichier, '', $chemin);
233                                if (is_array($notification = notifications_charger_infos($type_notification))){
234                                        $notifications[$type_notification] = $notification;
235                                }
236                        }
237                }
238        }
239
240        return $notifications;
241}
242
243/**
244 * Lister les notifications que l'on peut créer via l'interface
245 *
246 * Le paramètre id_auteur permet de prendre en compte l'option
247 * 'unique' des notifications. Un auteur ayant déjà un abonnement pour
248 * un type de notification unique ne peut pas en créer un nouveau.
249 *
250 * @param integer $id_auteur : un éventuel id_auteur auquel se limiter
251 * @return array Un tableau listant les notifications et leurs informations
252 */
253function notifications_lister_creables ($id_auteur=null) {
254
255        $creables = array();
256
257        foreach (notifications_lister_disponibles() as $type => $def) {
258                if (isset($def['proposer_creation']) &&
259                        ($def['proposer_creation'])) {
260
261                        $creables[$type] = $def;
262                }
263        }
264
265        if ($id_auteur) {
266                foreach ($creables as $type => $def) {
267                        if ($def['unique']) {
268                                include_spip('base/abstract_sql');
269                                if (sql_countsel('spip_notifications_abonnements',
270                                                                 array(
271                                                                         'quoi='.sql_quote($type),
272                                                                         'id_auteur='.intval($id_auteur),
273                                                                 ))) {
274
275                                        unset($creables[$type]);
276                                }
277                        }
278                }
279        }
280
281        return $creables;
282}
283
284/*
285 * Charger les informations contenues dans le yaml d'une notification
286 *
287 * @param string $type_notification Le type de la notification
288 * @return array Un tableau contenant le YAML décodé
289 */
290function notifications_charger_infos($type_notification){
291        include_spip('inc/yaml');
292        $fichier = find_in_path("notifications/$type_notification.yaml");
293        $notification = yaml_decode_file($fichier);
294        if (is_array($notification)){
295                $notification['titre'] = $notification['titre'] ? _T_ou_typo($notification['titre']) : $type_notification;
296                $notification['description'] = $notification['description'] ? _T_ou_typo($notification['description']) : '';
297                $notification['icone'] = $notification['icone'] ? find_in_path($notification['icone']) : '';
298        }
299        return $notification;
300}
301
302/*
303 * Liste tous les modes d'envoi installés.
304 *
305 * @return array Un tableau listant les modes et leurs informations
306 */
307function notifications_modes_lister_disponibles(){
308        static $modes = null;
309
310        if (is_null($modes)){
311                $modes = array();
312                $liste = find_all_in_path('notifications/modes/', '.+[.]yaml$');
313
314                if (count($liste)){
315                        foreach ($liste as $fichier=>$chemin){
316                                $type_mode = preg_replace(',[.]yaml$,i', '', $fichier);
317                                $dossier = str_replace($fichier, '', $chemin);
318                                // On ne garde que les modes qui ont bien la fonction d'envoi
319                                if (charger_fonction('envoyer', "notifications/modes/$type_mode/", true)
320                                        and (
321                                                is_array($mode = notifications_modes_charger_infos($type_mode))
322                                        )
323                                ){
324                                        $modes[$type_mode] = $mode;
325                                }
326                        }
327                }
328        }
329
330        return $modes;
331}
332
333/*
334 * Charger les informations contenues dans le yaml d'un mode d'envoi
335 *
336 * @param string $type_mode Le type du mode d'envoi
337 * @return array Un tableau contenant le YAML décodé
338 */
339function notifications_modes_charger_infos($type_mode){
340        include_spip('inc/yaml');
341        $fichier = find_in_path("notifications/modes/$type_mode.yaml");
342        $mode = yaml_decode_file($fichier);
343        if (is_array($mode)){
344                $mode['titre'] = $mode['titre'] ? _T_ou_typo($mode['titre']) : $type_mode;
345                $mode['description'] = $mode['description'] ? _T_ou_typo($mode['description']) : '';
346                $mode['choix'] = $mode['choix'] ? _T_ou_typo($mode['choix']) : '';
347                $mode['icone'] = $mode['icone'] ? find_in_path($mode['icone']) : '';
348        }
349        return $mode;
350}
351
352/*
353 * Fonction centrale d'envoi d'UNE notification.
354 * C'est elle qui fait la jonction entre un destinataire, un mode d'envoi, et le bon contenu approprié au mode.
355 *
356 * @param mixed $contact Le destinataire à qui envoyer, cela peut-être un id_auteur, ou une information de contact (mail, téléphone, etc)
357 * @param string $mode Le mode d'envoi à utiliser
358 * @param string $quoi La nom de la notification
359 * @param int $id Un éventuel identifiant d'objet lié à la notification
360 * @param array $options Des options supplémentaires
361 * @return bool Retourne false si une erreur se produit
362 */
363function notifications_envoyer($destinataire, $mode, $quoi, $id=0, $options=array()){
364        // On commence par aller chercher la bonne information de contact adapté au mode
365        // Car si on ne la trouve pas... on envoie rien
366        if (
367                $mode_envoyer = charger_fonction('envoyer', "notifications/modes/$mode/", true)
368                and $mode_contact = charger_fonction('contact', "notifications/modes/$mode/", true)
369                and $contact = $mode_contact($destinataire)
370        ){
371                // On cherche maintenant le contenu
372                $contenu = array();
373                // Si la notification a une fonction dédiée au contenu, c'est ça qu'on prend
374                if ($notification_contenu = charger_fonction('contenu', "notifications/$quoi/", true)){
375                        $contenu_tmp = $notification_contenu($id, $options, $destinataire, $mode);
376                        if (is_array($contenu_tmp))
377                                $contenu = $contenu_tmp;
378                        elseif (is_string($contenu_tmp))
379                                $contenu['texte'] = $contenu_tmp;
380                }
381
382                // On construit le contexte utile
383                $contexte = array(
384                        'quoi' => $quoi,
385                        'id' => $id,
386                        'options' => $options,
387                        'destinataire' => $destinataire,
388                        'contact' => $contact,
389                        'mode' => $mode
390                );
391
392                // Pour ajouter des informations utiles on cherche un objet dans le nom de la notif
393                $type_objet = notifications_trouver_objet($quoi);
394
395                include_spip('base/objets');
396
397                // On ajoute au contexte si trouvé
398                if ($type_objet) {
399                        $cle_objet = id_table_objet($type_objet);
400                        $contexte['objet'] = $type_objet;
401                        $contexte['id_objet'] = $id;
402                        $contexte[$cle_objet] = $id;
403                }
404
405                //Si un expéditeur est défini on l'utilise
406                if ($options['from'])
407                        $contenu['from'] = $options['from'];
408
409                //si un nom d'expéditeur est défini
410                if ($options['nom_envoyeur'])
411                        $contenu['nom_envoyeur'] = $options['nom_envoyeur'];
412
413                // Le contenu de base est le contenu texte
414                // S'il n'existe pas on cherche le squelette directement
415                if (!$contenu['texte'] and find_in_path("notifications/${quoi}.html")){
416                        $contenu['texte'] = trim(recuperer_fond(
417                                "notifications/$quoi",
418                                $contexte
419                        ));
420                }
421
422                // On ne continue que si on a bien un texte de base
423                if ($contenu['texte']){
424                        // Existe-t-il une version HTML ? Sinon le squelette
425                        if (!$contenu['html'] and find_in_path("notifications/${quoi}_html.html")){
426                                $contenu['html'] = trim(recuperer_fond(
427                                        "notifications/${quoi}_html",
428                                        $contexte
429                                ));
430                        }
431
432                        // Existe-t-il une version courte ?
433                        if (!$contenu['court']){
434                                // Sinon le squelette
435                                if (find_in_path("notifications/${quoi}_court.html")){
436                                        $contenu['court'] = trim(recuperer_fond(
437                                                "notifications/${quoi}_court",
438                                                $contexte
439                                        ));
440                                }
441                                // Sinon on la construit à partir de la première ligne
442                                else{
443                                        include_spip('inc/texte');
444                                        // Nettoyer un peu les retours chariots
445                                        $contenu['court'] = str_replace("\r\n", "\r", $contenu['texte']);
446                                        $contenu['court'] = str_replace("\r", "\n", $contenu['court']);
447                                        // Découper
448                                        $contenu['court'] = explode("\n",trim($contenu['court']));
449                                        // Extraire la premiere ligne
450                                        $contenu['court'] = array_shift($contenu['court']);
451                                        // La couper si besoin
452                                        $contenu['court'] = couper($contenu['court'], 130);
453                                }
454                        }
455
456                        // Maintenant qu'on a tout on appelle le mode d'envoi
457                        return $mode_envoyer($contact, $contenu);
458                }
459        }
460
461        return false;
462}
463
464/**
465 * Trouver l'éventuel nom d'objet dans un nom de notification
466 *
467 * @param String $quoi : Le nom de la notification
468 *
469 * @return String : Le nom de l'objet SPIP correspondant, FALSE s'il
470 *                                      n'y en a pas
471 */
472function notifications_trouver_objet ($quoi) {
473
474        include_spip('base/abstract_sql');
475        include_spip('base/objets');
476
477        $type_objet = explode('_', $quoi);
478        array_pop($type_objet); // on enlève toujours le dernier mot
479
480        // Si on est en SPIP 3, on fait une meilleure recherche
481        if (function_exists('lister_tables_objets_sql')) {
482                while (!empty($type_objet)) {
483                        // Si le nom qui reste fait partie des objets éditoriaux
484                        // on s'arrête
485                        if (in_array(
486                                table_objet_sql(join('_', $type_objet)),
487                                array_keys(lister_tables_objets_sql())
488                        )) {
489                                $type_objet = join('_', $type_objet);
490                                break;
491                        }
492                        // Sinon on raccourcit du dernier élément et on continue
493                        // de chercher
494                        else {
495                                array_pop($type_objet);
496                        }
497                }
498        }
499        // Sinon en SPIP 2, le dernier mot séparé par "_" est considéré
500        // comme le vrai nom de notif, et on garde le reste comme étant un
501        // objet
502        elseif (!empty($type_objet)) {
503                $type_objet = join('_', $type_objet);
504                // Si on ne trouve pas de table correspondante on ne retourne
505                // rien
506                if ( ! id_table_objet($type_objet)) {
507                        $type_objet = false;
508                }
509        }
510        // Sinon pas d'objet du tout
511        else {
512                $type_objet = false;
513        }
514
515        return $type_objet;
516}
517
518function notifavancees_affiche_droite($flux){
519        if (in_array($flux['args']['exec'], array('auteur', 'infos_perso'))){
520                $boite = recuperer_fond(
521                        'prive/boite/notifications_auteur',
522                        array(
523                                'id_auteur' => $flux['args']['id_auteur']
524                        )
525                );
526                $flux['data'] .= $boite;
527        }
528
529        return $flux;
530}
531
532?>
Note: See TracBrowser for help on using the repository browser.