Rev 2046 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php// declare(encoding='UTF-8');/*** Le script récupère tous les commentaires et déterminations fait ce jour et envoie un mail* aux auteurs des observations récapitulant celle-ci* Si un commentaire porte sur un autre commentaire, un message est envoyé à l'auteur* de celui-ci pour l'avertir de celui-là** @category DEL* @package Scripts* @subpackage Commentaires* @author Mathias CHOUET <mathias@tela-botanica.org>* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>* @author Aurelien PERONNET <aurelien@tela-botanica.org>* @author Michel GALABRU <ajudant-gerber@tela-botanica.org>* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>* @copyright 1999-2015 Tela Botanica <accueil@tela-botanica.org>*/class AlerteMailCommentaires {protected $conteneur;protected $testeurCourriel = null;protected $recapitulatifAdmin = [];protected $messageRecapitulatif = null;protected $dateRenvoi = null;protected $observations_concernees = array();protected $commentaires_concernes = array();protected $correspondance_id_obs_auteurs = array();protected $utilisateursInfos = array();public function __construct($conteneur) {$this->conteneur = $conteneur;}public function executer() {try {$this->verifierModeUtilisation();$this->verifierDateRenvoi();$observationsCommentees = $this->chargerObservationsCommentees();$commentairesCommentes = $this->chargerCommentairesCommentes();$this->formaterObservationsCommentees($observationsCommentees);$this->formaterCommentairesCommentes($commentairesCommentes);$this->envoyerMessageAuxDestinataires();} catch (Exception $e) {echo "ERREUR: " . $e->getMessage() . "\n";}}/*** Passe en mode "test" si l'adresse email d'un testeur est fournie avec "-t"*/protected function verifierModeUtilisation() {$testeurCourriel = $this->conteneur->getParametre('t');if ($testeurCourriel) {if (filter_var($testeurCourriel, FILTER_VALIDATE_EMAIL)) {$this->testeurCourriel = $testeurCourriel;} else {$msg = "Veuillez indiquer une adresse de courriel valide à la suite du paramètre «-t».";throw new Exception($msg);}}}/*** Simule l'envoi à une date arbitraire, si celle-ci est fournie avec "-d"*/protected function verifierDateRenvoi() {$dateRenvoi = $this->conteneur->getParametre('d');if ($dateRenvoi) {if (preg_match('/^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$/', $dateRenvoi)) {$this->dateRenvoi = $dateRenvoi;} else {$msg = "Veuillez indiquer une date au format yyyy-mm-dd valide à la suite du paramètre «-d».";throw new Exception($msg);}}}/*** Charge toutes les observations ayant été commentées dans les dernières 24h* et dont l'auteur souhaite être averti des commentaires*/protected function chargerObservationsCommentees() {// Seuls les utilisateurs ayant explicitement refusé le mail sont ignorés$preferences = $this->conteneur->getBdd()->proteger('%"mail_notification_mes_obs":"0"%');$date = ($this->dateRenvoi == null) ? 'NOW()' : "'$this->dateRenvoi'";$requete = "SELECT do.id_observation, do.ce_utilisateur, do.courriel_utilisateur, do.date_observation". ", do.nom_sel, do.nom_ret, do.zone_geo, do.ce_zone_geo, do.lieudit, do.station". ", dc.nom_sel as dc_nom_sel, dc.utilisateur_prenom as dc_utilisateur_prenom, dc.utilisateur_nom as dc_utilisateur_nom, dc.texte as dc_texte". " FROM del_commentaire dc" // tous les commentaires. " LEFT JOIN del_observation do" // infos obs d'origine. " ON dc.ce_observation = do.id_observation"// ci-dessous un OR et non un AND car les non-inscrits ont tous le meme ce_utilisateur : 0. " WHERE (dc.ce_utilisateur != do.ce_utilisateur OR dc.utilisateur_courriel != do.courriel_utilisateur)" // en excluant les gens qui se parlent à eux-mêmes. " AND TO_SECONDS($date) - TO_SECONDS(dc.date) < 86400 AND TO_SECONDS($date) - TO_SECONDS(dc.date) > 0" // depuis moins de 24h. " AND do.ce_utilisateur NOT IN (". " SELECT id_utilisateur FROM del_utilisateur_infos WHERE preferences LIKE $preferences" // si l'auteur d'origine souhaite être averti. ")". " -- " .__FILE__.':'.__LINE__;$observations = $this->conteneur->getBdd()->recupererTous($requete);return $observations;}/*** Charge tous les commentaires ayant reçu une réponse dans les dernières 24h* et dont l'auteur souhaite être averti des réponses à ses commentaires,* le tout accompagné des infos de l'observation d'origine*/protected function chargerCommentairesCommentes() {// Seuls les utilisateurs ayant explicitement refusé le mail sont ignorés$preferences = $this->conteneur->getBdd()->proteger('%"mail_notification_mes_com":"0"%');$date = ($this->dateRenvoi == null) ? 'NOW()' : "'$this->dateRenvoi'";$requete = "SELECT do.id_observation, do.ce_utilisateur, do.courriel_utilisateur, do.prenom_utilisateur, do.nom_utilisateur". ", do.date_observation, do.nom_sel, do.nom_ret, do.zone_geo, do.ce_zone_geo, do.lieudit, do.station". ", dc.nom_sel as dc_nom_sel, dc.utilisateur_prenom as dc_utilisateur_prenom, dc.utilisateur_nom as dc_utilisateur_nom, dc.texte as dc_texte". ", dco.id_commentaire as dco_id_commentaire, dco.ce_utilisateur as dco_ce_utilisateur, dco.date as dco_date, dco.texte as dco_texte". ", dco.nom_sel as dco_nom_sel, dco.nom_ret as dco_nom_ret, dco.utilisateur_courriel as dco_utilisateur_courriel". " FROM del_commentaire dc" // tous les commentaires. " LEFT JOIN del_commentaire dco" // portant sur un autre commentaire. " ON dc.ce_commentaire_parent = dco.id_commentaire". " LEFT JOIN del_observation do" // infos obs d'origine. " ON dco.ce_observation = do.id_observation"// ci-dessous un OR et non un AND car les non-inscrits ont tous le meme ce_utilisateur : 0. " WHERE (dc.ce_utilisateur != dco.ce_utilisateur OR dc.utilisateur_courriel != dco.utilisateur_courriel)" // en excluant les gens qui se parlent à eux-mêmes. " AND TO_SECONDS($date) - TO_SECONDS(dc.date) < 86400 AND TO_SECONDS($date) - TO_SECONDS(dc.date) > 0" // depuis moins de 24h. " AND dco.ce_utilisateur NOT IN (". " SELECT id_utilisateur FROM del_utilisateur_infos WHERE preferences LIKE $preferences" // si l'auteur d'origine souhaite être averti. " )". " -- " .__FILE__.':'.__LINE__;$commentaires = $this->conteneur->getBdd()->recupererTous($requete);return $commentaires;}/*** Classe les observations par id_utilisateur (ou courriel si non inscrit)* de l'auteur puis par id_observation, et enfile les données des commentaires* relatifs à chaque obs*/protected function formaterObservationsCommentees($liste) {//print_r($liste);foreach ($liste as $o) {$id_obs = $o['id_observation'];$id_auteur_obs = $o['ce_utilisateur'];// si utilisateur non inscritif (($id_auteur_obs == 0) && ($o['courriel_utilisateur'] != '')) {$id_auteur_obs = $o['courriel_utilisateur'];}// mode gentlemanif (! isset($this->observations_concernees[$id_auteur_obs])) {$this->observations_concernees[$id_auteur_obs] = array();}if (! isset($this->observations_concernees[$id_auteur_obs][$id_obs])) {// infos à mentionner dans l'email$infos = array();$infos['id'] = $id_obs;$infos['nom_sci'] = $this->formaterNomSci($o);$infos['date'] = $this->formaterDate($o['date_observation']);$infos['lieu'] = $this->formaterLieu($o);$infos['lien'] = $this->obtenirLienFiche($id_obs);$infos['commentaires'] = array();$this->observations_concernees[$id_auteur_obs][$id_obs] = $infos;$this->observations_concernees[$id_auteur_obs][$id_obs]['commentaires'] = array();}// isolation des données du commentaire$commentaire = $this->arrayTranchette($o, 'dc_', true);//print_r($commentaire);$commentaire['auteur'] = $this->formaterAuteurCommentaire($o);$this->observations_concernees[$id_auteur_obs][$id_obs]['commentaires'][] = $commentaire;}//print_r($this->observations_concernees); exit;}/*** Classe les commentaires par id_utilisateur (ou courriel si non inscrit)* de l'auteur puis par id_commentaire, et enfile les données des réponses* (commentaires) relatives à chaque commentaire*/protected function formaterCommentairesCommentes($liste) {//print_r($liste); exit;foreach ($liste as $o) {// infos sur le commentaire d'origine$id_co = $o['dco_id_commentaire'];$id_auteur_co = $o['dco_ce_utilisateur'];// si utilisateur non inscritif (($id_auteur_co == 0) && ($o['dco_utilisateur_courriel'] != '')) {$id_auteur_co = $o['dco_utilisateur_courriel'];}// mode gentlemanif (! isset($this->commentaires_concernes[$id_auteur_co])) {$this->commentaires_concernes[$id_auteur_co] = array();}// @TODO grouper sur l'obs avant de grouper sur le commentaire d'origine// afin de ne pas répéter l'obs si 2 commentaires d'origine portent// sur la mêmeif (! isset($this->commentaires_concernes[$id_auteur_co][$id_co])) {// infos à mentionner dans l'email$infos = array();$infos['id_obs'] = $o['id_observation'];$id_auteur_obs = $o['ce_utilisateur'];// si utilisateur non inscritif (($id_auteur_obs == 0) && ($o['courriel_utilisateur'] != '')) {$id_auteur_obs = $o['courriel_utilisateur'];}$infos['id_auteur_obs'] = $id_auteur_obs;$infos['auteur_obs'] = $this->formaterAuteurObs($o);$infos['nom_sci'] = $this->formaterNomSci($o);$infos['nom_sel_co'] = $o['dco_nom_sel'];$infos['nom_sci_co'] = $this->formaterNomSci($o, 'dco_');$infos['date'] = $this->formaterDate($o['date_observation']);$infos['date_co'] = $this->formaterDate($o['dco_date']);$infos['texte_co'] = $o['dco_texte'];$infos['lieu'] = $this->formaterLieu($o);$infos['lien'] = $this->obtenirLienFiche($o['id_observation']);$infos['commentaires'] = array();$this->commentaires_concernes[$id_auteur_co][$id_co] = $infos;$this->commentaires_concernes[$id_auteur_co][$id_co]['commentaires'] = array();}// isolation des données du commentaire$commentaire = $this->arrayTranchette($o, 'dc_', true);$commentaire['auteur'] = $this->formaterAuteurCommentaire($o);$this->commentaires_concernes[$id_auteur_co][$id_co]['commentaires'][] = $commentaire;}//print_r($this->commentaires_concernes); exit;}/*** Envoie un message par destinataire (auteur d'une observation ayant reçu* un commentaire ou d'un commentaire ayant reçu une réponse), en format* texte brut + HTML, avec un squelette différent selon que le destinataire* est inscrit ou non; en mode test, n'envoie les messages qu'au testeur*/protected function envoyerMessageAuxDestinataires() {// liste des auteurs à contacter$auteurs = array_unique(array_merge(array_keys($this->observations_concernees), array_keys($this->commentaires_concernes)));foreach ($auteurs as $auteurId) {$messageTxt = '';$messageHtml = '';// données concernant cet auteur$obsDeCetAuteur = null;if (isset($this->observations_concernees[$auteurId])) {$obsDeCetAuteur = $this->observations_concernees[$auteurId];}$comDeCetAuteur = null;if (isset($this->commentaires_concernes[$auteurId])) {$comDeCetAuteur = $this->commentaires_concernes[$auteurId];}$donnees = $this->formaterDonneesPourMessage($auteurId, $obsDeCetAuteur, $comDeCetAuteur);if (is_numeric($auteurId)) { // inscritsif ($auteurId != 0) {$messageTxt = $this->formaterMessageTxt($donnees, true);$messageHtml = $this->formaterMessageHtml($donnees, true);if ($this->testeurCourriel == null) {$this->envoyerMessage($messageHtml, $messageTxt, $auteurId);}}} else { // non-inscrits$messageTxt = $this->formaterMessageTxt($donnees, false);$messageHtml = $this->formaterMessageHtml($donnees, false);if ($this->testeurCourriel == null) {$this->envoyerMessageAdresseArbitraire($messageHtml, $messageTxt, $auteurId);}}$this->recapitulatifAdmin[$auteurId] = array('txt' => $messageTxt, 'html' => $messageHtml);}if ($this->testeurCourriel == null) {$this->envoyerMessageRecap();}$this->envoyerMessagesTesteur();}// Envoie un message sans passer par l'annuaire, pour les utilisateurs non inscritsprotected function envoyerMessageAdresseArbitraire($messageHtml, $messageTxt, $adresseAuteur) {$dateFmt = $this->formaterDateCourante();$sujet = sprintf($this->conteneur->getParametre('titre_message_recapitulatif'), $dateFmt);$messagerie = $this->conteneur->getMessagerie();// envoi mixte HTML + texte$envoieStatut = $messagerie->envoyerHtml($adresseAuteur, $sujet, $messageHtml, $messageTxt);return $envoieStatut;}/*** Organise un peu les données d'un auteur pour les traiter plus facilement* dans les squelettes de messages*/protected function formaterDonneesPourMessage($auteurId, $liste_obs, $liste_com) {$donnees = array('liste_observations' => array(),'liste_commentaires' => array());if ($liste_obs != null) {$donnees['liste_observations'] = $liste_obs;}if ($liste_com != null) {$donnees['liste_commentaires'] = $liste_com;}if (is_numeric($auteurId)) { // inscrit$infosUtilisateur = $this->telechargerUtilisateurInfos($auteurId);$donnees['auteur_formate'] = $this->formaterIntituleUtilisateur($infosUtilisateur);} else { // non-inscrit$donnees['auteur_formate'] = $auteurId;}return $donnees;}/*** Rédige un message HTML en appliquant les données fournies au squelette* adéquat, selon que le destinataire est inscrit ou non*/protected function formaterMessageHtml($donnees, $inscrit=true) {if ($inscrit) {$squelette = dirname(__FILE__).DS.'squelettes'.DS.'commentaires.tpl.html';} else {$squelette = dirname(__FILE__).DS.'squelettes'.DS.'commentaires_non_inscrits.tpl.html';}$squelettePhp = $this->conteneur->getSquelettePhp();$msgHtml = $squelettePhp->analyser($squelette, $donnees);return $msgHtml;}/*** Rédige un message en texte brut en appliquant les données fournies au squelette* adéquat, selon que le destinataire est inscrit ou non*/protected function formaterMessageTxt($donnees, $inscrit=true) {if ($inscrit) {$squelette = dirname(__FILE__).DS.'squelettes'.DS.'commentaires.tpl.txt';} else {$squelette = dirname(__FILE__).DS.'squelettes'.DS.'commentaires_non_inscrits.tpl.txt';}$squelettePhp = $this->conteneur->getSquelettePhp();$msgTxt = $squelettePhp->analyser($squelette, $donnees);// Nettoyage des tabulations pour indentation du code PHP$msgTxt = str_replace("\t", '', $msgTxt);return $msgTxt;}// envoie un message à un utilisateur inscrit, à l'aide de l'annuaireprotected function envoyerMessage($messageHtml, $messageTxt, $id_destinataire) {$url = sprintf($this->conteneur->getParametre('url_service_messagerie'), $id_destinataire);$dateFmt = $this->formaterDateCourante();$sujet = sprintf($this->conteneur->getParametre('titre_message_recapitulatif'), $dateFmt);$donnees = array('utilisateur_courriel' => $this->conteneur->getParametre('adresse_expediteur_recapitulatif'),'reponse_courriel' => $this->conteneur->getParametre('adresse_reponse'), // reply-to'format' => 'html','sujet' => $sujet,'message' => $messageHtml,'message_txt' => $messageTxt);$clientRest = $this->conteneur->getRestClient();$clientRest->modifier($url, $donnees);}protected function envoyerMessageRecap() {$msgRecap = $this->obtenirMessageRecap();$dateFmt = $this->formaterDateCourante();$sujet = "IdentiPlante : commentaires du $dateFmt";$messagerie = $this->conteneur->getMessagerie();$destinataire = $this->conteneur->getParametre('email_recap');$messagerie->envoyerTxt($destinataire, $sujet, $msgRecap);}protected function obtenirMessageRecap() {if ($this->messageRecapitulatif == null) {$msgRecap = '';$separateur = str_repeat('-', 50);$utilisateursIntitules = $this->obtenirInfosUtilisateurs();foreach ($this->recapitulatifAdmin as $utilisateurId => $message) {$messageTxt = $message['txt'];$intitule = $utilisateursIntitules[$utilisateurId];$msgRecap .= "Message envoyé à : $intitule\n\n$messageTxt\n$separateur\n";}$intituleRecap = implode("\n", $utilisateursIntitules);$msgTpl = "Messages envoyés aux utilisateurs suivant :\n%s\n%s\n%s";$this->messageRecapitulatif = sprintf($msgTpl, $intituleRecap, $separateur, $msgRecap);}return $this->messageRecapitulatif;}// envoie au testeur une copie de chaque type de message envoyé aux utilisateursprotected function envoyerMessagesTesteur() {if ($this->testeurCourriel != null) {$messagerie = $this->conteneur->getMessagerie();$dateFmt = $this->formaterDateCourante();$sujet = "TESTEUR : commentaires du $dateFmt";$msgRecap = $this->obtenirMessageRecap();$messagerie->envoyerTxt($this->testeurCourriel, $sujet, $msgRecap);// deux types de messages (inscrits et non inscrits)$messageInscrits = null;$messageNonInscrits = null;// méga sous optimalforeach($this->recapitulatifAdmin as $idUtil => $mess) {if ($messageInscrits != null && $messageNonInscrits != null) {break; // arrière, Satan ! (mais c'est bien pratique)}if (is_numeric($idUtil) && ($idUtil != 0)) {$messageInscrits = $mess;} else {$messageNonInscrits = $mess;}}$sujet = "TESTEUR : HTML (inscrits) - commentaire du $dateFmt";$messagerie->envoyerHtml($this->testeurCourriel, $sujet, $messageInscrits['html'], $messageInscrits['txt']);$sujet = "TESTEUR : TXT (inscrits) - commentaire du $dateFmt";$messagerie->envoyerTxt($this->testeurCourriel, $sujet, $messageInscrits['txt']);$sujet = "TESTEUR : HTML (non inscrits) - commentaire du $dateFmt";//echo "MNE HTML:: " . $messageNonInscrits['html'] . "\n\n"; exit;$messagerie->envoyerHtml($this->testeurCourriel, $sujet, $messageNonInscrits['html'], $messageNonInscrits['txt']);$sujet = "TESTEUR : TXT (non inscrits) - commentaire du $dateFmt";$messagerie->envoyerTxt($this->testeurCourriel, $sujet, $messageNonInscrits['txt']);}}protected function obtenirInfosUtilisateurs() {$idUtilisateurs = array_keys($this->recapitulatifAdmin);$utilisateursIntitules = [];foreach ($idUtilisateurs as $utilisateurId) {if (is_numeric($utilisateurId)) { // inscrit$infosUtilisateur = $this->telechargerUtilisateurInfos($utilisateurId);$intitule = $this->formaterUtilisateurInfos($infosUtilisateur);} else { // non-inscrit$intitule = $utilisateurId . " - utilisateur non inscrit";}$utilisateursIntitules[$utilisateurId] = $intitule;}asort($utilisateursIntitules);return $utilisateursIntitules;}protected function telechargerUtilisateurInfos($utilisateurId) {if (! isset($this->utilisateursInfos[$utilisateurId])) {$urlTpl = $this->conteneur->getParametre('url_service_utilisateur');$url = sprintf($urlTpl, $utilisateurId);$clientRest = $this->conteneur->getRestClient();$json = $clientRest->consulter($url);$infos = json_decode($json, true);if (is_array($infos)) {$infos = array_shift($infos);}$this->utilisateursInfos[$utilisateurId] = isset($infos['id']) ? $infos : $utilisateurId;}return $this->utilisateursInfos[$utilisateurId];}protected function formaterUtilisateurInfos($infos) {$utilisateurId = isset($infos['id']) ? $infos['id'] : intval($infos);if (isset($infos['courriel']) && isset($infos['intitule'])) {$prenomNom = $infos['nom'].' '.$infos['prenom'];$pseudo = empty($infos['pseudo']) ? '' : '['.$infos['pseudo'].'] ';$courriel = $infos['courriel'];$intitule = "$prenomNom $pseudo($courriel) - id#$utilisateurId";} else {$intitule = "Utilisateur avec id $utilisateurId introuvable";}return $intitule;}protected function formaterNomSci($obs, $prefixe='') {$cnr = $prefixe . 'nom_ret';$cns = $prefixe . 'nom_sel';$nom = 'Espèce indéterminée';if ($obs[$cnr] != '') {$nom = $obs[$cnr];} else if($obs[$cns] != '') {$nom = $obs[$cns];}return $nom;}protected function formaterDate($date) {$dateFmt = '(date inconnue)';if ($date != '0000-00-00 00:00:00') {$time = strtotime($date);$dateFmt = date('d/m/Y', $time);}return $dateFmt;}protected function formaterLieu($obs) {$lieuInfos = [];$champsLieu = ['zone_geo', 'lieudit', 'station'];foreach ($champsLieu as $champ) {if (trim($obs[$champ]) == '') {continue;}$lieuIntitule = $obs[$champ];if ($champ == 'zone_geo') {$codeDept = $this->convertirCodeZoneGeoVersDepartement($obs['ce_zone_geo']);$lieuIntitule .= empty($codeDept) ? '' : " ($codeDept)";}$lieuInfos[] = $lieuIntitule;}$lieu = (count($lieuInfos) > 0) ? implode(' > ', $lieuInfos) : '(lieu inconnu)';return $lieu;}protected function formaterDateCourante() {$date = ($this->dateRenvoi == null) ? time() : strtotime($this->dateRenvoi);$dateFmt = date('d-m-Y', $date);return $dateFmt;}protected function formaterAuteurObs($obs) {return $obs['prenom_utilisateur'].' '.$obs['nom_utilisateur'];}protected function formaterAuteurCommentaire($commentaire) {return $commentaire['dc_utilisateur_prenom'].' '.$commentaire['dc_utilisateur_nom'];}protected function formaterIntituleUtilisateur($infos) {$intituleUtilisateur = isset($infos['intitule']) ? $infos['intitule'] : '';return $intituleUtilisateur;}protected function convertirCodeZoneGeoVersDepartement($code_zone_geo) {$code_departement = '';if (preg_match('/^INSEE-C:([0-9]{2})[0-9]{3}$/', $code_zone_geo, $match)) {$code_departement = $match[1];}return $code_departement;}protected function obtenirLienFiche($id_obs) {return sprintf($this->conteneur->getParametre('url_fiche_observation'), $id_obs);}/*** Copie dans un nouveau tableau les valeurs de $tab dont les clefs* commencent par $prefixe*/protected function arrayTranchette($tab, $prefixe, $enleverPrefixe=false) {$res = array();foreach ($tab as $k => $v) {if (strpos($k, $prefixe) === 0) {$clef = $k;if ($enleverPrefixe === true) {$clef = substr($k, strlen($prefixe));}$res[$clef] = $v;}}return $res;}}