Merge branch 'master' of /home/git/platal
authorAymeric Augustin <aymeric.augustin@m4x.org>
Fri, 4 Apr 2008 12:44:44 +0000 (14:44 +0200)
committerAymeric Augustin <aymeric.augustin@m4x.org>
Fri, 4 Apr 2008 12:44:44 +0000 (14:44 +0200)
68 files changed:
ChangeLog
Makefile
bin/cron/checkdb.php
bin/kill_sessions.sh [new file with mode: 0755]
classes/platal.php
classes/plupload.php
htdocs/images/googleapps/.gitignore [new file with mode: 0644]
htdocs/javascript/profile.js
htdocs/javascript/xorg.js
include/emails.inc.php
include/globals.inc.php.in
include/googleapps.inc.php
include/notifs.inc.php
include/rss.inc.php
include/user.func.inc.php
include/userset.inc.php
include/validations/nomusage.inc.php
include/xorg.misc.inc.php
include/xorg/session.inc.php
modules/admin.php
modules/core.php
modules/email.php
modules/forums.php
modules/googleapps.php
modules/lists/lists.inc.php
modules/marketing.php
modules/platal.php
modules/profile.php
modules/register.php
modules/search.php
modules/search/classes.inc.php
modules/stats.php
modules/xnetevents.php
modules/xnetgrp.php
plugins/function.make_forlife.php [new file with mode: 0644]
templates/admin/ipwatcher.tpl
templates/admin/utilisateurs.tpl
templates/admin/valider.tpl
templates/axletter/letter.mail.tpl
templates/axletter/show.tpl
templates/carnet/notif.mail.tpl
templates/carnet/panel.tpl
templates/core/password_prompt.tpl
templates/emails/index.tpl
templates/emails/redirect.tpl
templates/emails/test.mail.tpl
templates/events/index.tpl
templates/forums/admin.tpl [new file with mode: 0644]
templates/googleapps/admin.job.tpl [new file with mode: 0644]
templates/googleapps/admin.tpl [new file with mode: 0644]
templates/googleapps/admin.user.tpl [new file with mode: 0644]
templates/googleapps/index.tpl
templates/include/minifiche.tpl
templates/newsletter/nl.mail.tpl
templates/newsletter/show.tpl
templates/newsletter/submit.tpl
templates/profile/mentor.tpl
templates/profile/profile.tpl
templates/profile/referent.tpl
templates/search/quick.form.tpl
templates/stats/index.tpl
templates/stats/profile.tpl [new file with mode: 0644]
templates/xnet/skin.tpl
templates/xnetevents/index.tpl
upgrade/0.9.16/04_ip.sql
upgrade/0.9.16/08_forums.sql
upgrade/0.9.16/09_watch_cat.sql [new file with mode: 0644]
upgrade/0.9.16/10_logger.sql [new file with mode: 0644]

index d9c720e..6ae5b44 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 ================================================================================
-VERSION 0.9.16                                                        XX XX 2008
+VERSION 0.9.17                                                        XX XX 2008
+
+
+================================================================================
+VERSION 0.9.16                                                        31 03 2008
 
 New:
 
@@ -14,6 +18,7 @@ New:
 
     * Emails:
         - Imap mail storage can be activated/deactivated from interface    -VZA
+        - Mail storage backends are now integrated with redirections       -VZA
 
     * Lists:
         - Unsure mails are moderated                                       -FRU
@@ -23,10 +28,14 @@ New:
 
 Bug/Wish:
 
+    * Carnet:
+        - #734: Fix notification emails and carnet for female users        -VZA
+
     * Emails:
         - #726: Don't send the email if an attachment can't be downloaded  -FRU
         - #750: Fix email list in test email                               -FRU
         - #802: Fix upload content type checking on some buggy PHP         -FRU
+        - #803: Prevents UI from allowing 'last active alias deletion'     -Car
 
     * Lists:
         - #793: Show broken members on ML                                  -FRU
@@ -45,11 +54,13 @@ Bug/Wish:
         - #728: Update CSV                                                 -FRU
         - #743: Don't show a warning when subscriber has no forlife        -FRU
         - #730: XnetEvents are not synchronized with aliases               -VZA
+        - #772: Indicate there are members-only events for non-members     -JAC
 
     * XnetGrp:
         - #732: Adapt subscription text to sex                             -FRU
         - #735: Encoding of list description in member edition form        -FRU
         - #740: Can add a picture in the announces                         -FRU
+        - #799: Improve asked inscription interface                        -JAC
 
 From 0.9.15 branch:
 
@@ -1164,6 +1175,7 @@ ACRONYMS:
     * CAT: Florian El Ahdab     (LeChat)    <florian.el-ahdab@m4x.org>
     * FAL: Raphaël Marichez     (Falco)     <raphael.marichez@m4x.org>
     * FRU: Florent Bruneau      (Fruneau)   <florent.bruneau@m4x.org>
+    * JAC: Stéphane Jacob       (jacou)     <stephane.jacob@m4x.org>
     * JS : Jean Sébastien Bedo              <jean-sebastien.bedo@m4x.org>
     * MC : Pierre Habouzit      (MadCoder)  <pierre.habouzit@m4x.org>
     * mYk: Aymeric Augustin     (mYk)       <aymeric.augustin@m4x.org>
index bbc1afb..eed1687 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -37,16 +37,12 @@ q:
 ## core
 ##
 
-core: spool/templates_c spool/mails_c include/globals.inc.php configs/platal.cron htdocs/.htaccess spool/conf
+core: spool/templates_c spool/mails_c include/globals.inc.php configs/platal.cron htdocs/.htaccess spool/conf spool/tmp
 
-spool/templates_c spool/mails_c spool/uploads spool/conf spool/uploads/temp:
+spool/templates_c spool/mails_c spool/uploads spool/conf spool/tmp:
        mkdir -p $@
        chmod o+w $@
 
-spool/uploads/temp/.htaccess: spool/uploads/temp Makefile
-       echo "Order deny,allow" > $@
-       echo "Deny from all" >> $@
-
 htdocs/.htaccess: htdocs/.htaccess.in Makefile
        @REWRITE_BASE="/~$$(id -un)"; \
        test "$$REWRITE_BASE" = "/~web" && REWRITE_BASE="/"; \
@@ -68,7 +64,7 @@ wiki: get-wiki build-wiki
 
 build-wiki: $(WIKI_NEEDS) | get-wiki
 
-htdocs/uploads: spool/uploads/temp/.htaccess
+htdocs/uploads:
        cd htdocs && ln -sf ../spool/uploads
 
 htdocs/wiki:
index e180f80..b891fec 100755 (executable)
@@ -85,13 +85,6 @@ check("SELECT  u.user_id, nom, prenom, promo,
 check("select uid from adresses where pub != 'private' and pub !='ax' and pub != 'public'", "Utiliseur n'ayant pas de flag de publicite pour une adresse");
 check("select uid from tels where tel_pub != 'private' and tel_pub !='ax' and tel_pub != 'public'", "Utiliseur n'ayant pas de flag de publicite pour un numero de telephone");
 
-/* validite de adresses */
-check("select uid, count(adrid) from adresses group by uid having count(adrid) > 7", "Utilisateurs ayant trop d'adresses");
-
-/* Validite des tables de langues, competences, mentoring*/
-check("select uid, count(lid) from langues_ins group by uid having count(lid) > 10","Utilisateurs ayant trop de langues");
-check("select uid, count(cid) from competences_ins group by uid having count(cid) > 20","Utilisateurs ayant trop de competences");
-
 /* validite de aliases */
 check("SELECT a.*
         FROM aliases       AS a
@@ -182,5 +175,14 @@ check("SELECT  matricule,nom,prenom,matricule_ax,COUNT(matricule_ax) AS c
         WHERE  matricule_ax != '0'
         GROUP BY  matricule_ax
         having  c > 1", "à chaque personne de l'annuaire de l'AX (identification_ax) doit correspondre AU PLUS UNE personne de notre annuaire (auth_user_md5) -> si ce n'est pas le cas il faut regarder en manuel ce qui ne va pas !");
+
+/* verifie qu'il n'y a pas d'utilisateurs ayant un compte Google Apps désactivé et une redirection encore active vers Google Apps */
+check("SELECT  a.alias, g.g_status, u.mail_storage
+         FROM  auth_user_md5 AS u
+   INNER JOIN  aliases AS a ON (a.id = u.user_id AND a.type = 'a_vie')
+   INNER JOIN  gapps_accounts AS g ON (g.l_userid = u.user_id)
+        WHERE  FIND_IN_SET('googleapps', u.mail_storage) > 0 AND g.g_status != 'active'",
+      "utilisateurs ayant une redirection vers Google Apps alors que leur compte GApps n'est pas actif");
+
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
 ?>
diff --git a/bin/kill_sessions.sh b/bin/kill_sessions.sh
new file mode 100755 (executable)
index 0000000..7816df1
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+find /var/lib/php5 -maxdepth 1 -name 'sess_*' -type f -delete
index cec37f2..4c1f60a 100644 (file)
@@ -259,7 +259,7 @@ class Platal
         }
 
         $val = call_user_func_array($hook['hook'], $args);
-        if ($val & PL_DO_AUTH) {
+        if ($val == PL_DO_AUTH) {
             // The handler need a better auth with the current args
             if (!call_user_func(array($globals->session, 'doAuth'))) {
                 $this->force_login($page);
index 7184bbd..ea192f0 100644 (file)
@@ -49,7 +49,7 @@ class PlUpload
     private function makeFilename($file_id)
     {
         global $globals;
-        $filename = $globals->spoolroot . '/spool/uploads/temp/';
+        $filename = $globals->spoolroot . '/spool/tmp/';
         if (!file_exists($filename)) {
             if (!mkdir($filename)) {
                 trigger_error('can\'t create upload directory: ' . $filename, E_USER_ERROR);
@@ -162,7 +162,7 @@ class PlUpload
     static public function listRawFiles($forlife = '*', $category = '*', $uniq = false, $basename = false)
     {
         global $globals;
-        $filename = $globals->spoolroot . '/spool/uploads/temp/';
+        $filename = $globals->spoolroot . '/spool/tmp/';
         $filename .= $forlife . '--' . $category;
         if (!$uniq) {
             $filename .= '--*';
diff --git a/htdocs/images/googleapps/.gitignore b/htdocs/images/googleapps/.gitignore
new file mode 100644 (file)
index 0000000..d455c33
--- /dev/null
@@ -0,0 +1,2 @@
+/activity-monthly.png
+/activity-yearly.png
index d59a365..5c25580 100644 (file)
@@ -405,7 +405,7 @@ function updateCountry()
 {
     var val = document.forms.prof_annu.countries_sel.value;
     var show = true;
-    if (val == '') {
+    if (val == '' || val == '00') {
         show = false;
     }
     if (document.getElementById('countries_' + val) != null) {
@@ -420,11 +420,11 @@ function addCountry()
     var val  = cb.value;
     var text = cb.options[cb.selectedIndex].text;
     var html = '<div id="countries_' + val + '" style="clear: both; margin-bottom: 0.7em">'
-        + '  <div style="float: left; width: 50%">' + text + '</div>'
-        + '  <input type="hidden" name="countries[' + val + ']" value="' + text + '" />'
-        + '  <a href="javascript:removeCountry(\'' + val + '\')">'
+        + '  <a href="javascript:removeCountry(\'' + val + '\')" style="display: block; float:right">'
         + '    <img src="images/icons/cross.gif" alt="" title="Supprimer ce pays" />'
         + '  </a>'
+        + '  <div style="float: left; width: 50%">' + text + '</div>'
+        + '  <input type="hidden" name="countries[' + val + ']" value="' + text + '" />'
         + '</div>';
     $('#countries').append(html);
     updateCountry();
@@ -454,6 +454,8 @@ function updateSecteur()
     var secteur = document.forms.prof_annu.secteur_sel.value;
     if (secteur == '') {
         secteur = '-1';
+        document.getElementById('ss_secteur_sel').innerHTML = '';
+        return;
     }
     $.get(platal_baseurl + 'profile/ajax/secteur/-1/' + secteur,
           function(data) {
index 0e5f5d0..2a7b1fa 100644 (file)
@@ -165,6 +165,11 @@ function goodiesPopup(node) {
     }
 }
 
+function disableGoodiesPopups() {
+    __goodies_active = false;
+}
+
+var __goodies_active = true;
 var __goodies_ical_sites = [
     {'url_prefix': '',
      'img': 'images/icons/calendar_view_day.gif',
@@ -206,9 +211,11 @@ function __goodies_popupText(url, sites) {
 
 function __goodies_popup(node, sites, default_title) {
     var mouseover_cb = function() {
-        var rss_text = __goodies_popupText(node.href, sites);
-        var rss_title = (node.title ? node.title : default_title);
-        return overlib(rss_text, CAPTION, rss_title, CLOSETEXT, 'Fermer', DELAY, 800, STICKY, WIDTH, 150);
+        if (__goodies_active) {
+            var rss_text = __goodies_popupText(node.href, sites);
+            var rss_title = (node.title ? node.title : default_title);
+            return overlib(rss_text, CAPTION, rss_title, CLOSETEXT, 'Fermer', DELAY, 800, STICKY, WIDTH, 150);
+        }
     }
     var mouseout_cb = function() {
         nd();
index 4909b68..bcf0cc4 100644 (file)
@@ -27,13 +27,18 @@ define("ERROR_INVALID_EMAIL", 3);
 define("ERROR_LOOP_EMAIL", 4);
 
 // function fix_bestalias() {{{1
-
+// Checks for an existing 'bestalias' among the the current user's aliases, and
+// eventually selects a new bestalias when required.
 function fix_bestalias($uid)
 {
-    $res = XDB::query("SELECT COUNT(*) FROM aliases WHERE id={?} AND FIND_IN_SET('bestalias',flags) AND type!='homonyme'", $uid);
-    if ($n = $res->fetchOneCell()) {
+    $res = XDB::query("SELECT  COUNT(*)
+                         FROM  aliases
+                        WHERE  id = {?} AND FIND_IN_SET('bestalias', flags) AND type != 'homonyme'",
+                      $uid);
+    if ($res->fetchOneCell()) {
         return;
     }
+
     XDB::execute("UPDATE  aliases
                      SET  flags=CONCAT(flags,',','bestalias')
                    WHERE  id={?} AND type!='homonyme'
@@ -42,7 +47,9 @@ function fix_bestalias($uid)
 }
 
 // function valide_email() {{{1
-
+// Returns a cleaned-up version of the @p email string. It removes garbage
+// characters, and determines the canonical form (without _ and +) for
+// Polytechnique.org email addresses.
 function valide_email($str)
 {
     global $globals;
@@ -59,11 +66,12 @@ function valide_email($str)
 }
 
 // class Bogo {{{1
-
+// The Bogo class represents a spam filtering level in plat/al architecture.
 class Bogo
 {
     // properties {{{2
 
+    private $uid;
     private $state;
     private $_states = Array('let_spams', 'tag_spams', 'tag_and_drop_spams', 'drop_spams');
 
@@ -74,6 +82,8 @@ class Bogo
         if (!$uid) {
             return;
         }
+
+        $this->uid = $uid;
         $res = XDB::query('SELECT email FROM emails WHERE uid={?} AND flags="filter"', $uid);
         if ($res->numRows()) {
             $this->state = $res->fetchOneCell();
@@ -86,11 +96,11 @@ class Bogo
 
     // public function change() {{{2
 
-    public function change($uid, $state)
+    public function change($state)
     {
         $this->state = is_int($state) ? $this->_states[$state] : $state;
         XDB::execute('UPDATE emails SET email={?} WHERE uid={?} AND flags = "filter"',
-            $this->state, $uid);
+                     $this->state, $this->uid);
     }
 
     // pubic function level() {{{2
@@ -102,25 +112,66 @@ class Bogo
 }
 
 // class Email {{{1
-
-class Email
+// Represents an "email address" used as final recipient for plat/al-managed
+// addresses; it can be subclasses a Redirection emails (third-party) or as
+// Storage emails (Polytechnique.org).
+abstract class Email
 {
-    // properties {{{2
+    protected $uid;
 
+    // Basic email properties; $sufficient indicates if the email can be used as
+    // an unique redirection; $email contains the delivery email address.
+    public $type;
+    public $sufficient;
     public $email;
+    public $display_email;
+
+    // Redirection status properties.
     public $active;
     public $broken;
     public $disabled;
     public $rewrite;
+
+    // Redirection bounces stats.
     public $panne;
     public $last;
     public $panne_level;
 
+    // Activates the email address as a redirection.
+    public abstract function activate();
+
+    // Deactivates the email address as a redirection.
+    public abstract function deactivate();
+
+    // Sets the rewrite rule for the given address.
+    public abstract function set_rewrite($rewrite);
+
+    // Resets the error counts associated with the redirection.
+    public abstract function clean_errors();
+
+    // Email backend capabilities ('rewrite' refers to From: rewrite for mails
+    // forwarded by Polytechnique.org's MXs; 'removable' indicates if the email
+    // can be definitively removed; 'disable' indicates if the email has a third
+    // status 'disabled' in addition to 'active' and 'inactive').
+    public abstract function has_rewrite();
+    public abstract function is_removable();
+    public abstract function has_disable();
+}
+
+// class EmailRedirection {{{1
+// Implementation of Email for third-party redirection (redirection of emails to
+// external user-supplied addresses).
+class EmailRedirection extends Email
+{
     // constructor {{{2
 
-    public function __construct($row)
+    public function __construct($uid, $row)
     {
+        $this->uid = $uid;
+        $this->sufficient = true;
+
         list($this->email, $flags, $this->rewrite, $this->panne, $this->last, $this->panne_level) = $row;
+        $this->display_email = $this->email;
         $this->active   = ($flags == 'active');
         $this->broken   = ($flags == 'panne');
         $this->disabled = ($flags == 'disable');
@@ -128,14 +179,14 @@ class Email
 
     // public function activate() {{{2
 
-    public function activate($uid)
+    public function activate()
     {
         if (!$this->active) {
             XDB::execute("UPDATE  emails
                              SET  panne_level = IF(flags = 'panne', panne_level - 1, panne_level),
                                   flags = 'active'
-                           WHERE  uid={?} AND email={?}", $uid, $this->email);
-            $_SESSION['log']->log("email_on", $this->email.($uid!=S::v('uid') ? "(admin on $uid)" : ""));
+                           WHERE  uid={?} AND email={?}", $this->uid, $this->email);
+            $_SESSION['log']->log("email_on", $this->email.($this->uid!=S::v('uid') ? "(admin on {$this->uid})" : ""));
             $this->active = true;
             $this->broken = false;
         }
@@ -143,34 +194,34 @@ class Email
 
     // public function deactivate() {{{2
 
-    public function deactivate($uid)
+    public function deactivate()
     {
         if ($this->active) {
             XDB::execute("UPDATE  emails SET flags =''
-                           WHERE  uid={?} AND email={?}", $uid, $this->email);
-            $_SESSION['log']->log("email_off",$this->email.($uid!=S::v('uid') ? "(admin on $uid)" : "") );
+                           WHERE  uid={?} AND email={?}", $this->uid, $this->email);
+            $_SESSION['log']->log("email_off",$this->email.($this->uid != S::v('uid') ? "(admin on {$this->uid})" : "") );
             $this->active = false;
         }
     }
 
-    // public function rewrite() {{{2
+    // public function set_rewrite() {{{2
 
-    public function rewrite($rew, $uid)
+    public function set_rewrite($rewrite)
     {
-        if ($this->rewrite == $rew) {
+        if ($this->rewrite == $rewrite) {
             return;
         }
-        if (!$rew || !isvalid_email($rew)) {
-            $rew = '';
+        if (!$rewrite || !isvalid_email($rewrite)) {
+            $rewrite = '';
         }
-        XDB::execute('UPDATE emails SET rewrite={?} WHERE uid={?} AND email={?}', $rew, $uid, $this->email);
-        $this->rewrite = $rew;
+        XDB::execute('UPDATE emails SET rewrite={?} WHERE uid={?} AND email={?}', $rewrite, $this->uid, $this->email);
+        $this->rewrite = $rewrite;
         return;
     }
 
-    // function cleanErrors() {{{2
+    // public function clean_errors() {{{2
 
-    public function cleanErrors($uid)
+    public function clean_errors()
     {
         if (!S::has_perms()) {
             return false;
@@ -181,12 +232,133 @@ class Email
         return XDB::execute("UPDATE  emails
                                 SET  panne_level = 0, panne = 0, last = 0
                               WHERE  uid = {?} AND email = {?}",
-                            $uid, $this->email);
+                            $this->uid, $this->email);
+    }
+
+    // public function has_rewrite() {{{2
+
+    public function has_rewrite()
+    {
+        return true;
+    }
+
+    // public function is_removable() {{{2
+
+    public function is_removable()
+    {
+        return true;
+    }
+
+    // public function has_disable() {{{2
+
+    public function has_disable()
+    {
+        return true;
     }
 }
 
-// class Redirect {{{1
+// class EmailStorage {{{1
+// Implementation of Email for email storage backends from Polytechnique.org.
+class EmailStorage extends Email
+{
+    // Shortname to realname mapping for known mail storage backends.
+    private $display_names = array(
+        'imap'       => 'Accès de secours aux emails (IMAP)',
+        'googleapps' => 'Compte GMail / Google Apps',
+    );
+
+    // Retrieves the current list of actives storages.
+    private function get_storages()
+    {
+        $res = XDB::query("SELECT  mail_storage
+                             FROM  auth_user_md5
+                            WHERE  user_id = {?}", $this->uid);
+        return new FlagSet($res->fetchOneCell());
+    }
+
+    // Updates the list of active storages.
+    private function set_storages($storages)
+    {
+        XDB::execute("UPDATE  auth_user_md5
+                         SET  mail_storage = {?}
+                       WHERE  user_id = {?}", $storages->flags(), $this->uid);
+    }
 
+    // Returns the list of allowed storages for the @p user.
+    static public function get_allowed_storages($uid)
+    {
+        global $globals;
+        $storages = array();
+
+        // Google Apps storage is available for users with valid Google Apps account.
+        require_once 'googleapps.inc.php';
+        if ($globals->mailstorage->googleapps_domain &&
+            GoogleAppsAccount::account_status($uid) == 'active') {
+            $storages[] = 'googleapps';
+        }
+
+        // IMAP storage is always visible to administrators, and is allowed for
+        // everyone when the service is marked as 'active'.
+        if ($globals->mailstorage->imap_active || S::has_perms()) {
+            $storages[] = 'imap';
+        }
+
+        return $storages;
+    }
+
+
+    public function __construct($uid, $name)
+    {
+        $this->uid = $uid;
+        $this->email = $name;
+        $this->display_email = (isset($this->display_names[$name]) ? $this->display_names[$name] : $name);
+
+        $storages = $this->get_storages();
+        $this->sufficient = ($name == 'googleapps');
+        $this->active = $storages->hasFlag($name);
+        $this->broken = false;
+        $this->disabled = false;
+        $this->rewrite = '';
+        $this->panne = $this->last = $this->panne_level = 0;
+    }
+
+    public function activate()
+    {
+        if (!$this->active) {
+            $storages = $this->get_storages();
+            $storages->addFlag($this->email);
+            $this->set_storages($storages);
+            $this->active = true;
+        }
+    }
+
+    public function deactivate()
+    {
+        if ($this->active) {
+            $storages = $this->get_storages();
+            $storages->rmFlag($this->email);
+            $this->set_storages($storages);
+            $this->active = false;
+        }
+
+    }
+
+    // Source rewrite can't be enabled for email storage addresses.
+    public function set_rewrite($rewrite) {}
+
+    // Email storage are not supposed to be broken, hence not supposed to be
+    // cleaned-up.
+    public function clean_errors() {}
+
+    // Capabilities.
+    public function has_rewrite() { return false; }
+    public function is_removable() { return false; }
+    public function has_disable() { return false; }
+}
+
+// class Redirect {{{1
+// Redirect is a placeholder class for an user's active redirections (third-party
+// redirection email, or Polytechnique.org mail storages).
 class Redirect
 {
     // properties {{{2
@@ -201,15 +373,22 @@ class Redirect
 
     public function __construct($_uid)
     {
-        $this->uid=$_uid;
+        $this->uid = $_uid;
+        $this->bogo = new Bogo($_uid);
+
+        // Adds third-party email redirections.
         $res = XDB::iterRow("SELECT  email, flags, rewrite, panne, last, panne_level
                                FROM  emails
                               WHERE  uid = {?} AND flags != 'filter'", $_uid);
-        $this->emails=Array();
+        $this->emails = Array();
         while ($row = $res->next()) {
-            $this->emails[] = new Email($row);
+            $this->emails[] = new EmailRedirection($_uid, $row);
+        }
+
+        // Adds local email storage backends.
+        foreach (EmailStorage::get_allowed_storages($_uid) as $storage) {
+            $this->emails[] = new EmailStorage($_uid, $storage);
         }
-        $this->bogo = new Bogo($_uid);
     }
 
     // public function other_active() {{{2
@@ -217,7 +396,7 @@ class Redirect
     public function other_active($email)
     {
         foreach ($this->emails as $mail) {
-            if ($mail->email!=$email && $mail->active) {
+            if ($mail->email != $email && $mail->active && $mail->sufficient) {
                 return true;
             }
         }
@@ -233,8 +412,8 @@ class Redirect
         }
         XDB::execute('DELETE FROM emails WHERE uid={?} AND email={?}', $this->uid, $email);
         $_SESSION['log']->log('email_del',$email.($this->uid!=S::v('uid') ? " (admin on {$this->uid})" : ""));
-        foreach ($this->emails as $i=>$mail) {
-            if ($email==$mail->email) {
+        foreach ($this->emails as $i => $mail) {
+            if ($email == $mail->email) {
                 unset($this->emails[$i]);
             }
         }
@@ -262,7 +441,7 @@ class Redirect
                 return SUCCESS;
             }
         }
-        $this->emails[] = new Email(array($email, 'active', '', '0000-00-00', '0000-00-00', 0));
+        $this->emails[] = new EmailRedirection($this->uid, array($email, 'active', '', '0000-00-00', '0000-00-00', 0));
 
         // security stuff
         check_email($email, "Ajout d'une adresse surveillée aux redirections de " . $this->uid);
@@ -276,11 +455,11 @@ class Redirect
     {
         foreach ($this->emails as &$mail) {
             if (in_array($mail->email, $emails_actifs)) {
-                $mail->activate($this->uid);
+                $mail->activate();
             } else {
-                $mail->deactivate($this->uid);
+                $mail->deactivate();
             }
-            $mail->rewrite($emails_rewrite[$mail->email], $this->uid);
+            $mail->set_rewrite($emails_rewrite[$mail->email]);
         }
         check_redirect($this);
     }
@@ -295,15 +474,15 @@ class Redirect
             if ($mail->email == $email) {
                 $thisone = $i;
             }
-            $allinactive &= !$mail->active || $mail->email == $email;
+            $allinactive &= !$mail->active || !$mail->sufficient || $mail->email == $email;
         }
         if ($thisone === false) {
             return ERROR_INVALID_EMAIL;
         }
         if ($allinactive || $activate) {
-            $this->emails[$thisone]->activate($this->uid);
+            $this->emails[$thisone]->activate();
         } else {
-            $this->emails[$thisone]->deactivate($this->uid);
+            $this->emails[$thisone]->deactivate();
         }
         check_redirect($this);
         if ($allinactive && !$activate) {
@@ -319,21 +498,21 @@ class Redirect
     {
         foreach ($this->emails as &$mail) {
             if ($mail->email == $email) {
-                $mail->rewrite($redirect, $this->uid);
+                $mail->set_rewrite($redirect);
                 check_redirect($this);
                 return;
             }
         }
     }
 
-    // function cleanErrors() {{{2
+    // function clean_errors() {{{2
 
-    public function cleanErrors($email)
+    public function clean_errors($email)
     {
         foreach ($this->emails as &$mail) {
             if ($mail->email == $email) {
                 check_redirect($this);
-                return $mail->cleanErrors($this->uid);
+                return $mail->clean_errors();
             }
         }
         return false;
@@ -347,7 +526,7 @@ class Redirect
                          SET  flags = 'disable'
                        WHERE  flags = 'active' AND uid = {?}", $this->uid);
         foreach ($this->emails as &$mail) {
-            if ($mail->active) {
+            if ($mail->active && $mail->has_disable()) {
                 $mail->disabled = true;
                 $mail->active   = false;
             }
@@ -384,7 +563,7 @@ class Redirect
         $mxs = $res->fetchAllAssoc();
         $mails = array();
         foreach ($this->emails as &$mail) {
-            if ($mail->active) {
+            if ($mail->active && strstr($mail->email, '@') !== false) {
                 list(,$domain) = explode('@', $mail->email);
                 getmxrr($domain, $lcl_mxs);
                 if (empty($lcl_mxs)) {
@@ -407,69 +586,25 @@ class Redirect
         }
         return $mails;
     }
-}
-
-// class MailStorage {{{1
-class MailStorage {
-    protected $uid;
-    protected $name;
-    protected $storage;
-
-    public function __construct($_uid, $_name)
-    {
-        $this->uid = $_uid;
-        $this->name = $_name;
-
-        $res = XDB::query("SELECT  mail_storage
-                             FROM  auth_user_md5
-                            WHERE  user_id = {?}", $this->uid);
-        $this->storages = new FlagSet($res->fetchOneCell());
-    }
 
-    public function disable()
-    {
-        $this->storages->rmFlag($this->name);
-        XDB::execute("UPDATE  auth_user_md5
-                         SET  mail_storage = {?}
-                       WHERE  user_id = {?}", $this->storages->flags(), $this->uid);
-        return true;
-    }
-
-    public function enable()
-    {
-        $this->storages->addFlag($this->name);
-        XDB::execute("UPDATE  auth_user_md5
-                         SET  mail_storage = {?}
-                       WHERE  user_id = {?}", $this->storages->flags(), $this->uid);
-        return true;
-    }
+    // function active_emails() {{{2
 
-    public function active()
+    public function active_emails()
     {
-        return $this->storages->hasFlag($this->name);
+        $emails = array();
+        foreach ($this->emails as $mail) {
+            if ($mail->active) {
+                $emails[] = $mail;
+            }
+        }
+        return $emails;
     }
-}
 
-class MailStorageIMAP extends MailStorage {
-    public function __construct($_uid)
-    {
-        parent::__construct($_uid, 'imap');
-    }
-}
+    // function get_uid() {{{2
 
-class MailStorageGoogleApps extends MailStorage {
-    public function __construct($_uid)
+    public function get_uid()
     {
-        parent::__construct($_uid, 'googleapps');
-    }
-    
-    public function disable() {
-        $redirect = new Redirect(S::v('uid'));
-        if (!$redirect->other_active(NULL)) {
-            return false;
-        }
-        
-        return parent::disable();
+        return $this->uid;
     }
 }
 
index 4fc17fa..c5148e4 100644 (file)
@@ -43,6 +43,7 @@ class PlatalGlobals
 
     /** paths */
     public $baseurl;
+    public $baseurl_http;
     public $spoolroot;
 
     public $locale;
@@ -56,7 +57,8 @@ class PlatalGlobals
         $this->read_config();
         if (isset($_SERVER) && isset($_SERVER['SERVER_NAME'])) {
             $base = empty($_SERVER['HTTPS']) ? 'http://' : 'https://';
-            $this->baseurl   = @trim($base.$_SERVER['SERVER_NAME'].dirname($_SERVER['PHP_SELF']), '/');
+            $this->baseurl      = @trim($base    .$_SERVER['SERVER_NAME'].dirname($_SERVER['PHP_SELF']), '/');
+            $this->baseurl_http = @trim('http://'.$_SERVER['SERVER_NAME'].dirname($_SERVER['PHP_SELF']), '/');
         }
 
         $this->setlocale();
index abfa384..54e3efe 100644 (file)
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
  ***************************************************************************/
 
-// Checks the admin status of the @p account_name.
-function is_google_apps_administrator($account_name) {
-    static $last_account_name = null;
-    static $last_result = null;
-
-    if ($last_account_name == $account_name) {
-        return $last_result;
-    }
-
-    $res = XDB::query(
-        "SELECT  g_admin
-           FROM  gapps_accounts
-          WHERE  g_account_name = {?} AND g_status = 'active'",
-        $account_name);
-    $last_account_name = $account_name;
-    $last_result = ($res->numRows() > 0 ? (bool)$res->fetchOneRow() : false);
-    return $last_result;
-}
-
-// Post-queue job cleanup functions; they are used to update the plat/al database
-// when a specific Google Apps queue job enters 'success' state.
+// Post-processes the successful Google Apps account creation queue job.
 function post_queue_u_create($job) {
     global $globals;
 
@@ -51,15 +31,16 @@ function post_queue_u_create($job) {
         return;
     }
 
-    // Adds a redirection to the Google Apps delivery address.
+    // Adds a redirection to the Google Apps delivery address, if requested by
+    // the user at creation time.
     $account = new GoogleAppsAccount($userid, $forlife);
     if ($account->activate_mail_redirection) {
         require_once('emails.inc.php');
-        $storage = new MailStorageGoogleApps($userid);
-        $storage->enable();
+        $storage = new EmailStorage($userid, 'googleapps');
+        $storage->activate();
     }
 
-    // Sends an email to the account owner.
+    // Sends the 'account created' email to the user, with basic documentation.
     $res = XDB::query(
         "SELECT  FIND_IN_SET('femme', u.flags), prenom
            FROM  auth_user_md5 AS u
@@ -77,6 +58,7 @@ function post_queue_u_create($job) {
     $mailer->send();
 }
 
+// Post-processes the successful Google Apps account update queue job.
 function post_queue_u_update($job) {
     global $globals;
 
@@ -93,11 +75,11 @@ function post_queue_u_update($job) {
     if (isset($parameters['suspended']) && $parameters['suspended'] == false) {
         require_once('emails.inc.php');
         $account = new GoogleAppsAccount($userid, $forlife);
-        if ($account->g_status == 'active') {
+        if ($account->active()) {
             // Re-adds the email redirection (if the user did request it).
             if ($account->activate_mail_redirection) {
-                $storage = new MailStorageGoogleApps($userid);
-                $storage->enable();
+                $storage = new EmailStorage($userid, 'googleapps');
+                $storage->activate();
             }
 
             // Sends an email to the account owner.
@@ -120,13 +102,21 @@ function post_queue_u_update($job) {
 }
 
 // Reprensentation of an SQL-stored Google Apps account.
+// This class is the interface with the gappsd SQL tables: gappsd is the python
+// daemon which deals with Google Apps provisioning APIs.
+// TODO(vincent.zanotti): add the url of gappsd, when available.
 class GoogleAppsAccount
 {
+    // User identification: user id, and forlife.
     private $uid;
     public $g_account_name;
 
+    // Local account parameters.
     public $sync_password;
     public $activate_mail_redirection;
+
+    // Account status, obtained from Google Apps provisioning & reporting APIs.
+    public $g_account_id;
     public $g_status;
     public $g_suspension;
     public $r_disk_usage;
@@ -135,6 +125,7 @@ class GoogleAppsAccount
     public $r_last_webmail;
     public $reporting_date;
 
+    // Pending requests in the gappsd job queue (cf. top note).
     public $pending_create;
     public $pending_delete;
     public $pending_update;
@@ -143,17 +134,25 @@ class GoogleAppsAccount
     public $pending_update_password;
     public $pending_update_suspension;
 
+    // Pending requests in plat/al validation queue.
     public $pending_validation_unsuspend;
 
-    public function __construct($uid, $account_name)
+    // Constructs the account object, by retrieving all informations from the
+    // GApps account table, from GApps job queue, and from plat/al validation queue.
+    public function __construct($uid, $account_name = NULL)
     {
+        if ($account_name == NULL) {
+            require_once 'user.func.inc.php';
+            $account_name = get_user_forlife($uid, '_silent_user_callback');
+        }
+
         $this->uid = $uid;
         $this->g_account_name = $account_name;
         $this->g_status = NULL;
 
         $res = XDB::query(
             "SELECT  l_sync_password, l_activate_mail_redirection,
-                     g_account_name, g_status, g_suspension, r_disk_usage,
+                     g_account_name, g_account_id, g_status, g_suspension, r_disk_usage,
                      UNIX_TIMESTAMP(r_creation) as r_creation,
                      UNIX_TIMESTAMP(r_last_login) as r_last_login,
                      UNIX_TIMESTAMP(r_last_webmail) as r_last_webmail
@@ -163,6 +162,7 @@ class GoogleAppsAccount
         if ($account = $res->fetchOneAssoc()) {
             $this->sync_password = $account['l_sync_password'];
             $this->activate_mail_redirection = $account['l_activate_mail_redirection'];
+            $this->g_account_id = $account['g_account_id'];
             $this->g_status = $account['g_status'];
             $this->g_suspension = $account['g_suspension'];
             $this->r_disk_usage = $account['r_disk_usage'];
@@ -181,11 +181,10 @@ class GoogleAppsAccount
         }
     }
 
-    // Account object initialization methods.
+    // Determines if changes to the Google Account are currently waiting in the
+    // GApps job queue, and initializes the local values accordingly.
     private function load_pending_counts()
     {
-        // Determines if changes to the Google Account are currently waiting
-        // in the Google Apps queue.
         $res = XDB::query(
             "SELECT  SUM(j_type = 'u_create') AS pending_create,
                      SUM(j_type = 'u_update') AS pending_update,
@@ -206,6 +205,8 @@ class GoogleAppsAccount
         $this->pending_update_suspension = false;
     }
 
+    // Checks for unsuspend requests waiting for validation in plat/al
+    // validation queue.
     private function load_pending_validations()
     {
         require_once('validations.inc.php');
@@ -213,10 +214,11 @@ class GoogleAppsAccount
             Validate::get_typed_requests_count($this->uid, 'gapps-unsuspend');
     }
 
+    // Retrieves all the pending update job in the gappsd queue for the current
+    // user, and analyzes the scope of the update (ie. the fields in the user
+    // account which are going to be updated).
     private function load_pending_updates()
     {
-        // If updates are pending, determines their nature (more specifically:
-        // determines which part of the account is concerned).
         $res = XDB::iterator(
             "SELECT  j_parameters
                FROM  gapps_queue
@@ -240,7 +242,10 @@ class GoogleAppsAccount
     }
 
     // Creates a queue job of the @p type, for the user represented by this
-    // GoogleAppsAccount object, using @p parameters.
+    // GoogleAppsAccount object, using @p parameters. @p parameters is supposed
+    // to be a one-dimension array of key-value mappings.
+    // The created job as a 'normal' priority, and is scheduled for immediate
+    // execution.
     private function create_queue_job($type, $parameters) {
         $parameters["username"] = $this->g_account_name;
         XDB::execute(
@@ -255,21 +260,44 @@ class GoogleAppsAccount
             json_encode($parameters));
     }
 
+
+    // Returns true if the account is currently active.
+    public function active()
+    {
+        return $this->g_status == 'active';
+    }
+
+    // Returns true if the account exists in Google Apps.
+    public function provisioned()
+    {
+        return $this->g_status == 'active' or $this->g_status == 'disabled';
+    }
+
+    // Returns true if the account exists, but cannot be used (user-requested
+    // suspension, or Google-requested suspension).
+    public function suspended()
+    {
+        return $this->g_status == 'disabled';
+    }
+
+
     // Changes the GoogleApps password.
     public function set_password($password) {
-        if ($this->g_status == NULL || $this->g_status == 'unprovisioned') {
+        if (!$this->provisioned()) {
             return;
         }
 
         if (!$this->pending_update_password) {
             $this->create_queue_job('u_update', array('password' => $password));
+            $this->pending_update_password = true;
         }
     }
 
+
     // Changes the password synchronization status ("sync = true" means that the
     // Polytechnique.org password will be replicated to the Google Apps account).
     public function set_password_sync($sync) {
-        if ($this->g_status == NULL || $this->g_status == 'unprovisioned') {
+        if (!$this->provisioned()) {
             return;
         }
 
@@ -284,19 +312,24 @@ class GoogleAppsAccount
 
     // Suspends the Google Apps account.
     public function suspend() {
-        if ($this->g_status == NULL || $this->g_status == 'unprovisioned') {
+        if (!$this->provisioned()) {
             return;
         }
 
         if (!$this->pending_update_suspension) {
             $this->create_queue_job('u_update', array('suspended' => true));
             $this->pending_update_suspension = true;
+            XDB::execute(
+                "UPDATE  gapps_accounts
+                    SET  g_status = 'disabled'
+                  WHERE  g_account_name = {?} AND g_status = 'active'",
+                $this->g_account_name);
         }
     }
 
     // Adds an unsuspension request to the validation queue (used on user-request).
     public function unsuspend($activate_mail_redirection = NULL) {
-        if ($this->g_status == NULL || $this->g_status == 'unprovisioned') {
+        if (!$this->provisioned()) {
             return;
         }
         if ($activate_mail_redirection !== NULL) {
@@ -305,7 +338,8 @@ class GoogleAppsAccount
                 "UPDATE  gapps_accounts
                     SET  l_activate_mail_redirection = {?}
                   WHERE  g_account_name = {?}",
-                $activate_mail_redirection);
+                $activate_mail_redirection,
+                $this->g_account_name);
         }
 
         if (!$this->pending_update_suspension && !$this->pending_validation_unsuspend) {
@@ -319,7 +353,7 @@ class GoogleAppsAccount
     // Unsuspends the Google Apps account (used on admin-request, or on validation of
     // an user-request).
     public function do_unsuspend() {
-        if ($this->g_status == NULL || $this->g_status == 'unprovisioned') {
+        if (!$this->provisioned()) {
             return;
         }
 
@@ -346,7 +380,7 @@ class GoogleAppsAccount
         return false;
     }
 
-    // Adds a creation request in the job queue.
+    // Creates a new Google Apps account with the @p local parameters.
     public function create($password_sync, $password, $redirect_mails) {
         if ($this->g_status != NULL) {
             return;
@@ -361,7 +395,7 @@ class GoogleAppsAccount
                 $this->uid);
             list($nom, $nom_usage, $prenom) = $res->fetchOneRow();
 
-            // Adds an entry in the gapps_accounts table.
+            // Adds an 'unprovisioned' entry in the gapps_accounts table.
             XDB::execute(
                 "INSERT  INTO gapps_accounts
                     SET  l_userid = {?},
@@ -392,6 +426,26 @@ class GoogleAppsAccount
             $this->__construct($this->uid, $this->g_account_name);
         }
     }
+
+
+    // Returns the status of the Google Apps account for @p user, or false
+    // when no account exists.
+    static public function account_status($uid) {
+        $res = XDB::query(
+            "SELECT  g_status
+               FROM  gapps_accounts
+              WHERE  l_userid = {?}", $uid);
+        return ($res->numRows() > 0 ? $res->fetchOneCell() : false);
+    }
+
+    // Returns true if the @p user is an administrator of the Google Apps domain.
+    static public function is_administrator($uid) {
+        $res = XDB::query(
+            "SELECT  g_admin
+               FROM  gapps_accounts
+              WHERE  l_userid = {?} AND g_status = 'active'", $uid);
+        return ($res->numRows() > 0 ? (bool)$res->fetchOneRow() : false);
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 95ae89c..0bcf655 100644 (file)
@@ -82,7 +82,7 @@ function _select_notifs_base($table, $mail, $where)
     $sql = "
         (
             SELECT  u.promo, u.prenom, IF(u.nom_usage='',u.nom,u.nom_usage) AS nom,
-                    u.deces != 0 AS dcd,
+                    u.deces != 0 AS dcd, (u.flags = 'femme') AS sexe,
                     a.alias AS bestalias,
                     wo.*,
                     {$our['contact_sql']} AS contact,
@@ -90,7 +90,7 @@ function _select_notifs_base($table, $mail, $where)
     if ($mail) {
         $sql.=",
             w.uid AS aid, v.prenom AS aprenom, IF(v.nom_usage='',v.nom,v.nom_usage) AS anom,
-            b.alias AS abestalias, (v.flags='femme') AS sexe, q.core_mail_fmt AS mail_fmt";
+            b.alias AS abestalias, (v.flags='femme') AS asexe, q.core_mail_fmt AS mail_fmt";
     }
 
     $sql .= "
@@ -203,10 +203,10 @@ class AllNotifs
             $aid = $tmp['aid'];
             if (empty($this->_data[$aid])) {
                 $this->_data[$aid] = Array("prenom" => $tmp['aprenom'], 'nom' => $tmp['anom'],
-                    'bestalias'=>$tmp['abestalias'], 'sexe' => $tmp['sexe'], 'mail_fmt' => $tmp['mail_fmt'],
+                    'bestalias'=>$tmp['abestalias'], 'sexe' => $tmp['asexe'], 'mail_fmt' => $tmp['mail_fmt'],
                     'dcd'=>$tmp['dcd']);
             }
-            unset($tmp['aprenom'], $tmp['anom'], $tmp['abestalias'], $tmp['aid'], $tmp['sexe'], $tmp['mail_fmt'], $tmp['dcd']);
+            unset($tmp['aprenom'], $tmp['anom'], $tmp['abestalias'], $tmp['aid'], $tmp['asexe'], $tmp['mail_fmt'], $tmp['dcd']);
             $this->_data[$aid]['data'][$tmp['cid']][] = $tmp;
         }
     }
index 9dc4f86..89d63ca 100644 (file)
@@ -37,7 +37,8 @@ function init_rss($template, $alias, $hash, $require_uid = true)
     $res = XDB::query(
         'SELECT  a.id
            FROM  aliases         AS a
-     INNER JOIN  auth_user_quick AS q ON ( a.id = q.user_id AND q.core_rss_hash = {?} )
+     INNER JOIN  auth_user_md5   AS u ON (a.id = u.user_id AND u.perms IN ("admin", "user"))
+     INNER JOIN  auth_user_quick AS q ON (a.id = q.user_id AND q.core_rss_hash = {?})
           WHERE  a.alias = {?} AND a.type != "homonyme"', $hash, $alias);
     $uid = $res->fetchOneCell();
 
index 05da262..8a53e76 100644 (file)
@@ -48,7 +48,7 @@ function user_clear_all_subs($user_id, $really_del=true)
         $tables_to_clear['contact'] = array('contacts');
         XDB::execute("UPDATE auth_user_md5
                          SET date_ins = 0, promo_sortie = 0, nom_usage = '',  password = '', perms = 'pending',
-                             nationalite = '', cv = '', section = 0, date = 0, smtppass = ''
+                             nationalite = '', cv = '', section = 0, date = 0, smtppass = '', mail_storage = ''
                        WHERE user_id = {?}", $uid);
         XDB::execute("DELETE virtual.* FROM virtual INNER JOIN virtual_redirect AS r USING(vid) WHERE redirect = {?}",
                      $alias.'@'.$globals->mail->domain);
@@ -397,7 +397,7 @@ function &get_user_details($login, $from_uid = '', $view = 'private')
                        s.text AS section, p.x, p.y, p.pub AS photo_pub,
                        u.matricule_ax,
                        m.expertise != '' AS is_referent,
-                       COUNT(e.email) > 0 AS actif
+                       (COUNT(e.email) > 0 OR FIND_IN_SET('googleapps', u.mail_storage) > 0) AS actif
                  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 AND a.type='a_vie')
index 6392160..3829090 100644 (file)
@@ -186,7 +186,8 @@ class MinificheView extends MultipageView
                 ad1.text AS app1text, ad1.url AS app1url, ai1.type AS app1type,
                 adr.city, gp.a2, gp.pays AS countrytxt, gr.name AS region,
                 IF(u.nom_usage<>'',u.nom_usage,u.nom) AS sortkey,
-                COUNT(em.email) > 0 AS actif" . (S::logged() ? ", c.contact AS contact" : '');
+                (COUNT(em.email) > 0 OR FIND_IN_SET('googleapps', u.mail_storage) > 0) AS actif" .
+                (S::logged() ? ", c.contact AS contact" : '');
     }
 
     public function joins()
index c3ff4bf..26181b6 100644 (file)
@@ -92,6 +92,13 @@ class UsageReq extends Validate
             if ($this->nom_usage) {
                 $res .= "\n\n  Les alias {$this->alias}@{$globals->mail->domain} et @{$globals->mail->domain2} sont maintenant à ta disposition !";
             }
+            if ($globals->mailstorage->googleapps_domain) {
+                require_once 'googleapps.inc.php';
+                $account = new GoogleAppsAccount(S::v('uid'), S::v('forlife'));
+                if ($account->active()) {
+                    $res .= "\n\n  Si tu utilises Google Apps, tu peux changer ton nom d'usage sur https://mail.google.com/a/polytechnique.org/#settings/accounts";
+                }
+            }
             return $res;
         } else {
             return "  La demande de changement de nom d'usage que tu avais faite a été refusée.";
index 2c8c88a..b025e7a 100644 (file)
@@ -155,12 +155,14 @@ function soundex_fr($sIn)
     static $convVIn, $convVOut, $convGuIn, $convGuOut, $accents;
     if (!isset($convGuIn)) {
         global $uc_convert, $lc_convert;
-        $convGuIn  = array( 'GUI', 'GUE', 'GA', 'GO', 'GU', 'SC', 'CA', 'CO', 'CU', 'QU', 'Q', 'CC', 'CK', 'G', 'ST', 'PH');
-        $convGuOut = array( 'KI',  'KE',  'KA', 'KO', 'KU',  'SK', 'KA', 'KO', 'KU', 'K', 'K',  'K',  'K',  'J', 'T', 'F');
+        $convGuIn  = array( 'GUI', 'GUE', 'GA', 'GO', 'GU', 'SCI', 'SCE', 'SC', 'CA', 'CO',
+                            'CU', 'QU', 'Q', 'CC', 'CK', 'G', 'ST', 'PH');
+        $convGuOut = array( 'KI', 'KE', 'KA', 'KO', 'K', 'SI', 'SE', 'SK', 'KA', 'KO',
+                            'KU', 'K', 'K', 'K', 'K', 'J', 'T', 'F');
         $convVIn   = array( '/E?(AU)/', '/([EA])?[UI]([NM])([^EAIOUY]|$)/', '/[AE]O?[NM]([^AEIOUY]|$)/',
             '/[EA][IY]([NM]?[^NM]|$)/', '/(^|[^OEUIA])(OEU|OE|EU)([^OEUIA]|$)/', '/OI/',
             '/(ILLE?|I)/', '/O(U|W)/', '/O[NM]($|[^EAOUIY])/', '/(SC|S|C)H/',
-            '/([^AEIOUY1])[^AEIOUYLKTP]([UAO])([^AEIOUY])/', '/([^AEIOUY]|^)([AUO])[^AEIOUYLKTP]([^AEIOUY1])/', '/^KN/',
+            '/([^AEIOUY1])[^AEIOUYLKTPNR]([UAO])([^AEIOUY])/', '/([^AEIOUY]|^)([AUO])[^AEIOUYLKTP]([^AEIOUY1])/', '/^KN/',
             '/^PF/', '/C([^AEIOUY]|$)/',
             '/C/', '/Z$/', '/(?<!^)Z+/', '/ER$/', '/H/', '/W/');
         $convVOut  = array( 'O', '1\3', 'A\1',
@@ -190,7 +192,7 @@ function soundex_fr($sIn)
     // on réinterprète les voyelles
     $sIn = preg_replace( $convVIn, $convVOut, $sIn);
     // on supprime les terminaisons T, D, S, X (et le L qui précède si existe)
-    $sIn = preg_replace( '`L?[TDSX]$`', '', $sIn );
+    $sIn = preg_replace( '`L?[TDX]S?$`', '', $sIn );
     // on supprime les E, A et Y qui ne sont pas en première position
     $sIn = preg_replace( '`(?!^)Y([^AEOU]|$)`', '\1', $sIn);
     $sIn = preg_replace( '`(?!^)[EA]`', '', $sIn);
@@ -232,7 +234,14 @@ function make_forlife($prenom, $nom, $promo)
  */
 function ip_to_uint($ip)
 {
-    return ip2long($ip);
+    $part = explode('.', $ip);
+    $v = 0;
+    $fact = 0x1000000;
+    for ($i = 0 ; $i < 4 ; ++$i) {
+        $v += $fact * $part[$i];
+        $fact >>= 8;
+    }
+    return $v;
 }
 
 /** Convert uint to ip (to build a human understandable ip)
@@ -259,14 +268,16 @@ function check_ip($level)
         }
         $ips[] = $_SERVER['REMOTE_ADDR'];
         foreach ($ips as &$ip) {
-            $ip = "ip = " . ip_to_uint($ip);
+            $ip = '(ip & mask) = (' . ip_to_uint($ip) . '& mask)';
         }
-        $res = XDB::query('SELECT  state
+        $res = XDB::query('SELECT  state, description
                              FROM  ip_watch
                             WHERE  ' . implode(' OR ', $ips) . '
                          ORDER BY  state DESC');
         if ($res->numRows()) {
-            $_SESSION['check_ip'] = $res->fetchOneCell();
+            $state = $res->fetchOneAssoc();
+            $_SESSION['check_ip'] = $state['state'];
+            $_SESSION['check_ip_desc'] = $state['description'];
         } else {
             $_SESSION['check_ip'] = 'safe';
         }
@@ -304,8 +315,10 @@ function check_redirect($red = null)
     if (is_null($red)) {
         $red = new Redirect(S::v('uid'));
     }
-    $_SESSION['no_redirect'] = !$red->other_active('');
-    $_SESSION['mx_failures'] = $red->get_broken_mx();
+    if ($red->get_uid() == S::v('uid')) {
+        $_SESSION['no_redirect'] = !$red->other_active('');
+        $_SESSION['mx_failures'] = $red->get_broken_mx();
+    }
 }
 
 function send_warning_mail($title)
@@ -320,6 +333,12 @@ function send_warning_mail($title)
     $mailer->send();
 }
 
+function kill_sessions()
+{
+    assert(S::has_perms());
+    shell_exec('sudo -u root ' . dirname(dirname(__FILE__)) . '/bin/kill_sessions.sh');
+}
+
 
 /******************************************************************************
  * Dynamic configuration update/edition stuff
index b40e8fa..62f5d30 100644 (file)
@@ -317,13 +317,13 @@ function start_connexion ($uid, $identified)
 function set_skin()
 {
     global $globals;
-    if (S::logged() && !S::has('skin')) {
+    if (S::logged() && (!S::has('skin') || S::has('suid'))) {
         $uid = S::v('uid');
-    $res = XDB::query("SELECT  skin_tpl
-                             FROM  auth_user_quick AS a
-                       INNER JOIN  skins           AS s ON a.skin = s.id
-                            WHERE  user_id = {?} AND skin_tpl != ''", $uid);
-    if ($_SESSION['skin'] = $res->fetchOneCell()) {
+        $res = XDB::query("SELECT  skin_tpl
+                          FROM  auth_user_quick AS a
+                          INNER JOIN  skins           AS s ON a.skin = s.id
+                          WHERE  user_id = {?} AND skin_tpl != ''", $uid);
+        if ($_SESSION['skin'] = $res->fetchOneCell()) {
             return;
         }
     }
index 976be74..ef9fa0e 100644 (file)
@@ -460,7 +460,7 @@ class AdminModule extends PLModule
                         break;
                     case "clean_fwd":
                         if (!empty($val)) {
-                            $redirect->cleanErrors($val);
+                            $redirect->clean_errors($val);
                         }
                         break;
                     case "add_alias":
@@ -549,6 +549,11 @@ class AdminModule extends PLModule
                                          promo     = $promo,
                                          comment   = '".addslashes($comm)."'
                                    WHERE user_id = '{$mr['user_id']}'";
+                        if ($perms == 'disabled' && $old_fields['perms'] != 'disabled') {
+                            // A user has been banned ==> ensure his php session has been killed
+                            // This solution is ugly and overkill, but, it should be efficient.
+                            kill_sessions();
+                        }
                         if (XDB::execute($query)) {
                             user_reindex($mr['user_id']);
 
@@ -560,7 +565,7 @@ class AdminModule extends PLModule
                             $mailer->assign('old', $old_fields);
                             $mailer->assign('new', $new_fields);
                             $mailer->send();
-                            
+
                             // update number of subscribers (perms or deceased may have changed)
                             update_NbIns();
 
@@ -587,7 +592,7 @@ class AdminModule extends PLModule
                         if ($globals->mailstorage->googleapps_domain && Env::v('newpass_clair') != "********") {
                             require_once 'googleapps.inc.php';
                             $account = new GoogleAppsAccount($mr['user_id'], $mr['forlife']);
-                            if ($account->g_status == 'active' && $account->sync_password) {
+                            if ($account->active() && $account->sync_password) {
                                 $account->set_password($pass_encrypted);
                             }
                         }
@@ -1096,17 +1101,18 @@ class AdminModule extends PLModule
         switch (Post::v('action')) {
         case 'create':
             if (trim(Post::v('ipN')) != '') {
-                Xdb::execute('INSERT IGNORE INTO ip_watch (ip, state, detection, last, uid, description)
-                                          VALUES ({?}, {?}, CURDATE(), NOW(), {?}, {?})',
-                             ip_to_uint(trim(Post::v('ipN'))), Post::v('stateN'), S::i('uid'), Post::v('descriptionN'));
+                Xdb::execute('INSERT IGNORE INTO ip_watch (ip, mask, state, detection, last, uid, description)
+                                          VALUES ({?}, {?}, {?}, CURDATE(), NOW(), {?}, {?})',
+                             ip_to_uint(trim(Post::v('ipN'))), ip_to_uint(trim(Post::v('maskN'))),
+                             Post::v('stateN'), S::i('uid'), Post::v('descriptionN'));
             };
             break;
 
         case 'edit':
             Xdb::execute('UPDATE ip_watch
-                             SET state = {?}, last = NOW(), uid = {?}, description = {?}
+                             SET state = {?}, last = NOW(), uid = {?}, description = {?}, mask = {?}
                            WHERE ip = {?}', Post::v('stateN'), S::i('uid'), Post::v('descriptionN'),
-                          ip_to_uint(Post::v('ipN')));
+                          ip_to_uint(Post::v('maskN')), ip_to_uint(Post::v('ipN')));
             break;
 
         default:
@@ -1123,7 +1129,7 @@ class AdminModule extends PLModule
             $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.detection, w.state, a.alias AS forlife
+                            w.mask, w.detection, w.state, a.alias AS forlife
                       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)
@@ -1134,13 +1140,15 @@ class AdminModule extends PLModule
 
             $table = array();
             $props = array();
-            while (list($ip, $host, $date, $state, $forlife) = $it->next()) {
+            while (list($ip, $host, $mask, $date, $state, $forlife) = $it->next()) {
                 $ip = uint_to_ip($ip);
+                $mask = uint_to_ip($mask);
                 if (count($props) == 0 || $props['ip'] != $ip) {
                     if (count($props) > 0) {
                         $table[] = $props;
                     }
                     $props = array('ip'        => $ip,
+                                   'mask'      => $mask,
                                    'host'      => $host,
                                    'detection' => $date,
                                    'state'     => $state,
@@ -1154,7 +1162,7 @@ class AdminModule extends PLModule
             }
             $page->assign('table', $table);
         } elseif ($action == 'edit') {
-            $sql = "SELECT  w.detection, w.state, w.last, w.description,
+            $sql = "SELECT  w.detection, w.state, w.last, w.description, w.mask,
                             a1.alias AS edit, a2.alias AS forlife, s.host
                       FROM  ip_watch        AS w
                  LEFT JOIN  aliases         AS a1 ON (a1.id = w.uid AND a1.type = 'a_vie')
@@ -1166,9 +1174,10 @@ class AdminModule extends PLModule
             $it = Xdb::iterRow($sql, ip_to_uint($ip));
 
             $props = array();
-            while (list($detection, $state, $last, $description, $edit, $forlife, $host) = $it->next()) {
+            while (list($detection, $state, $last, $description, $mask, $edit, $forlife, $host) = $it->next()) {
                 if (count($props) == 0) {
                     $props = array('ip'          => $ip,
+                                   'mask'        => uint_to_ip($mask),
                                    'host'        => $host,
                                    'detection'   => $detection,
                                    'state'       => $state,
index 4e98a8f..f5bac89 100644 (file)
@@ -29,6 +29,7 @@ class CoreModule extends PLModule
             'login'       => $this->make_hook('login',      AUTH_COOKIE),
             'send_bug'    => $this->make_hook('bug', AUTH_COOKIE),
             'purge_cache' => $this->make_hook('purge_cache', AUTH_COOKIE, 'admin'),
+            'kill_sessions' => $this->make_hook('kill_sessions', AUTH_COOKIE, 'admin'),
             'get_rights'  => $this->make_hook('get_rights', AUTH_MDP, 'admin'),
 
             'wiki_help'    => $this->make_hook('wiki_help', AUTH_PUBLIC),
@@ -86,6 +87,11 @@ class CoreModule extends PLModule
         http_redirect(empty($_SERVER['HTTP_REFERER']) ? './' : $_SERVER['HTTP_REFERER']);
     }
 
+    function handler_kill_sessions(&$page)
+    {
+        kill_sessions();
+    }
+
     function handler_get_rights(&$page, $level)
     {
         if (S::has('suid')) {
index f35b354..63cd1ab 100644 (file)
@@ -42,6 +42,7 @@ class EmailModule extends PLModule
     function handler_emails(&$page, $action = null, $email = null)
     {
         global $globals;
+        require_once 'emails.inc.php';
 
         $page->changeTpl('emails/index.tpl');
         $page->assign('xorg_title','Polytechnique.org - Mes emails');
@@ -65,21 +66,12 @@ class EmailModule extends PLModule
               ORDER BY  LENGTH(alias)";
         $page->assign('aliases', XDB::iterator($sql, $uid));
 
-    $homonyme = XDB::query("SELECT alias FROM aliases INNER JOIN homonymes ON (id = homonyme_id) WHERE user_id = {?} AND type = 'homonyme'", $uid);
-    $page->assign('homonyme', $homonyme->fetchOneCell());
+        $homonyme = XDB::query("SELECT alias FROM aliases INNER JOIN homonymes ON (id = homonyme_id) WHERE user_id = {?} AND type = 'homonyme'", $uid);
+        $page->assign('homonyme', $homonyme->fetchOneCell());
 
         // Affichage des redirections de l'utilisateur.
-        $sql = "SELECT email
-                FROM emails
-                WHERE uid = {?} AND FIND_IN_SET('active', flags)";
-        $page->assign('mails', XDB::iterator($sql, $uid));
-
-        // Affichage des backends actifs de stockage des emails.
-        $sql = "SELECT  mail_storage
-                  FROM  auth_user_md5
-                 WHERE  user_id = {?}";
-        $storages = XDB::query($sql, $uid)->fetchOneCell();
-        $page->assign('storage', explode(',', $storages));
+        $redirect = new Redirect($uid);
+        $page->assign('mails', $redirect->active_emails());
 
         // on regarde si l'utilisateur a un alias et si oui on l'affiche !
         $forlife = S::v('forlife');
@@ -231,26 +223,6 @@ class EmailModule extends PLModule
             $redirect->modify_one_email_redirect($email, $rewrite);
         }
 
-        if ($action == 'storage') {
-            if ($email == 'imap') {
-                $storage = new MailStorageIMAP(S::v('uid'));
-            } else if ($email == 'googleapps') {
-                $storage = new MailStorageGoogleApps(S::v('uid'));
-            } else {
-                $storage = NULL;
-            }
-
-            if ($storage) {
-                $subaction = @func_get_arg(3);
-                if ($subaction == 'active') {
-                    $storage->enable();
-                }
-                if ($subaction == 'inactive') {
-                    $storage->disable();
-                }
-            }
-        }
-
         if (Env::has('emailop')) {
             $actifs = Env::v('emails_actifs', Array());
             print_r(Env::v('emails_rewrite'));
@@ -286,17 +258,8 @@ class EmailModule extends PLModule
         $page->assign('alias', $res->fetchAllAssoc());
         $page->assign('emails',$redirect->emails);
 
-        $res = XDB::query(
-                "SELECT  mail_storage
-                   FROM  auth_user_md5
-                  WHERE  user_id = {?}", $uid);
-        $page->assign('storage', explode(',', $res->fetchOneCell()));
-
-        $res = XDB::query(
-                "SELECT  g_status
-                   FROM  gapps_accounts
-                  WHERE  l_userid = {?}", $uid);
-        $page->assign('googleapps', ($res->numRows() > 0 ? $res->fetchOneCell() : false));
+        require_once 'googleapps.inc.php';
+        $page->assign('googleapps', GoogleAppsAccount::account_status($uid));
     }
 
     function handler_antispam(&$page, $statut_filtre = null)
@@ -309,7 +272,7 @@ class EmailModule extends PLModule
 
         $bogo = new Bogo(S::v('uid'));
         if (isset($statut_filtre)) {
-            $bogo->change(S::v('uid'), $statut_filtre + 0);
+            $bogo->change($statut_filtre + 0);
         }
         $page->assign('filtre',$bogo->level());
     }
@@ -458,22 +421,22 @@ class EmailModule extends PLModule
     function handler_test(&$page, $forlife = null)
     {
         global $globals;
+        require_once 'emails.inc.php';
+
         if (!S::has_perms() || !$forlife) {
             $forlife = S::v('bestalias');
         }
-        $mailer = new PlMailer('emails/test.mail.tpl');
-        $mailer->assign('email', $forlife . '@' . $globals->mail->domain);
-        $iterator = XDB::iterator("SELECT  email
-                                     FROM  emails AS e
-                               INNER JOIN  aliases AS a ON (e.uid = a.id)
-                                    WHERE  FIND_IN_SET('active', e.flags) AND a.alias = {?}",
-                                  $forlife);
-        $mailer->assign('redirects', $iterator);
-        $res = XDB::query("SELECT  FIND_IN_SET('femme', u.flags), prenom
+
+        $res = XDB::query("SELECT  FIND_IN_SET('femme', u.flags), prenom, user_id
                              FROM  auth_user_md5 AS u
                        INNER JOIN  aliases AS a ON (a.id = u.user_id)
                             WHERE  a.alias = {?}", $forlife);
-        list($sexe, $prenom) = $res->fetchOneRow();
+        list($sexe, $prenom, $uid) = $res->fetchOneRow();
+        $redirect = new Redirect($uid);
+
+        $mailer = new PlMailer('emails/test.mail.tpl');
+        $mailer->assign('email', $forlife . '@' . $globals->mail->domain);
+        $mailer->assign('redirects', $redirect->active_emails());
         $mailer->assign('sexe', $sexe);
         $mailer->assign('prenom', $prenom);
         $mailer->send();
@@ -666,12 +629,14 @@ L'équipe d'administration <support@" . $globals->mail->domain . '>';
         $page->changeTpl('emails/lost.tpl');
 
         $page->assign('lost_emails', XDB::iterator('
-          SELECT u.user_id, a.alias
-          FROM auth_user_md5 AS u
-            INNER JOIN aliases AS a ON (a.id = u.user_id AND a.type = "a_vie")
-            LEFT JOIN emails AS e ON (u.user_id=e.uid AND FIND_IN_SET("active",e.flags))
-          WHERE e.uid IS NULL AND u.deces = 0
-          ORDER BY u.promo DESC, u.nom, u.prenom'));
+            SELECT  u.user_id, a.alias
+              FROM  auth_user_md5 AS u
+        INNER JOIN  aliases AS a ON (a.id = u.user_id AND a.type = "a_vie")
+         LEFT JOIN  emails  AS e ON (u.user_id=e.uid AND FIND_IN_SET("active",e.flags))
+             WHERE  e.uid IS NULL AND
+                    FIND_IN_SET("googleapps", u.mail_storage) = 0 AND
+                    u.deces = 0
+          ORDER BY  u.promo DESC, u.nom, u.prenom'));
     }
 }
 
index f61d801..3354d85 100644 (file)
@@ -150,14 +150,14 @@ class ForumsModule extends PLModule
         $page->assign('xorg_title','Polytechnique.org - Administration - Bannissements des forums');
         $page->assign('title', 'Gestion des mises au ban');
         $table_editor = new PLTableEditor('admin/forums','forums.innd','id_innd');
-        $table_editor->describe('ipmin','min plage IP',true);
-        $table_editor->describe('ipmax','max plage IP',true);
-        $table_editor->describe('uid','utilisateur',true);
-        $table_editor->describe('write_perm','perm. poster',true);
-        $table_editor->describe('read_perm','perm. lire',true);
-        $table_editor->describe('priority','priorite',true);
+        $table_editor->add_sort_field('priority', true, true);
+        $table_editor->describe('read_perm','lecture',true);
+        $table_editor->describe('write_perm','écriture',true);
+        $table_editor->describe('priority','priorité',true);
         $table_editor->describe('comment','commentaire',true);
         $table_editor->apply($page, $action, $id);
+        $page->changeTpl('forums/admin.tpl');
+        $page->addJsLink('jquery.js');
     }
 
     static function run_banana(&$page, $params = null)
index 3da22f5..a78ab6c 100644 (file)
@@ -29,7 +29,10 @@ class GoogleAppsModule extends PLModule
         }
 
         return array(
-            'googleapps' => $this->make_hook('index', AUTH_MDP),
+            'googleapps'            => $this->make_hook('index', AUTH_MDP),
+            'admin/googleapps'      => $this->make_hook('admin', AUTH_MDP. 'admin'),
+            'admin/googleapps/job'  => $this->make_hook('admin_job', AUTH_MDP, 'admin'),
+            'admin/googleapps/user' => $this->make_hook('admin_user', AUTH_MDP, 'admin'),
         );
     }
 
@@ -47,12 +50,12 @@ class GoogleAppsModule extends PLModule
         $page->assign('redirect_active', false);
         $page->assign('redirect_unique', true);
 
-        if ($account->g_status == 'active') {
+        if ($account->active()) {
             $redirect = new Redirect(S::v('uid'));
-            $page->assign('redirect_unique', !$redirect->other_active(NULL));
+            $page->assign('redirect_unique', !$redirect->other_active('googleapps'));
 
-            $storage = new MailStorageGoogleApps(S::v('uid'));
-            $page->assign('redirect_active', $storage->active());
+            $storage = new EmailStorage(S::v('uid'), 'googleapps');
+            $page->assign('redirect_active', $storage->active);
         }
 
         // Updates the Google Apps account as required.
@@ -69,19 +72,18 @@ class GoogleAppsModule extends PLModule
                 }
             }
 
-            if ($action == 'suspend' && Post::has('suspend') && $account->g_status == 'active') {
+            if ($action == 'suspend' && Post::has('suspend') && $account->active()) {
                 if ($account->pending_update_suspension) {
                     $page->trig("Ton compte est déjà en cours de désactivation.");
                 } else {
-                    $storage = new MailStorageGoogleApps(S::v('uid'));
-                    if ($storage->disable()) {
+                    if ($redirect->modify_one_email('googleapps', false) == SUCCESS) {
                         $account->suspend();
                         $page->trig("Ton compte Google Apps est dorénavant désactivé.");
                     } else {
                         $page->trig("Ton compte Google Apps est ta seule adresse de redirection. Ton compte ne peux pas être désactivé.");
                     }
                 }
-            } elseif ($action == 'unsuspend' && Post::has('unsuspend') && $account->g_status == 'disabled') {
+            } elseif ($action == 'unsuspend' && Post::has('unsuspend') && $account->suspended()) {
                 $account->unsuspend(Post::b('redirect_mails', true));
                 $page->trig("Ta demande de réactivation a bien été prise en compte.");
             }
@@ -106,6 +108,113 @@ class GoogleAppsModule extends PLModule
 
         $page->assign('account', $account);
     }
+
+    function handler_admin(&$page, $action = null) {
+        require_once("googleapps.inc.php");
+        $page->changeTpl('googleapps/admin.tpl');
+        $page->assign('xorg_title', 'Polytechnique.org - Administration Google Apps');
+        $page->assign('googleapps_admin', GoogleAppsAccount::is_administrator(S::v('uid')));
+
+        if ($action == 'ack') {
+            $qid = @func_get_arg(2);
+            if ($qid) {
+                XDB::execute(
+                    "DELETE FROM  gapps_queue
+                           WHERE  q_id = {?} AND p_status = 'hardfail'", $qid);
+                $page->trig("La requête échouée a bien été retirée.");
+            }
+        }
+
+        // Retrieves latest pending administrative requests from the gappsd queue.
+        $res = XDB::iterator(
+            "SELECT  q_id, q_recipient_id, a.alias, j_type, j_parameters,
+                     UNIX_TIMESTAMP(q.p_entry_date) AS p_entry_date
+               FROM  gapps_queue AS q
+          LEFT JOIN  aliases AS a ON (a.id = q_recipient_id AND a.type = 'a_vie')
+              WHERE  p_status IN ('idle', 'active', 'softfail') AND
+                     p_admin_request IS TRUE
+           ORDER BY  p_entry_date");
+        while ($request = $res->next()) {
+            $j_parameters = json_decode($request['j_parameters'], true);
+            unset($j_parameters['username']);
+            $parameters = array_keys($j_parameters);
+            $request['parameters'] = implode(', ', $parameters);
+
+            $page->append('admin_requests', $request);
+        }
+
+        // Retrieves latest failed requests from the gappsd queue.
+        $res = XDB::iterator(
+            "SELECT  q.q_id, q.q_recipient_id, a.alias, q.j_type, q.r_result,
+                     UNIX_TIMESTAMP(q.p_entry_date) AS p_entry_date
+               FROM  gapps_queue AS q
+          LEFT JOIN  aliases AS a ON (a.id = q.q_recipient_id AND a.type = 'a_vie')
+              WHERE  q.p_status = 'hardfail'
+           ORDER BY  p_entry_date DESC
+              LIMIT  20");
+        $page->assign('failed_requests', $res);
+    }
+
+    function handler_admin_job(&$page, $job = null) {
+        require_once("googleapps.inc.php");
+        $page->changeTpl('googleapps/admin.job.tpl');
+        $page->assign('xorg_title', 'Polytechnique.org - Administration Google Apps');
+        $page->assign('googleapps_admin', GoogleAppsAccount::is_administrator(S::v('uid')));
+
+        if ($job) {
+            $res = XDB::query(
+                "SELECT  q.*, ao.alias AS q_owner, ar.alias AS q_recipient
+                   FROM  gapps_queue AS q
+              LEFT JOIN  aliases AS ao ON (ao.id = q.q_owner_id AND ao.type = 'a_vie')
+              LEFT JOIN  aliases AS ar ON (ar.id = q.q_recipient_id AND ar.type = 'a_vie')
+                  WHERE  q_id = {?}", $job);
+            $sql_job = $res->fetchOneAssoc();
+            $sql_job['decoded_parameters'] = var_export(json_decode($sql_job['j_parameters'], true), true);
+            $page->assign('job', $sql_job);
+        }
+    }
+
+    function handler_admin_user(&$page, $user = null, $action = null) {
+        require_once("emails.inc.php");
+        require_once("googleapps.inc.php");
+        $page->changeTpl('googleapps/admin.user.tpl');
+        $page->assign('xorg_title', 'Polytechnique.org - Administration Google Apps');
+        $page->assign('googleapps_admin', GoogleAppsAccount::is_administrator(S::v('uid')));
+
+        if (!$user && Post::has('login')) {
+            $user = Post::v('login');
+        }
+        if ($user && !is_numeric($user)) {
+            $res = XDB::query("SELECT id FROM aliases WHERE alias = {?} AND type != 'homonyme'", $user);
+            $user = $res->fetchOneCell();
+        }
+
+        if ($user) {
+            $account = new GoogleAppsAccount($user);
+            $storage = new EmailStorage($user, 'googleapps');
+
+            // Force synchronization of plat/al and Google Apps passwords.
+            if ($action == 'forcesync' && $account->sync_password) {
+                $res = XDB::query("SELECT password FROM auth_user_md5 WHERE user_id = {?}", $user);
+                $account->set_password($res->fetchOneCell());
+                $page->trig('Le mot de passe a été synchronisé.');
+            }
+
+            // Displays basic account information.
+            $page->assign('account', $account);
+            $page->assign('admin_account', GoogleAppsAccount::is_administrator($user));
+            $page->assign('googleapps_storage', $storage->active);
+            $page->assign('user', $user);
+
+            // Retrieves user's pending requests.
+            $res = XDB::iterator(
+                "SELECT  q_id, q_recipient_id, p_status, j_type, UNIX_TIMESTAMP(p_entry_date) AS p_entry_date
+                   FROM  gapps_queue
+                  WHERE  q_recipient_id = {?}
+               ORDER BY  p_entry_date DESC", $user);
+            $page->assign('requests', $res);
+        }
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 15858ce..c3a5abf 100644 (file)
@@ -29,10 +29,11 @@ function list_sort_owners(&$members, $tri_promo = true) {
     foreach($members as $mem) {
         list($m, $dom) = explode('@',$mem);
         if ($dom == $globals->mail->domain || $dom == $globals->mail->domain2) {
-            $res = XDB::query('SELECT  prenom, IF(nom_usage="", nom, nom_usage), promo, e.uid IS NULL
+            $res = XDB::query('SELECT  prenom, IF(nom_usage="", nom, nom_usage), promo,
+                                       (e.uid IS NULL AND FIND_IN_SET("googleapps", u.mail_storage) = 0)
                                  FROM  auth_user_md5 AS u
                            INNER JOIN  aliases AS a ON u.user_id = a.id
-                            LEFT JOIN  emails AS e ON ( e.flags = \'active\' AND e.uid = u.user_id)
+                            LEFT JOIN  emails AS e ON (e.flags = "active" AND e.uid = u.user_id)
                                 WHERE  a.alias = {?}
                              GROUP BY  u.user_id', $m);
             if(list($prenom, $nom, $promo, $broken) = $res->fetchOneRow()) {
index 997865e..23593c0 100644 (file)
@@ -179,7 +179,7 @@ class MarketingModule extends PLModule
 
         $res = Xdb::query("SELECT  u.nom, u.prenom, u.promo, FIND_IN_SET('femme', u.flags) AS sexe,
                                    u.deces = '0000-00-00' AS alive, a.alias AS forlife, b.alias AS bestalias,
-                                   e.email, e.last
+                                   IF(e.email IS NOT NULL, e.email, IF(FIND_IN_SET('googleapps', u.mail_storage), 'googleapps', NULL)) AS email, e.last
                              FROM  auth_user_md5 AS u
                        INNER JOIN  aliases       AS a ON (a.id = u.user_id AND a.type = 'a_vie')
                        INNER JOIN  aliases       AS b ON (b.id = u.user_id AND FIND_IN_SET('bestalias', b.flags))
index 1585214..0fb4c19 100644 (file)
@@ -202,7 +202,7 @@ class PlatalModule extends PLModule
             if ($globals->mailstorage->googleapps_domain) {
                 require_once 'googleapps.inc.php';
                 $account = new GoogleAppsAccount(S::v('uid'), S::v('forlife'));
-                if ($account->g_status == 'active' && $account->sync_password) {
+                if ($account->active() && $account->sync_password) {
                     $account->set_password($password);
                 }
             }
@@ -366,10 +366,8 @@ Adresse de secours : " . Post::v('email') : ""));
             // updates the Google Apps password as well.
             if ($globals->mailstorage->googleapps_domain) {
                 require_once 'googleapps.inc.php';
-                require_once 'user.func.inc.php';
-                $forlife = get_user_forlife($uid, '_silent_user_callback');
-                $account = new GoogleAppsAccount($uid, $forlife);
-                if ($account->g_status == 'active' && $account->sync_password) {
+                $account = new GoogleAppsAccount($uid);
+                if ($account->active() && $account->sync_password) {
                     $account->set_password($password);
                 }
             }
index fc6bd7d..bde1cf2 100644 (file)
@@ -190,27 +190,29 @@ class ProfileModule extends PLModule
                       WHERE  matricule={?}", $x);
             $login = $res->fetchOneCell();
         } else {
-            $login = get_user_forlife($x);
+            $login = get_user_forlife($x, S::logged() ? '_default_user_callback'
+                                                      : '_silent_user_callback');
         }
 
         if (empty($login)) {
-            if (preg_match('/([-a-z]+)\.([-a-z]+)\.([0-9]{4})/i', $x, $matches)) {
-                $matches = str_replace('-', '_', $matches);
-                $res = XDB::query("SELECT user_id
-                                     FROM auth_user_md5
-                                    WHERE prenom LIKE {?} AND nom LIKE {?} AND promo = {?}
-                                          AND perms = 'pending'",
-                                  $matches[1], $matches[2], $matches[3]);
-                if ($res->numRows() == 1) {
-                    $uid = $res->fetchOneCell();
-                    pl_redirect('marketing/public/' . $uid);
-                }
+            $user = get_not_registered_user($x, true);
+            if ($user->total() != 1) {
+                return PL_NOT_FOUND;
             }
-            return PL_NOT_FOUND;
+            $user = $user->next();
+            if (S::logged()) {
+                pl_redirect('marketing/public/' . $user['user_id']);
+            }
+            $user['forlife'] = $x;
+        } else {
+            $new   = Env::v('modif') == 'new';
+            $user  = get_user_details($login, S::v('uid'), $view);
+        }
+
+        if (S::logged()) {
+            $_SESSION['log']->log('view_profile', $login);
         }
 
-        $new   = Env::v('modif') == 'new';
-        $user  = get_user_details($login, S::v('uid'), $view);
         $title = $user['prenom'] . ' ' . ( empty($user['nom_usage']) ? $user['nom'] : $user['nom_usage'] );
         $page->assign('xorg_title', $title);
 
@@ -255,6 +257,7 @@ class ProfileModule extends PLModule
                 $user['forlife'].'@'.$globals->mail->domain,
                 $user['forlife'].'@'.$globals->mail->domain2);
         $page->assign('virtualalias', $res->fetchOneCell());
+        $page->assign('view', $view);
 
         $page->addJsLink('close_on_esc.js');
         header('Last-Modified: ' . date('r', strtotime($user['date'])));
index 24af93e..1af07e5 100644 (file)
@@ -161,20 +161,18 @@ class RegisterModule extends PLModule
                     }
 
                     // Check if the given email is known as dangerous
-                    $res = Xdb::iterRow("SELECT  w.state, w.description, a.alias
-                                           FROM  emails       AS e
-                                     INNER JOIN  emails_watch AS w ON (e.email = w.email AND w.state != 'safe')
-                                     INNER JOIN  aliases      AS a ON (e.uid = a.id AND a.type = 'a_vie')
-                                          WHERE  e.email = {?}
-                                       ORDER BY  a.alias", Post::v('email'));
-                    $aliases = array();
-                    while(list($gstate, $gdescription, $alias) = $res->next()) {
-                        $state       = $gstate;
-                        $description = $gdescription;
-                        $aliases[]   = $alias;
-                    }
-                    if (count($aliases) != 0) {
+                    $res = XDB::query("SELECT  w.state, w.description
+                                         FROM  emails_watch AS w
+                                        WHERE  w.email = {?} AND w.state != 'safe'",
+                                        Post::v('email'));
+                    $email_banned = false;
+                    if ($res->numRows()) {
+                        list($state, $description) = $res->fetchOneRow();
                         $alert .= "Email surveille propose a l'inscription - ";
+                        $sub_state['email_desc'] = $description;
+                        if ($state == 'dangerous') {
+                            $email_banned = true;
+                        }
                     }
                     if ($sub_state['watch']) {
                         $alter .= "Inscription d'un utilisateur surveillé - ";
@@ -193,12 +191,15 @@ class RegisterModule extends PLModule
                             $alert .= "Date de naissance incorrecte à l'inscription - ";
                         }
                         $sub_state['email']     = Post::v('email');
-                        if (check_ip('unsafe')) {
+                        $ip_banned = check_ip('unsafe');
+                        if ($ip_banned) {
+                            $alert .= "Tentative d'inscription depuis une IP surveillee";
+                        }
+                        if ($email_banned || $ip_banned) {
                             $err = "Une erreur s'est produite lors de l'inscription."
                                  . " Merci de contacter <a href='mailto:register@{$globals->mail->domain}>"
                                  . " register@{$globals->mail->domain}</a>"
                                  . " pour nous faire part de cette erreur";
-                            $alert .= "Tentative d'inscription depuis une IP surveillee";
                         } else {
                             $sub_state['step'] = 4;
                             if (count($sub_state['backs']) >= 3) {
@@ -403,7 +404,7 @@ class RegisterModule extends PLModule
             if ($globals->mailstorage->googleapps_domain) {
                 require_once 'googleapps.inc.php';
                 $account = new GoogleAppsAccount(S::v('uid'), S::v('forlife'));
-                if ($account->g_status == 'active' && $account->sync_password) {
+                if ($account->active() && $account->sync_password) {
                     $account->set_password($password);
                 }
             }
@@ -482,8 +483,8 @@ class RegisterModule extends PLModule
         }
         if (Post::v('imap')) {
             require_once 'emails.inc.php';
-            $storage = new MailStorageIMAP(S::v('uid'));
-            $storage->enable();
+            $storage = new EmailStorage(S::v('uid'), 'imap');
+            $storage->activate();
         }
 
         pl_redirect('profile/edit');
index f74b4f5..a708d12 100644 (file)
@@ -89,6 +89,9 @@ class SearchModule extends PLModule
 
         if (Env::has('quick') || $action == 'geoloc') {
             $quick = trim(Env::v('quick'));
+            if (S::logged() && !Env::has('page')) {
+                $_SESSION['log']->log('search', 'quick=' . $quick);
+            }
             $list = 'profile|prf|fiche|fic|referent|ref|mentor';
             if (S::has_perms()) {
                 $list .= '|admin|adm|ax';
@@ -180,6 +183,9 @@ class SearchModule extends PLModule
                 'school' => array('field' => 'id', 'table' => 'applis_def', 'text' => 'text', 'exact' => false),
                 'city' => array('table' => 'geoloc_city', 'text' => 'name', 'exact' => false)
             );
+            if (!Env::has('page')) {
+                $_SESSION['log']->log('search', 'adv=' . var_export($_GET, true));
+            }
             foreach ($textFields as $field=>&$query) {
                 if (!Env::v($field) && Env::v($field . 'Txt')) {
                     $res = XDB::query("SELECT  {$query['field']}
index ea58298..49cb896 100644 (file)
@@ -36,7 +36,7 @@ require_once("xorg.misc.inc.php");
     ad1.text AS app1text, ad1.url AS app1url, ai1.type AS app1type,
     es.label AS secteur, ef.fonction_fr AS fonction,
     IF(n.nat=\'\',n.pays,n.nat) AS nat, n.a2 AS iso3166,
-    COUNT(em.email) > 0 AS actif,';
+    (COUNT(em.email) > 0 OR FIND_IN_SET("googleapps", u.mail_storage) > 0) AS actif,';
 // hide private information if not logged
 if (S::logged())
     $globals->search->result_fields .='
index 6d97fcd..f5c6c17 100644 (file)
@@ -42,6 +42,7 @@ class StatsModule extends PLModule
             'stats/graph/evolution'
                               => $this->make_hook('graph_evo', AUTH_COOKIE),
             'stats/promos'    => $this->make_hook('promos',    AUTH_COOKIE),
+            'stats/profile'   => $this->make_hook('profile',   AUTH_COOKIE),
 
             'stats/coupures'  => $this->make_hook('coupures',  AUTH_PUBLIC),
         );
@@ -295,6 +296,30 @@ EOF2;
             $page->assign('mxs', $res);
         }
     }
+
+    function handler_profile(&$page, $period = 'overall')
+    {
+        $page->changeTpl('stats/profile.tpl');
+
+        $time = '';
+        switch ($period) {
+          case 'week': case 'month': case 'year':
+            $time = ' AND e.stamp > DATE_SUB(CURDATE(), INTERVAL 1 ' . strtoupper($period) . ')';
+            break;
+        }
+        $rows = XDB::iterator("SELECT  IF(u.nom_usage != '', u.nom_usage, u.nom) AS nom,
+                                       u.prenom, u.promo, e.data AS forlife, COUNT(*) AS count
+                                 FROM  logger.events AS e
+                           INNER JOIN  logger.actions AS act ON (e.action = act.id)
+                           INNER JOIN  aliases AS a ON (a.alias = e.data)
+                           INNER JOIN  auth_user_md5 AS u ON (u.user_id = a.id)
+                                WHERE  act.text = 'view_profile' $time
+                             GROUP BY  e.data
+                             ORDER BY  count DESC
+                                LIMIT  10");
+        $page->assign('profiles', $rows);
+        $page->assign('period', $period);
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 3910dbc..056ca5a 100644 (file)
@@ -127,13 +127,18 @@ class XnetEventsModule extends PLModule
              LEFT JOIN  groupex.evenements_participants AS ep ON (ep.eid = e.eid AND ep.uid = {?})
                  WHERE  asso_id = {?}
                    AND  archive = " . ($archive ? "1 " : "0 ")
-            . (is_member() || may_update() ? "" : " AND accept_nonmembre != 0 ")
               . "GROUP BY  e.eid
                  ORDER BY  inscr_open DESC, debut DESC", S::v('uid'), $globals->asso('id'));
 
         $evts = array();
+        $undisplayed_events = 0;
 
         while ($e = $evenements->next()) {
+            if (!is_member() && !may_update() && !$e['accept_nonmembre']) {
+                $undisplayed_events ++;
+                continue;
+            }
+
             $e['show_participants'] = ($e['show_participants'] && (is_member() || may_update()));
             $res = XDB::query(
                 "SELECT titre, details, montant, ei.item_id, nb, ep.paid
@@ -168,6 +173,7 @@ class XnetEventsModule extends PLModule
         }
 
         $page->assign('evenements', $evts);
+        $page->assign('undisplayed_events', $undisplayed_events);
     }
 
     function handler_sub(&$page, $eid = null)
index 794fdc7..79496d2 100644 (file)
@@ -209,7 +209,7 @@ class XnetGrpModule extends PLModule
         global $globals;
         $site = $globals->asso('site');
         if (!$site) {
-            $page->trig('Le groupe n\'a pas de site web');
+            $page->trig('Le groupe n\'a pas de site web.');
             return $this->handler_index($page);
         }
         http_redirect($site);
@@ -432,7 +432,7 @@ class XnetGrpModule extends PLModule
                            m.perms='admin' AS admin,
                            m.origine='X' AS x,
                            u.perms!='pending' AS inscrit,
-                           m.uid, IF(e.email IS NULL,NULL,1) AS actif
+                           m.uid, IF(e.email IS NULL AND FIND_IN_SET('googleapps', u.mail_storage) = 0, NULL, 1) AS actif
                      FROM  groupex.membres AS m
                 LEFT JOIN  auth_user_md5   AS u ON ( u.user_id = m.uid )
                 LEFT JOIN  aliases         AS a ON ( a.id = m.uid AND a.type='a_vie' )
@@ -510,10 +510,11 @@ class XnetGrpModule extends PLModule
                              . "j'ai le plaisir de t'annoncer que ton inscription a été validée !\n"
                              . "\n"
                              . "Bien cordialement,\n"
+                             . "-- \n"
                              . "{$_SESSION["prenom"]} {$_SESSION["nom"]}.";
                     $mailer->setTxtBody($message);
                     $mailer->send();
-                    $page->kill("$prenom $nom a bien été inscrit" . ($sexe ? 'e' : '') . ".");
+                    pl_redirect("member/$u");
                 }
                 elseif (Env::has('refuse'))
                 {
@@ -524,7 +525,7 @@ class XnetGrpModule extends PLModule
                     $mailer->setSubject('['.$globals->asso('nom').'] Demande d\'inscription annulée');
                     $mailer->setTxtBody(Env::v('motif'));
                     $mailer->send();
-                    $page->kill("la demande $prenom $nom a bien été refusée");
+                    $page->kill("La demande de $prenom $nom a bien été refusée.");
                 } else {
                     $page->assign('show_form', true);
                     $page->assign('prenom', $prenom);
@@ -538,7 +539,7 @@ class XnetGrpModule extends PLModule
         }
 
         if (is_member()) {
-            $page->kill("tu es déjà membre !");
+            $page->kill("Tu es déjà membre !");
             return;
         }
 
@@ -722,7 +723,7 @@ class XnetGrpModule extends PLModule
                     pl_redirect("member/$email");
                 }
             } else {
-                $page->trig("« <strong>$email</strong> » n'est pas une adresse mail valide");
+                $page->trig("« <strong>$email</strong> » n'est pas une adresse mail valide.");
             }
         }
     }
@@ -857,10 +858,10 @@ class XnetGrpModule extends PLModule
         if ($res->numRows() == 0) {
             $x = get_not_registered_user($login);
             if (!$x) {
-                $page->trig("Le login $login ne correspond à aucun X");
+                $page->trig("Le login $login ne correspond à aucun X.");
                 return false;
             } else if (count($x) > 1) {
-                $page->trig("Le login $login correspond a plusieurs camarades");
+                $page->trig("Le login $login correspond a plusieurs camarades.");
                 return false;
             }
             $uid = $x[0]['user_id'];
@@ -959,7 +960,7 @@ class XnetGrpModule extends PLModule
                             $perms ? 'admin' : 'membre',
                             $user['uid'], $globals->asso('id'));
                 $user['perms'] = $perms;
-                $page->trig('permissions modifiées');
+                $page->trig('Permissions modifiées !');
             }
 
             // Update ML subscriptions
@@ -968,7 +969,7 @@ class XnetGrpModule extends PLModule
                 if ($ask == $state) {
                     if ($state && $email_changed) {
                         $mmlist->replace_email($ml, $from_email, $user['email2']);
-                        $page->trig("L'abonnement de {$user['prenom']} {$user['nom']} à $ml@ a été mis à jour");
+                        $page->trig("L'abonnement de {$user['prenom']} {$user['nom']} à $ml@ a été mis à jour.");
                     }
                     continue;
                 }
@@ -978,14 +979,14 @@ class XnetGrpModule extends PLModule
                                ."cours sur <strong>$ml@</strong> !!!");
                 } elseif ($ask) {
                     $mmlist->mass_subscribe($ml, Array($user['email2']));
-                    $page->trig("{$user['prenom']} {$user['nom']} a été abonné à $ml@");
+                    $page->trig("{$user['prenom']} {$user['nom']} a été abonné à $ml@.");
                 } else {
                     if ($email_changed) {
                         $mmlist->mass_unsubscribe($ml, Array($from_email));
                     } else {
                         $mmlist->mass_unsubscribe($ml, Array($user['email2']));
                     }
-                    $page->trig("{$user['prenom']} {$user['nom']} a été désabonné de $ml@");
+                    $page->trig("{$user['prenom']} {$user['nom']} a été désabonné de $ml@.");
                 }
             }
 
@@ -997,14 +998,14 @@ class XnetGrpModule extends PLModule
                     XDB::query("INSERT INTO  virtual_redirect (vid,redirect)
                                      SELECT  vid,{?} FROM virtual WHERE alias={?}",
                                $user['email'], $ml);
-                    $page->trig("{$user['prenom']} {$user['nom']} a été abonné à $ml");
+                    $page->trig("{$user['prenom']} {$user['nom']} a été abonné à $ml.");
                 } else {
                     XDB::query("DELETE FROM  virtual_redirect
                                       USING  virtual_redirect
                                  INNER JOIN  virtual USING(vid)
                                       WHERE  redirect={?} AND alias={?}",
                                $user['email'], $ml);
-                    $page->trig("{$user['prenom']} {$user['nom']} a été désabonné de $ml");
+                    $page->trig("{$user['prenom']} {$user['nom']} a été désabonné de $ml.");
                 }
             }
         }
@@ -1131,12 +1132,12 @@ class XnetGrpModule extends PLModule
                  ($art['promo_min'] != 0 && ($art['promo_min'] <= 1900 || $art['promo_min'] >= 2020)) ||
                  ($art['promo_max'] != 0 && ($art['promo_max'] <= 1900 || $art['promo_max'] >= 2020))))
             {
-                $page->trig("L'intervalle de promotions est invalide");
+                $page->trig("L'intervalle de promotions est invalide.");
                 Post::kill('valid');
             }
 
             if (!trim($art['titre']) || !trim($art['texte'])) {
-                $page->trig("L'article doit avoir un titre et un contenu");
+                $page->trig("L'article doit avoir un titre et un contenu.");
                 Post::kill('valid');
             }
 
@@ -1195,7 +1196,7 @@ class XnetGrpModule extends PLModule
                                     $art['promo_min'], $art['promo_max'], $art['peremption'], "", S::v('uid'),
                                     $upload);
                     $article->submit();
-                    $page->trig("L'affichage sur la page d'accueil de Polytechnique.org est en attente de validation");
+                    $page->trig("L'affichage sur la page d'accueil de Polytechnique.org est en attente de validation.");
                 } else if ($upload && $upload->exists()) {
                     $upload->rm();
                 }
@@ -1204,7 +1205,7 @@ class XnetGrpModule extends PLModule
                     $article = new NLReq(S::v('uid'), $globals->asso('nom') . " : " .$art['titre'],
                                          $art['texte'], $art['contact_html']);
                     $article->submit();
-                    $page->trig("La parution dans la Lettre Mensuelle est en attente de validation");
+                    $page->trig("La parution dans la Lettre Mensuelle est en attente de validation.");
                 }
             } else {
                 XDB::query("UPDATE groupex.announces
@@ -1240,7 +1241,7 @@ class XnetGrpModule extends PLModule
                 $art = $res->fetchOneAssoc();
                 $art['contact_html'] = $art['contacts'];
             } else {
-                $page->kill("Aucun article correspond à l'identifiant indiqué");
+                $page->kill("Aucun article correspond à l'identifiant indiqué.");
             }
         }
 
diff --git a/plugins/function.make_forlife.php b/plugins/function.make_forlife.php
new file mode 100644 (file)
index 0000000..8578f90
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2008 Polytechnique.org                              *
+ *  http://opensource.polytechnique.org/                                   *
+ *                                                                         *
+ *  This program is free software; you can redistribute it and/or modify   *
+ *  it under the terms of the GNU General Public License as published by   *
+ *  the Free Software Foundation; either version 2 of the License, or      *
+ *  (at your option) any later version.                                    *
+ *                                                                         *
+ *  This program is distributed in the hope that it will be useful,        *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *  GNU General Public License for more details.                           *
+ *                                                                         *
+ *  You should have received a copy of the GNU General Public License      *
+ *  along with this program; if not, write to the Free Software            *
+ *  Foundation, Inc.,                                                      *
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
+ ***************************************************************************/
+require_once 'platal.inc.php';
+
+function smarty_function_make_forlife($params, &$smarty)
+{
+  return make_forlife($params['nom'], $params['prenom'], $params['promo']);
+}
+
+/* vim: set expandtab enc=utf-8: */
+?>
index 947c86c..ae30afc 100644 (file)
@@ -41,7 +41,7 @@
   {foreach from=$table item=ip}
   <tr class="{cycle values="pair,impair"}">
     <td>
-      <strong>{$ip.ip}</strong><br />
+      <strong>{$ip.ip}/{$ip.mask}</strong><br />
       <small>{$ip.host}</small><br />
       Ajoutée le {$ip.detection|date_format}
     </td>
   {/if}
   </tr>
   <tr class="pair">
+    <td class="titre">Masque d'influence</td>
+    <td><input type="text" name="maskN" value="{$ip.mask}" /></td>
+  </tr>
+  <tr class="pair">
     <td class="titre">Danger</td>
     <td>
       <select name="stateN">
index 33859af..cca5bc1 100644 (file)
@@ -316,6 +316,8 @@ Pour ceci changer ses permissions en 'disabled'.
   </table>
 </form>
 
+<p><strong>* à ne modifier qu'avec l'accord express de l'utilisateur !!!</strong></p>
+
 <form id="bans" method="post" action="admin/user">
   <table cellspacing="0" cellpadding="2" class="tinybicol">
     <tr>
@@ -325,10 +327,10 @@ Pour ceci changer ses permissions en 'disabled'.
     </tr>
     <tr class="impair">
       <td class="titre">
-        Poster :
+        Poster
       </td>
       <td>
-        <input type="text" name="write_perm" size="40" maxlength="255" value="{$bans.write_perm}" />
+        <input type="text" name="write_perm" size="32" maxlength="255" value="{$bans.write_perm}" />
       </td>
       <td class="action">
         <a href="javascript:ban_write()">Bannir</a>
@@ -336,10 +338,10 @@ Pour ceci changer ses permissions en 'disabled'.
     </tr>
     <tr class="pair">
       <td class="titre">
-        Lire :
+        Lire
       </td>
       <td>
-        <input type="text" name="read_perm" size="40" maxlength="255" value="{$bans.read_perm}" />
+        <input type="text" name="read_perm" size="32" maxlength="255" value="{$bans.read_perm}" />
       </td>
       <td class="action">
         <a href="javascript:ban_read()">Bannir</a>
@@ -349,10 +351,9 @@ Pour ceci changer ses permissions en 'disabled'.
       <td class="titre">
         Commentaire
       </td>
-      <td>
+      <td colspan="2">
         <input type="text" name="comment" size="40" maxlength="255" value="{$bans.comment}" />
       </td>
-      <td/>
     </tr>
     <tr class="center">
       <td colspan="3">
@@ -363,10 +364,6 @@ Pour ceci changer ses permissions en 'disabled'.
   </table>
 </form>
 
-<p>
-<strong>* à ne modifier qu'avec l'accord express de l'utilisateur !!!</strong>
-</p>
-
 {javascript name="ajax"}
 {test_email forlife=$mr.forlife}
 
@@ -377,14 +374,14 @@ Pour ceci changer ses permissions en 'disabled'.
         Redirections
       </th>
     </tr>
-    {assign var=actives value=false} 
-    {assign var=disabled value=false} 
+    {assign var=actives value=false}
+    {assign var=disabled value=false}
     {foreach item=mail from=$emails}
     {cycle assign=class values="impair,pair"}
     <tr class="{$class}">
-      {if $mail->active}
+      {if $mail->active && $mail->has_disable()}
         {assign var=actives value=true}
-      {elseif $mail->disabled}
+      {elseif $mail->disabled && $mail->has_disable()}
         {assign var=disabled value=true}
       {/if}
       <td class="titre">
@@ -401,18 +398,20 @@ Pour ceci changer ses permissions en 'disabled'.
       </td>
       <td>
         {if $mail->broken}<span style="color: #f00">{/if}
-        {$mail->email}
+        {$mail->display_email}
         {if $mail->broken}<em> (en panne)</em></span>{/if}
       </td>
       <td class="action">
+        {if $mail->is_removable()}
         <a href="javascript:del_fwd('{$mail->email}')">delete</a>
+        {/if}
       </td>
     </tr>
     {if $mail->panne && $mail->panne neq "0000-00-00"}
     <tr class="{$class}">
       <td colspan="3" class="smaller" style="color: #f00">
         {icon name=error title="Panne"}
-        Panne de {$mail->email} le {$mail->panne|date_format}
+        Panne de {$mail->display_email} le {$mail->panne|date_format}
         {if $mail->panne neq $mail->last}confirmée le {$mail->last|date_format}{/if}
       </td>
       <td class="action">
index 3f226f3..040473b 100644 (file)
@@ -23,9 +23,8 @@
 {javascript name="jquery"}
 <script type="text/javascript">//<![CDATA[
 {literal}
-function activateField(name, id, obj) {
-  $("#" + name + "_" + id).show();
-  return true;
+function toggleField(name, id, obj) {
+  $("#" + name + "_" + id).toggle();
 }
 {/literal}
 //]]></script>
@@ -61,14 +60,14 @@ function activateField(name, id, obj) {
   </tr>
   {include file=$valid->formu()}
   {if $valid->editor()}
-  <tr>
+  <tr onclick="toggleField('edit', '{$valid->id()}')" style="cursor: pointer">
     <th colspan="2">
-     {if $preview_id neq $valid->id()}
+      {if $preview_id neq $valid->id()}
       <div style="float: left">
-        <a href="javascript:activateField('edit', '{$valid->id()}')">{icon name="add"}</a>
+        {icon name="add"}
       </div>
       {/if}
-      Editer
+      Éditer
     </th>
   </tr>
   <tr {if $preview_id neq $valid->id()}style="display: none"{/if} id="edit_{$valid->id()}">
@@ -80,17 +79,17 @@ function activateField(name, id, obj) {
           <input type="hidden" name="type"   value="{$valid->type}" />
           <input type="hidden" name="stamp"  value="{$valid->stamp}" />
           <br />
-          <input type="submit" name="edit"   value="Editer" />
+          <input type="submit" name="edit"   value="Éditer" />
         </div>
       </form>
     </td>
   </tr>
   {/if}
-  <tr>
+  <tr onclick="toggleField('comment', '{$valid->id()}')" style="cursor: pointer">
     <th colspan='2'>
       {if $valid->comments|@count eq 0}
       <div style="float: left">
-        <a href="javascript:activateField('comment', '{$valid->id()}')">{icon name="add"}</a>
+        {icon name="add"}
       </div>
       {/if}
       Commentaires
@@ -119,7 +118,16 @@ function activateField(name, id, obj) {
       </form>
     </td>
   </tr>
-  <tr><th colspan='2'>Réponse</th></tr>
+  <tr>
+    <th colspan='2'>
+      {if $preview_id neq $valid->id()}
+      <div style="float: left">
+        {icon name="null"}
+      </div>
+      {/if}
+      Réponse
+    </th>
+  </tr>
   <tr>
     <td colspan='2' {popup caption="Règles de validation" text=$valid->ruleText()}>
       <form action="admin/validate" method="post">
@@ -131,7 +139,7 @@ function activateField(name, id, obj) {
               <option value="{$automatic_answer.answer}">{$automatic_answer.title}</option>
             {/foreach}
           </select>
-          <a href="admin/validate/answers">{icon name="page_edit" title="Editer les réponses automatiques"}</a>
+          <a href="admin/validate/answers">{icon name="page_edit" title="Éditer les réponses automatiques"}</a>
         </div>
         <div class='center'>
           Ajouté dans l'email&nbsp;:<br />
index 3f0bb05..5ae5706 100644 (file)
 --------------------------------------------------------------------
 Cette lettre est envoyée par l'AX grâce aux outils de Polytechnique.org.
 
+{if $is_mail}
 archives         : <https://www.polytechnique.org/ax>
 ne plus recevoir : <https://www.polytechnique.org/ax/out{if $hash}/{$hash}{/if}>
+{else}
+archives         : &lt;https://www.polytechnique.org/ax&gt;
+ne plus recevoir : &lt;https://www.polytechnique.org/ax/out{if $hash}/{$hash}{/if}&gt;
+{/if}
 
 {if !$is_mail}
 </pre>
index c85689b..16f9942 100644 (file)
@@ -51,7 +51,7 @@
   <tr><th>{$am->title(true)}</th></tr>
   <tr>
     <td>
-      {include file="axletter/letter.tpl"}
+      {include file="axletter/letter.mail.tpl"}
     </td>
   </tr>
 </table>
index 3f132e2..829e12e 100644 (file)
@@ -35,17 +35,17 @@ Tu trouveras les mêmes informations sur [[https://www.polytechnique.org/carnet/
 
 {foreach from=$u.data key=cid item=d}
 
-!{if $d|@count eq 1}{$cats[$cid].mail_sg}{else}{$cats[$cid].mail}{/if}&nbsp;:
+!{if $d|@count eq 1}{if $d[0].sexe}{$cats[$cid].mail_sg_xette}{else}{$cats[$cid].mail_sg}{/if}{else}{$cats[$cid].mail}{/if}:
 
-{foreach from=$d key=promo item=x}
-* (X{$x.promo}), le {$x.date|date_format:"%d %b %Y"}, [[https://www.polytechnique.org/profile/private/{$x.bestalias}|{$x.prenom} {$x.nom}]]
+{foreach from=$d item=x}
+* (X{$x.promo}), le {$x.date|date_format:"%d %B %Y"}, [[https://www.polytechnique.org/profile/private/{$x.bestalias}|{$x.prenom} {$x.nom}]]
 {/foreach}
 
 {/foreach}
--- 
+--
 L'Équipe de Polytechnique.org
 
-'''''Note&nbsp;:'''''  Tu reçois ce mail ce mail car tu as activé la notification automatique par mail des événements que tu surveilles.\\
+'''''Note:'''''  Tu reçois ce mail ce mail car tu as activé la notification automatique par mail des événements que tu surveilles.\\
 Tu peux changer cette options sur la [[https://www.polytechnique.org/carnet/notifs|page de configuration des notifications]].
 
 {/if}
index f7baa37..541a5da 100644 (file)
@@ -51,7 +51,11 @@ Il faut pour cela se rendre sur la page de <a href='carnet/notifs'>configuration
     {if ($promo|@count) > 1}
       {$notifs->_cats[$cid].mail}&nbsp;:
     {else}
-      {$notifs->_cats[$cid].mail_sg}&nbsp;:
+      {if $promo[0].sexe}
+        {$notifs->_cats[$cid].mail_sg_xette}&nbsp;:
+      {else}
+        {$notifs->_cats[$cid].mail_sg}&nbsp;:
+      {/if}
     {/if}
   {/foreach}
 {/if}</h2>
@@ -80,7 +84,7 @@ Il faut pour cela se rendre sur la page de <a href='carnet/notifs'>configuration
       {$promo[row].date|date_format}
     </td>
     {if $promo[row].data}
-    <tr><td>{$promo[row].data|smarty:nodefaults}</td></tr>
+    </tr><tr><td>{$promo[row].data|smarty:nodefaults}</td>
     {/if}
   </tr>
   {/section}
index c65f3b2..23dfe8d 100644 (file)
@@ -43,33 +43,12 @@ Si tu n'es pas {insert name="getName"}, change le login ci-dessous, ou rends-toi
 </p>
 {/if}
 
-{if !$smarty.session.auth}
-<p>
-<strong>Tu ne connais pas ton mot de passe ?</strong>
-</p>
-<ul>
-  <li>
-  Si tu viens de terminer ta pré-inscription, <strong>il est dans le mail</strong> que
-  nous t'avons envoyé (expéditeur pre-inscription@{#globals.mail.domain#}).
-  </li>
-  <li>
-  Si tu n'es jamais venu sur le site, <strong>il faut t'enregistrer auprès de
-    nous</strong> pour obtenir un accès. {#globals.core.sitename#} c'est l'e-mail des X,
-  l'annuaire en ligne, plus un tas d'autres services.  Nous te fournirons un accès le plus
-  rapidement possible. <strong> <a href="register/">Clique ici pour nous demander tes
-      paramètres personnels.</a></strong>
-  </li>
-</ul>
-{/if}
-
 {if $smarty.request.response}<!-- failed login code //-->
-<br />
 <div class="erreur">
   Erreur d'identification. Essaie à nouveau !
 </div>
-{/if}
-
 <br />
+{/if}
 
 <form action="{$smarty.server.REQUEST_URI}" method="post" id="login" onsubmit="doChallengeResponse(); return false;" style="display: none">
   <table class="bicol" cellpadding="4" summary="Formulaire de login">
@@ -105,14 +84,17 @@ Si tu n'es pas {insert name="getName"}, change le login ci-dessous, ou rends-toi
     <tr>
       <td></td>
       <td>
-        <input type="checkbox" name="remember" id="remember" /><label for="remember">Garder l'accès aux services après déconnexion</label>
-      </td>
-    </tr>
-    <tr>
-      <td></td>
-      <td>
-        Coche la case ci-dessus pour être automatiquement reconnu lors de ta prochaine connexion depuis cet ordinateur.
-        Il n'est pas conseillé de la cocher si cette machine n'est pas <b>strictement</b> personnelle.
+        <script type="text/javascript">{literal}
+          function confirm_remember(input) {
+            if (input.checked && !confirm('Cocher cette case te permet d\'être automatiquement reconnu à ta prochaine connexion depuis cet ordinateur. '
+            + 'Il n\'est pas conseillé de cocher la case si cette machine n\'est pas strictement personnelle.\n\nVeux-tu vraiment cocher cette case ?')) {
+              input.checked = false;
+              return false;
+            }
+            return true;
+          }
+        {/literal}</script>
+        <input type="checkbox" name="remember" id="remember" onchange="return confirm_remember(this);" /><label for="remember">Garder l'accès aux services après déconnexion</label>
       </td>
     </tr>
     <tr>
@@ -128,11 +110,27 @@ Si tu n'es pas {insert name="getName"}, change le login ci-dessous, ou rends-toi
       </td>
     </tr>
   </table>
-  <p>     
-    Problème de connexion ? <a href="Xorg/FAQ?display=light#connect" class="popup2">La réponse est là.</a>
-  </p>
 </form>
 
+{if !$smarty.session.auth}
+<p>
+<strong>Tu ne connais pas ton mot de passe ?</strong>
+</p>
+<ul>
+  <li>
+  Si tu viens de terminer ta pré-inscription, <strong>il est dans le mail</strong> que
+  nous t'avons envoyé (expéditeur pre-inscription@{#globals.mail.domain#}).
+  </li>
+  <li>
+  Si tu n'es jamais venu sur le site, <strong>il faut t'enregistrer auprès de
+    nous</strong> pour obtenir un accès. {#globals.core.sitename#} c'est l'e-mail des X,
+  l'annuaire en ligne, plus un tas d'autres services.  Nous te fournirons un accès le plus
+  rapidement possible. <strong> <a href="register/">Clique ici pour nous demander tes
+      paramètres personnels.</a></strong>
+  </li>
+</ul>
+{/if}
+
 <div id="nologin" style="background: #fcc; color: red">
   Pour assurer la confidentialité de ton mot de passe, il est chiffré sur ta machine
   avant de nous être transmis. Pour cela, il faut
@@ -143,6 +141,10 @@ Si tu n'es pas {insert name="getName"}, change le login ci-dessous, ou rends-toi
   </div>
 </div>
 
+<p>     
+  <strong>Problème de connexion ?</strong> <a href="Xorg/FAQ?display=light#connect" class="popup2">La réponse est là.</a>
+</p>
+
 <script type="text/javascript">
   document.getElementById('login').style.display="";
   document.getElementById('nologin').style.display="none";
index 636b1c8..849ab0b 100644 (file)
@@ -85,29 +85,18 @@ ton homonyme et toi-même ne disposeraient plus que des adresses de la forme pre
   </tr>
   <tr class="impair">
     <td>
-      {if $mails->total() eq 0}
+      {if count($mails) eq 0}
       <p class="erreur">
         Tu n'as actuellement aucune adressse de redirection. Tout courrier électronique qui t'es adresses
         ci-dessus génère une erreur. Modifie au plus vite ta liste de redirection.<br/>
       </p>
       {else}
       Actuellement, tout courrier électronique qui t'y est adressé, est envoyé
-      {if $mails->total() eq 1} à l'adresse{else} aux adresses{/if}&nbsp;:
+      {if count($mails) eq 1} à l'adresse{else} aux adresses{/if}&nbsp;:
       <ul>
-        {iterate from=$mails item=m}
-        <li><strong>{$m.email}</strong></li>
-        {/iterate}
-      </ul>
-      {/if}
-      {if count($storage) neq 0}
-      Ton courrier est également stocké sur {if count($storage) eq 1}le compte suivant{else} les comptes suivants{/if}&nbsp;:
-      <ul>
-        {if in_array('googleapps', $storage)}
-        <li><a href="googleapps"><strong>Compte Google Apps / GMail de Polytechnique.org</strong></a></li>
-        {/if}
-        {if in_array('imap', $storage)}
-        <li><a href="Xorg/IMAP"><strong>Accès de secours aux emails (IMAP)</strong></a></li>
-        {/if}
+        {foreach from=$mails item=m}
+        <li><strong>{$m->display_email}</strong></li>
+        {/foreach}
       </ul>
       {/if}
       {test_email}
index dec1119..9742816 100644 (file)
       var remove = $(".active_email:checked");
       if (remove.length <= 1) {
         remove.attr("disabled", "disabled");
+        remove.parent('td').parent('tr').children('td').children('.remove_email').hide();
       } else {
         remove.removeAttr("disabled");
+        $('.remove_email').show();
       }
     }
 
           $.get(link.href, {},function() {
             $('tr[@id=line_' + email.replace('@', '_at_') + ']').remove();
             showRemove();
+            activeEnable();
           });
         }
         return false;
         }
     }
 
+    function updateRedirect(checked, email)
+    {
+        activeEnable();
+        Ajax.update_html(null, 'emails/redirect/' + (checked ? '' : 'in') + 'active/' + email, redirectUpdate);
+    }
+
     {/literal}
   //]]></script>
   {javascript name="jquery"}
   <div class="center">
     <table class="bicol" summary="Adresses de redirection">
       <tr>
-        <th>Email</th>
+        <th>Redirection</th>
         <th>Actif</th>
         <th>Réécriture</th>
         <th>&nbsp;</th>
           <strong>
             {if $e->broken}<span class="erreur">{assign var="erreur" value="1"}{/if}
             {if $e->panne neq '0000-00-00'}{assign var="panne" value="1"}{icon name=error title="En panne"}{/if}
-            {$e->email}
+            {$e->display_email}
             {if $e->broken}</span>{/if}
           </strong>
         </td>
         <td>
-          <input type="checkbox" value="{$e->email}" class="active_email"
+          <input type="checkbox" value="{$e->email}" {if $e->sufficient}class="active_email"{/if}
                  {if $e->active}checked="checked"{/if}
                  {if $smarty.foreach.redirect.total eq 1}disabled="disabled"{/if}
-                 onchange="Ajax.update_html(null,'{$globals->baseurl}/emails/redirect/'+(this.checked?'':'in')+'active/{$e->email}', redirectUpdate)" /></td>
+                 onchange="updateRedirect(this.checked, '{$e->email}')" /></td>
         <td>
+          {if $e->has_rewrite()}
           <select onchange="Ajax.update_html(null,'emails/redirect/rewrite/{$e->email}/'+this.value, redirectUpdate)">
             <option value=''>--- aucune ---</option>
             {assign var=dom1 value=#globals.mail.domain#}
               value='{$a.alias}@{#globals.mail.domain2#}'>{$a.alias}@{#globals.mail.domain2#}</option>
             {/foreach}
           </select>
+          {else}
+          <em>pas de réécriture</em>
+          {/if}
         </td>
         <td>
+          {if $e->is_removable()}
           <a href="emails/redirect/remove/{$e->email}"
              class="remove_email"
              onclick="return removeRedirect(this, &quot;{$e->email}&quot;);" >
             {icon name=cross title="Supprimer"}
           </a>
+          {else}
+          {if $e->sufficient}<span class="remove_email"></span>{/if}
+          <a href="emails/redirect#{$e->email}">{icon name=information title="Plus d'informations"}</a>
+          {/if}
         </td>
       </tr>
       {/foreach}
-      {if $googleapps eq 'active'}
-      <tr class="{cycle values="pair,impair"}">
-        <td><strong>Compte GMail / Google Apps</strong></td>
-        <td>
-          <input type="checkbox" value="googleapps" disabled="disabled"
-                 {if in_array('googleapps', $storage)}checked="checked"{/if} />
-        </td>
-        <td>-</td>
-        <td>
-          <a href="emails/redirect#googleapps">{icon name=information title="Plus d'informations"}</a>
-        </td>
-      </tr>
-      {/if}
-      <script type="text/javascript">activeEnable(); showRemove();</script>
       <tr class="{cycle values="pair,impair"}"><td colspan="4">
         <form action="emails/redirect" method="post">
         <div>
         </form>
       </td></tr>
     </table>
+    <script type="text/javascript">activeEnable(); showRemove();</script>
   </div>
 {if $panne}
 <p class="smaller">
 </fieldset>
 {/if}
 
-{* TODO(vincent.zanotti): remove the following block of code when both IMAP and GApps will be active. *}
-{if in_array('imap', $storage) neq 0 or #globals.mailstorage.imap_active# or hasPerm('admin')}
-  {assign var=has_imap value=true}
-{else}
-  {assign var=has_imap value=false}
-{/if}
-{if $googleapps or #globals.mailstorage.googleapps_active# or hasPerm('admin')}
-  {assign var=has_googleapps value=true}
-{else}
-  {assign var=has_googleapps value=false}
-{/if}
-
-{if $has_imap or $has_googleapps}
+{if #globals.mailstorage.googleapps_active# or #globals.mailstorage.imap_active# or hasPerm('admin') or $googleapps}
 <h1>Tes comptes de stockage de courrier</h1>
 {/if}
-{if $has_imap}
+{if #globals.mailstorage.imap_active# or hasPerm('admin')}
 <p>
   Polytechnique.org te propose de conserver les mails que tu reçois, pendant une durée limitée (environ 30 jours).
   Grâce à ce service, tu disposes d'une sauvegarde de tes mails en secours, au cas où, par exemple, tu effacerais
 </p>
 
 <table class="bicol" summary="Compte de stockage">
-  <col width="75%" />
-  <col width="25%" />
+  <col width="55%" />
+  <col width="45%" />
   <tr>
     <th colspan="2">Compte de stockage</th>
   </tr>
       </a><br />Hébergé par Polytechnique.org
     </td>
     <td style="text-align: center; vertical-align: middle">
-      <form action="emails/redirect/storage/imap/{if in_array('imap', $storage)}inactive{else}active{/if}" method="post">
-        {if in_array('imap', $storage)}
-        <input type="submit" value="Désactiver" />
-        {else}
-        <input type="submit" value="Activer" />
-        {/if}
-      </form>
+      <a href="emails/redirect#line_imap">Voir l'état de la redirection vers l'IMAP</a>
     </td>
   </tr>
 </table>
 {/if}
 
-{if $has_googleapps}
+{if #globals.mailstorage.googleapps_active# or hasPerm('admin') or $googleapps}
 <br />
 <p>
   Grâce à un partenariat avec Google, Polytechnique.org te propose également un compte
 </p>
 
 <table class="bicol" summary="Compte de stockage" id="googleapps">
-  <col width="75%" />
-  <col width="25%" />
+  <col width="55%" />
+  <col width="45%" />
   <tr>
     <th colspan="2">Compte de stockage</th>
   </tr>
     {if $googleapps eq 'active'}
     <td>
       <a href="googleapps">
-        <strong>Redirection des emails vers GMail / Google Apps</strong>
+        <strong>Compte GMail / Google Apps</strong>
       </a><br />Hébergé par Google
     </td>
     <td style="text-align: center; vertical-align: middle">
-      <form action="emails/redirect/storage/googleapps/{if in_array('googleapps', $storage)}inactive{else}active{/if}" method="post">
-        {if in_array('googleapps', $storage)}
-        <input type="submit" value="Désactiver" />
-        {else}
-        <input type="submit" value="Activer" />
-        {/if}
-      </form>
+      Ton compte Google Apps est actif.<br />
+      <a href="emails/redirect#line_googleapps">Voir l'état de la redirection vers GMail</a>
     </td>
     {else}
     <td colspan="2">
index c761fa1..ba39165 100644 (file)
 {if $sexe}Chère{else}Cher{/if} {$prenom},
 
 Tu reçois ce mail car tu as demandé la confirmation du bon fonctionnement de ton adresse polytechnicienne {$email}.
-{if $redirects->total() gt 1}Si toutes tes redirections fonctionnent correctement tu devrais recevoir une copie de ce mail
+{if count($redirects) gt 1}Si toutes tes redirections fonctionnent correctement tu devrais recevoir une copie de ce mail
 dans les boîtes suivantes :
-{iterate from=$redirects item=mail}
-* {$mail.email}
-{/iterate}
+{foreach from=$redirects item=mail}
+* {$mail->display_email}
+{/foreach}
 {/if}
 
 Tu trouveras sur le site divers outils pour gérer ton adresse email :
index 226a6a9..9ecbe18 100644 (file)
@@ -131,7 +131,18 @@ Bienvenue {$smarty.session.prenom}{if $birthday}
     {/foreach}
     {if !$has_evts}
     <tr>
-      <td class="half">Aucun article actuellement</td>
+      <td class="half">
+        {if $smarty.session.core_rss_hash}
+        <a href="rss/{$smarty.session.forlife}/{$smarty.session.core_rss_hash}/rss.xml" style="display:block;float:right" title="Annonces">
+          {icon name=feed title='fil rss'}
+        </a>
+        {else}
+        <a href='prefs/rss?referer=events'  style="display:block;float:right">
+          {icon name=feed_add title='Activer mon fil rss'}
+        </a>
+        {/if}
+        Aucun article actuellement
+      </td>
     </tr>
     {/if}
   </table>
diff --git a/templates/forums/admin.tpl b/templates/forums/admin.tpl
new file mode 100644 (file)
index 0000000..f58fdf2
--- /dev/null
@@ -0,0 +1,57 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2008 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.org/                                  *}
+{*                                                                        *}
+{*  This program is free software; you can redistribute it and/or modify  *}
+{*  it under the terms of the GNU General Public License as published by  *}
+{*  the Free Software Foundation; either version 2 of the License, or     *}
+{*  (at your option) any later version.                                   *}
+{*                                                                        *}
+{*  This program is distributed in the hope that it will be useful,       *}
+{*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *}
+{*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *}
+{*  GNU General Public License for more details.                          *}
+{*                                                                        *}
+{*  You should have received a copy of the GNU General Public License     *}
+{*  along with this program; if not, write to the Free Software           *}
+{*  Foundation, Inc.,                                                     *}
+{*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
+{*                                                                        *}
+{**************************************************************************}
+
+Le tableau suivant permet de gérer la mise au ban (le bannissement) de certains utilisateurs aux forums.
+
+Chaque ligne permet de gérer les accès limités à :
+<ul>
+<li>une plage d'adresses IP donnée (entre ipmin et ipmax),</li>
+<li>à tout le monde (uid=0) ou seulement à un utilisateur donné,</li>
+<li>en restreignant l'accès en lecture à un ensemble de forums décrits par un masque,</li>
+<li>en restreignant l'accès en écriture à un ensemble de forums décrits par un masque.</li>
+</ul>
+
+<p>
+Dans les masques le <strong>*</strong> remplace n'importe quel texte et le <strong>!</strong> bloque l'accès au lieu de l'autoriser. Par exemple : <code>xorg.*,!xorg.prive.*</code> autorise tous les forums xorg sauf ceux qui s'appellent xorg.prive.qqchose.
+</p>
+
+<p>
+Les différentes règles sont appliquées par ordre de priorité décroissante.
+</p>
+
+{include file="core/table-editor.tpl"}
+
+{literal}
+<script type="text/javascript">
+  $('#body td table tr').each(function() { 
+    var uidcell = $('td:eq(3)',this);
+    if (uidcell.length != 1) {
+      return;
+    }
+    var uid = uidcell.text().replace(/^\s+/g,'').replace(/\s+$/g,'');
+    uidcell.replaceWith('<'+'a href="admin/user/'+uid+'">'+uid+'</'+'a>');
+  });
+</script>
+{/literal}
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
+
diff --git a/templates/googleapps/admin.job.tpl b/templates/googleapps/admin.job.tpl
new file mode 100644 (file)
index 0000000..56638c9
--- /dev/null
@@ -0,0 +1,86 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2008 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.org/                                  *}
+{*                                                                        *}
+{*  This program is free software; you can redistribute it and/or modify  *}
+{*  it under the terms of the GNU General Public License as published by  *}
+{*  the Free Software Foundation; either version 2 of the License, or     *}
+{*  (at your option) any later version.                                   *}
+{*                                                                        *}
+{*  This program is distributed in the hope that it will be useful,       *}
+{*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *}
+{*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *}
+{*  GNU General Public License for more details.                          *}
+{*                                                                        *}
+{*  You should have received a copy of the GNU General Public License     *}
+{*  along with this program; if not, write to the Free Software           *}
+{*  Foundation, Inc.,                                                     *}
+{*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<h1>Requête de la queue Google Apps</h1>
+
+{if $job}
+<table class="bicol">
+  <col width="50%" />
+  <col width="50%" />
+  <tr>
+    <th style="text-align: left" colspan="2">Queue id: {$job.q_id}</th>
+  </tr>
+
+  <tr class="impair">
+    <td class="titre">Propriétaire</td><td>{if $job.q_owner}{$job.q_owner}{else}<em>none</em>{/if}</td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Destinataire</td><td>{if $job.q_recipient}{$job.q_recipient}{else}<em>none</em>{/if}</td>
+  </tr>
+
+  <tr class="pair">
+    <td class="titre">Statut</td><td><code>{$job.p_status}</code></td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Priorité</td><td><code>{$job.p_priority}</code></td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Requête administrateur ?</td><td>{if $job.p_admin_request}oui{else}non{/if}</td>
+  </tr>
+
+  <tr class="impair">
+    <td class="titre">Entrée dans la queue</td><td>{$job.p_entry_date}</td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Date d'activation</td><td>{$job.p_notbefore_date}</td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Début de traitement</td><td>{if $job.p_start_date}{$job.p_start_date}{else}<em>none</em>{/if}</td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Fin de traitement</td><td>{if $job.p_end_date}{$job.p_end_date}{else}<em>none</em>{/if}</td>
+  </tr>
+
+  <tr class="pair">
+    <td class="titre">Erreurs récupérables</td><td>{$job.r_softfail_count}</td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Dernière erreur récupérable</td><td><code>{if $job.r_softfail_date}{$job.r_softfail_date}{else}<em>none</em>{/if}</code></td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Résultat du traitement</td><td><code>{if $job.r_result}{$job.r_result}{else}<em>none</em>{/if}</code></td>
+  </tr>
+
+  <tr class="impair">
+    <td class="titre">Type de requête</td><td><code>{$job.j_type}</code></td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Paramètres</td><td><pre>{$job.decoded_parameters}</pre></td>
+  </tr>
+</table>
+{else}
+<p><strong>Aucune requête n'a été trouvée.</strong></p>
+{/if}
+
+<p>Retourner à la <a href="admin/googleapps">page d'administration de Google Apps</a>.</p>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/googleapps/admin.tpl b/templates/googleapps/admin.tpl
new file mode 100644 (file)
index 0000000..67e9ccb
--- /dev/null
@@ -0,0 +1,100 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2008 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.org/                                  *}
+{*                                                                        *}
+{*  This program is free software; you can redistribute it and/or modify  *}
+{*  it under the terms of the GNU General Public License as published by  *}
+{*  the Free Software Foundation; either version 2 of the License, or     *}
+{*  (at your option) any later version.                                   *}
+{*                                                                        *}
+{*  This program is distributed in the hope that it will be useful,       *}
+{*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *}
+{*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *}
+{*  GNU General Public License for more details.                          *}
+{*                                                                        *}
+{*  You should have received a copy of the GNU General Public License     *}
+{*  along with this program; if not, write to the Free Software           *}
+{*  Foundation, Inc.,                                                     *}
+{*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<h1>Gestion des utilisateurs</h1>
+
+<form method="post" action="admin/googleapps/user">
+<table class="tinybicol" cellspacing="0" cellpadding="2">
+  <tr>
+    <th>Administrer un utilisateur (Google Apps)</th>
+  </tr>
+  <tr>
+    <td class="center"><input type="text" name="login" size="40" maxlength="255" value="" /></td>
+  </tr>
+  <tr>
+    <td class="center"><input type="submit" value="Valider" /></td>
+  </tr>
+</table>
+</form>
+
+<h1>Queue de requêtes vers Google Apps</h1>
+
+<p>
+  Requête nécessitant <a href="Equipe/Infra-GoogleApps#admin-cli">l'intervention manuelle</a>
+  d'un administrateur Google Apps {if $googleapps_admin}(tu en es un){/if}&nbsp;:
+</p>
+<table class="bicol" style="text-align: center">
+  <tr>
+    <th>qid</th>
+    <th>date</th>
+    <th>recipient</th>
+    <th>type</th>
+    <th>parameters</th>
+  </tr>
+  {foreach from=$admin_requests item=r}
+  <tr class="{cycle values="impair,pair"}">
+    <td><a href="admin/googleapps/job/{$r.q_id}">{$r.q_id}</a></td>
+    <td>{$r.p_entry_date|date_format:"%Y-%m-%d %H:%M"}</td>
+    <td>{if $r.alias}<a href="admin/googleapps/user/{$r.alias}">{$r.alias}</a>{else}-{/if}</td>
+    <td>{$r.j_type}</td>
+    <td>{$r.parameters}</td>
+  </tr>
+  {/foreach}
+</table>
+
+<p>
+  Requêtes ayant échoué récemment (plus d'information dans la <a href="Equipe/Infra-GoogleApps">documentation</a>) :
+</p>
+<table class="bicol" style="text-align: center">
+  <tr>
+    <th>qid</th>
+    <th>date</th>
+    <th>recipient</th>
+    <th>type</th>
+    <th>reason</th>
+    <th></th>
+  </tr>
+  {iterate from=$failed_requests item=r}
+  <tr class="{cycle values="impair,pair"}">
+    <td><a href="admin/googleapps/job/{$r.q_id}">{$r.q_id}</a></td>
+    <td>{$r.p_entry_date|date_format:"%Y-%m-%d %H:%M"}</td>
+    <td>{if $r.alias}<a href="admin/googleapps/user/{$r.alias}">{$r.alias}</a>{else}-{/if}</td>
+    <td>{$r.j_type}</td>
+    <td><code>{$r.r_result}</code></td>
+    <td><a href="admin/googleapps/ack/{$r.q_id}">{icon name=cross title="Retirer cet échec"}</a></td>
+  </tr>
+  {/iterate}
+</table>
+
+<h1>Statistiques d'utilisation de Google Apps</h1>
+
+<div style="text-align: center">
+  <img src="images/googleapps/activity-monthly.png" alt="Activité Google Apps - 1 mois" width="500 height="250" />
+  <br /><em>Utilisation des comptes Google Apps sur les 31 derniers jours</em>.
+</div>
+
+<div style="text-align: center">
+  <img src="images/googleapps/activity-yearly.png" alt="Activité Google Apps - 1 an" width="500 height="250" />
+  <br /><em>Utilisation des comptes Google Apps sur les 12 derniers mois</em>.
+</div>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/googleapps/admin.user.tpl b/templates/googleapps/admin.user.tpl
new file mode 100644 (file)
index 0000000..cb2af6f
--- /dev/null
@@ -0,0 +1,105 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2008 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.org/                                  *}
+{*                                                                        *}
+{*  This program is free software; you can redistribute it and/or modify  *}
+{*  it under the terms of the GNU General Public License as published by  *}
+{*  the Free Software Foundation; either version 2 of the License, or     *}
+{*  (at your option) any later version.                                   *}
+{*                                                                        *}
+{*  This program is distributed in the hope that it will be useful,       *}
+{*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *}
+{*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *}
+{*  GNU General Public License for more details.                          *}
+{*                                                                        *}
+{*  You should have received a copy of the GNU General Public License     *}
+{*  along with this program; if not, write to the Free Software           *}
+{*  Foundation, Inc.,                                                     *}
+{*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<h1>Compte Google Apps</h1>
+
+{if $account}
+{assign var=a value=$account}
+<table class="bicol">
+  <col width="50%" />
+  <col width="50%" />
+  <tr>
+    <th colspan="2" style="text-align: left">
+      <div style="float: left; text-align: left">
+        Compte = {$a->g_account_name}
+      </div>
+      <div style="float: right; text-align: right">
+        Google id = {$a->g_account_id}<br />
+        Plat/al id = {$user}
+      </div>
+    </th>
+  </tr>
+
+  <tr class="impair">
+    <td class="titre">Statut du compte</td>
+    <td>
+      <strong>{$a->g_status}</strong>
+      {if $admin_account}<br /><strong>Compte administrateur de Google Apps</strong>{/if}
+    </td>
+  </tr>
+  {if $a->suspended()}
+  <tr class="impair">
+    <td class="titre">Raison de suspension</td><td>{$a->g_suspension}</td>
+  </tr>
+  {/if}
+  <tr class="impair">
+    <td class="titre">Mots de passes synchronisés</td>
+    <td>
+      {if $a->sync_password}
+        oui (<a href="admin/googleapps/user/{$a->g_account_name}/forcesync">lancer une synchronisation</a>)
+      {else}non{/if}
+    </td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Redirection des mails</td><td>{if $googleapps_storage}activée{else}désactivee{/if}</td>
+  </tr>
+
+  <tr class="pair">
+    <td class="titre">Date de création</td><td>{$a->r_creation|date_format:"%Y-%m-%d"}</td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Dernière connexion</td><td>{$a->r_last_login|date_format:"%Y-%m-%d"}</td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Dernière utilisation du webmail</td><td>{$a->r_last_webmail|date_format:"%Y-%m-%d"}</td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Utilisation du quota mail</td><td>{$a->r_disk_usage/1024/1024|string_format:"%.2f"}MB</td>
+  </tr>
+</table><br />
+
+<table class="bicol" style="text-align: center">
+  <tr>
+    <th colspan="4" style="text-align: left">Requêtes en attente</th>
+  </tr>
+  <tr>
+    <th>qid</th>
+    <th>date</th>
+    <th>statut</th>
+    <th>type</th>
+  </tr>
+  {iterate from=$requests item=r}
+  <tr class="{cycle values="impair,pair"}">
+    <td><a href="admin/googleapps/job/{$r.q_id}">{$r.q_id}</a></td>
+    <td>{$r.p_entry_date|date_format:"%Y-%m-%d %H:%M"}</td>
+    <td>{$r.p_status}</td>
+    <td>{$r.j_type}</td>
+  </tr>
+  {/iterate}
+</table>
+{else}
+<p><strong>Aucun utilisateur n'a été trouvé.</strong></p>
+{/if}
+
+<p>Retourner à la <a href="admin/googleapps">page d'administration de Google Apps</a>.</p>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 23400c9..da046f3 100644 (file)
   </tr>
 </table>
 
-{elseif $account->g_status eq 'disabled' or $account->pending_update_suspension}
+{elseif $account->suspended() or $account->pending_update_suspension}
 <br />
 <table class="bicol" id="status">
   <tr>
       message sur ce compte.
     </td>
   </tr>
-  {if $account->pending_validation_unsuspend or ($account->g_status eq 'disabled' and $account->pending_update_suspension)}
+  {if $account->pending_validation_unsuspend or ($account->suspended() and $account->pending_update_suspension)}
   <tr class="pair">
     <td>
       La réactivation de ton compte est en attente de validation.<br />
       Tu recevras un email dès que l'opération sera terminée.
     </td>
   </tr>
-  {elseif $account->g_status neq 'disabled' and $account->pending_update_suspension}
+  {elseif !$account->suspended() and $account->pending_update_suspension}
   <tr class="pair">
     <td>
       Les opérations de désactivation de ton compte Google Apps ne sont pas terminées, tu ne peux donc pas encore demander sa réactivation.
           <form action="googleapps/password#password" method="post" id="changepass2">
             <input type="hidden" name="response2"  value="" />
           </form><br />
-          Pour une sécurité optimale, ton mot de passe circule de manière cryptée (https) et est stocké crypté irréversiblement sur nos serveurs, ainsi que sur ceux de Google.
+          Pour une sécurité optimale, ton mot de passe circule de manière sécurisée (https).
+          Il est chiffré irréversiblement sur nos serveurs, ainsi que sur ceux de Google.
         </li>
       </ul>
     </td>
index 4fa451b..66ecc64 100644 (file)
 {*                                                                        *}
 {**************************************************************************}
 
-
-{if !$c.inscrit || $c.dcd}<div class='grayed'>{/if}
+{if (!$c.inscrit && $smarty.session.auth ge AUTH_COOKIE) || $c.dcd}<div class='grayed'>{/if}
 <div class="contact" {if $c.inscrit}{if $smarty.session.auth ge AUTH_COOKIE}title="fiche mise à jour le {$c.date|date_format}"{/if}{/if}>
 
   <div class="nom">
     {if $c.sexe}&bull;{/if}
-    {if !$c.dcd && $c.inscrit}<a href="profile/{$c.forlife}" class="popup2">{/if}
+    {if !$c.dcd && ($c.inscrit || $smarty.session.auth eq AUTH_PUBLIC)}<a href="profile/{if $c.inscrit}{$c.forlife}{else}{make_forlife nom=$c.nom prenom=$c.prenom promo=$c.promo}{/if}" class="popup2">{/if}
     {if $c.nom_usage}{$c.nom_usage} {$c.prenom}<br />({$c.nom}){else}{$c.nom} {$c.prenom}{/if}
-    {if !$c.dcd && $c.inscrit}</a>{/if}
+    {if !$c.dcd && ($c.inscrit || $smarty.session.auth eq AUTH_PUBLIC)}</a>{/if}
   </div>
 
   <div class="appli">
   </div>
 
 </div>
-{if !$c.inscrit || $c.dcd}</div>{/if}
+{if (!$c.inscrit && $smarty.session.auth ge AUTH_COOKIE) || $c.dcd}</div>{/if}
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index a9771cf..d32325e 100644 (file)
 Cette lettre est envoyée à tous les Polytechniciens sur Internet par
 l'intermédiaire de Polytechnique.org.
 
+{if $is_mail}
 archives         : <https://www.polytechnique.org/nl>
 écrire           : <https://www.polytechnique.org/nl/submit>
 ne plus recevoir : <https://www.polytechnique.org/nl/out>
-
+{else}
+archives         : &lt;https://www.polytechnique.org/nl&gt;
+écrire           : &lt;https://www.polytechnique.org/nl/submit&gt;
+ne plus recevoir : &lt;https://www.polytechnique.org/nl/out&gt;
+{/if}
 {if !$is_mail}
 </pre>
 {/if}
index 8cb9332..7b162ca 100644 (file)
@@ -47,7 +47,7 @@
   <tr><th>{$nl->title(true)}</th></tr>
   <tr>
     <td>
-      {include file="newsletter/nl.mail.tpl"}
+      {include file="newsletter/nl.mail.tpl" escape=true}
     </td>
   </tr>
 </table>
index 5d3dbb9..0ce0049 100644 (file)
@@ -46,12 +46,11 @@ Il te faut te limiter à 8 lignes de 68 caractères.
 {/if}
 
 <form action="nl/submit" method='post'>
-  <table class='tinybicol'>
+  <table class='bicol'>
     <tr><th>Version texte</th></tr>
     <tr id='text'>
     <td><pre>{$art->toText()}</pre></td>
     </tr>
-    {if $art->check()}
     <tr><th>Version html</th></tr>
     <tr id='html'>
       <td>
@@ -60,6 +59,7 @@ Il te faut te limiter à 8 lignes de 68 caractères.
         </div>
       </td>
     </tr>
+    {if $art->check()}
     <tr>
       <th>Soumettre</th>
     </tr>
@@ -120,7 +120,7 @@ Tu peux <a href='nl/submit#conseils'>lire les conseils de rédaction</a> avant d
           {icon name=information title="Syntaxe wiki"} Voir les marqueurs de mise en forme autorisés
         </a>
       </td>
-    <tr>
+    </tr>
     <tr class='pair'>
       <td colspan='2' class='center'>
         <input type='submit' name='see' value='visualiser' />
index 1944c38..f414d16 100644 (file)
@@ -20,6 +20,8 @@
 {*                                                                        *}
 {**************************************************************************}
 
+<p>{icon name=information title="Afficher ma fiche référent"}Tu peux consulter ta <a class="popup2" href="referent/{$smarty.session.forlife}">fiche référent</a> qui n'est accessible que par les X.
+</p>
 <p>
   Si tu acceptes que ceux des camarades te contactent afin de te demander
   conseil, dans les domaines que tu connais bien, et pour lesquels tu pourrais
@@ -28,7 +30,7 @@
 <p>
   Tu peux mentionner ici les domaines de compétences, les expériences
   notamment internationales sur la base desquels tu seras identifiable depuis
-  <a href="referent/search">la page de recherche d'un conseil professionnel</a>.<br />
+  <a href="referent/search#mentors">la page de recherche d'un conseil professionnel</a>.<br />
 </p>
 <p>Le mentoring est particulièrement important pour les camarades&nbsp;:</p>
 <ul>
index 24b7972..d4572fb 100644 (file)
@@ -187,13 +187,19 @@ function chgMainWinLoc(strPage)
     {$x.cv|miniwiki:title|smarty:nodefaults}
   </div>
   {/if}
-  {if !$logged}
+  {if $view eq 'public'}
   <div class="part">
     <small>
     Cette fiche est publique et visible par tout internaute,<br />
     vous pouvez aussi voir <a href="profile/private/{$x.forlife}?display=light">celle&nbsp;réservée&nbsp;aux&nbsp;X</a>.
     </small>
   </div>
+  {elseif $view eq 'ax'}
+  <div class="part">
+    <small>
+    Cette fiche est privée et ne recense que les informations transmises à l'AX.
+    </small>
+  </div>
   {/if}
   <div class="spacer"></div>
 </div>
index 3798294..dc90920 100644 (file)
@@ -27,6 +27,8 @@
 {include wiki=Docs.Emploi}
 {/if}
 
+<a name="mentors"></a>
+
 <p>
 Actuellement, {$mentors_number} mentors et référents se sont déclarés sur {#globals.core.sitename#}.
 </p>
index af2e360..0c7ed25 100644 (file)
@@ -39,7 +39,7 @@
       <td style="width: 78%">
         <input type="checkbox" name="with_soundex" id="with_soundex" value="1" {if $smarty.request.with_soundex}checked="checked"{/if} /> <label for="with_soundex">Activer la recherche par proximité sonore.</label>
         <br /><input type='checkbox' name='order' id="order" value='date_mod' {if $smarty.request.order eq "date_mod"}checked='checked'{/if} /> <label for="order">Mettre les fiches modifiées récemment en premier.</label>
-        <br /><input type='checkbox' name='nonins' id="nonins" readonly="readonly" {if $smarty.request.nonins}checked='checked'{/if} value='1' /> <label for="nonins">Chercher uniquement des non inscrits.</label>
+        <br /><input type='checkbox' name='nonins' id="nonins" {if $smarty.request.nonins}checked='checked'{/if} value='1' /> <label for="nonins">Chercher uniquement des non inscrits.</label>
       </td>
     {else}
     <tr class="noprint">
index 9c6c7cc..8a2705d 100644 (file)
@@ -33,6 +33,7 @@ Quelques statistiques sur l'utilisation des services de Polytechnique.org ainsi
 <li><a href="stats/evolution">Nombre d'inscrits au cours du temps</a></li>
 <li><a href="stats/promos/{$smarty.session.promo}">Nombre d'inscrits dans ta promotion</a></li>
 <li><a href="stats/promos">Nombre d'inscrits par promotion</a></li>
+<li><a href="stats/profile">Consultations des fiches de l'annuaire</a></li>
 </ul>
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/stats/profile.tpl b/templates/stats/profile.tpl
new file mode 100644 (file)
index 0000000..c2fcb34
--- /dev/null
@@ -0,0 +1,65 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2008 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.org/                                  *}
+{*                                                                        *}
+{*  This program is free software; you can redistribute it and/or modify  *}
+{*  it under the terms of the GNU General Public License as published by  *}
+{*  the Free Software Foundation; either version 2 of the License, or     *}
+{*  (at your option) any later version.                                   *}
+{*                                                                        *}
+{*  This program is distributed in the hope that it will be useful,       *}
+{*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *}
+{*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *}
+{*  GNU General Public License for more details.                          *}
+{*                                                                        *}
+{*  You should have received a copy of the GNU General Public License     *}
+{*  along with this program; if not, write to the Free Software           *}
+{*  Foundation, Inc.,                                                     *}
+{*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
+{*                                                                        *}
+{**************************************************************************}
+
+
+<h1>
+  Fiches les plus consultées
+</h1>
+
+<ul>
+  <li>
+    {if $period neq 'overall'}<a href="stats/profile/overall">{/if}
+    Classement de tous les temps
+    {if $period neq 'overall'}</a>{/if}
+  </li>
+  <li>
+    {if $period neq 'year'}<a href="stats/profile/year">{/if}
+    Classement sur l'année écoulée
+    {if $period neq 'year'}</a>{/if}
+ </li>
+ <li>
+    {if $period neq 'month'}<a href="stats/profile/month">{/if}
+    Classement sur le mois écoulé
+    {if $period neq 'month'}</a>{/if}
+ </li>
+ <li>
+    {if $period neq 'week'}<a href="stats/profile/week">{/if}
+    Classement sur la semaine écoulée
+    {if $period neq 'week'}</a>{/if}
+ </li>
+
+</ul>
+
+<table class="tinybicol">
+  <tr>
+    <th>Nom</th>
+    {if hasPerms('admin')}<th>Consultations</th>{/if}
+  </tr>
+  {iterate from=$profiles item=profile}
+  <tr class="{cycle values="pair,impair"}">
+    <td><a href="profile/{$profile.forlife}" class="popup">{$profile.prenom} {$profile.nom} (X{$profile.promo})</a></td>
+    {if hasPerms('admin')}<td class="right">{$profile.count}</td>{/if}
+  </tr>
+  {/iterate}
+</table>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 9cd5883..e4b929c 100644 (file)
             - <a href="send_bug" class="popup_840x600">signaler un bug</a>
           {/if}
           <br />
-          © Copyright 2000-2008 <a href="http://x-org.polytechnique.org/">Association Polytechnique.org</a>
+          Plat/al {#globals.version#} - © Copyright 2000-2008 <a href="http://x-org.polytechnique.org/">Association Polytechnique.org</a>
         </td>
       </tr>
     {/if}
index c577130..eff4fd5 100644 (file)
 
 {foreachelse}
 
-
 <p class="descr">
 {if $archive}
   Aucun événement n'a été archivé par les animateurs du groupe.
 
 {/foreach}
 
+{if $undisplayed_events neq 0}
+<p class="descr">
+  Il y a {$undisplayed_events} événement{if $undisplayed_events > 1}s non affichés car ils sont réservés
+  {else} non affiché car il est réservé{/if} aux membres de ce groupe.
+</p>
+{/if}
+
 {if $evenements}
 <p class="descr">
   En cliquant sur l'icône {icon name=calendar_view_day title="Événement iCal"} associée à un événement,
index 4fcd93a..ba8260f 100644 (file)
@@ -37,6 +37,8 @@ ALTER TABLE ip_watch
 DROP PRIMARY KEY,
 DROP COLUMN ip,
 CHANGE COLUMN ip2 ip INT(11) UNSIGNED NOT NULL,
-ADD PRIMARY KEY ip (ip);
+ADD COLUMN mask int(11) unsigned NOT NULL DEFAULT 4294967295,
+ADD PRIMARY KEY ip (ip),
+ADD INDEX network (ip, mask);
 
 # vim:set syntax=mysql:
index f208a2a..00af187 100644 (file)
@@ -1,4 +1,6 @@
-CREATE TABLE `forums.innd` (
+USE forums;
+
+CREATE TABLE IF NOT EXISTS `innd` (
   `id_innd` int(10) unsigned NOT NULL auto_increment,
   `ipmin` int(10) unsigned default '0' COMMENT 'ip_address',
   `ipmax` int(10) unsigned default '4294967295' COMMENT 'ip_address',
@@ -10,4 +12,4 @@ CREATE TABLE `forums.innd` (
   PRIMARY KEY  (`id_innd`)
 ) DEFAULT CHARSET=utf8;
 
-INSERT INTO `forums.innd` VALUES (1,0,4294967295,NULL,'xorg.*,!xorg.prive.*','xorg.*,!xorg.prive.*,!xorg.pa.emploi',0,'par defaut pour tous');
+INSERT INTO `innd` VALUES (1,0,4294967295,NULL,'xorg.*,!xorg.prive.*','xorg.*,!xorg.prive.*,!xorg.pa.emploi',0,'par defaut pour tous');
diff --git a/upgrade/0.9.16/09_watch_cat.sql b/upgrade/0.9.16/09_watch_cat.sql
new file mode 100644 (file)
index 0000000..7b11027
--- /dev/null
@@ -0,0 +1,7 @@
+ALTER TABLE watch_cat ADD COLUMN mail_sg_xette varchar(80) DEFAULT NULL AFTER mail_sg;
+UPDATE watch_cat SET mail_sg_xette = 'Cette camarade a mis sa fiche à jour' WHERE id = 1;
+UPDATE watch_cat SET mail_sg_xette = 'Cette camarade s\'est inscrite' WHERE id = 2;
+UPDATE watch_cat SET mail_sg_xette = 'Cette camarade nous a quittés' WHERE id = 3;
+UPDATE watch_cat SET mail_sg_xette = 'Cette camarade fête son anniversaire cette semaine' WHERE id = 4;
+
+# vim:set syntax=mysql:
diff --git a/upgrade/0.9.16/10_logger.sql b/upgrade/0.9.16/10_logger.sql
new file mode 100644 (file)
index 0000000..fab186d
--- /dev/null
@@ -0,0 +1,10 @@
+INSERT INTO logger.actions (text, description)
+     VALUES ('view_profile', 'Consultation d\'une fiche'),
+            ('search', 'Réalisation d\'une recherche');
+
+use logger;
+ALTER TABLE events ADD INDEX action (action);
+
+use x4dat;
+
+# vim:set syntax=mysql: