Changeset 112980 in spip-zone


Ignore:
Timestamp:
Dec 20, 2018, 11:37:03 AM (3 months ago)
Author:
cedric@…
Message:

Quand on a des grosses listes de subscribers une bonne pratique conseillee par les plateformes d'envoi de mail consiste a n'envoyer qu'aux inscrits "actifs" (ie qu'on a vu vivants il y a moins de 6 mois, c'est a dire ayant ouvert ou lu un mail)
En attendant de gerer ca automatiquement dans la gestion des inscrits dans le plugin, voici un spip-cli pour nettoyer des listes des inscrits zombies
spip mailsubscribinglist:clean --from='6 month'

Location:
_plugins_/mailsubscribers/trunk
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • _plugins_/mailsubscribers/trunk/paquet.xml

    r112780 r112980  
    22        prefix="mailsubscribers"
    33        categorie="communication"
    4         version="2.10.0"
     4        version="2.10.1"
    55        etat="stable"
    66        compatibilite="[3.0.0;3.2.*]"
  • _plugins_/mailsubscribers/trunk/spip-cli/MailsubscribinglistClean.php

    r112780 r112980  
    11<?php
     2namespace Spip\Cli\Command;
    23
    3 use Symfony\Component\Console\Command\Command;
     4use Spip\Cli\Console\Command;
    45use Symfony\Component\Console\Input\InputArgument;
    56use Symfony\Component\Console\Input\InputInterface;
     
    89use Symfony\Component\Console\Helper\ProgressHelper;
    910
    10 class MailsubscriberSubscribe extends Command {
     11class MailsubscribinglistClean extends Command {
    1112        protected function configure() {
    1213                $this
    13                         ->setName('mailsubscriber:subscribe')
    14                         ->setDescription('Inscrire un email a des listes de diffusion')
     14                        ->setName('mailsubscribinglist:clean')
     15                        ->setDescription('Nettoyer les listes en desinscrivant tous les subscribers qui n\'ont pas été vu vivants depuis plus de N mois')
    1516                        ->addOption(
    16                                 'email',
    17                                 null,
    18                                 InputOption::VALUE_REQUIRED,
    19                                 'email a inscrire',
    20                                 null
    21                         )
    22                         ->addOption(
    23                                 'nom',
     17                                'from',
    2418                                null,
    2519                                InputOption::VALUE_OPTIONAL,
    26                                 'Nom de la personne inscrite',
     20                                'Duree d\'inactivité à prendre en compte au format strtotime : \'10 days\', \'6 months\'…',
    2721                                ''
    2822                        )
     
    3125                                null,
    3226                                InputOption::VALUE_OPTIONAL,
    33                                 'Listes (separées par des virgules si plusieurs)',
     27                                'Listes à nettoyer, séparées par des virgules. Par défaut, toutes',
    3428                                null
    35                         )
    36                         ->addOption(
    37                                 'lang',
    38                                 null,
    39                                 InputOption::VALUE_OPTIONAL,
    40                                 'Lang de l\'inscrit',
    41                                 null
    42                         )
    43                         ->addOption(
    44                                 'force',
    45                                 null,
    46                                 InputOption::VALUE_OPTIONAL,
    47                                 'permet de forcer une inscription sans doubleoptin',
    48                                 null
    49                         )
    50                         ->addOption(
    51                                 'graceful',
    52                                 null,
    53                                 InputOption::VALUE_OPTIONAL,
    54                                 'permet de ne pas reinscrire quelqu\'un qui s\'est desabonne',
    55                                 true
    5629                        )
    5730                        ->addOption(
    5831                                'notify',
    5932                                null,
    60                                 InputOption::VALUE_OPTIONAL,
    61                                 'indique si on veut ou non notifier par email',
    62                                 true
     33                                InputOption::VALUE_NONE,
     34                                'indique si on veut ou non notifier par email les désabonnements, ce qui permettrait aux personnes de se réinscrire si besoin'
     35                        )
     36                        ->addOption(
     37                                'yes',
     38                                'y',
     39                                InputOption::VALUE_NONE,
     40                                'Desinscrire sans demander confirmation'
    6341                        )
    6442                ;
     
    6947                include_spip('inc/filtres');
    7048
    71                 global $spip_racine;
    72                 global $spip_loaded;
     49                #global $spip_racine;
     50                #global $spip_loaded;
    7351
    74                 $email = $input->getOption('email');
    75                 if (!$email) {
    76                         $output->writeln("<error>Indiquez un email</error>");
     52                $from = $input->getOption('from');
     53                if (!$from) {
     54                        $from = strtotime('-6 months');
     55                }
     56                else {
     57                        $from = strtotime('-' . $from);
     58                }
     59                if (!$from) {
     60                        $output->writeln("<error>from invalide</error>");
    7761                        exit(1);
    7862                }
    79                 if (!$email = email_valide($email)) {
    80                         $output->writeln("<error>Indiquez un email valide</error>");
     63                $from = date('Y-m-d H:i:s', $from);
     64
     65                $options = array();
     66                if ($input->getOption('notify')) {
     67                        $options['notify'] = true;
     68                }
     69                else {
     70                        $options['notify'] = false;
     71                }
     72
     73                $in_listes = '';
     74                $listes = $input->getOption('listes');
     75                if (!is_null($listes)) {
     76                        $listes = explode(',', $listes);
     77                        $options['listes'] = $listes;
     78
     79                        $id_mailsubscribinglists = sql_allfetsel('id_mailsubscribinglist', 'spip_mailsubscribinglists', sql_in('identifiant', $listes));
     80                        $id_mailsubscribinglists = array_column($id_mailsubscribinglists, 'id_mailsubscribinglist');
     81                        $in_listes = " AND " . sql_in('id_mailsubscribinglist', $id_mailsubscribinglists);
     82                }
     83
     84                // charger en memoire TOUS les emails ayant ete vu vivants depuis $from
     85                $email_alive = sql_allfetsel('distinct email', 'spip_mailshots_destinataires', sql_in('statut', array('clic', 'read')) . ' AND date>' . sql_quote($from));
     86                $email_alive = array_column($email_alive, 'email');
     87                $output->writeln("<info>Emails vus vivants depuis $from : " . count($email_alive) . "</info>");
     88
     89
     90                $id_mailsubscribers_alive = sql_allfetsel("id_mailsubscriber", "spip_mailsubscribers", sql_in('email', $email_alive));
     91                $id_mailsubscribers_alive = array_column($id_mailsubscribers_alive, 'id_mailsubscriber');
     92                $output->writeln("<info>Mailsubscribers vus vivants depuis $from : " . count($id_mailsubscribers_alive) . "</info>");
     93
     94                // trouver tous les zombies
     95                $id_mailsubscribers_zombies = sql_allfetsel('id_mailsubscriber', 'spip_mailsubscribers', "statut='valide' AND " . sql_in('id_mailsubscriber', $id_mailsubscribers_alive, 'NOT'));
     96                $id_mailsubscribers_zombies = array_column($id_mailsubscribers_zombies, 'id_mailsubscriber');
     97                $output->writeln("Mailsubscribers zombies depuis $from : " . count($id_mailsubscribers_zombies));
     98
     99                // et restreindre aux listes demandées uniquement (si besoin)
     100                $id_mailsubscribers_unsub = sql_allfetsel("DISTINCT id_mailsubscriber", 'spip_mailsubscriptions', sql_in('id_mailsubscriber',$id_mailsubscribers_zombies). " AND statut='valide' AND id_segment=0" . $in_listes);
     101                $id_mailsubscribers_unsub = array_column($id_mailsubscribers_unsub, 'id_mailsubscriber');
     102                $nb_unsub = count($id_mailsubscribers_unsub);
     103                $this->io->care("Mailsubscribers a désabonner".($listes ? " des listes ". implode(',',$listes) : '') . " : " . $nb_unsub);
     104
     105                // compter par liste pour indication
     106                $details = sql_allfetsel("id_mailsubscribinglist, count(id_mailsubscriber) as N", 'spip_mailsubscriptions', sql_in('id_mailsubscriber',$id_mailsubscribers_zombies). " AND statut='valide' AND id_segment=0" . $in_listes,'id_mailsubscribinglist');
     107                foreach ($details as $d) {
     108                        if ($l = sql_fetsel('identifiant, titre', 'spip_mailsubscribinglists', 'id_mailsubscribinglist='.intval($d['id_mailsubscribinglist']))) {
     109                                $this->io->care("#".$d['id_mailsubscribinglist'] . " " . $l['titre'] . " : " . $d['N']);
     110                        }
     111                }
     112
     113
     114                // verifier que aucun des emails qu'on va unsub n'a ete vu vivant (double check donc, qu'on a pas fait d'erreur dans la selection)
     115                $emails_unsub = sql_allfetsel('email', 'spip_mailsubscribers', sql_in('id_mailsubscriber', $id_mailsubscribers_unsub));
     116                $emails_unsub = array_column($emails_unsub, 'email');
     117                $alive_unsub = sql_allfetsel('email, max(date) as date_max, statut', 'spip_mailshots_destinataires', sql_in('statut', array('clic', 'read')) . ' AND ' . sql_in('email', $emails_unsub) . ' AND date>' . sql_quote($from), 'email');
     118                if (count($alive_unsub)) {
     119                        $output->writeln("<error>Probleme de selections : on retrouve ".count($alive_unsub)." emails vivants dans ceux qu'on veut desinscrire</error>");
    81120                        exit(1);
    82121                }
    83122
    84                 $options = array();
    85                 foreach (array('nom', 'lang', 'force', 'graceful', 'notify') as $o) {
    86                         if (!is_null($value= $input->getOption($o))) {
    87                                 $options[$o] = $value;
    88                         }
     123                if (
     124                        !$input->getOption('yes')
     125                        and !$this->io->confirm("Désinscrire les $nb_unsub subscribers".($listes ? " des listes ". implode(',',$listes) : '')." ?", false)
     126                ){
     127                        $this->io->care("Action annulée");
     128                        return;
    89129                }
    90130
    91                 $listes = $input->getOption('listes');
    92                 if (!is_null($listes)) {
    93                         $options['listes'] = explode(',', $listes);
     131
     132                MailsubscribinglistClean::unsubscribeAll($this->io, $emails_unsub, $options);
     133        }
     134
     135        public static function logRecord($io, $fichier_log, $texte) {
     136                $io->text($texte);
     137                file_put_contents($fichier_log, rtrim($texte) . "\n",FILE_APPEND);
     138        }
     139
     140        public static function unsubscribeAll($io, $emails, $options) {
     141
     142                $now = time();
     143                $d = date('Ymd-His', $now);
     144                $fichier_log = _DIR_LOG . 'mailsubscribinglist-clean-'.$d.'.log';
     145                $io->care("Ecriture des desinscriptions dans $fichier_log");
     146
     147                MailsubscribinglistClean::logRecord($io, $fichier_log,'# '. date('Y-m-d H:i:s', $now) . ' Desinscriptions ' . json_encode($options));
     148
     149                $nb_total = count($emails);
     150                $nb = 0;
     151                $unsubscribe = charger_fonction('unsubscribe', 'newsletter');
     152                foreach ($emails as $email) {
     153                        $nb++;
     154                        MailsubscribinglistClean::logRecord($io, $fichier_log,"$nb/$nb_total: $email");
     155                        $unsubscribe($email, $options);
    94156                }
    95157
    96                 $subscribe = charger_fonction('subscribe', 'newsletter');
    97                 $subscribe($email, $options);
    98 
    99                 $subscriber = charger_fonction('subscriber', 'newsletter');
    100                 $infos = $subscriber($email);
    101 
    102                 $output->writeln(var_export($infos, true));
    103158        }
    104159}
Note: See TracChangeset for help on using the changeset viewer.