Only notifies user about a broken redirection twice a month, fixes a few things.
[platal.git] / modules / xnet.php
index 195d4bb..3645faa 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /***************************************************************************
- *  Copyright (C) 2003-2009 Polytechnique.org                              *
+ *  Copyright (C) 2003-2011 Polytechnique.org                              *
  *  http://opensource.polytechnique.org/                                   *
  *                                                                         *
  *  This program is free software; you can redistribute it and/or modify   *
@@ -24,73 +24,76 @@ class XnetModule extends PLModule
     function handlers()
     {
         return array(
-            'index'     => $this->make_hook('index',     AUTH_PUBLIC),
-            'exit'      => $this->make_hook('exit',      AUTH_PUBLIC),
-
-            'admin'     => $this->make_hook('admin',     AUTH_MDP, 'admin'),
-            'groups'    => $this->make_hook('groups',    AUTH_PUBLIC),
-            'groupes.php' => $this->make_hook('groups2', AUTH_PUBLIC),
-            'plan'      => $this->make_hook('plan',      AUTH_PUBLIC),
-            'photo'     => $this->make_hook('photo',     AUTH_MDP),
-            'autologin' => $this->make_hook('autologin', AUTH_MDP),
+            'index'       => $this->make_hook('index',     AUTH_PUBLIC),
+            'exit'        => $this->make_hook('exit',      AUTH_PUBLIC),
+
+            'admin'       => $this->make_hook('admin',     AUTH_MDP, 'admin'),
+            'groups'      => $this->make_hook('groups',    AUTH_PUBLIC),
+            'groupes.php' => $this->make_hook('groups2',   AUTH_PUBLIC),
+            'plan'        => $this->make_hook('plan',      AUTH_PUBLIC),
+            'photo'       => $this->make_hook('photo',     AUTH_MDP),
+            'autologin'   => $this->make_hook('autologin', AUTH_MDP),
+            'login/ext'   => $this->make_hook('login_ext', AUTH_PUBLIC),
+            'register/ext' => $this->make_hook('register_ext', AUTH_PUBLIC),
+            'recovery/ext' => $this->make_hook('recovery_ext', AUTH_PUBLIC),
+            'tmpPWD/ext'  => $this->make_hook('tmpPWD_ext', AUTH_PUBLIC),
+            'edit'        => $this->make_hook('edit',      AUTH_MDP, 'user'),
+            'password'    => $this->make_hook('password',  AUTH_MDP, 'user'),
+
+            'Xnet'        => $this->make_wiki_hook(),
         );
     }
 
-    function handler_photo(&$page, $x = null)
+    function handler_photo($page, $x = null)
     {
-        if (is_null($x)) {
+        if (!$x || !($profile = Profile::get($x))) {
             return PL_NOT_FOUND;
         }
 
-        $res = XDB::query("SELECT attachmime, attach
-                             FROM aliases
-                       INNER JOIN photo ON(id = uid)
-                            WHERE alias = {?}", $x);
+        // Retrieve the photo and its mime type.
+        $photo = $profile->getPhoto(true, true);
 
-        if ((list($type, $data) = $res->fetchOneRow())) {
-            Header("Content-type: image/$type");
-            echo $data;
-        } else {
-            Header('Content-type: image/png');
-            echo file_get_contents(dirname(__FILE__).'/../htdocs/images/none.png');
-        }
-        exit;
+        // Display the photo, or a default one when not available.
+        $photo->send();
     }
 
-    function handler_index(&$page)
+    function handler_index($page)
     {
         $page->nomenu = true;
         $page->changeTpl('xnet/index.tpl');
     }
 
-    function handler_exit(&$page)
+    function handler_exit($page)
     {
         Platal::session()->stopSUID();
         Platal::session()->destroy();
         $page->changeTpl('xnet/deconnexion.tpl');
     }
 
-    function handler_admin(&$page)
+    function handler_admin($page)
     {
         $page->changeTpl('xnet/admin.tpl');
 
         if (Get::has('del')) {
             $res = XDB::query('SELECT id, nom, mail_domain
-                                           FROM groupex.asso WHERE diminutif={?}',
+                                           FROM groups WHERE diminutif={?}',
                                         Get::v('del'));
             list($id, $nom, $domain) = $res->fetchOneRow();
             $page->assign('nom', $nom);
             if ($id && Post::has('del')) {
                 S::assert_xsrf_token();
 
-                XDB::query('DELETE FROM groupex.membres WHERE asso_id={?}', $id);
+                XDB::query('DELETE FROM group_members WHERE asso_id={?}', $id);
                 $page->trigSuccess('membres supprimés');
 
                 if ($domain) {
-                    XDB::query('DELETE FROM  virtual_domains WHERE domain={?}', $domain);
-                    XDB::query('DELETE FROM  virtual, virtual_redirect
-                                                USING  virtual INNER JOIN virtual_redirect USING (vid)
-                                                WHERE  alias LIKE {?}', '%@'.$domain);
+                    XDB::execute('DELETE  v
+                                    FROM  email_virtual         AS v
+                              INNER JOIN  email_virtual_domains AS d ON (v.domain = d.id)
+                                   WHERE  d.name = {?}',
+                                 $domain);
+                    XDB::execute('DELETE FROM  email_virtual_domains
+                                        WHERE  name = {?}', $domain);
                     $page->trigSuccess('suppression des alias mails');
 
                     $mmlist = new MMList(S::v('uid'), S::v('password'), $domain);
@@ -102,7 +105,7 @@ class XnetModule extends PLModule
                     }
                 }
 
-                XDB::query('DELETE FROM groupex.asso WHERE id={?}', $id);
+                XDB::query('DELETE FROM groups WHERE id={?}', $id);
                 $page->trigSuccess("Groupe $nom supprimé");
                 Get::kill('del');
             }
@@ -111,106 +114,324 @@ class XnetModule extends PLModule
             }
         }
 
-        if (Post::has('diminutif')) {
+        if (Post::has('diminutif') && Post::v('diminutif') != "") {
             S::assert_xsrf_token();
 
-            XDB::query('INSERT INTO groupex.asso (id,diminutif)
-                                 VALUES(NULL,{?})', Post::v('diminutif'));
-            pl_redirect('../'.Post::v('diminutif').'/edit');
+            $res = XDB::query('SELECT  COUNT(*)
+                                 FROM  groups
+                                WHERE  diminutif = {?}',
+                              Post::v('diminutif'));
+
+            if ($res->fetchOneCell() == 0) {
+                XDB::execute('INSERT INTO  groups (id, diminutif)
+                                   VALUES  (NULL, {?})',
+                             Post::v('diminutif'));
+                pl_redirect(Post::v('diminutif') . '/edit');
+            } else {
+                $page->trigError('Le diminutif demandé est déjà pris.');
+            }
         }
 
-        $res = XDB::query('SELECT nom,diminutif FROM groupex.asso ORDER by NOM');
+        $res = XDB::query('SELECT  nom, diminutif
+                             FROM  groups
+                         ORDER BY  nom');
         $page->assign('assos', $res->fetchAllAssoc());
     }
 
-    function handler_plan(&$page)
+    function handler_plan($page)
     {
         $page->changeTpl('xnet/plan.tpl');
 
         $page->setType('plan');
 
         $res = XDB::iterator(
-                'SELECT  dom.id, dom.nom as domnom, asso.diminutif, asso.nom
-                   FROM  groupex.dom
-             INNER JOIN  groupex.asso ON dom.id = asso.dom
-                  WHERE  FIND_IN_SET("GroupesX", dom.cat) AND FIND_IN_SET("GroupesX", asso.cat)
-               ORDER BY  dom.nom, asso.nom');
+                'SELECT  dom.id, dom.nom as domnom, groups.diminutif, groups.nom
+                   FROM  group_dom AS dom
+             INNER JOIN  groups ON dom.id = groups.dom
+                  WHERE  FIND_IN_SET("GroupesX", dom.cat) AND FIND_IN_SET("GroupesX", groups.cat)
+               ORDER BY  dom.nom, groups.nom');
         $groupesx = array();
         while ($tmp = $res->next()) { $groupesx[$tmp['id']][] = $tmp; }
         $page->assign('groupesx', $groupesx);
 
         $res = XDB::iterator(
-                'SELECT  dom.id, dom.nom as domnom, asso.diminutif, asso.nom
-                   FROM  groupex.dom
-             INNER JOIN  groupex.asso ON dom.id = asso.dom
-                  WHERE  FIND_IN_SET("Binets", dom.cat) AND FIND_IN_SET("Binets", asso.cat)
-               ORDER BY  dom.nom, asso.nom');
+                'SELECT  dom.id, dom.nom as domnom, groups.diminutif, groups.nom
+                   FROM  group_dom AS dom
+             INNER JOIN  groups ON dom.id = groups.dom
+                  WHERE  FIND_IN_SET("Binets", dom.cat) AND FIND_IN_SET("Binets", groups.cat)
+               ORDER BY  dom.nom, groups.nom');
         $binets = array();
         while ($tmp = $res->next()) { $binets[$tmp['id']][] = $tmp; }
         $page->assign('binets', $binets);
 
         $res = XDB::iterator(
-                'SELECT  asso.diminutif, asso.nom
-                   FROM  groupex.asso
+                'SELECT  diminutif, nom
+                   FROM  groups
                   WHERE  cat LIKE "%Promotions%"
                ORDER BY  diminutif');
         $page->assign('promos', $res);
 
         $res = XDB::iterator(
-                'SELECT  asso.diminutif, asso.nom
-                   FROM  groupex.asso
+                'SELECT  diminutif, nom
+                   FROM  groups
                   WHERE  FIND_IN_SET("Institutions", cat)
                ORDER BY  diminutif');
         $page->assign('inst', $res);
     }
 
-    function handler_groups2(&$page)
+    function handler_groups2($page)
     {
-        $this->handler_groups(&$page, Get::v('cat'), Get::v('dom'));
+        $this->handler_groups($page, Get::v('cat'), Get::v('dom'));
     }
 
-    function handler_groups(&$page, $cat = null, $dom = null)
+    function handler_groups($page, $cat = null, $dom = null)
     {
         if (!$cat) {
-            $this->handler_index(&$page);
+            $this->handler_index($page);
         }
 
-        $cat = strtolower($cat);
+        $cat = mb_strtolower($cat);
 
         $page->changeTpl('xnet/groupes.tpl');
         $page->assign('cat', $cat);
         $page->assign('dom', $dom);
 
-        $res  = XDB::query("SELECT id,nom FROM groupex.dom
-                             WHERE FIND_IN_SET({?}, cat)
-                          ORDER BY nom", $cat);
+        $res  = XDB::query("SELECT  id,nom
+                              FROM  group_dom
+                             WHERE  FIND_IN_SET({?}, cat)
+                          ORDER BY  nom", $cat);
         $doms = $res->fetchAllAssoc();
         $page->assign('doms', $doms);
 
         if (empty($doms)) {
-            $res = XDB::query("SELECT diminutif, nom, site FROM groupex.asso
-                                   WHERE FIND_IN_SET({?}, cat)
-                                ORDER BY nom", $cat);
+            $res = XDB::query("SELECT  diminutif, nom, site
+                                 FROM  groups
+                                WHERE  FIND_IN_SET({?}, cat)
+                                ORDER  BY nom", $cat);
             $page->assign('gps', $res->fetchAllAssoc());
         } elseif (!is_null($dom)) {
-            $res = XDB::query("SELECT diminutif, nom, site FROM groupex.asso
-                                WHERE FIND_IN_SET({?}, cat) AND dom={?}
-                             ORDER BY nom", $cat, $dom);
+            $res = XDB::query("SELECT  diminutif, nom, site
+                                 FROM  groups
+                                WHERE  FIND_IN_SET({?}, cat) AND dom={?}
+                             ORDER BY  nom", $cat, $dom);
             $page->assign('gps', $res->fetchAllAssoc());
         }
 
         $page->setType($cat);
     }
 
-    function handler_autologin(&$page)
+    function handler_autologin($page)
     {
         $allkeys = func_get_args();
         unset($allkeys[0]);
         $url = join('/',$allkeys);
-        header("Content-type: text/javascript; charset=utf-8");
+        pl_content_headers("text/javascript");
         echo '$.ajax({ url: "'.$url.'?forceXml=1", dataType: "xml", success: function(xml) { $("body",xml).insertBefore("body"); $("body:eq(1)").remove(); }});';
         exit;
     }
+
+    function handler_login_ext($page)
+    {
+        if (!S::logged()) {
+            $page->changeTpl('xnet/login.tpl');
+        } else {
+            pl_redirect('');
+        }
+    }
+
+    function handler_register_ext($page, $hash = null)
+    {
+        XDB::execute('DELETE FROM  register_pending_xnet
+                            WHERE  DATE_SUB(NOW(), INTERVAL 1 MONTH) > date');
+        $res = XDB::fetchOneAssoc('SELECT  uid, hruid
+                                     FROM  register_pending_xnet
+                                    WHERE  hash = {?}',
+                                  $hash);
+
+        if (is_null($hash) || is_null($res)) {
+            $page->trigErrorRedirect('Cette adresse n\'existe pas ou n\'existe plus sur le serveur.', '');
+        }
+
+        if (Post::has('pwhash') && Post::t('pwhash')) {
+            XDB::query('UPDATE  accounts
+                           SET  password = {?}, state = \'active\'
+                         WHERE  uid = {?} AND state = \'pending\' AND type = \'xnet\'',
+                       Post::t('pwhash'), $res['uid']);
+            XDB::query('DELETE FROM  register_pending_xnet
+                              WHERE  uid = {?}',
+                       $res['uid']);
+
+            S::logger($res['uid'])->log('passwd', '');
+
+            // Try to start a session (so the user don't have to log in); we will use
+            // the password available in Post:: to authenticate the user.
+            Post::kill('wait');
+            Platal::session()->startAvailableAuth();
+
+            $page->changeTpl('xnet/register.success.tpl');
+            $page->assign('hruid', $res['hruid']);
+        } else {
+            $page->changeTpl('platal/password.tpl');
+            $page->assign('xnet', true);
+            $page->assign('hruid', $res['hruid']);
+            $page->assign('do_auth', true);
+        }
+    }
+
+    function handler_recovery_ext($page)
+    {
+        $page->changeTpl('xnet/recovery.tpl');
+
+        if (!Post::has('login')) {
+            return;
+        }
+
+        $user = User::getSilent(Post::t('login'));
+        if (is_null($user)) {
+            $page->trigError('Le compte n\'existe pas.');
+            return;
+        }
+        if ($user->state != 'active') {
+            $page->trigError('Ton compte n\'est pas activé.');
+            return;
+        }
+
+        $page->assign('ok', true);
+
+        $hash = rand_url_id();
+        XDB::execute('INSERT INTO  account_xnet_lost_passwords (uid, date, hash)
+                           VALUES  ({?}, NOW(), {?})',
+                     $user->id(), $hash);
+
+        $mymail = new PlMailer();
+        $mymail->setFrom('"Gestion des mots de passe" <support+password@' . Platal::globals()->mail->domain . '>');
+        $mymail->addTo($user);
+        $mymail->setSubject("Votre certificat d'authentification");
+        $mymail->setTxtBody("Visitez la page suivante qui expire dans six heures :
+http://polytechnique.net/tmpPWD/$hash
+
+Si en cliquant dessus vous n'y arrivez pas, copiez intégralement l'adresse dans la barre de votre navigateur. Si vous n'avez pas utilisé ce lien dans six heures, vous pouvez tout simplement recommencer cette procédure.
+
+--
+Polytechnique.org
+\"Le portail des élèves & anciens élèves de l'École polytechnique\"
+
+Email envoyé à " . Post::t('login'));
+        $mymail->send();
+
+        S::logger($user->id())->log('recovery', $user->bestEmail());
+    }
+
+    function handler_tmpPWD_ext($page, $hash = null)
+    {
+        global $globals;
+        XDB::execute('DELETE FROM  account_xnet_lost_passwords
+                            WHERE  DATE_SUB(NOW(), INTERVAL 380 MINUTE) > date');
+
+        $uid = XDB::fetchOneCell('SELECT  uid
+                                    FROM  account_xnet_lost_passwords
+                                   WHERE  hash = {?}',
+                                 $hash);
+        if (is_null($uid)) {
+            $page->trigErrorRedirect("Cette adresse n'existe pas ou n'existe plus sur le serveur.", '');
+        }
+
+        $hruid = XDB::fetchOneCell('SELECT  hruid
+                                      FROM  accounts
+                                     WHERE  uid = {?}',
+                                   $uid);
+
+        if (Post::has('pwhash') && Post::t('pwhash')) {
+            $password = Post::t('pwhash');
+            XDB::query('UPDATE  accounts
+                           SET  password = {?}
+                         WHERE  uid = {?} AND state = \'active\'',
+                       $password, $uid);
+            XDB::query('DELETE FROM  account_xnet_lost_passwords
+                              WHERE  hash = {?}',
+                       $hash);
+
+            S::logger($uid)->log('passwd', '');
+
+            // Try to start a session (so the user don't have to log in); we will use
+            // the password available in Post:: to authenticate the user.
+            Post::kill('wait');
+            Platal::session()->startAvailableAuth();
+
+            $page->changeTpl('xnet/register.success.tpl');
+            $page->assign('hruid', $hruid);
+        } else {
+            $page->changeTpl('platal/password.tpl');
+            $page->assign('xnet_reset', true);
+            $page->assign('hruid', $hruid);
+            $page->assign('do_auth', true);
+        }
+    }
+
+
+
+    function handler_edit($page)
+    {
+        global $globals;
+
+        $user = S::user();
+        if (empty($user)) {
+            return PL_NOT_FOUND;
+        }
+        if ($user->type != 'xnet') {
+            pl_redirect('index');
+        }
+
+        $page->changeTpl('xnet/edit.tpl');
+        if (Post::has('change')) {
+            S::assert_xsrf_token();
+
+            // Convert user status to X
+            if (!Post::blank('login_X')) {
+                $forlife = $this->changeLogin($page, $user, Post::t('login_X'));
+                if ($forlife) {
+                    pl_redirect('index');
+                }
+            }
+
+            // Update user info
+            XDB::query('UPDATE  accounts
+                           SET  full_name = {?}, directory_name = {?}, display_name = {?},
+                                sex = {?}, email = {?}
+                         WHERE  uid = {?}',
+                       Post::t('full_name'), Post::t('directory_name'), Post::t('display_name'),
+                       (Post::t('sex') == 'male') ? 'male' : 'female', Post::t('email'), $user->id());
+            if (XDB::affectedRows()) {
+                $user = User::getWithUID($user->id());
+                S::set('user', $user);
+                $page->trigSuccess('Données mises à jour.');
+            }
+        }
+
+        $page->addJsLink('password.js');
+        $page->assign('user', $user);
+    }
+
+    function handler_password ($page)
+    {
+        if (Post::has('pwhash') && Post::t('pwhash'))  {
+            S::assert_xsrf_token();
+
+            S::set('password', $password = Post::t('pwhash'));
+            XDB::execute('UPDATE  accounts
+                             SET  password = {?}
+                           WHERE  uid={?}', $password,
+                         S::i('uid'));
+            S::logger()->log('passwd');
+            Platal::session()->setAccessCookie(true);
+            $page->changeTpl('platal/password.success.tpl');
+            $page->run();
+        }
+
+        $page->changeTpl('platal/password.tpl');
+        $page->assign('xnet_reset', true);
+        $page->assign('do_auth', false);
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: