Merge commit 'origin/fusionax' into account
authorVincent Zanotti <vincent.zanotti@m4x.org>
Fri, 10 Apr 2009 16:48:39 +0000 (18:48 +0200)
committerVincent Zanotti <vincent.zanotti@m4x.org>
Fri, 10 Apr 2009 16:48:39 +0000 (18:48 +0200)
Conflicts:
modules/admin.php

Signed-off-by: Vincent Zanotti <vincent.zanotti@m4x.org>
1  2 
Makefile
include/wiki/farmconfig.php
modules/admin.php
modules/profile.php
modules/profile/jobs.inc.php
modules/profile/mentor.inc.php
templates/xnetgrp/inscrire.tpl

diff --combined Makefile
+++ b/Makefile
@@@ -28,9 -28,6 +28,9 @@@ all: buil
  
  build: core conf banana wiki openid medals jquery
  
 +check:
 +      @!(find . -name '*.php' -exec php -l {} ";" | grep -v 'No syntax errors detected')
 +
  q:
        @echo -e "Code statistics\n"
        @sloccount $(filter-out wiki/ spool/, $(wildcard */)) 2> /dev/null | egrep '^[a-z]*:'
@@@ -46,7 -43,7 +46,7 @@@
  ##
  
  core:
-       [ -d core ] || ( git submodule init && git submodule update )
+       [ -d core/.git ] || ( git submodule init && git submodule update )
        make -C core all
  
  ##
@@@ -164,10 -161,7 +164,10 @@@ $(MEDAL_THUMBNAILS): $(subst /medals/th
  JQUERY_PLUGINS=color
  JQUERY_PLUGINS_PATHES=$(addprefix htdocs/javascript/jquery.,$(addsuffix .js,$(JQUERY_PLUGINS)))
  
 -jquery: htdocs/javascript/jquery.js htdocs/javascript/jquery.autocomplete.js $(JQUERY_PLUGINS_PATHES)
 +JQUERY_UI=core tabs
 +JQUERY_UI_PATHES=$(addprefix htdocs/javascript/ui.,$(addsuffix .js,$(JQUERY_UI)))
 +
 +jquery: htdocs/javascript/jquery.js htdocs/javascript/jquery.autocomplete.js $(JQUERY_PLUGINS_PATHES) $(JQUERY_UI_PATHES)
  
  htdocs/javascript/jquery.js: DOWNLOAD_SRC = http://jquery.com/src/jquery-latest.min.js
  htdocs/javascript/jquery.js:
@@@ -181,11 -175,7 +181,11 @@@ $(JQUERY_PLUGINS_PATHES): DOWNLOAD_SRC 
  $(JQUERY_PLUGINS_PATHES):
        @$(download)
  
 +$(JQUERY_UI_PATHES): DOWNLOAD_SRC = http://ui.jquery.com/latest/ui/$(@F)
 +$(JQUERY_UI_PATHES):
 +      @$(download)
 +
  ################################################################################
  
 -.PHONY: build dist clean core wiki build-wiki banana htdocs/images/banana htdocs/css/banana.css include/banana/banana.inc.php http*
 +.PHONY: build dist clean core wiki build-wiki banana htdocs/images/banana htdocs/css/banana.css include/banana/banana.inc.php http* check
  
@@@ -6,6 -6,7 +6,7 @@@ $EnableUpload     = 1
  $UploadMaxSize    = 500000;
  $LinkWikiWords    = 0;   # disable WikiWord links
  $EnableIMSCaching = 1;   # allow browser caching
+ $EnablePageListProtect = 0; # We use our own permission system.
  
  $ScriptUrl        = '.';          #\
  $UploadUrlFmt     = './uploads';  # } works thanks to the <base /> in skin
@@@ -96,8 -97,16 +97,8 @@@ function doBicol($column=false
  function doPlatalLink($link, $text)
  {
      if (strlen(trim($text)) == 0) {
 -        $res = XDB::query("SELECT u.nom, u.prenom, u.promo, q.profile_nick AS surnom
 -                             FROM auth_user_md5   AS u
 -                       INNER JOIN auth_user_quick AS q USING(user_id)
 -                       INNER JOIN aliases         AS a ON u.user_id = a.id
 -                            WHERE a.alias = {?}", $link);
 -        $row = $res->fetchOneAssoc();
 -        $text = $row['prenom'] . ' ' . $row['nom'] . ' X' . $row['promo'];
 -        if ($row['surnom']) {
 -            $text .= ' (alias ' . $row['surnom'] . ')';
 -        }
 +        $user = User::get($link);
 +        $text = $user->fullName();
      }
      return '<a href="profile/' . $link . '" class="popup2">' . $text . '</a>';
  }
diff --combined modules/admin.php
@@@ -25,7 -25,6 +25,7 @@@ class AdminModule extends PLModul
      {
          return array(
              'phpinfo'                      => $this->make_hook('phpinfo', AUTH_MDP, 'admin'),
 +            'get_rights'                   => $this->make_hook('get_rights', AUTH_MDP, 'admin'),
              'admin'                        => $this->make_hook('default', AUTH_MDP, 'admin'),
              'admin/ax-xorg'                => $this->make_hook('ax_xorg', AUTH_MDP, 'admin'),
              'admin/dead-but-active'        => $this->make_hook('dead_but_active', AUTH_MDP, 'admin'),
@@@ -49,7 -48,7 +49,8 @@@
              'admin/ipwatch'                => $this->make_hook('ipwatch', AUTH_MDP, 'admin'),
              'admin/icons'                  => $this->make_hook('icons', AUTH_MDP, 'admin'),
              'admin/accounts'               => $this->make_hook('accounts', AUTH_MDP, 'admin'),
 +            'admin/account/types'          => $this->make_hook('account_types', AUTH_MDP, 'admin'),
+             'admin/jobs'                   => $this->make_hook('jobs', AUTH_MDP, 'admin'),
          );
      }
  
          exit;
      }
  
 +    function handler_get_rights(&$page, $level)
 +    {
 +        if (S::suid()) {
 +            $page->kill('Déjà en SUID');
 +        }
 +        $user =& S::user();
 +        Platal::session()->startSUID($user, $level);
 +
 +        pl_redirect('/');
 +    }
 +
      function handler_default(&$page)
      {
          $page->changeTpl('admin/index.tpl');
      {
          global $globals;
          $page->changeTpl('admin/utilisateurs.tpl');
 -        $page->setTitle('Administration - Edit/Su/Log');
 -        require_once("emails.inc.php");
 +        $page->setTitle('Administration - Compte');
  
 -        if (S::has('suid')) {
 +        if (S::suid()) {
              $page->kill("Déjà en SUID !!!");
          }
  
          // Loads the user identity using the environment.
 -        if ($login) {
 -            $user = User::get($login);
 -        } else if (Env::has('user_id')) {
 -            $user = User::get(Env::i('user_id'));
 -        } else if (Env::has('login')) {
 -            $user = User::get(Env::v('login'));
 -        }
 +        $user = User::get($login);
 +        $login = $user->login();
 +        $registered = ($user->state != 'pending');
  
 -        if ($user) {
 -            $login = $user->login();
 -            $registered = ($user->forlifeEmail() != null);
 -        } else {
 -            return;
 +        // Form processing
 +        if (!empty($_POST)) {
 +            S::assert_xsrf_token();
 +            if (Post::has('uid') && Post::i('uid') != $user->id()) {
 +                $page->kill('Une erreur s\'est produite');
 +            }
          }
  
          // Handles specific requests (AX sync, su, ...).
 -        if(Env::has('logs_button') && $registered) {
 +        if(Post::has('logs_account')) {
              pl_redirect("admin/logger?loguser=$login&year=".date('Y')."&month=".date('m'));
          }
  
 -        if (Env::has('ax_button') && $registered) {
 -            pl_redirect("admin/synchro_ax/" . $user->login());
 -        }
 -
 -        if(Env::has('suid_button') && $registered) {
 -            S::logger()->log("suid_start", "login on " . $user->login());
 -            if (!Platal::session()->startSUID($user->id())) {
 -                $page->trigError('Impossible d\'effectuer un SUID sur ' . $user->id());
 +        if(Post::has('su_button') && $registered) {
 +            if (!Platal::session()->startSUID($user)) {
 +                $page->trigError('Impossible d\'effectuer un SUID sur ' . $user->login());
              } else {
                  pl_redirect("");
              }
          }
  
 -        // Fetches user data.
 -        $userinfo_query = "SELECT  *, FIND_IN_SET('watch', flags) AS watch, FIND_IN_SET('femme', flags) AS sexe,
 -                                   (year(naissance) > promo - 15 or year(naissance) < promo - 25) AS naiss_err
 -                             FROM  auth_user_md5
 -                            WHERE  user_id = {?}";
 -        $mr = XDB::query($userinfo_query, $user->id())->fetchOneAssoc();
 -        $redirect = ($registered ? new Redirect($user) : null);
 -
 -        // Processes admin requests, if any.
 -        foreach($_POST as $key => $val) {
 -            S::assert_xsrf_token();
 -
 -            switch ($key) {
 -                // Email redirection actions.
 -                case "add_fwd":
 -                    $email = trim(Env::v('email'));
 -                    if (!isvalid_email_redirection($email)) {
 -                        $page->trigError("Email non valide: $email");
 -                    } else {
 -                        $redirect->add_email($email);
 -                        $page->trigSuccess("Ajout de $email effectué");
 -                    }
 -                    break;
 -
 -                case "del_fwd":
 -                    if (!empty($val)) {
 -                        $redirect->delete_email($val);
 -                    }
 -                    break;
 -
 -                case "activate_fwd":
 -                    if (!empty($val)) {
 -                        $redirect->modify_one_email($val, true);
 -                    }
 -                    break;
 -                case "deactivate_fwd":
 -                    if (!empty($val)) {
 -                        $redirect->modify_one_email($val, false);
 -                    }
 -                    break;
 -                case "disable_fwd":
 -                    $redirect->disable();
 -                    break;
 -                case "enable_fwd":
 -                    $redirect->enable();
 -                    break;
 -                case "clean_fwd":
 -                    if (!empty($val)) {
 -                        $redirect->clean_errors($val);
 -                    }
 -                    break;
 -
 -                // Alias actions.
 -                case "add_alias":
 -                    global $globals;
 -
 -                    // Splits new alias in user and fqdn.
 -                    $alias = trim(Env::v('email'));
 -                    if (strpos($alias, '@') !== false) {
 -                        list($alias, $domain) = explode('@', $alias);
 -                    } else {
 -                        $domain = $globals->mail->domain;
 -                    }
 -
 -                    // Checks for alias' user validity.
 -                    if (!preg_match('/[-a-z0-9\.]+/s', $alias)) {
 -                        $page->trigError("'$alias' n'est pas un alias valide");
 -                    }
 -
 -                    // Eventually adds the alias to the right domain.
 -                    if ($domain == $globals->mail->alias_dom || $domain == $globals->mail->alias_dom2) {
 -                        $req = new AliasReq($user, $alias, 'Admin request', false);
 -                        if ($req->commit()) {
 -                            $page->trigSuccess("Nouvel alias '$alias@$domain' attribué");
 -                        } else {
 -                            $page->trigError("Impossible d'ajouter l'alias '$alias@$domain', il est probablement déjà attribué");
 -                        }
 -                    } elseif ($domain == $globals->mail->domain || $domain == $globals->mail->domain2) {
 -                        $res = XDB::execute("INSERT INTO aliases (id,alias,type) VALUES ({?}, {?}, 'alias')",
 -                                            $user->id(), $alias);
 -                        if ($res) {
 -                            $page->trigSuccess("Nouvel alias '$alias' ajouté");
 -                        } else {
 -                            $page->trigError("Impossible d'ajouter l'alias '$alias', il est probablement déjà attribué");
 -                        }
 -                    } else {
 -                        $page->trigError("Le domaine '$domain' n'est pas valide");
 -                    }
 -                    break;
 -
 -                case "del_alias":
 -                    if (!empty($val)) {
 -                        XDB::execute("DELETE FROM  aliases
 -                                            WHERE  id = {?} AND alias = {?} AND
 -                                                   type NOT IN ('a_vie', 'homonyme')",
 -                                     $user->id(), $val);
 -                        XDB::execute("UPDATE  emails
 -                                         SET  rewrite = ''
 -                                       WHERE  uid = {?} AND rewrite LIKE CONCAT({?}, '@%')",
 -                                     $user->id(), $val);
 -                        fix_bestalias($user);
 -                        $page->trigSuccess("L'alias '$val' a été supprimé");
 -                    }
 -                    break;
 -
 -                case "best":
 -                    XDB::execute("UPDATE  aliases
 -                                     SET  flags = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', flags, ','), ',bestalias,', ','))
 -                                   WHERE  id = {?}", $user->id());
 -                    XDB::execute("UPDATE  aliases
 -                                     SET  flags = CONCAT_WS(',', IF(flags = '', NULL, flags), 'bestalias')
 -                                   WHERE  id = {?} AND alias = {?}", $user->id(), $val);
 -
 -                    // 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);
 -                    break;
 -
 -                // Profile edition.
 -                case "u_edit":
 -                    // Loads new values from environment.
 -                    require_once('secure_hash.inc.php');
 -                    $pass_encrypted = Env::v('newpass_clair') != "********" ? hash_encrypt(Env::v('newpass_clair')) : Env::v('passw');
 -                    $naiss    = Env::v('naissanceN');
 -                    $deces    = Env::v('decesN');
 -                    $perms    = Env::v('permsN');
 -                    $prenom    = Env::v('prenomN');
 -                    $nom      = Env::v('nomN');
 -                    $nomusage = Env::v('nomusageN');
 -                    $promo    = Env::i('promoN');
 -                    $sexe     = Env::v('sexeN');
 -                    $comm     = trim(Env::v('commentN'));
 -                    $watch    = Env::v('watchN');
 -
 -                    $flags    = ($sexe ? 'femme' : '');
 -                    if ($watch) {
 -                        $flags .= ($flags ? ',watch' : 'watch');
 -                    }
 -                    if ($watch && !$comm) {
 -                        $page->trigError("Il est nécessaire de mettre un commentaire pour surveiller un compte");
 -                        break;
 -                    }
 -
 -                    // Fetches fields to watch for changes.
 -                    $watch_query = "SELECT  naissance, deces, password, perms, nom_usage,
 -                                           prenom, nom, flags, promo, comment
 -                                      FROM  auth_user_md5
 -                                     WHERE user_id = {?}";
 -                    $old_fields = XDB::query($watch_query, $user->id())->fetchOneAssoc();
 -
 -                    // If user was newly banned, we need to ensure her php session
 -                    // is killed. This hack is ugly (and largely overkill); it should
 -                    // however suits our needs.
 -                    if ($perms == 'disabled' && $old_fields['perms'] != 'disabled') {
 -                        kill_sessions();
 -
 -                        // Also serve a reminder to the admin: disabling an account
 -                        // does not deactivate email forwarding.
 -                        $page->trigWarning("N'oubliez pas, le cas échéant, de désactiver les redirections et le compte GoogleApps de l'utilisateur.");
 -                    }
 -
 -                    // Updates the user profile with the new values.
 -                    $res = XDB::execute("UPDATE  auth_user_md5
 -                                            SET  naissance = {?}, deces = {?}, password = {?},
 -                                                 perms = {?}, prenom = {?}, nom = {?}, nom_usage = {?},
 -                                                 flags = {?}, promo = {?}, comment = {?}
 -                                          WHERE  user_id = {?}",
 -                                        $naiss, $deces, $pass_encrypted,
 -                                        $perms, $prenom, $nom, $nomusage,
 -                                        $flags, $promo, $comm, $user->id());
 -                    if ($res) {
 -                        require_once("user.func.inc.php");
 -                        user_reindex($user->id());
 -                        $new_fields = XDB::query($watch_query, $user->id())->fetchOneAssoc();
 -
 -                        $mailer = new PlMailer("admin/useredit.mail.tpl");
 -                        $mailer->assign("admin", S::user()->login());
 -                        $mailer->assign("user", $user->login());
 -                        $mailer->assign('old', $old_fields);
 -                        $mailer->assign('new', $new_fields);
 -                        $mailer->send();
 -
 -                        $globals->updateNbIns();
 -                        $page->trigSuccess("Update was successful.");
 -                    } else {
 -                        $page->trigError("Update failed, please double check your values.");
 -                    }
 -
 -                    // Checks for changes, and updates other tables of plat/al.
 -                    if (Env::v('nomusageN') != $mr['nom_usage']) {
 -                        set_new_usage($user->id(), Env::v('nomusageN'), make_username(Env::v('prenomN'), Env::v('nomusageN')));
 -                    }
 -                    if (Env::v('decesN') != $mr['deces']) {
 -                        require_once 'notifs.inc.php';
 -                        register_watch_op($user->id(), WATCH_DEATH, $mr['deces']);
 -                        user_clear_all_subs($user->id(), false);
 -                    }
 +        // Account Form {{{
 +        $to_update = array();
 +        if (Post::has('disable_weak_access')) {
 +            $to_update['weak_password'] = null;
 +        } else if (Post::has('update_account')) {
 +            if (Post::s('full_name') != $user->fullName()) {
 +                // XXX: Update profile if a profile is associated
 +                $to_update['full_name'] = Post::s('full_name');
 +            }
 +            if (Post::s('display_name') != $user->displayName()) {
 +                // XXX: Update profile if a profile is associated
 +                $to_update['display_name'] = Post::s('display_name');
 +            }
 +            if (Post::s('sex') != ($user->isFemale() ? 'female' : 'male')) {
 +                $to_update['sex'] = Post::s('sex');
 +            }
 +            if (!Post::blank('hashpass')) {
 +                $to_update['password'] = Post::s('hashpass');
 +            }
 +            if (!Post::blank('weak_password')) {
 +                $to_update['weak_password'] = Post::s('weak_password');
 +            }
 +            if (Post::i('token_access', 0) != ($user->token_access ? 1 : 0)) {
 +                $to_update['token'] = Post::i('token_access') ? rand_url_id(16) : null;
 +            }
 +            if (Post::i('skin', 0) != $user->skin) {
 +                $to_update['skin'] = Post::i('skin', 0);
 +                if ($to_update['skin'] == 0) {
 +                    $to_update['skin'] = null;
 +                }
 +            }
 +            if (Post::s('state') != $user->state) {
 +                $to_update['state'] = Post::s('state');
 +            }
 +            if (Post::i('is_admin', 0) != ($user->is_admin ? 1 : 0)) {
 +                $to_update['is_admin'] = Post::b('is_admin');
 +            }
 +            if (Post::s('type') != $user->type) {
 +                $to_update['type'] = Post::s('type');
 +            }
 +            if (Post::i('watch', 0) != ($user->watch ? 1 : 0)) {
 +                $to_update['flags'] = new PlFlagset();
 +                $to_update['flags']->addFlag('watch', Post::i('watch'));
 +            }
 +            if (Post::t('comment') != $user->comment) {
 +                $to_update['comment'] = Post::blank('comment') ? null : Post::t('comment');
 +            }
 +        }
 +        if (!empty($to_update)) {
 +            $set = array();
 +            foreach ($to_update as $k => $value) {
 +                $set[] = XDB::format($k . ' = {?}', $value);
 +            }
 +            XDB::execute('UPDATE  accounts
 +                             SET  ' . implode(', ', $set) . ' 
 +                           WHERE  uid = ' . XDB::format('{?}', $user->id()));
 +            $page->trigSuccess('Données du compte mise à jour avec succès');
 +            $user = User::getWithUID($user->id());
 +        }
 +        // }}}
 +
 +        // Profile form {{{
 +        if (Post::has('add_profile') || Post::has('del_profile') || Post::has('owner')) {
 +            if (Post::i('del_profile', 0) != 0) {
 +                XDB::execute('DELETE FROM  account_profiles
 +                                    WHERE  uid = {?} AND pid = {?}',
 +                             $user->id(), Post::i('del_profile'));
 +            } else if (!Post::blank('new_profile')) {
 +                $profile = Profile::get(Post::t('new_profile'));
 +                if (!$profile) {
 +                    $page->trigError('Le profil ' . Post::t('new_profile') . ' n\'existe pas');
 +                } else {
 +                    XDB::execute('INSERT IGNORE INTO  account_profiles (uid, pid)
 +                                              VALUES  ({?}, {?})',
 +                                 $user->id(), $profile->id());
 +                }
 +            }
 +            XDB::execute('UPDATE  account_profiles
 +                             SET  perms = IF(pid = {?}, CONCAT(perms, \',owner\'), REPLACE(perms, \'owner\', \'\'))
 +                           WHERE  uid = {?}',
 +                         Post::i('owner'), $user->id());
 +        }
 +        // }}}
  
 -                    // Eventually updates the Google Apps account.
 -                    if ($globals->mailstorage->googleapps_domain) {
 -                        // If the user did choose to use synchronized passwords,
 -                        // and the password was changed, updates the Google Apps
 -                        // password as well.
 -                        if (Env::v('newpass_clair') != "********") {
 -                            require_once 'googleapps.inc.php';
 -                            $account = new GoogleAppsAccount($user);
 -                            if ($account->active() && $account->sync_password) {
 -                                $account->set_password($pass_encrypted);
 -                            }
 -                        }
 -                    }
 +        // Email forwards form {{{
 +        require_once("emails.inc.php");
 +        $redirect = ($registered ? new Redirect($user) : null);
 +        if (Post::has('add_fwd')) {
 +            $email = Post::t('email');
 +            if (!isvalid_email_redirection($email)) {
 +                $page->trigError("Email non valide: $email");
 +            } else {
 +                $redirect->add_email($email);
 +                $page->trigSuccess("Ajout de $email effectué");
 +            }
 +        } else if (!Post::blank('del_fwd')) {
 +            $redirect->delete_email(Post::t('del_fwd'));
 +        } else if (!Post::blank('activate_fwd')) {
 +            $redirect->modify_one_email(Post::t('activate_fwd', true));
 +        } else if (!Post::blank('deactivate_fwd')) {
 +            $redirect->modify_one_email(Post::t('deactivate_fwd', false));
 +        } else if (Post::has('disable_fwd')) {
 +            $redirect->disable();
 +        } else if (Post::has('enable_fwd')) {
 +            $redirect->enable();
 +        } else if (!Post::blank('clean_fwd')) {
 +            $redirect->clean_errors(Post::t('clean_fwd'));
 +        }
 +        // }}}
 +
 +        // Email alias form {{{
 +        if (Post::has('add_alias')) {
 +            // Splits new alias in user and fqdn.
 +            $alias = Env::t('email');
 +            if (strpos($alias, '@') !== false) {
 +                list($alias, $domain) = explode('@', $alias);
 +            } else {
 +                $domain = $globals->mail->domain;
 +            }
  
 +            // Checks for alias' user validity.
 +            if (!preg_match('/[-a-z0-9\.]+/s', $alias)) {
 +                $page->trigError("'$alias' n'est pas un alias valide");
 +            }
  
 -                    // Reloads the user profile, to ensure the latest version will
 -                    // be served to the administrator.
 -                    $mr = XDB::query($userinfo_query, $user->id())->fetchOneAssoc();
 +            // Eventually adds the alias to the right domain.
 +            if ($domain == $globals->mail->alias_dom || $domain == $globals->mail->alias_dom2) {
 +                $req = new AliasReq($user, $alias, 'Admin request', false);
 +                if ($req->commit()) {
 +                    $page->trigSuccess("Nouvel alias '$alias@$domain' attribué");
 +                } else {
 +                    $page->trigError("Impossible d'ajouter l'alias '$alias@$domain', il est probablement déjà attribué");
 +                }
 +            } elseif ($domain == $globals->mail->domain || $domain == $globals->mail->domain2) {
 +                $res = XDB::execute("INSERT INTO  aliases (id, alias, type)
 +                                          VALUES  ({?}, {?}, 'alias')",
 +                                    $user->id(), $alias);
 +                $page->trigSuccess("Nouvel alias '$alias' ajouté");
 +            } else {
 +                $page->trigError("Le domaine '$domain' n'est pas valide");
 +            }
 +        } else if (!Post::blank('del_alias')) {
 +            XDB::execute("DELETE FROM  aliases
 +                                WHERE  id = {?} AND alias = {?} AND
 +                                       type NOT IN ('a_vie', 'homonyme')",
 +                         $user->id(), $val);
 +            XDB::execute("UPDATE  emails
 +                             SET  rewrite = ''
 +                           WHERE  uid = {?} AND rewrite LIKE CONCAT({?}, '@%')",
 +                         $user->id(), $val);
 +            fix_bestalias($user);
 +            $page->trigSuccess("L'alias '$val' a été supprimé");
 +        } else if (!Post::blank('best')) {
 +            XDB::execute("UPDATE  aliases
 +                             SET  flags = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', flags, ','), ',bestalias,', ','))
 +                           WHERE  id = {?}", $user->id());
 +            XDB::execute("UPDATE  aliases
 +                             SET  flags = CONCAT_WS(',', IF(flags = '', NULL, flags), 'bestalias')
 +                           WHERE  id = {?} AND alias = {?}", $user->id(), $val);
 +            // 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);
 +        }
 +        // }}}
 +
 +        // Forum form {{{
 +        if (Post::has('b_edit')) {
 +            XDB::execute("DELETE FROM  forum_innd
 +                                WHERE  uid = {?}", $user->id());
 +            if (Env::v('write_perm') != "" || Env::v('read_perm') != ""  || Env::v('commentaire') != "" ) {
 +                XDB::execute("INSERT INTO  forum_innd
 +                                      SET  ipmin = '0', ipmax = '4294967295',
 +                                           write_perm = {?}, read_perm = {?},
 +                                           comment = {?}, priority = '200', uid = {?}",
 +                             Env::v('write_perm'), Env::v('read_perm'), Env::v('comment'), $user->id());
 +            }
 +        }
 +        // }}}
  
 -                    break;
  
 -                // User re-registration.
 -                case "u_kill":
 -                    require_once('user.func.inc.php');
 -                    user_clear_all_subs($user->id());
 -                    $globals->updateNbIns();
 -                    $page->trigSuccess("'" . $user->id() . "' a été désinscrit !");
 -
 -                    $mailer = new PlMailer("admin/useredit.mail.tpl");
 -                    $mailer->assign("admin", S::user()->login());
 -                    $mailer->assign("user", $user->login());
 -                    $mailer->assign("deletion", true);
 -                    $mailer->send();
 -                    break;
 +        $page->addJsLink('ui.core.js');
 +        $page->addJsLink('ui.tabs.js');
  
 -                // Forum ban update.
 -                case "b_edit":
 -                    XDB::execute("DELETE FROM forums.innd WHERE uid = {?}", $user->id());
 -                    if (Env::v('write_perm') != "" || Env::v('read_perm') != ""  || Env::v('commentaire') != "" ) {
 -                        XDB::execute("INSERT INTO  forums.innd
 -                                              SET  ipmin = '0', ipmax = '4294967295',
 -                                                   write_perm = {?}, read_perm = {?},
 -                                                   comment = {?}, priority = '200', uid = {?}",
 -                                     Env::v('write_perm'), Env::v('read_perm'), Env::v('comment'), $user->id());
 -                    }
 -                    break;
 -            }
 -        }
  
          // Displays last login and last host information.
          $res = XDB::query("SELECT  start, host
          $page->assign('host', $host);
  
          // Display active aliases.
 -        $page->assign('virtuals', XDB::iterator(
 -                "SELECT  alias
 -                   FROM  virtual
 -             INNER JOIN  virtual_redirect USING (vid)
 -                  WHERE  type = 'user' AND (redirect = {?} OR redirect = {?})",
 -                $user->forlifeEmail(),
 -                // TODO: remove this über-ugly hack. The issue is that you need
 -                // to remove all @m4x.org addresses in virtual_redirect first.
 -                $user->login() . '@' . $globals->mail->domain2));
 -
 -        $page->assign('aliases', XDB::iterator(
 -                "SELECT  alias, type='a_vie' AS for_life,FIND_IN_SET('bestalias',flags) AS best,expire
 -                   FROM  aliases
 -                  WHERE  id = {?} AND type != 'homonyme'
 -               ORDER BY  type != 'a_vie'", $user->id()));
 +        $page->assign('virtuals', $user->emailAliases());
 +        $page->assign('aliases', XDB::iterator("SELECT  alias, type='a_vie' AS for_life,
 +                                                        FIND_IN_SET('bestalias',flags) AS best, expire
 +                                                  FROM  aliases
 +                                                 WHERE  id = {?} AND type != 'homonyme'
 +                                              ORDER BY  type != 'a_vie'", $user->id()));
 +        $page->assign('account_types', XDB::iterator('SELECT * FROM account_types ORDER BY type'));
 +        $page->assign('skins', XDB::iterator('SELECT id, name FROM skins ORDER BY name'));
 +        $page->assign('profiles', XDB::iterator('SELECT  p.pid, p.hrpid, FIND_IN_SET(\'owner\', ap.perms) AS owner
 +                                                   FROM  account_profiles AS ap
 +                                             INNER JOIN  profiles AS p ON (ap.pid = p.pid)
 +                                                  WHERE  ap.uid = {?}', $user->id()));
  
          // Displays email redirection and the general profile.
          if ($registered && $redirect) {
  
          // Displays forum bans.
          $res = XDB::query("SELECT  write_perm, read_perm, comment
 -                             FROM  forums.innd
 +                             FROM  forum_innd
                              WHERE  uid = {?}", $user->id());
          $bans = $res->fetchOneAssoc();
          $page->assign('bans', $bans);
      {
          $page->changeTpl('admin/homonymes.tpl');
          $page->setTitle('Administration - Homonymes');
 -        require_once("homonymes.inc.php");
 +        $this->load("homonyms.inc.php");
  
          if ($target) {
 -            if (! list($prenom,$nom,$forlife,$loginbis) = select_if_homonyme($target)) {
 -                $target=0;
 +            $user = User::getSilent($target);
 +            if (!$user || !($loginbis = select_if_homonyme($user))) {
 +                $target = 0;
              } else {
 -                $page->assign('nom',$nom);
 -                $page->assign('prenom',$prenom);
 -                $page->assign('forlife',$forlife);
 +                $page->assign('user', $user);
                  $page->assign('loginbis',$loginbis);
              }
          }
                  case 'mail':
                      S::assert_xsrf_token();
  
 -                    send_warning_homonyme($prenom, $nom, $forlife, $loginbis);
 -                    switch_bestalias($target, $loginbis);
 +                    send_warning_homonyme($user, $loginbis);
 +                    switch_bestalias($user, $loginbis);
                      $op = 'list';
 -                    $page->trigSuccess('Email envoyé à ' . $forlife . '.');
 +                    $page->trigSuccess('Email envoyé à ' . $user->forlifeEmail() . '.');
                      break;
  
                  case 'correct':
                      S::assert_xsrf_token();
  
 -                    switch_bestalias($target, $loginbis);
 -                    XDB::execute("UPDATE aliases SET type='homonyme',expire=NOW() WHERE alias={?}", $loginbis);
 -                    XDB::execute("REPLACE INTO homonymes (homonyme_id,user_id) VALUES({?},{?})", $target, $target);
 -                    send_robot_homonyme($prenom, $nom, $forlife, $loginbis);
 +                    switch_bestalias($user, $loginbis);
 +                    XDB::execute("UPDATE  aliases
 +                                     SET  type = 'homonyme', expire=NOW()
 +                                   WHERE  alias = {?}", $loginbis);
 +                    XDB::execute("REPLACE INTO  homonymes (homonyme_id,user_id)
 +                                        VALUES  ({?}, {?})", $target, $target);
 +                    send_robot_homonyme($user, $loginbis);
                      $op = 'list';
 -                    $page->trigSuccess('Email envoyé à ' . $forlife . ', alias supprimé.');
 +                    $page->trigSuccess('Email envoyé à ' . $user->forlifeEmail() . ', alias supprimé.');
                      break;
              }
          }
  
          if ($op == 'list') {
              $res = XDB::iterator(
 -                    "SELECT  a.alias AS homonyme,s.id AS user_id,s.alias AS forlife,
 -                             promo,prenom,nom,
 -                             IF(h.homonyme_id=s.id, a.expire, NULL) AS expire,
 -                             IF(h.homonyme_id=s.id, a.type, NULL) AS type
 +                    "SELECT  a.alias AS homonyme, s.alias AS forlife,
 +                             IF(h.homonyme_id = s.id, a.expire, NULL) AS expire,
 +                             IF(h.homonyme_id = s.id, a.type, NULL) AS type,
 +                             ac.uid AS user_id
                         FROM  aliases       AS a
                    LEFT JOIN  homonymes     AS h ON (h.homonyme_id = a.id)
                   INNER JOIN  aliases       AS s ON (s.id = h.user_id AND s.type='a_vie')
 -                 INNER JOIN  auth_user_md5 AS u ON (s.id=u.user_id)
 -                      WHERE  a.type='homonyme' OR a.expire!=''
 -                   ORDER BY  a.alias,promo");
 +                 INNER JOIN  accounts      AS ac ON (ac.uid = a.id)
 +                      WHERE  a.type = 'homonyme' OR a.expire != ''
 +                   ORDER BY  a.alias, forlife");
              $hnymes = Array();
              while ($tab = $res->next()) {
                  $hnymes[$tab['homonyme']][] = $tab;
          }
      }
  
 -    function handler_ax_xorg(&$page) {
 -        $page->changeTpl('admin/ax-xorg.tpl');
 -        $page->setTitle('Administration - AX/X.org');
 -
 -        // liste des différences
 -        $res = XDB::query(
 -                'SELECT  u.promo,u.nom AS nom,u.prenom AS prenom,ia.nom AS nomax,ia.prenom AS prenomax,u.matricule AS mat,ia.matricule_ax AS matax
 -                   FROM  auth_user_md5 AS u
 -             INNER JOIN  identification_ax AS ia ON u.matricule_ax = ia.matricule_ax
 -                  WHERE  (SOUNDEX(u.nom) != SOUNDEX(ia.nom) AND SOUNDEX(CONCAT(ia.particule,u.nom)) != SOUNDEX(ia.nom)
 -                         AND SOUNDEX(u.nom) != SOUNDEX(ia.nom_patro) AND SOUNDEX(CONCAT(ia.particule,u.nom)) != SOUNDEX(ia.nom_patro))
 -                         OR u.prenom != ia.prenom OR (u.promo != ia.promo AND u.promo != ia.promo+1 AND u.promo != ia.promo-1)
 -               ORDER BY  u.promo,u.nom,u.prenom');
 -        $page->assign('diffs', $res->fetchAllAssoc());
 -
 -        // gens à l'ax mais pas chez nous
 -        $res = XDB::query(
 -                'SELECT  ia.promo,ia.nom,ia.nom_patro,ia.prenom
 -                   FROM  identification_ax as ia
 -              LEFT JOIN  auth_user_md5 AS u ON u.matricule_ax = ia.matricule_ax
 -                  WHERE  u.nom IS NULL');
 -        $page->assign('mank', $res->fetchAllAssoc());
 -
 -        // gens chez nous et pas à l'ax
 -        $res = XDB::query('SELECT promo,nom,prenom FROM auth_user_md5 WHERE matricule_ax IS NULL');
 -        $page->assign('plus', $res->fetchAllAssoc());
 -    }
 -
 -    function handler_deaths(&$page, $promo = 0, $validate = false) {
 +    function handler_deaths(&$page, $promo = 0, $validate = false)
 +    {
          $page->changeTpl('admin/deces_promo.tpl');
          $page->setTitle('Administration - Deces');
  
 -        if (!$promo)
 -            $promo = Env::i('promo');
 -        if (Env::has('sub10')) $promo -= 10;
 -        if (Env::has('sub01')) $promo -=  1;
 -        if (Env::has('add01')) $promo +=  1;
 -        if (Env::has('add10')) $promo += 10;
 -
 -        $page->assign('promo',$promo);
 +        if (!$promo) {
 +            $promo = Env::t('promo', 'X1923');
 +        }
 +        $page->assign('promo', $promo);
 +        if (!$promo) {
 +            return;
 +        }
  
          if ($validate) {
              S::assert_xsrf_token();
  
 -            $res = XDB::iterRow("SELECT user_id,matricule,nom,prenom,deces FROM auth_user_md5 WHERE promo = {?}", $promo);
 -            while (list($uid,$mat,$nom,$prenom,$deces) = $res->next()) {
 -                $val = Env::v($mat);
 +            $res = XDB::iterRow('SELECT  p.hrpid, pd.directory_name, p.deathdate
 +                                   FROM  profiles AS p
 +                             INNER JOIN  profile_display AS pd ON (p.pid = pd.pid)
 +                                  WHERE  pd.promo = {?}', $promo);
 +            while (list($pid, $name, $death) = $res->next()) {
 +                $val = Env::v($pid);
                  if($val == $deces || empty($val)) {
                      continue;
                  }
  
 -                XDB::execute('UPDATE auth_user_md5 SET deces={?} WHERE matricule = {?}', $val, $mat);
 -                $page->trigSuccess('Ajout du décès de ' . $prenom . " " . $nom . ' le ' . $val . '.');
 -                if($deces == '0000-00-00' || empty($deces)) {
 -                    require_once('notifs.inc.php');
 -                    register_watch_op($uid, WATCH_DEATH, $val);
 +                XDB::execute('UPDATE  profiles
 +                                 SET  deathdate = {?}, deathdate_rec = NOW()
 +                               WHERE  hrpid = {?}', $val, $pid);
 +                $page->trigSuccess('Ajout du décès de ' . $name . ' le ' . $val . '.');
 +                if($death == '0000-00-00' || empty($death)) {
 +                    // TODO: FIX THIS DEPRECATED CALL
                      require_once('user.func.inc.php');
                      user_clear_all_subs($uid, false);   // by default, dead ppl do not loose their email
                  }
              }
          }
  
 -        $res = XDB::iterator('SELECT matricule, nom, prenom, deces FROM auth_user_md5 WHERE promo = {?} ORDER BY nom,prenom', $promo);
 +        $res = XDB::iterator('SELECT  p.hrpid, pd.directory_name, p.deathdate
 +                                FROM  profiles AS p
 +                          INNER JOIN  profile_display AS pd ON (p.pid = pd.pid)
 +                               WHERE  pd.promo = {?}
 +                            ORDER BY  pd.sort_name', $promo);
          $page->assign('decedes', $res);
      }
  
 -    function handler_dead_but_active(&$page) {
 +    function handler_dead_but_active(&$page)
 +    {
          $page->changeTpl('admin/dead_but_active.tpl');
          $page->setTitle('Administration - Décédés');
  
          $res = XDB::iterator(
 -                "SELECT  u.promo, u.nom, u.prenom, u.deces, u.matricule_ax, u.hruid, DATE(MAX(s.start)) AS last
 -                   FROM  auth_user_md5 AS u
 -              LEFT JOIN  logger.sessions AS s ON (s.uid = u.user_id AND suid = 0)
 -                  WHERE  perms IN ('admin', 'user') AND deces <> 0
 -               GROUP BY  u.user_id
 -               ORDER BY  u.promo, u.nom");
 +                'SELECT  a.hruid, pd.promo, p.ax_id, pd.directory_name, p.deathdate, DATE(MAX(s.start)) AS last
 +                   FROM  accounts AS a
 +             INNER JOIN  account_profiles AS ap ON (ap.uid = a.uid AND FIND_IN_SET(\'owner\', ap.perms))
 +             INNER JOIN  profiles AS p ON (p.pid = ap.pid)
 +             INNER JOIN  profile_display AS pd ON (pd.pid = p.pid)
 +              LEFT JOIN  logger.sessions AS s ON (s.uid = a.uid AND suid = 0)
 +                  WHERE  a.state = \'active\' AND p.deathdate IS NOT NULL
 +               GROUP BY  a.uid
 +               ORDER BY  pd.promo, pd.sort_name');
          $page->assign('dead', $res);
      }
  
 -    function handler_synchro_ax(&$page, $login = null, $action = null) {
 -        $page->changeTpl('admin/synchro_ax.tpl');
 -        $page->setTitle('Administration - Synchro AX');
 -
 -        // Checks for synchronization requirements.
 -        require_once('synchro_ax.inc.php');
 -        if (is_ax_key_missing()) {
 -            $page->assign('no_private_key', true);
 -            $page->run();
 -        }
 -
 -        // Determines user identity using environment.
 -        if ($login) {
 -            $user = User::get($login);
 -        } else if (Env::has('user')) {
 -            $user = User::get(Env::v('user'));
 -        } else if (Env::has('mat')) {
 -            $res = XDB::query("SELECT user_id FROM auth_user_md5 WHERE matricule = {?}", Env::i('mat'));
 -            $user = User::get($res->fetchOneCell());
 -        } else {
 -            return;
 -        }
 -
 -        // Finally synchronizes the AX and plat/al information.
 -        if ($action == 'import') {
 -            ax_synchronize($user->login(), S::v('uid'));
 -        }
 -
 -        require_once 'profil.func.inc.php';
 -        $userxorg = get_user_details($user->login(), S::v('uid'), 'ax');
 -        $userax = get_user_ax($userxorg['matricule_ax']);
 -        $diff = diff_user_details($userax, $userxorg, 'ax');
 -
 -        $page->assign('x', $userxorg);
 -        $page->assign('diff', $diff);
 -    }
 -
      function handler_validate(&$page, $action = 'list', $id = null)
      {
          $page->changeTpl('admin/valider.tpl');
          $page->assign('vit', new ValidateIterator());
      }
  
 -    function handler_validate_answers(&$page, $action = 'list', $id = null) {
 +    function handler_validate_answers(&$page, $action = 'list', $id = null)
 +    {
          $page->setTitle('Administration - Réponses automatiques de validation');
          $page->assign('title', 'Gestion des réponses automatiques');
          $table_editor = new PLTableEditor('admin/validate/answers','requests_answers','id');
          $table_editor->describe('answer','texte',false);
          $table_editor->apply($page, $action, $id);
      }
 -    function handler_skins(&$page, $action = 'list', $id = null) {
 +
 +    function handler_skins(&$page, $action = 'list', $id = null)
 +    {
          $page->setTitle('Administration - Skins');
          $page->assign('title', 'Gestion des skins');
          $table_editor = new PLTableEditor('admin/skins','skins','id');
          $table_editor->apply($page, $action, $id);
      }
  
 -    function handler_postfix_blacklist(&$page, $action = 'list', $id = null) {
 +    function handler_postfix_blacklist(&$page, $action = 'list', $id = null)
 +    {
          $page->setTitle('Administration - Postfix : Blacklist');
          $page->assign('title', 'Blacklist de postfix');
          $table_editor = new PLTableEditor('admin/postfix/blacklist','postfix_blacklist','email', true);
          $table_editor->describe('email','email',true);
          $table_editor->apply($page, $action, $id);
      }
 -    function handler_postfix_whitelist(&$page, $action = 'list', $id = null) {
 +
 +    function handler_postfix_whitelist(&$page, $action = 'list', $id = null)
 +    {
          $page->setTitle('Administration - Postfix : Whitelist');
          $page->assign('title', 'Whitelist de postfix');
          $table_editor = new PLTableEditor('admin/postfix/whitelist','postfix_whitelist','email', true);
          $table_editor->describe('email','email',true);
          $table_editor->apply($page, $action, $id);
      }
 -    function handler_mx_broken(&$page, $action = 'list', $id = null) {
 +
 +    function handler_mx_broken(&$page, $action = 'list', $id = null)
 +    {
          $page->setTitle('Administration - MX Défaillants');
          $page->assign('title', 'MX Défaillant');
          $table_editor = new PLTableEditor('admin/mx/broken', 'mx_watch', 'host', true);
          $table_editor->describe('text', 'Description du problème', false);
          $table_editor->apply($page, $action, $id);
      }
 -    function handler_logger_actions(&$page, $action = 'list', $id = null) {
 +
 +    function handler_logger_actions(&$page, $action = 'list', $id = null)
 +    {
          $page->setTitle('Administration - Actions');
          $page->assign('title', 'Gestion des actions de logger');
          $table_editor = new PLTableEditor('admin/logger/actions','logger.actions','id');
          $table_editor->describe('description','description',true);
          $table_editor->apply($page, $action, $id);
      }
 -    function handler_downtime(&$page, $action = 'list', $id = null) {
 +
 +    function handler_downtime(&$page, $action = 'list', $id = null)
 +    {
          $page->setTitle('Administration - Coupures');
          $page->assign('title', 'Gestion des coupures');
          $table_editor = new PLTableEditor('admin/downtime','coupures','id');
          $table_editor->apply($page, $action, $id);
      }
  
 +    function handler_account_types(&$page, $action = 'list', $id = null) 
 +    {
 +        $page->setTitle('Administration - Types de comptes');
 +        $page->assign('title', 'Gestion des types de comptes');
 +        $table_editor = new PLTableEditor('admin/account/types', 'account_types', 'type', true);
 +        $table_editor->describe('type', 'Catégorie', true);
 +        $table_editor->describe('perms', 'Permissions associées', true);
 +        $table_editor->apply($page, $action, $id);
 +    }
 +
      function handler_wiki(&$page, $action = 'list', $wikipage = null, $wikipage2 = null)
      {
 -        if (S::v('core_rss_hash')) {
 +        if (S::hasAuthToken()) {
             $page->setRssLink('Changement Récents',
 -                             '/Site/AllRecentChanges?action=rss&user=' . S::v('hruid') . '&hash=' . S::v('core_rss_hash'));
 +                             '/Site/AllRecentChanges?action=rss&user=' . S::v('hruid') . '&hash=' . S::v('token'));
          }
  
          // update wiki perms
          }
  
          $page->changeTpl('admin/wiki.tpl');
 -        $page->addJsLink('jquery.js');
          $page->assign('wiki_pages', $wiki_tree);
          $page->assign('perms_opts', $perms);
      }
              $sql = "SELECT  w.ip, IF(s.ip IS NULL,
                                       IF(w.ip = s2.ip, s2.host, s2.forward_host),
                                       IF(w.ip = s.ip, s.host, s.forward_host)),
 -                            w.mask, w.detection, w.state, u.hruid
 +                            w.mask, w.detection, w.state, a.hruid
                        FROM  ip_watch        AS w
                   LEFT JOIN  logger.sessions AS s  ON (s.ip = w.ip)
                   LEFT JOIN  logger.sessions AS s2 ON (s2.forward_ip = w.ip)
 -                 LEFT JOIN  auth_user_md5   AS u  ON (u.user_id = s.uid)
 -                  GROUP BY  w.ip, u.hruid
 -                  ORDER BY  w.state, w.ip, u.hruid";
 +                 LEFT JOIN  accounts        AS a  ON (a.uid = s.uid)
 +                  GROUP BY  w.ip, a.hruid
 +                  ORDER BY  w.state, w.ip, a.hruid";
              $it = Xdb::iterRow($sql);
  
              $table = array();
              $page->assign('table', $table);
          } elseif ($action == 'edit') {
              $sql = "SELECT  w.detection, w.state, w.last, w.description, w.mask,
 -                            u1.hruid AS edit, u2.hruid AS hruid, s.host
 +                            a1.hruid AS edit, a2.hruid AS hruid, s.host
                        FROM  ip_watch        AS w
 -                 LEFT JOIN  auth_user_md5   AS u1 ON (u1.user_id = w.uid)
 +                 LEFT JOIN  accounts        AS a1 ON (a1.uid = w.uid)
                   LEFT JOIN  logger.sessions AS s  ON (w.ip = s.ip)
 -                 LEFT JOIN  auth_user_md5   AS u2 ON (u2.user_id = s.uid)
 +                 LEFT JOIN  accounts        AS a2 ON (a2.uid = s.uid)
                       WHERE  w.ip = {?}
 -                  GROUP BY  u2.hruid
 -                  ORDER BY  u2.hruid";
 +                  GROUP BY  a2.hruid
 +                  ORDER BY  a2.hruid";
              $it = Xdb::iterRow($sql, ip_to_uint($ip));
  
              $props = array();
      function handler_accounts(&$page)
      {
          $page->changeTpl('admin/accounts.tpl');
 -        $page->assign('disabled', XDB::iterator('SELECT  u.nom, u.prenom, u.promo, u.comment, u.hruid
 -                                                   FROM  auth_user_md5 AS u
 -                                                  WHERE  perms = \'disabled\'
 -                                               ORDER BY  nom, prenom'));
 -        $page->assign('admins', XDB::iterator('SELECT  u.nom, u.prenom, u.promo, u.hruid
 -                                                 FROM  auth_user_md5 AS u
 -                                                WHERE  perms = \'admin\'
 -                                             ORDER BY  nom, prenom'));
 +        $page->assign('disabled', XDB::iterator('SELECT  a.hruid, FIND_IN_SET(\'watch\', a.flags) AS watch,
 +                                                         a.state = \'disabled\' AS disabled, a.comment
 +                                                   FROM  accounts AS a
 +                                                  WHERE  a.state = \'disabled\' OR FIND_IN_SET(\'watch\', a.flags)
 +                                               ORDER BY  a.hruid'));
 +        $page->assign('admins', XDB::iterator('SELECT  a.hruid
 +                                                 FROM  accounts AS a
 +                                                WHERE  a.is_admin
 +                                             ORDER BY  a.hruid'));
      }
+     function handler_jobs(&$page, $id = -1)
+     {
+         $page->changeTpl('admin/jobs.tpl');
+         if (Env::has('search')) {
+             $res = XDB::query("SELECT  e.id, e.name, e.acronym
+                                  FROM  profile_job_enum AS e
+                                 WHERE  e.name LIKE CONCAT('% ', {?}, '%') OR e.acronym LIKE CONCAT('% ', {?}, '%')",
+                               Env::t('job'), Env::t('job'));
+             if ($res->numRows() <= 20) {
+                 $page->assign('jobs', $res->fetchAllAssoc());
+             } else {
+                 $page->trigError("Il y a trop d'entreprises correspondant à ton choix. Affine-le !");
+             }
+             $page->assign('askedJob', Env::v('job'));
+             return;
+         }
+         if (Env::has('edit')) {
+             S::assert_xsrf_token();
+             $selectedJob = Env::has('selectedJob');
+             if (Env::has('change')) {
+                 XDB::execute('UPDATE  profile_job
+                                  SET  jobid = {?}
+                                WHERE  jobid = {?}',
+                              Env::i('newJobId'), $id);
+                 XDB::execute('DELETE FROM  profile_job_enum
+                                     WHERE  id = {?}',
+                              $id);
+                 $page->trigSuccess("L'entreprise a bien été remplacée.");
+             } else {
+                 XDB::execute('UPDATE  profile_job_enum
+                                  SET  name = {?}, acronym = {?}, url = {?}, email = {?},
+                                       NAF_code = {?}, AX_code = {?}, holdingid = {?}
+                                WHERE  id = {?}',
+                              Env::t('name'), Env::t('acronym'), Env::t('url'), Env::t('email'),
+                              Env::t('NAF_code'), Env::i('AX_code'), Env::i('holdingId'), $id);
+                 $page->trigSuccess("L'entreprise a bien été mise à jour.");
+             }
+         }
+         if (!Env::has('change') && $id != -1) {
+             $res = XDB::query('SELECT  e.id, e.name, e.acronym, e.url, e.email, e.NAF_code, e.AX_code,
+                                        h.id AS holdingId, h.name AS holdingName, h.acronym AS holdingAcronym
+                                  FROM  profile_job_enum AS e
+                             LEFT JOIN  profile_job_enum AS h ON (e.holdingid = h.id)
+                                 WHERE  e.id = {?}',
+                               $id);
+             if ($res->numRows() == 0) {
+                 $page->trigError('Auncune entreprise ne correspond à cet identifiant.');
+             } else {
+                 $page->assign('selectedJob', $res->fetchOneAssoc());
+             }
+         }
+     }
  }
  
  // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
diff --combined modules/profile.php
@@@ -40,6 -40,7 +40,7 @@@ class ProfileModule extends PLModul
              'profile/ajax/job'           => $this->make_hook('ajax_job',                   AUTH_COOKIE, 'user', NO_AUTH),
              'profile/ajax/sector'        => $this->make_hook('ajax_sector',                AUTH_COOKIE, 'user', NO_AUTH),
              'profile/ajax/sub_sector'    => $this->make_hook('ajax_sub_sector',            AUTH_COOKIE, 'user', NO_AUTH),
+             'profile/ajax/alternates'    => $this->make_hook('ajax_alternates',            AUTH_COOKIE, 'user', NO_AUTH),
              'profile/ajax/skill'         => $this->make_hook('ajax_skill',                 AUTH_COOKIE, 'user', NO_AUTH),
              'profile/ajax/searchname'    => $this->make_hook('ajax_searchname',            AUTH_COOKIE, 'user', NO_AUTH),
              'profile/ajax/buildnames'    => $this->make_hook('ajax_buildnames',            AUTH_COOKIE, 'user', NO_AUTH),
@@@ -67,7 -68,7 +68,7 @@@
              'admin/sections'             => $this->make_hook('admin_sections',             AUTH_MDP, 'admin'),
              'admin/networking'           => $this->make_hook('admin_networking',           AUTH_MDP, 'admin'),
              'admin/trombino'             => $this->make_hook('admin_trombino',             AUTH_MDP, 'admin'),
-             'admin/fonctions'            => $this->make_hook('admin_fonctions',            AUTH_MDP, 'admin'),
+             'admin/sectors'              => $this->make_hook('admin_sectors',              AUTH_MDP, 'admin'),
              'admin/corps_enum'           => $this->make_hook('admin_corps_enum',           AUTH_MDP, 'admin'),
              'admin/corps_rank'           => $this->make_hook('admin_corps_rank',           AUTH_MDP, 'admin'),
              'admin/names'                => $this->make_hook('admin_names',                AUTH_MDP, 'admin'),
              return PL_NOT_FOUND;
          }
  
 -        $login = S::logged() ? User::get($x) : User::getSilent($x);
 +        $login = (!is_numeric($x) || S::has_perms()) ? Profile::get($x) : null;
          if (!$login) {
 +            if (S::logged()) {
 +                $page->trigError($x . ' inconnu dans l\'annuaire');
 +            }
              return PL_NOT_FOUND;
          }
  
  
          // Determines is the user is registered, and fetches the user infos in
          // the appropriate way.
 -        $res = XDB::query("SELECT  perms IN ('admin','user','disabled')
 -                             FROM  auth_user_md5
 -                            WHERE  user_id = {?}", $login->id());
 -        if ($res->fetchOneCell()) {
 +        $owner = $login->owner();
 +        if (!$owner || $owner->state != 'pending') {
              $new  = Env::v('modif') == 'new';
 -            $user = get_user_details($login->login(), S::v('uid'), $view);
 +            // XXX: Deprecated...
 +            $user = get_user_details($login->hrid(), S::i('uid'), $view);
          } else {
              $new  = false;
              $user = array();
              if (S::logged()) {
 -                pl_redirect('marketing/public/' . $login->login());
 +                pl_redirect('marketing/public/' . $owner->login());
              }
          }
  
          // Profile view are logged.
          if (S::logged()) {
 -            S::logger()->log('view_profile', $login->login());
 +            S::logger()->log('view_profile', $login->hrid());
          }
  
          // Sets the title of the html page.
          $page->setTitle($login->fullName());
  
          // Prepares the display of the user's mugshot.
 -        $photo = 'photo/' . $login->login() . ($new ? '/req' : '');
 +        $photo = 'photo/' . $login->hrid() . ($new ? '/req' : '');
          if (!isset($user['photo_pub']) || !has_user_right($user['photo_pub'], $view)) {
              $photo = "";
          }
  
          // Determines and displays the virtual alias.
          global $globals;
 -        $res = XDB::query(
 -                "SELECT  alias
 -                   FROM  virtual
 -             INNER JOIN  virtual_redirect USING (vid)
 -             INNER JOIN  auth_user_quick ON (user_id = {?} AND emails_alias_pub = 'public')
 -                  WHERE  (redirect={?} OR redirect={?})
 -                         AND alias LIKE '%@{$globals->mail->alias_dom}'",
 -                $login->id(),
 -                $login->forlifeEmail(),
 -                // TODO(vzanotti): get ride of all @m4x.org addresses in the
 -                // virtual redirect base, and remove this über-ugly hack.
 -                $login->login() . '@' . $globals->mail->domain2);
 -        $page->assign('virtualalias', $res->fetchOneCell());
 +        $owner = $login->owner();
 +        if ($owner) {
 +            $page->assign('virtualalias', $owner->emailAlias());
 +        }
  
          // Adds miscellaneous properties to the display.
          // Adds the global user property array to the display.
          $page->assign_by_ref('x', $user);
 -        $page->assign_by_ref('user', $login);
 +        $page->assign_by_ref('user', $owner);
          $page->assign('logged', has_user_right('private', $view));
          $page->assign('view', $view);
  
  
      function handler_ax(&$page, $user = null)
      {
 -        $user = User::get($user);
 +        $user = Profile::get($user);
          if (!$user) {
              return PL_NOT_FOUND;
          }
 -
 -        $res = XDB::query("SELECT  matricule_ax
 -                             FROM  auth_user_md5
 -                            WHERE  user_id = {?}", $user->id());
 -        $mat = $res->fetchOneCell();
 -        if (!intval($mat)) {
 -            $page->kill("Le matricule AX de {$user->login()} est inconnu");
 +        if (!$user->ax_id) {
 +            $page->kill("Le matricule AX de {$user->hrid()} est inconnu");
          }
 -        http_redirect("http://www.polytechniciens.com/?page=AX_FICHE_ANCIEN&anc_id=$mat");
 +        http_redirect("http://www.polytechniciens.com/?page=AX_FICHE_ANCIEN&anc_id=" . $user->ax_id);
      }
  
 -    function handler_p_edit(&$page, $opened_tab = null, $mode = null)
 +    function handler_p_edit(&$page, $user = null, $opened_tab = null, $mode = null)
      {
          global $globals;
  
 -        // AX Synchronization
 -        require_once 'synchro_ax.inc.php';
 -        if (is_ax_key_missing()) {
 -            $page->assign('no_private_key', true);
 -        }
 -        if (Env::v('synchro_ax') == 'confirm' && !is_ax_key_missing()) {
 -            ax_synchronize(S::user()->login(), S::v('uid'));
 -            $page->trigSuccess('Ton profil a été synchronisé avec celui du site polytechniciens.com');
 +        if (is_null($user)) {
 +            $user = S::user();
 +            if (!$user->hasProfile()) {
 +                return PL_NOT_FOUND;
 +            } else {
 +                pl_redirect('profile/edit/' . $user->profile()->hrid());
 +            }
 +        } else {
 +            $user = Profile::get($user);
 +            if (!$user) {
 +                return PL_NOT_FOUND;
 +            } else if (!S::user()->canEdit($user) && Platal::notAllowed()) {
 +                return PL_FORBIDDEN;
 +            }
          }
  
          // Build the page
          $page->addJsLink('grades.js');
          $page->addJsLink('profile.js');
          $page->addJsLink('jquery.autocomplete.js');
 -        $wiz = new PlWizard('Profil', PlPage::getCoreTpl('plwizard.tpl'), true, true);
 +        $wiz = new PlWizard('Profil', PlPage::getCoreTpl('plwizard.tpl'), true, true, false);
 +        $wiz->addUserData('profile', $user);
 +        $wiz->addUserData('owner', $user->owner());
          $this->load('page.inc.php');
          $wiz->addPage('ProfileGeneral', 'Général', 'general');
          $wiz->addPage('ProfileAddresses', 'Adresses personnelles', 'adresses');
          $wiz->addPage('ProfileJobs', 'Informations professionnelles', 'emploi');
          $wiz->addPage('ProfileSkills', 'Compétences diverses', 'skill');
          $wiz->addPage('ProfileMentor', 'Mentoring', 'mentor');
 -        $wiz->apply($page, 'profile/edit', $opened_tab, $mode);
 +        $wiz->apply($page, 'profile/edit/' . $user->hrid(), $opened_tab, $mode);
  
 -         // Misc checks
 -        $res = XDB::query("SELECT  user_id
 -                             FROM  auth_user_md5
 -                            WHERE  user_id = {?} AND naissance = '0000-00-00'", S::i('uid'));
 -        if ($res->numRows()) {
 +        if (!$user->birthdate) {
              $page->trigWarning("Ta date de naissance n'est pas renseignée, ce qui t'empêcheras de réaliser"
                        . " la procédure de récupération de mot de passe si un jour tu le perdais.");
          }
          $page->assign('i', $id);
          $page->assign('job', array());
          $page->assign('new', true);
-         $res = XDB::query("SELECT  id, name
+         $res = XDB::query("SELECT  id, name AS label
                               FROM  profile_job_sector_enum");
          $page->assign('sectors', $res->fetchAllAssoc());
-         $res = XDB::query("SELECT  id, fonction_fr, FIND_IN_SET('titre', flags) AS title
-                              FROM  fonctions_def
-                          ORDER BY  id");
-         $page->assign('fonctions', $res->fetchAllAssoc());
          require_once "emails.combobox.inc.php";
          fill_email_combobox($page);
      }
          $page->assign('sel', $sssect);
      }
  
+     function handler_ajax_alternates(&$page, $id, $sssect)
+     {
+         header('Content-Type: text/html; charset=utf-8');
+         $res = XDB::iterator('SELECT  name
+                                 FROM  profile_job_alternates
+                                WHERE  subsubsectorid = {?}
+                             ORDER BY  id',
+                              $sssect);
+         $page->changeTpl('profile/jobs.alternates.tpl', NO_SKIN);
+         $alternate  = $res->next();
+         $alternates = $alternate['name'];
+         while ($alternate  = $res->next()) {
+             $alternates .= ', ' . $alternate['name'];
+         }
+         $page->assign('alternates', $alternates);
+     }
      function handler_ajax_skill(&$page, $cat, $id)
      {
          header('Content-Type: text/html; charset=utf-8');
          $page->assign('names', build_javascript_names($data));
      }
  
 -    function handler_p_orange(&$page)
 +    function handler_p_orange(&$page, $pid = null)
      {
          $page->changeTpl('profile/orange.tpl');
  
          require_once 'validations.inc.php';
 -
 -        $res = XDB::query("SELECT  e.entry_year, e.grad_year, d.promo, FIND_IN_SET('femme', u.flags) AS sexe
 -                             FROM  auth_user_md5     AS u
 -                       INNER JOIN  profile_display   AS d ON (d.pid = u.user_id)
 -                       INNER JOIN  profile_education AS e ON (e.uid = u.user_id AND FIND_IN_SET('primary', e.flags))
 -                            WHERE  u.user_id = {?}", S::v('uid'));
 -
 -        list($promo, $promo_sortie_old, $promo_display, $sexe) = $res->fetchOneRow();
 -        $page->assign('promo_sortie_old', $promo_sortie_old);
 -        $page->assign('promo', $promo);
 -        $page->assign('promo_display', $promo_display);
 -        $page->assign('sexe', $sexe);
 +        $profile = Profile::get($pid);
 +        if (is_null($profile)) {
 +            return PL_NOT_FOUND;
 +        }
 +        $page->assign('promo_sortie_old', $profile->grad_year);
 +        $page->assign('promo', $profile->entry_year);
 +        $page->assign('promo_display', $profile->promo());
 +        $page->assign('sexe', $profile->isFemale());
  
          if (!Env::has('promo_sortie')) {
              return;
          }
  
          $promo_sortie = Env::i('promo_sortie');
 -
 +        $promo = $profile->entry_year;
          if ($promo_sortie < 1000 || $promo_sortie > 9999) {
              $page->trigError('L\'année de sortie doit être un nombre de quatre chiffres.');
 -        }
 -        elseif ($promo_sortie < $promo + 3) {
 +        } elseif ($promo_sortie < $promo + 3) {
              $page->trigError('Trop tôt !');
 -        }
 -        elseif ($promo_sortie == $promo_sortie_old) {
 +        } elseif ($promo_sortie == $promo_sortie_old) {
              $page->trigWarning('Tu appartiens déjà à la promotion correspondante à cette année de sortie.');
 -        }
 -        elseif ($promo_sortie == $promo + 3) {
 -            XDB::execute("UPDATE  profile_education
 +        } elseif ($promo_sortie == $promo + 3) {
 +            XDB::execute('UPDATE  profile_education
                               SET  grad_year = {?}
 -                           WHERE  uid = {?} AND FIND_IN_SET('primary', flags)", $promo_sortie, S::v('uid'));
 -                $page->trigSuccess('Ton statut "orange" a été supprimé.');
 -                $page->assign('promo_sortie_old', $promo_sortie);
 -        }
 -        else {
 +                           WHERE  uid = {?} AND FIND_IN_SET(\'primary\', flags)',
 +                         $promo_sortie, $profile->id());
 +            $page->trigSuccess('Ton statut "orange" a été supprimé.');
 +            $page->assign('promo_sortie_old', $promo_sortie);
 +        else {
              $page->assign('promo_sortie', $promo_sortie);
  
              if (Env::has('submit')) {
          }
      }
  
 -    function handler_referent(&$page, $x = null)
 +    function handler_referent(&$page, $user)
      {
          require_once 'user.func.inc.php';
          $page->changeTpl('profile/fiche_referent.tpl', SIMPLE);
  
 -        $user = User::get($x);
 -        if ($user == null) {
 +        $user = Profile::get($user);
 +        if (!$user) {
              return PL_NOT_FOUND;
          }
  
 -        $res = XDB::query("SELECT cv FROM auth_user_md5 WHERE user_id = {?}", $user->id());
 -        $cv = $res->fetchOneCell();
 -
          $page->assign_by_ref('user', $user);
 -        $page->assign('cv', MiniWiki::WikiToHTML($cv, true));
 -        $page->assign('adr_pro', get_user_details_pro($user->id()));
 +        $page->assign('cv', MiniWiki::WikiToHTML($user->cv, true));
 +        //TODO: waiting for job refactoring to be done
 +        //$page->assign('adr_pro', get_user_details_pro($user->id()));
  
          /////  recuperations infos referent
  
          //expertise
 -        $res = XDB::query("SELECT expertise FROM profile_mentor WHERE uid = {?}", $user->id());
 +        $res = XDB::query('SELECT  expertise
 +                             FROM  profile_mentor
 +                            WHERE  uid = {?}', $user->id());
          $page->assign('expertise', $res->fetchOneCell());
  
          // Sectors
          $table_editor->describe('text','intitulé',true);
          $table_editor->apply($page, $action, $id);
      }
-     function handler_admin_fonctions(&$page, $action = 'list', $id = null) {
-         $page->setTitle('Administration - Fonctions');
-         $page->assign('title', 'Gestion des fonctions');
-         $table_editor = new PLTableEditor('admin/fonctions', 'fonctions_def', 'id', true);
-         $table_editor->describe('fonction_fr', 'intitulé', true);
-         $table_editor->describe('fonction_en', 'intitulé (ang)', true);
-         $table_editor->describe('flags', 'titre', true);
+     function handler_admin_sectors(&$page, $action = 'list', $id = null) {
+         $page->setTitle('Administration - Secteurs');
+         $page->assign('title', 'Gestion des secteurs');
+         $table_editor = new PLTableEditor('admin/sectors', 'profile_job_subsubsector_enum', 'id', true);
+         $table_editor->describe('sectorid', 'id du secteur', false);
+         $table_editor->describe('subsectorid', 'id du sous-secteur', false);
+         $table_editor->describe('name', 'nom', true);
+         $table_editor->describe('flags', 'affichage', true);
          $table_editor->apply($page, $action, $id);
      }
      function handler_admin_networking(&$page, $action = 'list', $id = null) {
@@@ -157,16 -157,16 +157,16 @@@ class ProfileJob extends ProfileGeocodi
                       S::i('uid'));
          foreach ($value as $id=>&$job) {
              if ($job['jobid']) {
-                 XDB::execute("INSERT INTO  profile_job (uid, id, functionid, description, sectorid, subsectorid,
+                 XDB::execute("INSERT INTO  profile_job (uid, id, description, sectorid, subsectorid,
                                                          subsubsectorid, email, url, pub, email_pub, jobid)
                                     VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})",
-                              S::i('uid'), $id, $job['fonction'], $job['description'], $job['sector'], $job['subSector'],
+                              S::i('uid'), $id, $job['description'], $job['sector'], $job['subSector'],
                               $job['subSubSector'], $job['w_email'], $job['w_url'], $job['pub'], $job['w_email_pub'], $job['jobid']);
              } else {
-                 XDB::execute("INSERT INTO  profile_job (uid, id, functionid, description, sectorid, subsectorid,
+                 XDB::execute("INSERT INTO  profile_job (uid, id, description, sectorid, subsectorid,
                                                          subsubsectorid, email, url, pub, email_pub)
                                     VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})",
-                              S::i('uid'), $id, $job['fonction'], $job['description'], $job['sector'], $job['subSector'],
+                              S::i('uid'), $id, $job['description'], $job['sector'], $job['subSector'],
                               $job['subSubSector'], $job['w_email'], $job['w_url'], $job['pub'], $job['w_email_pub']);
              }
              $address = new ProfileAddress();
@@@ -194,9 -194,9 +194,9 @@@ class ProfileJobs extends ProfilePag
      {
          // Checkout the CV
          $res = XDB::query("SELECT  cv
 -                             FROM  auth_user_md5
 -                            WHERE  user_id = {?}",
 -                          S::i('uid'));
 +                             FROM  profiles
 +                            WHERE  pid = {?}",
 +                          $this->pid());
          $this->values['cv'] = $res->fetchOneCell();
  
          // Checkout the corps
                                     rankid AS rank, corps_pub AS pub
                               FROM  profile_corps
                              WHERE  uid = {?}",
 -                          S::i('uid'));
 +                        $this->pid());
          $this->values['corps'] = $res->fetchOneAssoc();
  
          // Build the jobs tree
-         $res = XDB::iterRow("SELECT  j.id, j.jobid, je.name, j.functionid, j.sectorid, j.subsectorid, j.subsubsectorid,
+         $res = XDB::iterRow("SELECT  j.id, j.jobid, je.name, j.sectorid, j.subsectorid, j.subsubsectorid,
                                       s.name, j.description, j.email, j.email_pub, j.url, j.pub,
                                       je.acronym, je.url, je.email,
                                       aw.accuracy, aw.text, aw.postalText, aw.postalCode, aw.localityId,
                            LEFT JOIN  profile_addresses             AS ah ON (ah.jobid = j.jobid AND ah.type = 'hq')
                                WHERE  j.uid = {?}
                             ORDER BY  j.id",
 -                            S::i('uid'));
 +                            $this->pid());
          $this->values['jobs'] = array();
-         while (list($id, $jobid, $name, $function, $sector, $subSector, $subSubSector,
+         while (list($id, $jobid, $name, $sector, $subSector, $subSubSector,
                      $subSubSectorName, $description, $w_email, $w_emailPub, $w_url, $pub,
                      $hq_acronym, $hq_url, $hq_email,
                      $w_accuracy, $w_text, $w_postalText, $w_postalCode, $w_localityId,
              $this->values['jobs'][] = array('id'               => $id,
                                              'jobid'            => $jobid,
                                              'name'             => $name,
-                                             'function'         => $function,
                                              'sector'           => $sector,
                                              'subSector'        => $subSector,
                                              'subSubSector'     => $subSubSector,
                                  FROM  profile_phones
                                 WHERE  uid = {?} AND link_type = 'pro'
                              ORDER BY  link_id",
 -                             S::i('uid'));
 +                             $this->pid());
          $i = 0;
          $jobNb = count($this->values['jobs']);
          while ($phone = $res->next()) {
      protected function _saveData()
      {
          if ($this->changed['cv']) {
 -            XDB::execute("UPDATE  auth_user_md5
 +            XDB::execute("UPDATE  profiles
                               SET  cv = {?}
 -                           WHERE  user_id = {?}",
 -                         $this->values['cv'], S::i('uid'));
 +                           WHERE  pid = {?}",
 +                         $this->values['cv'], $this->pid());
          }
  
          if ($this->changed['corps']) {
                                    rankid = {?}, corps_pub = {?}
                             WHERE  uid = {?}",
                            $this->values['corps']['original'], $this->values['corps']['current'],
 -                          $this->values['corps']['rank'], $this->values['corps']['pub'], S::i('uid'));
 +                          $this->values['corps']['rank'], $this->values['corps']['pub'], $this->pid());
          }
      }
  
      public function _prepare(PlPage &$page, $id)
      {
          require_once "emails.combobox.inc.php";
 -        fill_email_combobox($page);
 +        fill_email_combobox($page, $this->owner, $this->profile);
  
          $res = XDB::query("SELECT  id, name AS label
                               FROM  profile_job_sector_enum");
          $page->assign('sectors', $res->fetchAllAssoc());
-         $res = XDB::query("SELECT  id, fonction_fr, FIND_IN_SET('titre', flags) AS title
-                              FROM  fonctions_def
-                          ORDER BY  id");
-         $page->assign('functions', $res->fetchAllAssoc());
  
          $res = XDB::iterator("SELECT  id, name
                                  FROM  profile_corps_enum
@@@ -31,7 -31,7 +31,7 @@@ class ProfileSectors implements Profile
                               INNER JOIN  profile_job_sector_enum    AS s  ON (m.sectorid = s.id)
                               INNER JOIN  profile_job_subsector_enum AS ss ON (s.id = ss.sectorid AND m.subsectorid = ss.id)
                                    WHERE  m.uid = {?}",
 -                                S::i('uid'));
 +                                $page->pid());
              while (list($s, $ss, $ssname) = $res->next()) {
                  if (!isset($value[$s])) {
                      $value[$s] = array($ss => $ssname);
@@@ -39,9 -39,9 +39,9 @@@
                      $value[$s][$ss] = $ssname;
                  }
              }
-         } else if (!is_array($value)) {
+         } elseif (!is_array($value)) {
              $value = array();
-         } else if (count($value) > 10) {
+         } elseif (count($value) > 10) {
              Platal::page()->trigError("Le nombre de secteurs d'expertise est limité à 10.");
              $success = false;
          }
  
          XDB::execute("DELETE FROM  profile_mentor_sector
                              WHERE  uid = {?}",
 -                     S::i('uid'));
 +                     $page->pid());
          if (!count($value)) {
              return;
          }
-         foreach ($value as $id=>&$sect) {
-             foreach ($sect as $sid=>&$name) {
+         foreach ($value as $id => $sect) {
+             foreach ($sect as $sid => $name) {
                  XDB::execute("INSERT INTO  profile_mentor_sector (uid, sectorid, subsectorid)
                                     VALUES  ({?}, {?}, {?})",
 -                             S::i('uid'), $id, $sid);
 +                             $page->pid(), $id, $sid);
              }
          }
      }
@@@ -82,7 -82,7 +82,7 @@@ class ProfileCountry implements Profile
                                     FROM  profile_mentor_country AS m
                               INNER JOIN  geoloc_countries       AS gc ON (m.country = gc.iso_3166_1_a2)
                                    WHERE  m.uid = {?}",
 -                                S::i('uid'));
 +                                $page->pid());
              while (list($id, $name) = $res->next()) {
                  $value[$id] = $name;
              }
      {
          XDB::execute("DELETE FROM  profile_mentor_country
                              WHERE  uid = {?}",
 -                     S::i('uid'));
 +                     $page->pid());
          foreach ($value as $id=>&$name) {
              XDB::execute("INSERT INTO  profile_mentor_country (uid, country)
                                 VALUES  ({?}, {?})",
 -                         S::i('uid'), $id);
 +                         $page->pid(), $id);
          }
      }
  }
@@@ -125,9 -125,9 +125,9 @@@ class ProfileMentor extends ProfilePag
      protected function _fetchData()
      {
          $res = XDB::query("SELECT  expertise
-                              FROM  mentor
+                              FROM  profile_mentor
                              WHERE  uid = {?}",
 -                          S::i('uid'));
 +                          $this->pid());
          $this->values['expertise'] = $res->fetchOneCell();
      }
  
          if ($this->changed['expertise']) {
              $expertise = trim($this->values['expertise']);
              if (empty($expertise)) {
-                 XDB::execute("DELETE FROM  mentor
+                 XDB::execute("DELETE FROM  profile_mentor
                                      WHERE  uid = {?}",
 -                             S::i('uid'));
 +                             $this->pid());
                  $this->values['expertise'] = null;
              } else {
-                 XDB::execute("REPLACE INTO  mentor (uid, expertise)
+                 XDB::execute("REPLACE INTO  profile_mentor (uid, expertise)
                                      VALUES  ({?}, {?})",
 -                             S::i('uid'), $expertise);
 +                             $this->pid(), $expertise);
                  $this->values['expertise'] = $expertise;
              }
          }
  
      public function _prepare(PlPage &$page, $id)
      {
-         $page->assign('sectors', XDB::iterator("SELECT  id, name
-                                                   FROM  profile_job_sector_enum"));
+         $page->assign('sectorList', XDB::iterator('SELECT  id, name
+                                                      FROM  profile_job_sector_enum'));
  
          $page->assign('countryList', XDB::iterator("SELECT  iso_3166_1_a2, countryFR
                                                        FROM  geoloc_countries
@@@ -20,7 -20,7 +20,7 @@@
  {*                                                                        *}
  {**************************************************************************}
  
 -<h1>Demande d'inscription à {$asso.nom}</h1>
 +<h1>Demande d'inscription à {$asso->nom}</h1>
  
  {if $user && $is_admin && $show_form}
  
  <p class="descr">
  <strong>Ta demande d'inscription a bien été envoyée !</strong> Tu seras averti{if $user->isFemale()}e{/if} par email de la suite qui lui sera donnée.
  <p>
 -<p class="descr">[<a href="{$platal->ns}">Retour à la page d'accueil de {$asso.nom}</a>]</p>
 +<p class="descr">[<a href="{$platal->ns}">Retour à la page d'accueil de {$asso->nom}</a>]</p>
  
  {else}
  
  <p class="descr">
 -Pour t'inscrire à {$asso.nom}, il te faut en demander l'autorisation aux animateurs du groupe via le
 +Pour t'inscrire à {$asso->nom}, il te faut en demander l'autorisation aux animateurs du groupe via le
  formulaire ci-dessous. Vérifie et corrige au besoin les différents champs, puis clique sur
  [&nbsp;M'inscrire&nbsp;!&nbsp;].
  </p>
  <form action="{$platal->ns}subscribe" method="post">
    {xsrf_token_field}
    <p class="descr">
 -  <strong>OUI, je souhaite être inscrit au groupe {$asso.nom}.</strong>
 +  <strong>OUI, je souhaite être inscrit au groupe {$asso->nom}.</strong>
    </p>
    <p class="descr">
    Indique ci-après <strong>tes motivations</strong> qui seront communiquées aux animateurs du groupe&nbsp;:
    </p> <textarea cols=80 rows=12 name="message">
  Chers Camarades,
  
 -Je souhaite m'inscrire à {$asso.nom}.
 +Je souhaite m'inscrire à {$asso->nom}.
  
  Merci d'avance d'avoir la gentillesse de valider mon inscription.
  
@@@ -94,8 -94,6 +94,6 @@@ https://www.polytechnique.org/profile/{
  </textarea>
    <div class="center">
      <input type="submit" name="inscrire" value="M'inscrire !" />
-     &nbsp;
-     <input type="reset" value="Annuler" />
    </div>
  </form>