Fixes output list of broken addresses using profile features.
[platal.git] / modules / email.php
index b0bb942..1496b04 100644 (file)
@@ -67,34 +67,41 @@ class EmailModule extends PLModule
                            WHERE  uid = {?}", $user->id());
             // Then gives the bestalias flag to the given email.
             list($email, $domain) = explode('@', $email);
-            XDB::execute("UPDATE  email_source_account  AS s
-                      INNER JOIN  email_virtual_domains AS d ON (s.domain = d.id)
-                             SET  s.flags = CONCAT_WS(',', IF(s.flags = '', NULL, s.flags), 'bestalias')
-                           WHERE  s.uid = {?} AND s.email = {?} AND d.name = {?}", $user->id(), $email, $domain);
+            XDB::execute("UPDATE  email_source_account
+                             SET  flags = CONCAT_WS(',', IF(flags = '', NULL, flags), 'bestalias')
+                           WHERE  uid = {?} AND email = {?}", $user->id(), $email);
+            XDB::execute('UPDATE  accounts              AS a
+                      INNER JOIN  email_virtual_domains AS d ON (d.name = {?})
+                             SET  a.best_domain = d.id
+                           WHERE  a.uid = {?}',
+                         $domain, $user->id());
 
             // As having a non-null bestalias value is critical in
             // plat/al's code, we do an a posteriori check on the
             // validity of the bestalias.
             fix_bestalias($user);
+            // Then refetch the user to update its bestalias.
+            S::set('user', User::getWithUID(S::user()->id()));
         }
 
         // Fetch and display aliases.
         $aliases = XDB::iterator("SELECT  CONCAT(s.email, '@', d.name) AS email, (s.type = 'forlife') AS forlife,
-                                          (s.email REGEXP '\\\\.[0-9]{2}$') AS hundred_year,
-                                          FIND_IN_SET('bestalias', s.flags) AS bestalias, s.expire,
-                                          (d.name = {?}) AS alias
+                                          (s.email REGEXP '\\\\.[0-9]{2}$') AS hundred_year, s.expire,
+                                          (FIND_IN_SET('bestalias', s.flags) AND a.best_domain = d.id) AS bestalias,
+                                          ((s.type = 'alias_aux') AND d.aliasing = d.id) AS alias
                                     FROM  email_source_account  AS s
-                              INNER JOIN  email_virtual_domains AS d ON (s.domain = d.id)
+                              INNER JOIN  accounts              AS a ON (s.uid = a.uid)
+                              INNER JOIN  email_virtual_domains AS m ON (s.domain = m.id)
+                              INNER JOIN  email_virtual_domains AS d ON (d.aliasing = m.id)
                                    WHERE  s.uid = {?}
                                 ORDER BY  !alias, s.email",
-                                 $globals->mail->alias_dom, $user->id());
+                                 $user->id());
         $page->assign('aliases', $aliases);
 
-        $alias = XDB::fetchOneCell('SELECT  COUNT(s.email)
-                                      FROM  email_source_account  AS s
-                                INNER JOIN  email_virtual_domains AS d ON (s.domain = d.id)
-                                     WHERE  s.uid = {?} AND d.name = {?}',
-                                   $user->id(), $globals->mail->alias_dom);
+        $alias = XDB::fetchOneCell('SELECT  COUNT(email)
+                                      FROM  email_source_account
+                                     WHERE  uid = {?} AND type = \'alias_aux\'',
+                                   $user->id());
         $page->assign('alias', $alias);
 
 
@@ -104,6 +111,13 @@ class EmailModule extends PLModule
         // Display active redirections.
         $redirect = new Redirect($user);
         $page->assign('mails', $redirect->active_emails());
+
+        // User's mail domains.
+        $mail_domains = array($user->alternateEmailDomain());
+        $mail_domains[] = User::$sub_mail_domains['all'] . $globals->mail->domain;
+        $mail_domains[] = User::$sub_mail_domains['all'] . $globals->mail->domain2;
+        $page->assign('main_email_domain', $user->mainEmailDomain());
+        $page->assign('mail_domains', $mail_domains);
     }
 
     function handler_alias($page, $action = null, $value = null)
@@ -120,22 +134,20 @@ class EmailModule extends PLModule
         if ($action == 'delete') {
             S::assert_xsrf_token();
 
-            XDB::execute('DELETE  s
-                            FROM  email_source_account  AS s
-                      INNER JOIN  email_virtual_domains AS d ON (s.domain = d.id)
-                           WHERE  s.uid = {?} AND d.name = {?}',
-                         $user->id(), $globals->mail->alias_dom);
+            XDB::execute('DELETE FROM  email_source_account
+                                WHERE  uid = {?} AND type = \'alias_aux\'',
+                         $user->id());
 
             require_once 'emails.inc.php';
             fix_bestalias($user);
         }
 
-        // Fetch existing @alias_dom aliases.
+        // Fetch existing auxiliary aliases.
         list($alias, $old_alias) = XDB::fetchOneRow('SELECT  CONCAT(s.email, \'@\', d.name), s.email
                                                        FROM  email_source_account  AS s
                                                  INNER JOIN  email_virtual_domains AS d ON (s.domain = d.id)
-                                                      WHERE  s.uid = {?} AND d.name = {?}',
-                                                    $user->id(), $globals->mail->alias_dom);
+                                                      WHERE  s.uid = {?} AND s.type = \'alias_aux\'',
+                                                    $user->id());
         $visibility = $user->hasProfile() && ($user->profile(true)->alias_pub == 'public');
         $page->assign('current', $alias);
         $page->assign('user', $user);
@@ -164,11 +176,10 @@ class EmailModule extends PLModule
                 return;
             } else {
                 // Checks if the alias has already been given.
-                $res = XDB::query('SELECT  COUNT(s.email)
-                                     FROM  email_source_account  AS s
-                               INNER JOIN  email_virtual_domains AS d ON (s.domain = d.id)
-                                    WHERE  s.email = {?} AND d.name = {?}',
-                                  $new_alias, $globals->mail->alias_dom);
+                $res = XDB::query('SELECT  COUNT(email)
+                                     FROM  email_source_account
+                                    WHERE  email = {?} AND type = \'alias_aux\'',
+                                  $new_alias);
                 if ($res->fetchOneCell() > 0) {
                     $page->trigError("L'alias $new_alias a déja été attribué. Tu ne peux donc pas l'obtenir.");
                     return;
@@ -284,9 +295,10 @@ class EmailModule extends PLModule
                          INNER JOIN  email_virtual_domains AS m ON (s.domain = m.id)
                          INNER JOIN  email_virtual_domains AS d ON (m.id = d.aliasing)
                               WHERE  s.uid = {?}
-                           ORDER BY  NOT (m.name = {?}), s.email, d.name',
-                            $user->id(), $globals->mail->alias_dom);
+                           ORDER BY  NOT(s.type = \'alias_aux\'), s.email, d.name',
+                            $user->id());
         $page->assign('alias', $alias->fetchAllAssoc());
+        $page->assign('best_email', $user->bestEmail());
 
         $page->assign('emails', $redirect->emails);
 
@@ -298,7 +310,7 @@ class EmailModule extends PLModule
         fill_email_combobox($page);
     }
 
-    function handler_antispam($page, $filter_status = null)
+    function handler_antispam($page, $filter_status = null, $redirection = null)
     {
         require_once 'emails.inc.php';
         $wp = new PlWikiPage('Xorg.Antispam');
@@ -308,10 +320,17 @@ class EmailModule extends PLModule
 
         $user = S::user();
         $bogo = new Bogo($user);
-        if (isset($filter_status)) {
-            $bogo->change($filter_status + 0);
+        if (!is_null($filter_status)) {
+            if (is_null($redirection)) {
+                $bogo->changeAll($filter_status);
+            } else {
+                $bogo->change($redirection, $filter_status);
+            }
         }
-        $page->assign('filter', $bogo->level());
+        $page->assign('filter', $bogo->state);
+        $page->assign('single_state', $bogo->single_state);
+        $page->assign('single_redirection', $bogo->single_redirection);
+        $page->assign('redirections', $bogo->redirections);
     }
 
     function handler_submit($page)
@@ -621,11 +640,12 @@ class EmailModule extends PLModule
         if ($warn == 'warn' && $email) {
             S::assert_xsrf_token();
 
+            // Usual verifications.
             $email = valide_email($email);
-            // vérifications d'usage
-            $uid = XDB::fetchOneCell("SELECT  uid
-                                        FROM  emails
-                                       WHERE  email = {?}", $email);
+            $uid = XDB::fetchOneCell('SELECT  uid
+                                        FROM  email_redirect_account
+                                       WHERE  redirect = {?}', $email);
+
             if ($uid) {
                 $dest = User::getWithUID($uid);
 
@@ -638,38 +658,14 @@ class EmailModule extends PLModule
         } elseif (Post::has('email')) {
             S::assert_xsrf_token();
 
-            $email = valide_email(Post::v('email'));
+            $email = Post::t('email');
 
-            list(,$fqdn) = explode('@', $email);
-            $fqdn = strtolower($fqdn);
-            if ($fqdn == 'polytechnique.org' || $fqdn == 'melix.org' ||  $fqdn == 'm4x.org' || $fqdn == 'melix.net') {
+            if (!User::isForeignEmailAddress($email)) {
                 $page->assign('neuneu', true);
             } else {
-                $page->assign('email',$email);
-                $x = XDB::fetchOneAssoc("SELECT  e1.uid, e1.panne != 0 AS panne, a.hruid,
-                                                 (COUNT(e2.uid) + IF(FIND_IN_SET('googleapps', eo.storage), 1, 0)) AS nb_mails
-                                           FROM  emails        AS e1
-                                     INNER JOIN  email_options AS eo ON (eo.uid = e1.uid)
-                                     INNER JOIN  accounts      AS a  ON (e1.uid = a.uid)
-                                      LEFT JOIN  emails        AS e2 ON (e1.uid = e2.uid
-                                                                         AND FIND_IN_SET('active', e2.flags)
-                                                                         AND e1.email != e2.email)
-                                          WHERE  e1.email = {?}
-                                       GROUP BY  e1.uid", $email);
-                if ($x) {
-                    // on écrit dans la base que l'adresse est cassée
-                    if (!$x['panne']) {
-                        XDB::execute("UPDATE  emails
-                                         SET  panne=NOW(), last=NOW(), panne_level = 1
-                                       WHERE  email = {?}", $email);
-                    } else {
-                        XDB::execute("UPDATE  emails
-                                         SET  panne_level = 1
-                                       WHERE  email = {?} AND panne_level = 0", $email);
-                    }
-                    $x['user'] = User::getWithUID($x['uid']);
-                    $page->assign_by_ref('x', $x);
-                }
+                $user = mark_broken_email($email);
+                $page->assign('user', $user);
+                $page->assign('email', $email);
             }
         }
     }
@@ -713,12 +709,11 @@ class EmailModule extends PLModule
         $page->assign('action', $action);
 
         if ($action == 'list') {
-            $sql = "SELECT  w.email, w.detection, w.state, a.alias AS forlife
-                      FROM  email_watch  AS w
-                 LEFT JOIN  emails        AS e USING(email)
-                 LEFT JOIN  aliases       AS a ON (a.uid = e.uid AND a.type = 'a_vie')
-                  ORDER BY  w.state, w.email, a.alias";
-            $it = Xdb::iterRow($sql);
+            $it = XDB::iterRow('SELECT  w.email, w.detection, w.state, s.email AS forlife
+                                  FROM  email_watch            AS w
+                            INNER JOIN  email_redirect_account AS r ON (w.email = r.redirect)
+                            INNER JOIN  email_source_account   AS s ON (s.uid = r.uid AND s.type = \'forlife\')
+                              ORDER BY  w.state, w.email, s.email');
 
             $table = array();
             $props = array();
@@ -740,15 +735,15 @@ class EmailModule extends PLModule
             }
             $page->assign('table', $table);
         } elseif ($action == 'edit') {
-            $sql = "SELECT  w.detection, w.state, w.last, w.description,
-                            a1.alias AS edit, a2.alias AS forlife
-                      FROM  email_watch AS w
-                 LEFT JOIN  aliases      AS a1 ON (a1.uid = w.uid AND a1.type = 'a_vie')
-                 LEFT JOIN  emails       AS e  ON (w.email = e.email)
-                 LEFT JOIN  aliases      AS a2 ON (a2.uid = e.uid AND a2.type = 'a_vie')
-                     WHERE  w.email = {?}
-                  ORDER BY  a2.alias";
-            $it = Xdb::iterRow($sql, $email);
+            $it = XDB::iterRow('SELECT  w.detection, w.state, w.last, w.description,
+                                        a.hruid AS edit, s.email AS forlife
+                                  FROM  email_watch            AS w
+                            INNER JOIN  email_redirect_account AS r ON (w.email = r.redirect)
+                            INNER JOIN  email_source_account   AS s ON (s.uid = r.uid AND s.type = \'forlife\')
+                            INNER JOIN  accounts               AS a ON (w.uid = a.uid)
+                                 WHERE  w.email = {?}
+                              ORDER BY  s.email',
+                               $email);
 
             $props = array();
             while (list($detection, $state, $last, $description, $edit, $forlife) = $it->next()) {
@@ -774,13 +769,14 @@ class EmailModule extends PLModule
 
         $page->assign('lost_emails',
                       XDB::iterator('SELECT  a.uid, a.hruid, pd.promo
-                                       FROM  accounts         AS a
-                                 INNER JOIN  email_options    AS eo ON (eo.uid = a.uid)
-                                  LEFT JOIN  emails           AS e  ON (a.uid = e.uid AND FIND_IN_SET(\'active\', e.flags))
-                                  LEFT JOIN  account_profiles AS ap ON (ap.uid = a.uid AND FIND_IN_SET(\'owner\', perms))
-                                  LEFT JOIN  profile_display  AS pd ON (ap.pid = pd.pid)
-                                      WHERE  e.uid IS NULL AND FIND_IN_SET(\'googleapps\', eo.storage) = 0
-                                             AND a.state = \'active\'
+                                       FROM  accounts               AS a
+                                 INNER JOIN  account_types          AS at ON (a.type = at.type)
+                                  LEFT JOIN  email_redirect_account AS er ON (er.uid = a.uid AND er.flags = \'active\' AND er.broken_level < 3
+                                                                              AND er.type != \'imap\' AND er.type != \'homonym\')
+                                  LEFT JOIN  account_profiles       AS ap ON (ap.uid = a.uid AND FIND_IN_SET(\'owner\', ap.perms))
+                                  LEFT JOIN  profile_display        AS pd ON (ap.pid = pd.pid)
+                                      WHERE  a.state = \'active\' AND er.redirect IS NULL AND FIND_IN_SET(\'mail\', at.perms)
+                                   GROUP BY  a.uid
                                    ORDER BY  pd.promo, a.hruid'));
     }
 
@@ -807,13 +803,13 @@ class EmailModule extends PLModule
                         if (empty($email) || $email == '@') {
                             $invalid_emails[] = trim($orig_email) . ': invalid email';
                         } elseif (!in_array($email, $valid_emails)) {
-                            $res = XDB::query('SELECT  COUNT(*)
-                                                 FROM  emails
-                                                WHERE  email = {?}', $email);
-                            if ($res->fetchOneCell() > 0) {
+                            $nb = XDB::fetchOneCell('SELECT  COUNT(*)
+                                                       FROM  email_redirect_account
+                                                      WHERE  redirect = {?}', $email);
+                            if ($nb > 0) {
                                 $valid_emails[] = $email;
                             } else {
-                                $invalid_emails[] = "$orig_email: no such redirection";
+                                $invalid_emails[] = $orig_email . ': no such redirection';
                             }
                         }
                     }
@@ -831,104 +827,69 @@ class EmailModule extends PLModule
             if ($list == '') {
                 $page->trigError('La liste est vide.');
             } else {
+                require_once 'notifs.inc.php';
+
                 $broken_user_list = array();
+                $broken_user_email_count = array();
                 $broken_list = explode("\n", $list);
                 sort($broken_list);
-                foreach ($broken_list as $orig_email) {
-                    $email = valide_email(trim($orig_email));
-                    if (empty($email) || $email == '@') {
-                        continue;
-                    }
 
-                    $sel = XDB::query(
-                        "SELECT  e1.uid, e1.panne != 0 AS panne, count(e2.uid) AS nb_mails,
-                                 acc.full_name, a.alias
-                           FROM  emails        AS e1
-                      LEFT JOIN  emails        AS e2 ON (e1.uid = e2.uid AND FIND_IN_SET('active', e2.flags)
-                                                         AND e1.email != e2.email)
-                     INNER JOIN  accounts      AS acc  ON (e1.uid = acc.uid)
-                     INNER JOIN  aliases       AS a  ON (acc.uid = a.uid AND FIND_IN_SET('bestalias', a.flags))
-                          WHERE  e1.email = {?}
-                       GROUP BY  e1.uid", $email);
-
-                    if ($x = $sel->fetchOneAssoc()) {
-                        if (!$x['panne']) {
-                            XDB::execute('UPDATE  emails
-                                             SET  panne=NOW(), last=NOW(), panne_level = 1
-                                           WHERE  email = {?}',
-                                          $email);
-                        } else {
-                            XDB::execute('UPDATE  emails
-                                             SET  last = CURDATE(), panne_level = panne_level + 1
-                                           WHERE  email = {?}
-                                                  AND DATE_ADD(last, INTERVAL 14 DAY) < CURDATE()',
-                                         $email);
-                        }
-
-                        if (!empty($x['nb_mails'])) {
+                foreach ($broken_list as $email) {
+                    if ($user = mark_broken_email($email, true)) {
+                        if ($user['nb_mails'] > 0 && $user['notify']) {
                             $mail = new PlMailer('emails/broken.mail.tpl');
-                            $mail->addTo("\"{$x['full_name']}\" <{$x['alias']}@"
-                                         . Platal::globals()->mail->domain . '>');
-                            $mail->assign('x', $x);
+                            $dest = User::getSilentWithUID($user['uid']);
+                            $mail->setTo($dest);
+                            $mail->assign('user', $user);
                             $mail->assign('email', $email);
                             $mail->send();
+                        } else {
+                            $profile = Profile::get($user['alias']);
+                            WatchProfileUpdate::register($profile, 'broken');
                         }
 
-                        if (!isset($broken_user_list[$x['alias']])) {
-                            $broken_user_list[$x['alias']] = array($email);
+                        if (!isset($broken_user_list[$user['uid']])) {
+                            $broken_user_list[$user['uid']] = array($email);
                         } else {
-                            $broken_user_list[$x['alias']][] = $email;
+                            $broken_user_list[$user['uid']][] = $email;
                         }
+                        $broken_user_email_count[$user['uid']] = $user['nb_mails'];
                     }
                 }
 
-                XDB::execute("UPDATE  emails
-                                 SET  panne_level = panne_level - 1
-                               WHERE  flags = 'active' AND panne_level > 1
-                                      AND DATE_ADD(last, INTERVAL 1 MONTH) < CURDATE()");
-                XDB::execute("UPDATE  emails
-                                 SET  panne_level = 0
-                               WHERE  flags = 'active' AND panne_level = 1
-                                      AND DATE_ADD(last, INTERVAL 1 YEAR) < CURDATE()");
+                XDB::execute('UPDATE  email_redirect_account
+                                 SET  broken_level = broken_level - 1
+                               WHERE  flags = \'active\' AND broken_level > 1
+                                      AND DATE_ADD(last, INTERVAL 1 MONTH) < CURDATE()');
+                XDB::execute('UPDATE  email_redirect_account
+                                 SET  broken_level = 0
+                               WHERE  flags = \'active\' AND broken_level = 1
+                                      AND DATE_ADD(last, INTERVAL 1 YEAR) < CURDATE()');
 
                 // Output the list of users with recently broken addresses,
                 // along with the count of valid redirections.
-                require_once 'notifs.inc.php';
                 pl_cached_content_headers('text/x-csv', 1);
 
                 $csv = fopen('php://output', 'w');
-                fputcsv($csv, array('nom', 'promo', 'alias', 'bounce', 'nbmails', 'url', 'corps', 'job', 'networking'), ';');
-                foreach ($broken_user_list as $alias => $mails) {
-                    $sel = Xdb::query(
-                        "SELECT  acc.uid, count(DISTINCT(e.email)) AS nb_mails,
-                                 IFNULL(pd.public_name, acc.full_name) AS fullname,
-                                 IFNULL(pd.promo, 0) AS promo, IFNULL(pce.name, 'Aucun') AS corps,
-                                 IFNULL(pje.name, 'Aucun') AS job, GROUP_CONCAT(pn.address SEPARATOR ', ') AS networking
-                           FROM  aliases            AS a
-                     INNER JOIN  accounts           AS acc ON (a.uid = acc.uid)
-                      LEFT JOIN  emails             AS e   ON (e.uid = acc.uid
-                                                               AND FIND_IN_SET('active', e.flags) AND e.panne = 0)
-                      LEFT JOIN  account_profiles   AS ap  ON (acc.uid = ap.uid AND FIND_IN_SET('owner', ap.perms))
-                      LEFT JOIN  profile_display    AS pd  ON (pd.pid = ap.pid)
-                      LEFT JOIN  profile_corps      AS pc  ON (pc.pid = ap.pid)
-                      LEFT JOIN  profile_corps_enum AS pce ON (pc.current_corpsid = pce.id)
-                      LEFT JOIN  profile_job        AS pj  ON (pj.pid = ap.pid)
-                      LEFT JOIN  profile_job_enum   AS pje ON (pj.jobid = pje.id)
-                      LEFT JOIN  profile_networking AS pn  ON (pn.pid = ap.pid)
-                          WHERE  a.alias = {?}
-                       GROUP BY  acc.uid", $alias);
-
-                    if ($x = $sel->fetchOneAssoc()) {
-                        if ($x['nb_mails'] == 0) {
-                            $user = User::getSilentWithUID($x['uid']);
-                            $profile = $user->profile();
-                            WatchProfileUpdate::register($profile, 'broken');
-                        }
-                        fputcsv($csv, array($x['fullname'], $x['promo'], $alias,
-                                            join(',', $mails), $x['nb_mails'],
-                                            'https://www.polytechnique.org/marketing/broken/' . $alias,
-                                            $x['corps'], $x['job'], $x['networking']), ';');
+                fputcsv($csv, array('nom', 'promo', 'bounces', 'nbmails', 'url', 'corps', 'job', 'networking'), ';');
+                foreach ($broken_user_list as $uid => $mails) {
+                    $profile = Profile::get($uid);
+                    $corps = $profile->getCorps();
+                    $current_corps = ($corps && $corps->current) ? $corps->current : '';
+                    $jobs = $profile->getJobs();
+                    $companies = array();
+                    foreach ($jobs as $job) {
+                        $companies[] = $job->company->name;
+                    }
+                    $networkings = $profile->getNetworking(Profile::NETWORKING_ALL);
+                    $networking_list = array();
+                    foreach ($networkings as $networking) {
+                        $networking_list[] = $networking['address'];
                     }
+                    fputcsv($csv, array($profile->fullName(), $profile->promo(),
+                                        join(',', $mails), $broken_user_email_count[$uid],
+                                        'https://www.polytechnique.org/marketing/broken/' . $profile->hrid(),
+                                        $current_corps, implode(',', $companies), implode(',', $networking_list)), ';');
                 }
                 fclose($csv);
                 exit;