Merge commit 'origin/fusionax' into account
authorStéphane Jacob <sj@m4x.org>
Tue, 21 Jul 2009 13:49:45 +0000 (15:49 +0200)
committerStéphane Jacob <sj@m4x.org>
Tue, 21 Jul 2009 13:49:45 +0000 (15:49 +0200)
144 files changed:
AUTHORS
ChangeLog
Makefile
SECURITY [new file with mode: 0644]
bin/check_security_fixes.py [new file with mode: 0755]
bin/cron/cron_ml_moderate.php
bin/cron/cron_validations.php
bin/cron/emails.check.php
classes/user.php
classes/xnetpage.php
classes/xorgsession.php
configs/platal.cron.in
core
htdocs/images/medals/eufor.jpg [new file with mode: 0644]
htdocs/javascript/do_challenge_response_logged.js
htdocs/javascript/motdepasse.js
htdocs/javascript/profile.js
htdocs/javascript/xorg.js
htdocs/xorg.php
include/banana/forum.inc.php
include/banana/hooks.inc.php
include/banana/ml.inc.php
include/banana/moderate.inc.php
include/emails.inc.php
include/geocoding.inc.php
include/googleapps.inc.php
include/name.func.inc.php
include/reminder.inc.php [new file with mode: 0644]
include/reminder/ax_letter.inc.php [new file with mode: 0644]
include/reminder/email_backup.inc.php [new file with mode: 0644]
include/reminder/email_warning.inc.php [new file with mode: 0644]
include/reminder/gapps.inc.php [new file with mode: 0644]
include/reminder/ml.inc.php [new file with mode: 0644]
include/reminder/nl.inc.php [new file with mode: 0644]
include/reminder/no_redirection.inc.php [new file with mode: 0644]
include/reminder/profile_update.inc.php [new file with mode: 0644]
include/reminder/promotion_ml.inc.php [new file with mode: 0644]
include/security.inc.php
include/validations/entreprises.inc.php
include/validations/orange.inc.php
include/validations/paiements.inc.php
include/vcard.inc.php
modules/admin.php
modules/auth.php
modules/auth/auth.inc.php
modules/axletter.php
modules/axletter/axletter.inc.php
modules/bandeau.php
modules/carnet.php
modules/email.php
modules/events.php
modules/forums.php
modules/gadgets.php
modules/googleapps.php
modules/lists.php
modules/lists/mail_templates/accept.txt [new file with mode: 0644]
modules/newsletter.php
modules/openid.php
modules/openid/openid.inc.php
modules/payment.php
modules/platal.php
modules/platal/review.inc.php
modules/profile.php
modules/profile/addresses.inc.php
modules/profile/general.inc.php
modules/profile/jobs.inc.php
modules/profile/page.inc.php
modules/register.php
modules/register/register.inc.php
modules/reminder.php [new file with mode: 0644]
modules/search.php
modules/search/classes.inc.php
modules/stats.php
modules/survey.php
modules/xnet.php
modules/xnetgrp.php
modules/xnetlists.php
plugins/function.display_phones.php
plugins/insert.getUserName.php
templates/admin/deces_promo.tpl
templates/admin/jobs.tpl
templates/admin/utilisateurs.tpl
templates/axletter/edit.tpl
templates/core/password_prompt.tpl
templates/core/password_prompt_logged.tpl
templates/emails/broken.tpl
templates/emails/redirect.tpl
templates/events/index.tpl
templates/gadgets/ig-skin.tpl
templates/geoloc/form.address.tpl
templates/googleapps/admin.user.tpl
templates/googleapps/index.tpl
templates/include/form.valid.edit-entreprises.tpl
templates/include/form.valid.entreprises.tpl
templates/include/form.valid.orange.tpl
templates/include/minifiche.tpl
templates/marketing/index.tpl
templates/marketing/private.tpl
templates/openid/idp_xrds.tpl
templates/openid/openid.tpl
templates/openid/trust.tpl
templates/openid/user_xrds.tpl
templates/payment/retour_paypal.tpl
templates/payment/xnet.tpl
templates/profile/general.searchname.tpl
templates/profile/groups.tpl
templates/profile/jobs.job.tpl
templates/profile/jobs.sector.tpl
templates/profile/jobs.sub_sector.tpl
templates/profile/profile.tpl
templates/register/end.tpl
templates/register/inscription.reussie.tpl
templates/register/inscrire.mail.tpl
templates/register/step2.tpl
templates/register/step3.tpl
templates/register/step4.tpl
templates/register/success.tpl [deleted file]
templates/reminder/base.tpl [new file with mode: 0644]
templates/reminder/email_warning.tpl [new file with mode: 0644]
templates/reminder/gapps.tpl [new file with mode: 0644]
templates/reminder/ml.tpl [new file with mode: 0644]
templates/reminder/no_redirection.tpl [new file with mode: 0644]
templates/reminder/notification.tpl [new file with mode: 0644]
templates/reminder/profile_update.tpl [new file with mode: 0644]
templates/search/adv.form.tpl
templates/search/quick.form.tpl
templates/skin/common.title.header.tpl
templates/survey/edit_question.tpl
templates/survey/edit_root.tpl
templates/survey/edit_survey.tpl
templates/survey/show_question.tpl
templates/survey/show_root.tpl
templates/xnetevents/edit.tpl
templates/xnetgrp/annuaire.tpl
templates/xnetgrp/edit.tpl
templates/xnetgrp/membres-add.tpl
upgrade/0.10.1/00_inscription.sql [new file with mode: 0644]
upgrade/0.10.1/01_groupex.sql [new file with mode: 0644]
upgrade/0.10.1/02_axletter.sql [new file with mode: 0644]
upgrade/newdirectory-0.0.1/07_corps
upgrade/newdirectory-0.0.1/14_watchnames.sql
upgrade/newdirectory-0.0.1/15_addresses.sql
upgrade/newdirectory-0.0.1/README
upgrade/newdirectory-0.0.1/addresses.php [new file with mode: 0755]

diff --git a/AUTHORS b/AUTHORS
index ff5290b..d760b15 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -3,17 +3,20 @@ Polytechnique.org TEAM :
     Pierre Habouzit         <pierre.habouzit@m4x.org>, <madcoder@debian.org>
     Aymeric Augustin        <aymeric.augustin@m4x.org>
     Jean Sébastien Bedo     <jean-sebastien.bedo@m4x.org>
+    Raphaël Barrois         <raphael.barrois@m4x.org>
     Florent Bruneau         <florent.bruneau@m4x.org>
     Sophie Charbonnier      <sophie.charbonnier@m4x.org>
     Yann Chevalier          <yann.chevalier@m4x.org>
     Jean-Marc Coic          <jean-marc.coic@m4x.org>
     Pascal Corpet           <pascal.corpet@m4x.org>
     Guillaume Gommard       <guillaume.gommard@m4x.org>
+    Stéphane Jacob          <stephane.jacob@m4x.org>
     Fabien Laborde          <fabien.laborde@m4x.org>
     Jeremy Lainé            <jeremy.laine@m4x.org>
     Olivier Le Floch        <olivier.le-floch@m4x.org>
     Raphael Marichez        <raphael.marichez@m4x.org>
     Vincent Palatin         <vincent.palatin@m4x.org>
+    Vincent Zanotti         <vincent.zanotti@m4x.org>
 
 
 XML-RPC stuff :
index ec4f070..d3ea9c1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -19,6 +19,44 @@ Bug/Wish:
 ================================================================================
 VERSION 0.10.1                                                        XX XX XXXX
 
+New:
+
+    * Events:
+        - Reminders                                                    -JAC/VZA
+
+Bug/Wish:
+
+    * Admin:
+        - #965: Prevents password hashes from being broadcasted by email   -VZA
+
+    * AXLetter:
+        - Enables axletter mailings to a subset of subscribers             -XEL
+
+    * Core:
+        - #680: Retrieve dead redirections thanks to inactive redirections -JAC
+
+    * Mail:
+        - Notifies the sender when a moderated message to a ML is accepted -JAC
+        - #963: Fixes notification email on removal of "nom d'usage"       -VZA
+        - #972: Adds a legend on the email redirection page                -JAC
+
+    * Payment:
+        - #669: Sends comments with the payment notifications              -JAC
+
+    * Profile:
+        - #951: The address of a dead person is her last address           -JAC
+        - #958: Fix the address in the professionnal vcard                 -JAC
+        - #970: Shows a confirmation message when the profile is modified  -JAC
+
+    * Marketing:
+        - #671: Displays more statistics about marketings                  -JAC
+
+    * Survey:
+        - #794: Adds wiki syntax to surveys                                -PIK
+
+    * XnetGrp:
+        - #973: Only site administrators can allow AX aggregation          -JAC
+
 From 0.10.0 branch:
 
     * Auth:
@@ -1339,6 +1377,7 @@ ACRONYMS:
     * THD: Thomas Deniau        (Totom)     <thomas.deniau@m4x.org>
     * VP : Vincent Palatin                  <vincent.palatin@m4x.org>
     * XdX: Alexandre Hô         (XandreX)   <alexandre.ho@m4x.org>
+    * XEL: Raphaël Barrois      (Xelnor)    <raphael.barrois@m4x.org>
     * VZA: Vincent Zanotti      (vinZ2)     <vincent.zanotti@m4x.org>
 
 ================================================================================
index a6c1935..446aedd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -118,20 +118,20 @@ get-wiki:
 openid: get-openid spool/openid/store
 
 # There is no obvious way to automatically use the latest version
+OPENID_VERSION = 2.1.3
 get-openid:
        @if ! test -d include/Auth; then                                  \
-           wget http://openidenabled.com/files/php-openid/packages/php-openid-2.1.2.tar.bz2; \
-           tar -xjf php-openid-2.1.2.tar.bz2;                            \
-           mv php-openid-2.1.2/Auth include/;                            \
-           rm php-openid-2.1.2.tar.bz2;                                  \
-           rm -r php-openid-2.1.2;                                       \
+           wget http://openidenabled.com/files/php-openid/packages/php-openid-$(OPENID_VERSION).tar.bz2; \
+           tar -xjf php-openid-$(OPENID_VERSION).tar.bz2;                \
+           mv php-openid-$(OPENID_VERSION)/Auth include/;                \
+           rm php-openid-$(OPENID_VERSION).tar.bz2;                      \
+           rm -r php-openid-$(OPENID_VERSION);                           \
        fi
 
 spool/openid/store:
        mkdir -p $@
        chmod o+w $@
 
-
 ##
 ## banana
 ##
diff --git a/SECURITY b/SECURITY
new file mode 100644 (file)
index 0000000..d031043
--- /dev/null
+++ b/SECURITY
@@ -0,0 +1,16 @@
+# List of security fixes that have been committed to the "master" branch.
+# This list is used to programmatically determine if a checkout of plat/al has
+# known vulnerabilities (which is useful for automatically disabling an unused
+# and unsafe checkout).
+#
+# In order to guarantee that only patched checkouts do have an updated SECURITY
+# file, updates of this file should be done within the same sommit that actually
+# fixes the security issue. Since the commit id is not known yet, it can be
+# replaced by '00000000', and updated later.
+#
+# Format: <date> <commit id> <commit description>
+# The commit id should refer to the id in the "master" branch, if the initial
+# commit in a version branch had another name.
+
+2009-10-19 e10bc2ef Prevents auth-groupex from leaking data to third-party attackers.
+2008-12-21 a25cdc91 Fixes a SQL injection in geoloc.inc.php.
diff --git a/bin/check_security_fixes.py b/bin/check_security_fixes.py
new file mode 100755 (executable)
index 0000000..4d87c93
--- /dev/null
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+#***************************************************************************
+#*  Copyright (C) 2003-2009 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                *
+#***************************************************************************/
+
+"""Checks that a working copy of plat/al has all the latest security patches
+applied. It uses the local SECURITY file to determine the list of mandatory
+patches.
+
+Important notice: do not execute this script directly from an automatic checkout
+of plat/al. It would be extremely unwise to execute it with root privileges from
+a place where everybody can change it !
+
+Usage (-w updates the local .htaccess to disable guilty working copies):
+  check_security_fixes.py [-w] -b REFERENCE_PLATAL PLATAL_TO_CHECK ...
+"""
+
+import optparse
+import os
+import re
+import sys
+import time
+
+
+class WorkingCopy(object):
+  """Helper class for analyzing the state of a working copy, and eventually
+  disabling it if an issue is found.
+
+  It disables the local checkout by updating its .htaccess file to deny all
+  requests with an explicit message which states how to fix the issue.
+  """
+
+  CORE_SECURITY_FILE = 'core/SECURITY'
+  MASTER_SECURITY_FILE = 'SECURITY'
+  SECURITY_FIX_RE = re.compile('^-[0-9]{4}')
+
+  HTACCESS_FILE = 'htdocs/.htaccess'
+  HTACCESS_TEMPLATE = 'Deny from all\nErrorDocument 403 "%s"\n'
+  HTACCESS_MTIME_DELTA = 86400 * 365 * 10
+  ERROR_MESSAGE_LINE = '<li>%s</li>\n'
+  ERROR_MESSAGE_TEMPLATE = """
+    Your local checkout of plat/al has been disabled for security reasons. It
+    appears that several critical flaws known in the plat/al codebase have not
+    been patched in your working copy. These flaws are listed below:
+    <ul>%s</ul>
+
+    Please have a look at the SECURITY and core/SECURITY files in any recent
+    plat/al checkout to get more details on which commits did fix those flaws.
+    <br/><br/>
+
+    <em>Note:</em> you can re-enable your working copy by typing
+    <code>make</code> in the root directory of your checkout (usually in
+    <code>~/dev/platal</code>).
+  """
+
+  def __init__(self, reference_path, checkout_path):
+    self.reference_path = reference_path
+    self.checkout_path = checkout_path
+
+  def GetPartialSecurityDiff(self, security_file):
+    """Diffs the reference and a local SECURITY file to find missing security
+    fixes. It filters out the diff result to extract the list of fixes."""
+
+    ref_file = os.path.join(self.reference_path, security_file)
+    wc_file = os.path.join(self.checkout_path, security_file)
+
+    diff = os.popen('diff -NBwu0 %s %s' % (ref_file, wc_file))
+    for line in diff.readlines():
+      if self.SECURITY_FIX_RE.match(line):
+        yield line[1:-1]
+
+  def GetSecurityDiff(self):
+    """Retrieves the missing security patches for various parts of plat/al."""
+
+    missing_fixes = []
+    missing_fixes.extend(self.GetPartialSecurityDiff(self.CORE_SECURITY_FILE))
+    missing_fixes.extend(self.GetPartialSecurityDiff(self.MASTER_SECURITY_FILE))
+    return missing_fixes
+
+  def GetErrorMessage(self, missing_fixes):
+    """Returns a the .htaccess HTML error message.
+
+    It builds an HTML message explaining why the working copy was disabled, how
+    to fix the underlying issues, and how to re-enable it."""
+
+    fixes_list = map(lambda item: self.ERROR_MESSAGE_LINE % item, missing_fixes)
+    return self.ERROR_MESSAGE_TEMPLATE % '\n'.join(fixes_list)
+
+  def Write403Htaccess(self, html_content):
+    """Updates the .htaccess to disable all requests, using |html_content| as
+    the error message. It also sets a modification time in the past to ensure
+    that any subsquent call to 'make' on the wc will actually overwrite the
+    .htaccess file."""
+
+    htaccess = os.path.join(self.checkout_path, self.HTACCESS_FILE)
+    ht_fd = open(htaccess, 'w')
+    ht_fd.write(self.HTACCESS_TEMPLATE % (html_content
+        .replace('\\', '\\\\')
+        .replace('"', '\\"')
+        .replace('\n', '\\\n')))
+    ht_fd.close()
+
+    mtime = time.time() - self.HTACCESS_MTIME_DELTA
+    os.utime(htaccess, (mtime, mtime))
+
+  def CheckAndDisableWorkingCopy(self, disable_when_flawed):
+    """Checks that the local working copy is in a sane state. If not, warns the
+    user by printing a message to the console, and disables the wc if
+    |disable_when_flawed| is set to true."""
+
+    missing_fixes = self.GetSecurityDiff()
+    if len(missing_fixes):
+      # Warn the user on the standard output.
+      print "Found %d missing security fixes in %s:" % (len(missing_fixes),
+                                                        self.checkout_path)
+      for issue in missing_fixes:
+        print "  * %s" % issue
+
+      # Disable the working copy.
+      if disable_when_flawed:
+        print "Disabling working copy in %s." % self.checkout_path
+        self.Write403Htaccess(self.GetErrorMessage(missing_fixes))
+
+def SelfCheckIsLatestVersion(base_path):
+  """Checks that this script is the latest available by comparing itself to
+  the reference script in |base_path|. It is important to do that check as
+  most deployment will want to execute this script with root privileges,
+  which implies that this script is deployed in a safe directory, and not
+  just executed from an automatically updated checkout of plat/al (how
+  unsafe would that be ...)."""
+
+  base_script = os.path.join(base_path, 'bin/check_security_fixes.py')
+  local_script = os.path.abspath(sys.argv[0])
+
+  if os.system('diff -q %s %s' % (base_script, local_script)) != 0:
+    sys.stderr.write('Please upgrade this script to the latest version.\n')
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('-b', '--base_path', action='store', dest='base_path')
+  parser.add_option('-w', '--write_htaccess', action='store_true',
+                    dest='write_htaccess', default=False)
+  (options, args) = parser.parse_args()
+
+  if options.base_path is None:
+    print "Error: option --base_path (or -b) is required for the script to run."
+    sys.exit(1)
+  if not os.path.exists(os.path.join(options.base_path,
+                                     WorkingCopy.MASTER_SECURITY_FILE)):
+    print "The base plat/al (%s) is too old to be used." % options.base_path
+    sys.exit(1)
+
+  SelfCheckIsLatestVersion(options.base_path)
+  for platal in args:
+    wc = WorkingCopy(options.base_path, platal)
+    wc.CheckAndDisableWorkingCopy(options.write_htaccess)
+
+if __name__ == '__main__':
+  main()
+
+# vim:set et sw=2 sts=2 sws=2 enc=utf-8:
index 044635a..e91d6e0 100755 (executable)
@@ -100,7 +100,7 @@ while ($sent_mails < $globals->lists->max_mail_per_min
     // send feedback to the mailing list owners
     if ($client->handle_request($list, $mid, $action, utf8_decode($reason))) {
         $sent_mails += $count;
-        $texte = "le message suivant :\n\n"
+        $texte = "Le message suivant :\n\n"
                . "    Auteur: {$mail['sender']}\n"
                . "    Sujet : « {$mail['subj']} »\n"
                . "    Date  : ".strftime("le %d %b %Y à %H:%M:%S", (int)$mail['stamp'])."\n\n"
index d08d381..bdf7330 100755 (executable)
@@ -37,17 +37,17 @@ list($nb, $age, $nbold, $nbveryold) = $res->fetchOneRow();
 $age = (time() - intval($age)) / 86400;
 $head = "";
 if ($age > 15) {
-    $head = "[autodestruction du serveur] ";
+    $head = "[Autodestruction du serveur] ";
 } elseif ($age > 7) {
-    $head = "[armageddon imminent] ";
+    $head = "[Armageddon imminent] ";
 } elseif ($age > 5) {
-    $head = "[guerre nucléaire] ";
+    $head = "[Guerre nucléaire] ";
 } elseif ($age > 3) {
     $head = "[ET Téléphone maison] ";
 } elseif ($age > 1) {
-    $head = "[réveil !] ";
+    $head = "[Réveil !] ";
 } elseif (!empty($nbveryold)) {
-    $head = "[urgent] ";
+    $head = "[Urgent] ";
 }
 
 
@@ -60,10 +60,10 @@ $plural = $nb == 1 ? "" : "s";
 $mymail = new PlMailer();
 $mymail->setFrom('validation@' . $globals->mail->domain);
 $mymail->addTo("validation@" . $globals->mail->domain);
-$mymail->setSubject($head . "il y a $nb validation$plural non effectuée$plural");
+$mymail->setSubject($head . "Il y a $nb validation$plural non effectuée$plural");
 
 $message =
-       "il y a $nb validation$plural à effectuer \n"
+       "Il y a $nb validation$plural à effectuer\n"
        .(empty($nbold)?"":"dont $nbold depuis le dernier mail !!!\n")
        .(empty($nbveryold)?"":"et dont *$nbveryold* ".($nbveryold == 1 ? "est" : "sont")." en retard de plus de 6h !!!")
        ."\n"
@@ -74,7 +74,7 @@ $res = XDB::iterRow("SELECT  type, count(*)
                    GROUP BY  type
                    ORDER BY  type");
 while (list($type, $nb) = $res->next()) {
-    $message .= "- $type: $nb\n";
+    $message .= "- $type : $nb\n";
 }
 
 $message = wordwrap($message,78);
index b237e52..520bb6a 100755 (executable)
 $panne_level = 3;
 
 require('./connect.db.inc.php');
+require("Console/Getopt.php");
+
+/*
+ * Parse the command-line options.
+ */
+$opts = Console_GetOpt::getopt($argv, 'v');
+$opt_verbose = false;
+
+if (PEAR::isError($opts)) {
+    echo $opts->getMessage();
+} else {
+    $opts = $opts[0];
+    foreach ($opts as $opt) {
+        if ($opt[0] == 'v') {
+            $opt_verbose = true;
+        }
+    }
+}
 
 /*
  * Check duplicated addresses
  */
-$sql = "SELECT a1.alias, a2.alias, e1.email
-          FROM emails        AS e1
-    INNER JOIN emails        AS e2 ON (e1.email = e2.email AND e1.uid != e2.uid
+$sql = "SELECT  a1.alias, a2.alias, e1.email
+          FROM  emails        AS e1
+    INNER JOIN  emails        AS e2 ON (e1.email = e2.email AND e1.uid != e2.uid
                                        AND (e1.uid < e2.uid OR NOT FIND_IN_SET('active', e2.flags)))
-     LEFT JOIN emails_watch  AS w  ON (e1.email = w.email)
-    INNER JOIN aliases       AS a1 ON (a1.id = e1.uid AND a1.type = 'a_vie')
-    INNER JOIN aliases       AS a2 ON (a2.id = e2.uid AND a2.type = 'a_vie')
-    INNER JOIN auth_user_md5 AS u1 ON (a1.id = u1.user_id)
-    INNER JOIN auth_user_md5 AS u2 ON (a2.id = u2.user_id)
-         WHERE FIND_IN_SET('active', e1.flags) AND u1.nom != u2.nom_usage AND u2.nom != u1.nom_usage AND w.email IS NULL
-      ORDER BY a1.alias";
+     LEFT JOIN  emails_watch  AS w  ON (e1.email = w.email)
+    INNER JOIN  aliases       AS a1 ON (a1.id = e1.uid AND a1.type = 'a_vie')
+    INNER JOIN  aliases       AS a2 ON (a2.id = e2.uid AND a2.type = 'a_vie')
+    INNER JOIN  auth_user_md5 AS u1 ON (a1.id = u1.user_id)
+    INNER JOIN  auth_user_md5 AS u2 ON (a2.id = u2.user_id)
+         WHERE  FIND_IN_SET('active', e1.flags) AND u1.nom != u2.nom_usage AND u2.nom != u1.nom_usage AND w.email IS NULL
+      ORDER BY  a1.alias";
 
 $it = Xdb::iterRow($sql);
 
@@ -56,8 +74,8 @@ if (count($conflits) > 0) {
         . "https://www.polytechnique.org/admin/emails/duplicated";
 
     echo "\n\n";
-    $sql = "INSERT IGNORE INTO emails_watch (email, state, detection, last)
-                        VALUES " . join(", ", $insert);
+    $sql = "INSERT IGNORE INTO  emails_watch (email, state, detection, last)
+                        VALUES  " . join(", ", $insert);
     XDB::execute($sql);
     if (XDB::errno() != 0) {
         echo 'Error : ' . XDB::error() . "\n$sql";
@@ -69,7 +87,7 @@ if (count($conflits) > 0) {
  */
 if ($panne_level > 0) {
     $sql = "SELECT  e.email, u.hruid
-              FROM  emails  AS e
+              FROM  emails        AS e
         INNER JOIN  auth_user_md5 AS u ON u.user_id = e.uid
              WHERE  e.panne_level = $panne_level AND e.flags = 'active'
           ORDER BY  u.hruid";
@@ -93,5 +111,26 @@ if ($panne_level > 0) {
                    WHERE  panne_level > $panne_level");
 }
 
+/*
+ * Retrieve the users with no active redirection, but still one working
+ * inactive redirection.
+ */
+if ($opt_verbose) {
+    $res = XDB::query("SELECT  u.hruid, ei.email
+                         FROM  auth_user_md5   AS u
+                    LEFT JOIN  emails          AS ea ON (ea.uid = u.user_id AND ea.flags='active')
+                   INNER JOIN  emails          AS ei ON (ei.uid = u.user_id AND ei.flags='')
+                        WHERE  FIND_IN_SET('googleapps', u.mail_storage) = 0 AND ea.email IS NULL
+                     GROUP BY  u.user_id");
+
+    if ($res->numRows()) {
+        $result = $res->fetchAllAssoc();
+        echo "Camarades n'ayant plus d'adresses actives, mais ayant une adresse inactive :\n";
+        foreach ($result as $user) {
+            echo '* ' . $user['email'] . ' pour ' . $user['hruid'] . "\n";
+        }
+        echo "\n";
+}
+
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
 ?>
index c533bd1..71b21c9 100644 (file)
@@ -24,6 +24,9 @@ class User extends PlUser
     private $_profile_fetched = false;
     private $_profile = null;
 
+    // Additional fields (non core)
+    protected $promo = null;
+
     // Implementation of the login to uid method.
     protected function getLogin($login)
     {
@@ -483,7 +486,7 @@ class User extends PlUser
     public static function _default_user_callback($login, $results)
     {
         $result_count = count($results);
-        if ($result_count == 0 || !S::has_perms()) {
+        if ($result_count == 0 || !S::admin()) {
             Platal::page()->trigError("Il n'y a pas d'utilisateur avec l'identifiant : $login");
         } else {
             Platal::page()->trigError("Il y a $result_count utilisateurs avec cet identifiant : " . join(', ', $results));
index 918f122..9ccdf37 100644 (file)
@@ -113,12 +113,12 @@ class XnetPage extends PlPage
                 $sub['créer une liste']     = "$dim/lists/create";
                 $sub['créer un alias']      = "$dim/alias/create";
             }
-            if (S::has_perms()) {
+            if (S::admin()) {
                 $sub['gérer les groupes'] = array('href' => 'admin', 'style' => 'color: gray;');
                 $sub['clear cache'] = array('href' => 'purge_cache?token=' . S::v('xsrf_token'), 'style' => 'color: gray;');
             }
             $menu['Administrer'] = $sub;
-        } elseif (S::has_perms()) {
+        } elseif (S::admin()) {
             $sub = array();
             $sub['gérer les groupes'] = 'admin';
             $sub['clear cache'] = 'purge_cache?token=' . S::v('xsrf_token');
index f757337..d61c69d 100644 (file)
@@ -208,7 +208,11 @@ class XorgSession extends PlSession
                          LEFT JOIN  gapps_accounts  AS g  ON(a.uid = g.l_userid AND g.g_status = 'active')
                          LEFT JOIN  logger.last_sessions AS ls ON (ls.uid = a.uid)
                          LEFT JOIN  logger.sessions AS s  ON(s.id = ls.id)
-                             WHERE  a.uid = {?} AND a.state = 'active'", $user->id());
+                             WHERE  a.uid = {?} AND u.perms IN('admin', 'user')", $user->id());
+        if ($res->numRows() != 1) {
+            return false;
+        }
+
         $sess = $res->fetchOneAssoc();
         $perms = $sess['perms'];
         unset($sess['perms']);
@@ -242,21 +246,6 @@ class XorgSession extends PlSession
         return true;
     }
 
-    /** Start a session without authentication data for the given user.
-     * This is used to identify the user after his registration, to be
-     * removed after rewriting registration procedure.
-     * XXX: Temporary
-     */
-    public function startWeakSession($user)
-    {
-        if (!$this->startSessionAs($user, AUTH_MDP)) {
-            $this->destroy();
-            return false;
-        }
-        S::set('auth', AUTH_MDP);
-        return true;
-    }
-
     private function securityChecks()
     {
         $mail_subject = array();
index 0994ace..f2ade2c 100644 (file)
@@ -4,16 +4,17 @@ WD=/home/web/prod/platal/bin/cron
 
 # db
 0  5 * * *     web     cd $WD; ./clean.php
-0 21 * * 1-6   web     cd $WD; ./checkdb.php    | mail -e -s "verifications sur la BDD de plat/al @VERSION@"         br@staff.m4x.org
-0 21 * * 0     web     cd $WD; ./checkdb.php -v | mail -e -s "verifications verbose sur la BDD de plat/al @VERSION@" br@staff.m4x.org
-0 20 * * *      web     cd $WD; ./emails.check.php | mail -e -s "qualite de l'annuaire"                   br@staff.m4x.org
+0 21 * * 1-6   web     cd $WD; ./checkdb.php    | mail -e -s "Verifications sur la BDD de plat/al @VERSION@"         br@staff.m4x.org
+0 21 * * 0     web     cd $WD; ./checkdb.php -v | mail -e -s "Verifications verbeuses sur la BDD de plat/al @VERSION@" br@staff.m4x.org
+0 20 2-31 * *   web     cd $WD; ./emails.check.php | mail -e -s "Qualite de l'annuaire"                   br@staff.m4x.org
+0 20 1 * *      web     cd $WD; ./emails.check.php  -v | mail -e -s "Qualite de l'annuaire : verbeux"                   br@staff.m4x.org
 0 22 * * *      web     cd $WD; ./phones.check.php > /dev/null
 
 # inscription report
 0  6 * * 1     web     cd $WD; ./rapports_inscription.php
 
 # notifs
-0  2 * * *     web     cd $WD; ./notifs.birthday.php    
+0  2 * * *     web     cd $WD; ./notifs.birthday.php
 0  4 * * 6     web     cd $WD; ./notifs.send.php
 
 # validations
@@ -23,7 +24,7 @@ WD=/home/web/prod/platal/bin/cron
 */5 * * * *     www-data     cd $WD; ./banana.feedgen.php > /dev/null
 
 # AX spammer
-15 * * * *      web     cd $WD; ./axletter.send.php | mail -e -s "envoi d'un mail de l'AX" br@staff.m4x.org
+15 * * * *      web     cd $WD; ./axletter.send.php | mail -e -s "Envoi d'un email de l'AX" br@staff.m4x.org
 
 # homonymes
 0 0 4 * *      web     cd $WD; ./homonymes.php
diff --git a/core b/core
index e8ddc3f..6c36b90 160000 (submodule)
--- a/core
+++ b/core
@@ -1 +1 @@
-Subproject commit e8ddc3f28701273de2b5c0f822146ab2a39dea91
+Subproject commit 6c36b907ae72344efb81730e3b41a0ddc9473cec
diff --git a/htdocs/images/medals/eufor.jpg b/htdocs/images/medals/eufor.jpg
new file mode 100644 (file)
index 0000000..5956b25
Binary files /dev/null and b/htdocs/images/medals/eufor.jpg differ
index 208e8d8..b34a2ec 100644 (file)
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
  ***************************************************************************/
 
-function readCookie(name)
-{
-    var nameEQ = name + "=";
-    var ca = document.cookie.split(';');
-    for(var i=0;i < ca.length;i++)
-    {
-        var c = ca[i];
-        while (c.charAt(0)==' ') c = c.substring(1,c.length);
-        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
-    }
-    return null;
-}
-
-
 function doChallengeResponse() {
     var new_pass = hash_encrypt(document.forms.login.password.value);
-    var old_pass = MD5(document.forms.login.password.value);
     
-    str = readCookie('ORGuid') + ":" +
+    str = document.forms.loginsub.username.value + ":" +
         hash_encrypt(document.forms.login.password.value) + ":" +
         document.forms.loginsub.challenge.value;
 
     document.forms.loginsub.response.value = hash_encrypt(str);
-    document.forms.loginsub.xorpass.value = hash_xor(new_pass, old_pass);
     document.forms.loginsub.remember.value = document.forms.login.remember.checked;
     document.forms.login.password.value = "";
     document.forms.loginsub.submit();
 }
+
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 353a8ad..2e53dc2 100644 (file)
@@ -39,4 +39,11 @@ function EnCryptedResponse() {
     document.forms.changepass2.submit();
     return true;
 }
+
+function EncryptedResponseInNestedForm() {
+    $('[name=nouveau]').val($('[name=password]').val());
+    $('[name=nouveau2]').val($('[name=password2]').val());
+    EnCryptedResponse();
+}
+
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 70159b3..a85063b 100644 (file)
@@ -120,6 +120,15 @@ function updateNameDisplay()
     });
 }
 
+function toggleParticle(id)
+{
+    if ($('#search_name_' + id).find("[name*='[particle]']").val() == '') {
+        $('#search_name_' + id).find("[name*='[particle]']").val(1);
+    } else {
+        $('#search_name_' + id).find("[name*='[particle]']").val('');
+    }
+}
+
 // Nationalities {{{1
 
 function delNationality(i)
@@ -335,15 +344,15 @@ function removeTel(id)
 
 function addPhoneComment(id)
 {
-    $(id + '_comment').show();
-    $(id + '_addComment').hide();
+    $('#' + id + '_comment').show();
+    $('#' + id + '_addComment').hide();
 }
 
 function removePhoneComment(id, pref)
 {
-    $(id + '_comment').hide();
-    $(id + '_comment').find("[name='" + pref + "[comment]']").val('');
-    $(id + '_addComment').show();
+    $('#' + id + '_comment').hide();
+    $('#' + id + '_comment').find("[name='" + pref + "[comment]']").val('');
+    $('#' + id + '_addComment').show();
 }
 
 // {{{1 Groups
index 89c35b2..3ea7bec 100644 (file)
@@ -212,6 +212,7 @@ function auto_links() {
     url  = document.URL;
     fqdn = url.replace(/^https?:\/\/([^\/]*)\/.*$/,'$1');
     light = (url.indexOf('display=light') > url.indexOf('?'));
+    resource_page = (url.indexOf('rss') > -1 || url.indexOf('ical') > -1);
 
     $("a,link").each(
         function(i) {
@@ -235,7 +236,7 @@ function auto_links() {
                     href = 'http://' + fqdn + '/' + href;
                 }
             }
-            if (this.nodeName.toLowerCase() == 'a') {
+            if (this.nodeName.toLowerCase() == 'a' && !resource_page) {
                 if (rss && href.indexOf('prefs/rss') < 0 &&  (href.indexOf('xml') > -1 || href.indexOf('hash'))) {
                     goodiesPopup(this, __goodies_rss);
                 } else if (ical) {
index 7f1a842..61418cf 100644 (file)
@@ -25,7 +25,8 @@ $platal = new Xorg('auth', 'carnet', 'email', 'events', 'forums',
                    'lists', 'marketing', 'payment', 'platal',
                    'profile', 'register', 'search', 'stats', 'admin',
                    'newsletter', 'axletter', 'bandeau', 'survey',
-                   'fusionax', 'gadgets', 'googleapps', 'poison', 'openid');
+                   'fusionax', 'gadgets', 'googleapps', 'poison',
+                   'openid', 'reminder');
 
 if (!($path = Env::v('n')) || ($path{0} < 'A' || $path{0} > 'Z')) {
     $platal->run();
index c609d4a..393d39a 100644 (file)
@@ -24,7 +24,7 @@ require_once 'banana/hooks.inc.php';
 
 function hook_checkcancel($_headers)
 {
-    return ($_headers['x-org-id'] == S::v('hruid') or S::has_perms());
+    return ($_headers['x-org-id'] == S::v('hruid') or S::admin());
 }
 
 class ForumsBanana extends Banana
@@ -41,7 +41,7 @@ class ForumsBanana extends Banana
         array_push(Banana::$msgparse_headers, 'x-org-id', 'x-org-mail');
         Banana::$nntp_host = 'news://web_' . $user->login()
                            . ":{$globals->banana->password}@{$globals->banana->server}:{$globals->banana->port}/";
-        if (S::has_perms()) {
+        if (S::admin()) {
             Banana::$msgshow_mimeparts[] = 'source';
         }
         Banana::$debug_nntp = ($globals->debug & DEBUG_BT);
index 6c4f19d..9e37484 100644 (file)
@@ -214,7 +214,7 @@ function make_Organization()
     global $globals;
     $perms = S::v('perms');
     $group = $globals->asso('nom');
-    if (S::has_perms()) {
+    if (S::admin()) {
         return "Administrateur de Polytechnique.org";
     } else if ($group && $perms->hasFlag('groupadmin')) {
         return "Animateur de $group";
@@ -319,7 +319,9 @@ class BananaHandler
     {
     }
 
-    public function process()
+    public function success() { }
+
+    public function process(&$success)
     {
         return PlWizard::CURRENT_PAGE;
     }
index e2457f3..2ec904b 100644 (file)
@@ -59,7 +59,7 @@ class MLBanana extends Banana
         Banana::$debug_smarty = ($globals->debug & DEBUG_SMARTY);
         Banana::$mbox_helper = $globals->banana->mbox_helper;
         Banana::$feed_updateOnDemand = true;
-        if (S::has_perms()) {
+        if (S::admin()) {
             Banana::$msgshow_mimeparts[] = 'source';
         }
         array_push(Banana::$msgparse_headers, 'x-org-id', 'x-org-mail');
index 753eb40..d789360 100644 (file)
@@ -25,7 +25,7 @@ require_once 'banana/hooks.inc.php';
 
 function hook_checkcancel($_headers)
 {
-    return ($_headers['x-org-id'] == S::v('hruid') or S::has_perms());
+    return ($_headers['x-org-id'] == S::v('hruid') or S::admin());
 }
 
 function hook_makeLink($params)
index e6ae449..084d25b 100644 (file)
@@ -74,6 +74,87 @@ function isvalid_email_redirection($email)
         !preg_match("/@(polytechnique\.(org|edu)|melix\.(org|net)|m4x\.org)$/", $email);
 }
 
+// function ids_from_mails() {{{1
+// Converts an array of emails to an array of email => uid
+function ids_from_mails(array $emails)
+{
+    global $globals;
+    $domain_mails = array();
+    $alias_mails  = array();
+    $other_mails  = array();
+
+    // Determine the type of the email adresses. It can eiher be a domain
+    // email (@polytechnique.org), an alias email (@melix.net) or any other
+    // email (potentially used as a redirection by one user)
+    foreach ($emails as $email) {
+        if (strpos($email, '@') === false) {
+            $user = $email;
+            $domain = $globals->mail->domain2;
+        } else {
+            list($user, $domain) = explode('@', $email);
+        }
+        if ($domain == $globals->mail->alias_dom || $domain == $globals->mail->alias_dom2) {
+            list($user) = explode('+', $user);
+            list($user) = explode('_', $user);
+            $alias_mails[$user] = $email;
+        } elseif ($domain == $globals->mail->domain || $domain == $globals->mail->domain2) {
+            list($user) = explode('+', $user);
+            list($user) = explode('_', $user);
+            $domain_mails[$user] = $email;
+        } else {
+            $other_mails[] = $email;
+        }
+    }
+    $uids = array();
+
+    // Look up user ids for addresses in domain
+    if (count($domain_mails)) {
+        $domain_users = array_map(array('XDB', 'escape'), array_keys($domain_mails));
+        $list = implode(',', $domain_users);
+        $res = XDB::query("SELECT   alias, id
+                             FROM   aliases
+                            WHERE   alias IN ($list)");
+        foreach ($res->fetchAllRow() as $row) {
+            list ($alias, $id) = $row;
+            $uids[$domain_mails[$alias]] = $id;
+        }
+    }
+
+    // Look up user ids for addresses in our alias domain
+    if (count($alias_mails)) {
+        $alias_users = array();
+        foreach (array_keys($alias_mails) as $user) {
+            $alias_users[] = XDB::escape($user."@".$globals->mail->alias_dom);
+        }
+        $list = implode(',', $alias_users);
+        $res = XDB::query("SELECT   v.alias, a.id
+                             FROM   virtual             AS v
+                       INNER JOIN   virtual_redirect    AS r USING(vid)
+                       INNER JOIN   aliases             AS a ON (a.type = 'a_vie'
+                                    AND r.redirect = CONCAT(a.alias, '@{$globals->mail->domain2}'))
+                            WHERE   v.alias IN ($list)");
+        foreach ($res->fetchAllRow() as $row) {
+            list ($alias, $id) = $row;
+            $uids[$alias_mails[$alias]] = $id;
+        }
+    }
+
+    // Look up user ids for other addresses in the email redirection list
+    if (count($other_mails)) {
+        $other_users = array_map(array('XDB', 'escape'), $other_mails);
+        $list = implode(',', $other_users);
+        $res = XDB::query("SELECT   email, uid
+                             FROM   emails
+                            WHERE   email IN ($list)");
+        foreach ($res->fetchAllRow() as $row) {
+            list ($email, $uid) = $row;
+            $uids[$other_mails[$email]] = $uid;
+        }
+    }
+
+    return $uids;
+}
+
 // class Bogo {{{1
 // The Bogo class represents a spam filtering level in plat/al architecture.
 class Bogo
@@ -252,7 +333,7 @@ class EmailRedirection extends Email
 
     public function clean_errors()
     {
-        if (!S::has_perms()) {
+        if (!S::admin()) {
             return false;
         }
         $this->panne       = 0;
@@ -328,7 +409,7 @@ class EmailStorage extends Email
 
         // 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()) {
+        if ($globals->mailstorage->imap_active || S::admin()) {
             $storages[] = 'imap';
         }
 
@@ -553,7 +634,7 @@ class Redirect
     {
         XDB::execute("UPDATE  emails
                          SET  flags = 'disable'
-                       WHERE  flags = 'active' AND uid = {?}", $this->user->id);
+                       WHERE  flags = 'active' AND uid = {?}", $this->user->id());
         foreach ($this->emails as &$mail) {
             if ($mail->active && $mail->has_disable()) {
                 $mail->disabled = true;
@@ -569,7 +650,7 @@ class Redirect
     {
         XDB::execute("UPDATE  emails
                          SET  flags = 'active'
-                       WHERE  flags = 'disable' AND uid = {?}", $this->user->id);
+                       WHERE  flags = 'disable' AND uid = {?}", $this->user->id());
         foreach ($this->emails as &$mail) {
             if ($mail->disabled) {
                 $mail->active   = true;
index cb27635..2e99434 100644 (file)
@@ -337,7 +337,12 @@ class GMapsGeocoder extends Geocoder {
             $address['text'] = $address['geoloc'];
             $address['postalText'] = $address['geocodedPostalText'];
             unset($address['geoloc'], $address['geocodedPostalText']);
+        } else {
+            $address['geoloc'] = str_replace("\n", "\r\n", $address['geoloc']);
+            $address['geocodedPostalText'] = str_replace("\n", "\r\n", $address['geocodedPostalText']);
         }
+        $address['text'] = str_replace("\n", "\r\n", $address['text']);
+        $address['postalText'] = str_replace("\n", "\r\n", $address['postalText']);
     }
  
     // Returns the address formated for postal use.
index b90a749..d63af4d 100644 (file)
@@ -107,6 +107,9 @@ class GoogleAppsAccount
     public $r_last_webmail;
     public $reporting_date;
 
+    // Nicknames (aliases) registered for that user, lazily loaded.
+    public $nicknames;
+
     // Pending requests in the gappsd job queue (cf. top note).
     public $pending_create;
     public $pending_delete;
@@ -260,6 +263,21 @@ class GoogleAppsAccount
         return $this->g_status == 'disabled';
     }
 
+    // Loads and returns the list of nicknames for the user.
+    public function nicknames()
+    {
+        if ($this->nicknames == null) {
+            $res = XDB::query(
+                "SELECT  g_nickname
+                   FROM  gapps_nicknames
+                  WHERE  g_account_name = {?}
+               ORDER BY  g_nickname",
+                $this->g_account_name);
+            $this->nicknames = $res->fetchColumn();
+        }
+        return $this->nicknames;
+    }
+
 
     // Changes the GoogleApps password.
     public function set_password($password) {
index d0c0f22..aef47cd 100644 (file)
@@ -283,7 +283,7 @@ function set_alias_names(&$sn_new, $sn_old, $update_new = false, $new_alias = nu
                      $new_alias, S::i('uid'));
     }
     require_once('user.func.inc.php');
-    user_reindex($uid);
+    user_reindex(S::i('uid'));
     return $has_new;
 }
 
diff --git a/include/reminder.inc.php b/include/reminder.inc.php
new file mode 100644 (file)
index 0000000..cede617
--- /dev/null
@@ -0,0 +1,227 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+// Base class for a reminder; it offers the factory for creating valid reminders
+// tailored for a given user, as well as base methods for reminder impls.
+// Sub-classes should define at least the abstract methods, and the static
+// IsCandidate method (prototype: (User &$user)).
+//
+// Usage:
+//   // Instantiates and returns a valid Reminder object for the user.
+//   $reminder = Reminder::GetCandidateReminder($user);
+//
+//   // Returns the named Reminder object.
+//   $reminder = Reminder::GetByName($user, 'ax_letter');
+abstract class Reminder
+{
+    // Details about the reminder.
+    public $name;
+    protected $type_id;
+    protected $weight;
+    protected $remind_delay_yes;
+    protected $remind_delay_no;
+    protected $remind_delay_dismiss;
+
+    // Details about the user.
+    protected $user;
+    protected $current_status;
+    protected $last_ask;
+
+    // Constructs the Reminder object from a mandatory User instance, a list of
+    // key-value pairs from the `reminder_type` and `reminder` tables.
+    function __construct(User &$user, array $type)
+    {
+        $this->user = &$user;
+
+        $this->type_id              = $type['type_id'];
+        $this->name                 = $type['name'];
+        $this->weight               = $type['weight'];
+        $this->remind_delay_yes     = $type['remind_delay_yes'];
+        $this->remind_delay_no      = $type['remind_delay_no'];
+        $this->remind_delay_dismiss = $type['remind_delay_dismiss'];
+
+        if (isset($type['status'])) {
+            $this->current_status = $type['status'];
+        }
+        if (isset($type['remind_last'])) {
+            $this->last_ask = $type['remind_last'];
+        }
+    }
+
+    // Updates (or creates) the reminder line for the pair (|user|, |reminder_id|)
+    // using the |status| as status, and the |next_ask| as the delay between now
+    // and the next ask (if any).
+    private static function UpdateStatus($user_id, $type_id, $status, $next_ask)
+    {
+        XDB::execute('REPLACE INTO  reminder
+                               SET  uid = {?}, type_id = {?}, status = {?},
+                                    remind_last = NOW(), remind_next = FROM_UNIXTIME({?})',
+                     $user_id, $type_id, $status,
+                     ($next_ask > 0 ? time() + $next_ask * 24 * 60 * 60 : null));
+    }
+
+    // Updates the status of the reminder for the current user.
+    protected function UpdateOnYes()
+    {
+        $this->UpdateStatus($this->user->id(), $this->type_id,
+                            'yes', $this->remind_delay_yes);
+    }
+    protected function UpdateOnNo()
+    {
+        $this->UpdateStatus($this->user->id(), $this->type_id,
+                            'no', $this->remind_delay_no);
+    }
+    protected function UpdateOnDismiss()
+    {
+        $this->UpdateStatus($this->user->id(), $this->type_id,
+                            'dismiss', $this->remind_delay_dismiss);
+    }
+
+    // Display and http handling helpers --------------------------------------
+
+    // Handles a hit on the reminder onebox (for links made using the GetBaseUrl
+    // method below).
+    abstract public function HandleAction($action);
+
+    // Displays a reduced version of the reminder and notifies that the action
+    // has been taken into account.
+    public function NotifiesAction(&$page)
+    {
+        header('Content-Type: text/html; charset=utf-8');
+        $page->changeTpl('reminder/notification.tpl', NO_SKIN);
+        $page->assign('previous_reminder', $this->title());
+    }
+
+    // Displays the reminder as a standalone html snippet. It should be used
+    // when the reminder is the only output of a page.
+    public function DisplayStandalone(&$page, $previous_reminder = null)
+    {
+        header('Content-Type: text/html; charset=utf-8');
+        $page->changeTpl('reminder/base.tpl', NO_SKIN);
+        $this->Prepare($page);
+        if ($previous_reminder) {
+            $page->assign('previous_reminder', $previous_reminder);
+        }
+    }
+
+    // Prepares the display by assigning template variables.
+    public function Prepare(&$page)
+    {
+        $page->assign_by_ref('reminder', $this);
+    }
+
+    // Returns the name of the inner template, or null if a simple text obtained
+    // from GetText should be printed.
+    public function template() { return null; }
+
+    // Returns the text to display in the onebox, or null if a
+    public function text() { return ''; }
+
+    // Returns the title of the onebox.
+    public function title() { return ''; }
+
+    // Should return true if this onebox needs to be considered as a warning and
+    // not just as a subscription offer.
+    public function warning() { return false; }
+
+    // Returns the base url for the reminder module.
+    public function baseurl()
+    {
+        return 'ajax/reminder/' . $this->name;
+    }
+
+    // Returns the url for the information page.
+    public function info() { return ''; }
+
+    // Static status update methods -------------------------------------------
+
+    // Marks the candidate reminder as having been accepted for user |user_id|.
+    // It is intended to be used when a reminder box has been bypassed, and when
+    // it should behave as if the user had clicked on 'yes'.
+    protected static function MarkCandidateAsAccepted($user_id, $candidate)
+    {
+        Reminder::UpdateStatus($user_id, $candidate['type_id'],
+                               'yes', $candidate['remind_delay_yes']);
+    }
+
+    // Static factories -------------------------------------------------------
+
+    // Returns a chosen class using the user data from |user|, and from the database.
+    public static function GetCandidateReminder(User &$user)
+    {
+        $res = XDB::query('SELECT  rt.*, r.status, r.remind_last
+                             FROM  reminder_type AS rt
+                        LEFT JOIN  reminder      AS r ON (rt.type_id = r.type_id AND r.uid = {?})
+                            WHERE  r.uid IS NULL OR r.remind_next < NOW()',
+                          $user->id());
+        $candidates  = $res->fetchAllAssoc();
+
+        $weight_map = create_function('$a', 'return $a["weight"];');
+        while (count($candidates) > 0) {
+            $position = rand(1, array_sum(array_map($weight_map, $candidates)));
+            foreach ($candidates as $key => $candidate) {
+                $position -= $candidate['weight'];
+                if ($position <= 0) {
+                    $class = self::GetClassName($candidate['name']);
+                    if ($class && call_user_func(array($class, 'IsCandidate'), $user, $candidate)) {
+                        return new $class($user, $candidate);
+                    }
+                    unset($candidates[$key]);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    // Returns an instantiation of the reminder class which name is |name|, using
+    // user data from |user|, and from the database.
+    public static function GetByName(User &$user, $name)
+    {
+        if (!($class = self::GetClassName($name))) {
+            return null;
+        }
+
+        $res = XDB::query('SELECT  rt.*, r.status, r.remind_last
+                             FROM  reminder_type AS rt
+                        LEFT JOIN  reminder      AS r ON (rt.type_id = r.type_id AND r.uid = {?})
+                            WHERE  rt.name = {?}',
+                          $user->id(), $name);
+        if ($res->numRows() > 0) {
+            return new $class($user, $res->fetchOneAssoc());
+        }
+
+        return null;
+    }
+
+    // Computes the name of the class for reminder named |name|, and preloads
+    // the class.
+    private static function GetClassName($name)
+    {
+        include_once "reminder/$name.inc.php";
+        $class = 'Reminder' . str_replace(' ', '', ucwords(str_replace('_', ' ', $name)));
+        return (class_exists($class) ? $class : null);
+    }
+}
+
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/include/reminder/ax_letter.inc.php b/include/reminder/ax_letter.inc.php
new file mode 100644 (file)
index 0000000..c7f62c9
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderAxLetter extends Reminder
+{
+    public function HandleAction($action)
+    {
+        if ($action == 'yes') {
+            Platal::load('axletter', 'axletter.inc.php');
+            AXLetter::subscribe();
+            $this->UpdateOnYes();
+        }
+
+        if ($action == 'dismiss') {
+            $this->UpdateOnDismiss();
+        }
+
+        if ($action == 'no') {
+            $this->UpdateOnNo();
+        }
+    }
+
+    public function text()
+    {
+        return "La lettre de l'AX te permet de recevoir régulièrement les
+            informations importantes de l'AX.";
+    }
+    public function title()
+    {
+        return "Inscription à la lettre de l'AX";
+    }
+    public function info()
+    {
+        return 'Xorg/MailsAX';
+    }
+
+    public static function IsCandidate(User &$user, $candidate)
+    {
+        Platal::load('axletter', 'axletter.inc.php');
+        $isSubscribed = AXLetter::subscriptionState();
+        if ($isSubscribed) {
+            Reminder::MarkCandidateAsAccepted($user->id(), $candidate);
+        }
+        return !$isSubscribed;
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/include/reminder/email_backup.inc.php b/include/reminder/email_backup.inc.php
new file mode 100644 (file)
index 0000000..76108f7
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderEmailBackup extends Reminder
+{
+    public function HandleAction($action)
+    {
+        if ($action == 'yes') {
+            require_once 'emails.inc.php';
+            $storage = new EmailStorage($this->user, 'imap');
+            $storage->activate();
+
+            $this->UpdateOnYes();
+        }
+
+        if ($action == 'dismiss') {
+            $this->UpdateOnDismiss();
+        }
+
+        if ($action == 'no') {
+            $this->UpdateOnNo();
+        }
+    }
+
+    public function text()
+    {
+        return "Tu peux bénéficier d'une sauvegarde des emails. Cela permet
+            d'avoir un accès de secours aux 30 derniers jours d'emails reçus
+            sur ton adresse Polytechnique.org.";
+    }
+    public function title()
+    {
+        return 'Sauvegarde de tes emails';
+    }
+    public function info()
+    {
+        return 'Xorg/IMAP';
+    }
+
+    public static function IsCandidate(User &$user, $candidate)
+    {
+        require_once 'emails.inc.php';
+        $storage  = new EmailStorage($user, 'imap');
+        if ($storage->active) {
+            Reminder::MarkCandidateAsAccepted($user->id(), $candidate);
+        }
+        return !$storage->active;
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/include/reminder/email_warning.inc.php b/include/reminder/email_warning.inc.php
new file mode 100644 (file)
index 0000000..1b8f901
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderEmailWarning extends Reminder
+{
+    public function HandleAction($action)
+    {
+        if ($action == 'dismiss') {
+            $this->UpdateOnDismiss();
+        }
+    }
+
+    public function template()
+    {
+        return 'reminder/email_warning.tpl';
+    }
+    public function title()
+    {
+        return "Problème avec ta redirections d'emails";
+    }
+    public function warning()
+    {
+        return true;
+    }
+
+    public static function IsCandidate(User &$user, $candidate)
+    {
+        return count(S::v('mx_failures', array())) > 0;
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/include/reminder/gapps.inc.php b/include/reminder/gapps.inc.php
new file mode 100644 (file)
index 0000000..a420070
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderGapps extends Reminder
+{
+    public function HandleAction($action)
+    {
+        switch ($action) {
+          case 'yes':
+            $this->UpdateOnDismiss();
+            pl_redirect('googleapps');
+            break;
+
+          case 'dismiss':
+            $this->UpdateOnDismiss();
+            break;
+
+          case 'no':
+            $this->UpdateOnNo();
+            break;
+        }
+    }
+
+    public function template()
+    {
+        return 'reminder/gapps.tpl';
+    }
+    public function title()
+    {
+        return "Création d'un compte Google Apps";
+    }
+    public function info()
+    {
+        return 'Xorg/GoogleApps';
+    }
+
+    public static function IsCandidate(User &$user, $candidate)
+    {
+        require_once 'googleapps.inc.php';
+        $isSubscribed = GoogleAppsAccount::account_status($user->id());
+        if ($isSubscribed == 'disabled') {
+            $isSubscribed = false;
+        }
+        if ($isSubscribed) {
+            Reminder::MarkCandidateAsAccepted($user->id(), $candidate);
+        }
+        return !$isSubscribed;
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/include/reminder/ml.inc.php b/include/reminder/ml.inc.php
new file mode 100644 (file)
index 0000000..fa45b0b
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderMl extends Reminder
+{
+    public function HandleAction($action)
+    {
+        switch ($action) {
+          case 'suscribe':
+            S::assert_xsrf_token();
+            $subs = array_keys(Post::v('sub_ml'));
+            $current_domain = null;
+
+            $res = XDB::iterRow("SELECT  sub, domain
+                                   FROM  register_subs
+                                  WHERE  uid = {?} AND type = 'list'
+                               ORDER BY  domain",
+                                S::i('uid'));
+            while (list($sub, $domain) = $res->next()) {
+                if (array_shift($subs) == "$sub@$domain") {
+                    if ($domain != $current_domain) {
+                        $current_domain = $domain;
+                    }
+                    $client = new MMList(S::v('uid'), S::v('password'), $domain);
+                    $client->subscribe($sub);
+                }
+            }
+
+            $this->UpdateOnYes();
+            pl_redirect('lists');
+            break;
+
+          case 'dismiss':
+            $this->UpdateOnDismiss();
+            break;
+
+          case 'no':
+            $this->UpdateOnNo();
+            break;
+        }
+    }
+
+    public function Prepare(&$page)
+    {
+        parent::Prepare($page);
+
+        $res = XDB::iterRow("SELECT  sub, domain
+                               FROM  register_subs
+                              WHERE  uid = {?} AND type = 'list'
+                           ORDER BY  domain",
+                            S::i('uid'));
+        $current_domain = null;
+        $lists = array();
+        while (list($sub, $domain) = $res->next()) {
+            if ($current_domain != $domain) {
+                $current_domain = $domain;
+                $client = new MMList(S::v('uid'), S::v('password'), $domain);
+            }
+            list($details, ) = $client->get_members($sub);
+            $lists["$sub@$domain"] = $details;
+        }
+        $page->assign_by_ref('lists', $lists);
+    }
+
+    public function template()
+    {
+        return 'reminder/ml.tpl';
+    }
+    public function title()
+    {
+        return "Inscription aux listes de diffusion";
+    }
+
+    public static function IsCandidate(User &$user, $candidate)
+    {
+        $res = XDB::query("SELECT  COUNT(*) AS lists
+                             FROM  register_subs
+                            WHERE  uid = {?} AND type = 'list'",
+                          $user->id());
+
+        $mlCount = $res->fetchOneCell();
+        if (!$mlCount) {
+            Reminder::MarkCandidateAsAccepted($user->id(), $candidate);
+        }
+        return ($mlCount > 0);
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/include/reminder/nl.inc.php b/include/reminder/nl.inc.php
new file mode 100644 (file)
index 0000000..ddb0109
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderNl extends Reminder
+{
+    public function HandleAction($action)
+    {
+        if ($action == 'yes') {
+            require_once 'newsletter.inc.php';
+            NewsLetter::subscribe();
+            $this->UpdateOnYes();
+        }
+
+        if ($action == 'dismiss') {
+            $this->UpdateOnDismiss();
+        }
+
+        if ($action == 'no') {
+            $this->UpdateOnNo();
+        }
+    }
+
+    public function text()
+    {
+        return "La lettre mensuelle de Polytechnique.org te permet de recevoir
+            chaque mois des informations sur les activités et nouvelles de la
+            communauté des X.";
+    }
+    public function title()
+    {
+        return "Inscription à la lettre mensuelle";
+    }
+
+    public static function IsCandidate(User &$user, $candidate)
+    {
+        require_once 'newsletter.inc.php';
+        $isSubscribed = NewsLetter::subscriptionState();
+        if ($isSubscribed) {
+            Reminder::MarkCandidateAsAccepted($user->id(), $candidate);
+        }
+        return !$isSubscribed;
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/include/reminder/no_redirection.inc.php b/include/reminder/no_redirection.inc.php
new file mode 100644 (file)
index 0000000..dd936fa
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderNoRedirection extends Reminder
+{
+    public function HandleAction($action)
+    {
+        if ($action == 'dismiss') {
+            $this->UpdateOnDismiss();
+        }
+    }
+
+    public function template()
+    {
+        return 'reminder/no_redirection.tpl';
+    }
+    public function title()
+    {
+        return "Problème avec ta redirection d'emails";
+    }
+    public function warning()
+    {
+        return true;
+    }
+    public function info()
+    {
+        return 'Xorg/MesAdressesDeRedirection';
+    }
+
+    public static function IsCandidate(User &$user, $candidate)
+    {
+        return S::v('no_redirect');
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/include/reminder/profile_update.inc.php b/include/reminder/profile_update.inc.php
new file mode 100644 (file)
index 0000000..4609977
--- /dev/null
@@ -0,0 +1,104 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderProfileUpdate extends Reminder
+{
+    public function HandleAction($action)
+    {
+        switch ($action) {
+          case 'dismiss':
+            $this->UpdateOnDismiss();
+            break;
+
+          case 'profile':
+            $this->UpdateOnDismiss();
+            pl_redirect('profile/edit');
+            break;
+
+          case 'photo':
+            $this->UpdateOnDismiss();
+            pl_redirect('photo/change');
+            break;
+
+          case 'geoloc':
+            $this->UpdateOnDismiss();
+            pl_redirect('profile/edit/adresses');
+            break;
+        }
+    }
+
+    public function Prepare(&$page)
+    {
+        parent::Prepare($page);
+
+        $res = XDB::query('SELECT  date < DATE_SUB(NOW(), INTERVAL 365 DAY) AS is_profile_old,
+                                   date AS profile_date, LENGTH(p.attach) > 0 AS has_photo
+                             FROM  auth_user_md5     AS u
+                        LEFT JOIN  photo             AS p ON (u.user_id = p.uid)
+                            WHERE  user_id = {?}',
+                          $this->user->id());
+        list($is_profile_old, $profile_date, $has_photo) = $res->fetchOneRow();
+
+        $page->assign('profile_incitation', $is_profile_old);
+        $page->assign('profile_last_update', $profile_date);
+        $page->assign('photo_incitation', !$has_photo);
+
+        $res = XDB::query('SELECT  COUNT(*)
+                             FROM  profile_addresses
+                            WHERE  pid = {?} AND accuracy = 0'
+                          $this->user->id());
+        $page->assign('geocoding_incitation', $res->fetchOneCell());
+    }
+
+    public function template()
+    {
+        return 'reminder/profile_update.tpl';
+    }
+    public function title()
+    {
+        return "Mise à jour de ton profil";
+    }
+    public function warning()
+    {
+        return true;
+    }
+
+    public static function IsCandidate(User &$user, $candidate)
+    {
+        $res = XDB::query('SELECT  date < DATE_SUB(NOW(), INTERVAL 365 DAY) AS is_profile_old,
+                                   p.attach AS photo
+                             FROM  auth_user_md5 AS u
+                        LEFT JOIN  photo         AS p ON (u.user_id = p.uid)
+                            WHERE  user_id = {?}',
+                          $user->id());
+        list($is_profile_old, $has_photo) = $res->fetchOneRow();
+
+        $res = XDB::query('SELECT  COUNT(*)
+                             FROM  profile_addresses
+                            WHERE  pid = {?} AND accuracy = 0'
+                          $this->user->id());
+
+        return ($res->fetchOneCell() || !$has_photo || $is_profile_old);
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/include/reminder/promotion_ml.inc.php b/include/reminder/promotion_ml.inc.php
new file mode 100644 (file)
index 0000000..b67b59b
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderPromotionMl extends Reminder
+{
+    public function HandleAction($action)
+    {
+        switch ($action) {
+          case 'yes':
+            $res = XDB::query('SELECT  id
+                                 FROM  groupex.asso
+                                WHERE  diminutif = {?}',
+                            S::v('promo'));
+            $asso_id = $res->fetchOneCell();
+            XDB::execute('REPLACE INTO  groupex.membres (uid, asso_id)
+                                VALUES  ({?}, {?})',
+                         S::v('uid'), $asso_id);
+            $mmlist = new MMList(S::v('uid'), S::v('password'));
+            $mmlist->subscribe('promo' . S::v('promo'));
+
+            $this->UpdateOnYes();
+            break;
+
+          case 'dismiss':
+            $this->UpdateOnDismiss();
+            break;
+
+          case 'no':
+            $this->UpdateOnNo();
+            break;
+        }
+    }
+
+    public function text()
+    {
+        return "La liste de diffusion de ta promotion permet de recevoir les
+            informations plus spécifiques de ta promotion pour pouvoir
+            participer plus facilement aux événements qu'elle organise. Tu
+            seras aussi inscrit dans le groupe de la promotion " .
+            $this->user->promo() . '.';
+    }
+    public function title()
+    {
+        return "Inscription à la liste de diffusion de ta promotion";
+    }
+
+    public static function IsCandidate(User &$user, $candidate)
+    {
+        // We only test if the user is in her promotion group for it is too
+        // expensive to check if she is in the corresponding ML as well.
+        $res = XDB::query('SELECT  COUNT(*)
+                             FROM  groupex.membres
+                            WHERE  uid = {?} AND asso_id = (SELECT  id
+                                                              FROM  groupex.asso
+                                                             WHERE  diminutif = {?})',
+                          $user->id(), S::v('promo'));
+
+        $mlCount = $res->fetchOneCell();
+        if ($mlCount) {
+            Reminder::MarkCandidateAsAccepted($user->id(), $candidate);
+        }
+        return ($mlCount == 0);
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
index 9e9aa45..e5c0b19 100644 (file)
@@ -108,7 +108,7 @@ function send_warning_mail($title)
 
 function kill_sessions()
 {
-    assert(S::has_perms());
+    assert(S::admin());
     shell_exec('sudo -u root ' . dirname(dirname(__FILE__)) . '/bin/kill_sessions.sh');
 }
 
index 8853164..6d269d8 100644 (file)
@@ -68,10 +68,9 @@ class EntrReq extends Validate
                 $where .= "name LIKE '%" . $name_array[$i] . "%'";
             }
         }
-        $res = XDB::iterator("SELECT  name
-                             FROM  profile_job_enum
-                            WHERE  "
-                          . $where);
+        $res = XDB::iterator('SELECT  name
+                                FROM  profile_job_enum
+                               WHERE  ' . $where);
         $this->suggestions = "| ";
         while ($sug = $res->next()) {
             $this->suggestions .= $sug['name'] . " | ";
@@ -147,6 +146,8 @@ class EntrReq extends Validate
 
     public function commit()
     {
+        // TODO: use address and phone classes to update profile_job_enum and profile_phones once they are done.
+
         $res = XDB::query('SELECT  id
                              FROM  profile_job_enum
                             WHERE  name = {?}',
@@ -159,15 +160,22 @@ class EntrReq extends Validate
                                VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?})',
                          $this->name, $this->acronym, $this->url, $this->email,
                          $this->holdingid, $this->NAF_code, $this->AX_code);
+
             $jobid = XDB::insertId();
             $display_tel = format_display_number($this->tel, $error_tel);
             $display_fax = format_display_number($this->fax, $error_fax);
-            XDB::execute('INSERT INTO  profile_phones (uid, link_type, link_id, tel_id, tel_type,
+            XDB::execute("INSERT INTO  profile_phones (uid, link_type, link_id, tel_id, tel_type,
                                        search_tel, display_tel, pub)
-                               VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}),
-                                       ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
-                         $jobid, 'hq', $this->id, 0, 'fixed', format_phone_number($this->tel), $display_tel, 'public', 
-                         $jobid, 'hq', $this->id, 1, 'fax', format_phone_number($this->fax), $display_fax, 'public');
+                               VALUES  ({?}, 'hq', 0, 0, 'fixed', {?}, {?}, 'public'),
+                                       ({?}, 'hq', 0, 1, 'fax', {?}, {?}, 'public')",
+                         $jobid, format_phone_number($this->tel), $display_tel,
+                         $jobid, format_phone_number($this->fax), $display_fax);
+
+            $gmapsGeocoder = new GMapsGeocoder();
+            $address = $gmapsGeocoder->getGeocodedAddress($this->address);
+            Geocoder::getAreaId($address, 'administrativeArea');
+            Geocoder::getAreaId($address, 'subAdministrativeArea');
+            Geocoder::getAreaId($address, 'locality');
             XDB::execute("INSERT INTO  profile_addresses (jobid, type, id, accuracy,
                                                           text, postalText, postalCode, localityId,
                                                           subAdministrativeAreaId, administrativeAreaId,
index ae5f3ee..1d2acda 100644 (file)
@@ -27,7 +27,9 @@ class OrangeReq extends Validate
 
     public $unique = true;
 
-    public $promo_sortie;
+    public $oldGradYear;
+    public $newGradYear;
+    public $entryYear;
 
     public $rules = "À priori accepter (la validation sert à repousser les
     petits malins). Refuse si tu connais la personne et que tu es sûr
@@ -36,14 +38,15 @@ class OrangeReq extends Validate
     // }}}
     // {{{ constructor
 
-    public function __construct(User &$_user, $_sortie)
+    public function __construct(User &$_user, $_newGradYear)
     {
         parent::__construct($_user, true, 'orange');
-        $this->promo_sortie  = $_sortie;
+        $this->newGradYear  = $_newGradYear;
         $res = XDB::query("SELECT  entry_year
                              FROM  profile_education
-                            WHERE  uid = {?} AND FIND_IN_SET('primary', flags)", $_uid);
-        $this->promo = $res->fetchOneCell();
+                            WHERE  uid = {?} AND FIND_IN_SET('primary', flags)", $this->user->id());
+        $this->entryYear   = $res->fetchOneCell();
+        $this->oldGradYear = $this->entryYear + 3;
     }
 
     // }}}
@@ -83,7 +86,7 @@ class OrangeReq extends Validate
     {
         XDB::execute("UPDATE  profile_education
                          SET  grad_year = {?}
-                       WHERE  uid = {?} AND FIND_IN_SET('primary', flags)", $this->promo_sortie, $this->uid);
+                       WHERE  uid = {?} AND FIND_IN_SET('primary', flags)", $this->newGradYear, $this->user->id());
         return true;
     }
 
index bb3afe4..2612f3b 100644 (file)
@@ -201,7 +201,12 @@ Si le télépaiement n'est pas lié à un groupe ou supérieur à 51 euros, lais
                     $mailer->assign('payment', $id);
                     $mailer->assign('prenom', $u['prenom']);
                     $mailer->assign('topay', $topay);
-                    $mailer->assign('to', $u['email']);
+
+                    if (strpos($u['email'], '@') === false) {
+                        $mailer->assign('to', $u['email'] . '@' . $globals->mail->domain);
+                    } else {
+                        $mailer->assign('to', $u['email']);
+                    }
                     $mailer->send();
                 }
             }
index ddbc4dd..619f954 100644 (file)
@@ -113,7 +113,7 @@ class VCard extends PlVCard
         // Pro
         if (!empty($user['adr_pro'])) {
             foreach ($user['adr_pro'] as $pro) {
-                $street = array($adr['adr1']);
+                $street = array($pro['adr1']);
                 if (!empty($pro['adr2'])) {
                     $street[] = $pro['adr2'];
                 }
index 1caaa6c..37bb102 100644 (file)
@@ -24,33 +24,33 @@ class AdminModule extends PLModule
     function handlers()
     {
         return array(
-            'phpinfo'                      => $this->make_hook('phpinfo', AUTH_MDP, 'admin'),
-            'get_rights'                   => $this->make_hook('get_rights', AUTH_MDP, 'admin'),
-            'admin'                        => $this->make_hook('default', AUTH_MDP, 'admin'),
-            'admin/ax-xorg'                => $this->make_hook('ax_xorg', AUTH_MDP, 'admin'),
-            'admin/dead-but-active'        => $this->make_hook('dead_but_active', AUTH_MDP, 'admin'),
-            'admin/deaths'                 => $this->make_hook('deaths', AUTH_MDP, 'admin'),
-            'admin/downtime'               => $this->make_hook('downtime', AUTH_MDP, 'admin'),
-            'admin/homonyms'               => $this->make_hook('homonyms', AUTH_MDP, 'admin'),
-            'admin/logger'                 => $this->make_hook('logger', AUTH_MDP, 'admin'),
-            'admin/logger/actions'         => $this->make_hook('logger_actions', AUTH_MDP, 'admin'),
-            'admin/postfix/blacklist'      => $this->make_hook('postfix_blacklist', AUTH_MDP, 'admin'),
-            'admin/postfix/delayed'        => $this->make_hook('postfix_delayed', AUTH_MDP, 'admin'),
+            'phpinfo'                      => $this->make_hook('phpinfo',                AUTH_MDP, 'admin'),
+            'get_rights'                   => $this->make_hook('get_rights',             AUTH_MDP, 'admin'),
+            'admin'                        => $this->make_hook('default',                AUTH_MDP, 'admin'),
+            'admin/ax-xorg'                => $this->make_hook('ax_xorg',                AUTH_MDP, 'admin'),
+            'admin/dead-but-active'        => $this->make_hook('dead_but_active',        AUTH_MDP, 'admin'),
+            'admin/deaths'                 => $this->make_hook('deaths',                 AUTH_MDP, 'admin'),
+            'admin/downtime'               => $this->make_hook('downtime',               AUTH_MDP, 'admin'),
+            'admin/homonyms'               => $this->make_hook('homonyms',               AUTH_MDP, 'admin'),
+            'admin/logger'                 => $this->make_hook('logger',                 AUTH_MDP, 'admin'),
+            'admin/logger/actions'         => $this->make_hook('logger_actions',         AUTH_MDP, 'admin'),
+            'admin/postfix/blacklist'      => $this->make_hook('postfix_blacklist',      AUTH_MDP, 'admin'),
+            'admin/postfix/delayed'        => $this->make_hook('postfix_delayed',        AUTH_MDP, 'admin'),
             'admin/postfix/regexp_bounces' => $this->make_hook('postfix_regexpsbounces', AUTH_MDP, 'admin'),
-            'admin/postfix/whitelist'      => $this->make_hook('postfix_whitelist', AUTH_MDP, 'admin'),
-            'admin/mx/broken'              => $this->make_hook('mx_broken', AUTH_MDP, 'admin'),
-            'admin/skins'                  => $this->make_hook('skins', AUTH_MDP, 'admin'),
-            'admin/synchro_ax'             => $this->make_hook('synchro_ax', AUTH_MDP, 'admin'),
-            'admin/user'                   => $this->make_hook('user', AUTH_MDP, 'admin'),
-            'admin/promo'                  => $this->make_hook('promo', AUTH_MDP, 'admin'),
-            'admin/validate'               => $this->make_hook('validate', AUTH_MDP, 'admin'),
-            'admin/validate/answers'       => $this->make_hook('validate_answers', AUTH_MDP, 'admin'),
-            'admin/wiki'                   => $this->make_hook('wiki', AUTH_MDP, 'admin'),
-            'admin/ipwatch'                => $this->make_hook('ipwatch', AUTH_MDP, 'admin'),
-            'admin/icons'                  => $this->make_hook('icons', AUTH_MDP, 'admin'),
-            'admin/accounts'               => $this->make_hook('accounts', AUTH_MDP, 'admin'),
-            'admin/account/types'          => $this->make_hook('account_types', AUTH_MDP, 'admin'),
-            'admin/jobs'                   => $this->make_hook('jobs', AUTH_MDP, 'admin'),
+            'admin/postfix/whitelist'      => $this->make_hook('postfix_whitelist',      AUTH_MDP, 'admin'),
+            'admin/mx/broken'              => $this->make_hook('mx_broken',              AUTH_MDP, 'admin'),
+            'admin/skins'                  => $this->make_hook('skins',                  AUTH_MDP, 'admin'),
+            'admin/synchro_ax'             => $this->make_hook('synchro_ax',             AUTH_MDP, 'admin'),
+            'admin/user'                   => $this->make_hook('user',                   AUTH_MDP, 'admin'),
+            'admin/promo'                  => $this->make_hook('promo',                  AUTH_MDP, 'admin'),
+            'admin/validate'               => $this->make_hook('validate',               AUTH_MDP, 'admin'),
+            'admin/validate/answers'       => $this->make_hook('validate_answers',       AUTH_MDP, 'admin'),
+            'admin/wiki'                   => $this->make_hook('wiki',                   AUTH_MDP, 'admin'),
+            'admin/ipwatch'                => $this->make_hook('ipwatch',                AUTH_MDP, 'admin'),
+            'admin/icons'                  => $this->make_hook('icons',                  AUTH_MDP, 'admin'),
+            'admin/accounts'               => $this->make_hook('accounts',               AUTH_MDP, 'admin'),
+            'admin/account/types'          => $this->make_hook('account_types',          AUTH_MDP, 'admin'),
+            'admin/jobs'                   => $this->make_hook('jobs',                   AUTH_MDP, 'admin'),
         );
     }
 
@@ -94,11 +94,11 @@ class AdminModule extends PLModule
 
         $sql = XDB::iterator(
                 "SELECT  crc, nb, update_time, create_time,
-                         FIND_IN_SET('del', release) AS del,
-                         FIND_IN_SET('ok', release) AS ok
-                   FROM  postfix_mailseen
+                         FIND_IN_SET('del', p.release) AS del,
+                         FIND_IN_SET('ok', p.release) AS ok
+                   FROM  postfix_mailseen AS p
                   WHERE  nb >= 30
-               ORDER BY  release != ''");
+               ORDER BY  p.release != ''");
 
         $page->assign_by_ref('mails', $sql);
     }
@@ -636,17 +636,19 @@ class AdminModule extends PLModule
         $page->assign('bans', $bans);
     }
 
-    function getHruid($line, $partial_result, $key)
+    function getHruid($line, $key, $relation)
     {
-        if (!isset($partial_result['nom']) ||
-            !isset($partial_result['prenom']) ||
-            !isset($partial_result['promo'])) {
-            return null;
+        $prenom = CSVImporter::getValue($line, 'prenom', $relation['prenom']);
+        $nom = CSVImporter::getValue($line, 'nom', $relation['nom']);
+        $promo = CSVImporter::getValue($line, 'promo', $relation['promo']);
+
+        if ($prenom != 'NULL' && $nom != 'NULL' && $promo != 'NULL') {
+            return make_forlife($prenom, $nom, $promo);
         }
-        return make_forlife($partial_result['prenom'], $partial_result['nom'], $partial_result['promo']);
+        return null;
     }
 
-    function getMatricule($line, $key)
+    function getMatricule($line, $key, $relation)
     {
         $mat = $line['matricule'];
         $year = intval(substr($mat, 0, 3));
@@ -684,11 +686,9 @@ class AdminModule extends PLModule
             $fields = array('hruid', 'nom', 'nom_ini', 'prenom', 'naissance_ini',
                             'prenom_ini', 'promo', 'promo_sortie', 'flags',
                             'matricule', 'matricule_ax', 'perms');
+            $importer->forceValue('hruid', array($this, 'getHruid'));
             $importer->forceValue('promo', $promo);
             $importer->forceValue('promo_sortie', $promo + 3);
-            // The hruid generation callback is set last, so that it is called once 'promo'
-            // has already been computed for that line.
-            $importer->forceValue('hruid', array($this, 'getHruid'));
             break;
           case 'ax':
             $fields = array('matricule', 'matricule_ax');
@@ -1199,20 +1199,41 @@ class AdminModule extends PLModule
         }
 
         if (Env::has('edit')) {
+            // TODO: use address and phone classes to update profile_job_enum and profile_phones once they are done.
+
             S::assert_xsrf_token();
             $selectedJob = Env::has('selectedJob');
 
+            XDB::execute("DELETE FROM  profile_phones
+                                WHERE  uid = {?} AND link_type = 'hq'",
+                         $id);
+            XDB::execute("DELETE FROM  profile_addresses
+                                WHERE  jobid = {?} AND type = 'hq'",
+                         $id);
+            XDB::execute('DELETE FROM  profile_job_enum
+                                WHERE  id = {?}',
+                         $id);
+
             if (Env::has('change')) {
                 XDB::execute('UPDATE  profile_job
                                  SET  jobid = {?}
                                WHERE  jobid = {?}',
                              Env::i('newJobId'), $id);
-                XDB::execute('DELETE FROM  profile_job_enum
-                                    WHERE  id = {?}',
-                             $id);
 
                 $page->trigSuccess("L'entreprise a bien été remplacée.");
             } else {
+                require_once 'profil.func.inc.php';
+                require_once 'geocoding.inc.php';
+
+                $display_tel = format_display_number(Env::v('tel'), $error_tel);
+                $display_fax = format_display_number(Env::v('fax'), $error_fax);
+                $gmapsGeocoder = new GMapsGeocoder();
+                $address = array('text' => Env::t('address'));
+                $address = $gmapsGeocoder->getGeocodedAddress($address);
+                Geocoder::getAreaId($address, 'administrativeArea');
+                Geocoder::getAreaId($address, 'subAdministrativeArea');
+                Geocoder::getAreaId($address, 'locality');
+
                 XDB::execute('UPDATE  profile_job_enum
                                  SET  name = {?}, acronym = {?}, url = {?}, email = {?},
                                       NAF_code = {?}, AX_code = {?}, holdingid = {?}
@@ -1220,16 +1241,41 @@ class AdminModule extends PLModule
                              Env::t('name'), Env::t('acronym'), Env::t('url'), Env::t('email'),
                              Env::t('NAF_code'), Env::i('AX_code'), Env::i('holdingId'), $id);
 
+                XDB::execute("INSERT INTO  profile_phones (uid, link_type, link_id, tel_id, tel_type,
+                                           search_tel, display_tel, pub)
+                                   VALUES  ({?}, 'hq', 0, 0, 'fixed', {?}, {?}, 'public'),
+                                           ({?}, 'hq', 0, 1, 'fax', {?}, {?}, 'public')",
+                             $id, format_phone_number(Env::v('tel')), $display_tel,
+                             $id, format_phone_number(Env::v('fax')), $display_fax);
+
+                XDB::execute("INSERT INTO  profile_addresses (jobid, type, id, accuracy,
+                                                              text, postalText, postalCode, localityId,
+                                                              subAdministrativeAreaId, administrativeAreaId,
+                                                              countryId, latitude, longitude, updateTime,
+                                                              north, south, east, west)
+                                   VALUES  ({?}, 'hq', 0, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?},
+                                            {?}, {?}, FROM_UNIXTIME({?}), {?}, {?}, {?}, {?})",
+                             $id, $address['accuracy'], $address['text'], $address['postalText'],
+                             $address['postalCode'], $address['localityId'],
+                             $address['subAdministrativeAreaId'], $address['administrativeAreaId'],
+                             $address['countryId'], $address['latitude'], $address['longitude'],
+                             $address['updateTime'], $address['north'], $address['south'],
+                             $address['east'], $address['west']);
+
                 $page->trigSuccess("L'entreprise a bien été mise à jour.");
             }
         }
 
         if (!Env::has('change') && $id != -1) {
-            $res = XDB::query('SELECT  e.id, e.name, e.acronym, e.url, e.email, e.NAF_code, e.AX_code,
-                                       h.id AS holdingId, h.name AS holdingName, h.acronym AS holdingAcronym
-                                 FROM  profile_job_enum AS e
-                            LEFT JOIN  profile_job_enum AS h ON (e.holdingid = h.id)
-                                WHERE  e.id = {?}',
+            $res = XDB::query("SELECT  e.id, e.name, e.acronym, e.url, e.email, e.NAF_code, e.AX_code,
+                                       h.id AS holdingId, h.name AS holdingName, h.acronym AS holdingAcronym,
+                                       t.display_tel AS tel, f.display_tel AS fax, a.text AS address
+                                 FROM  profile_job_enum  AS e
+                            LEFT JOIN  profile_job_enum  AS h ON (e.holdingid = h.id)
+                            LEFT JOIN  profile_phones    AS t ON (t.uid = e.id AND link_type = 'hq' AND tel_id = 0)
+                            LEFT JOIN  profile_phones    AS f ON (f.uid = e.id AND link_type = 'hq' AND tel_id = 1)
+                            LEFT JOIN  profile_addresses AS a ON (a.jobid = e.id AND a.type = 'hq')
+                                WHERE  e.id = {?}",
                               $id);
 
             if ($res->numRows() == 0) {
index 4599ab2..5376034 100644 (file)
@@ -24,18 +24,15 @@ class AuthModule extends PLModule
     function handlers()
     {
         return array(
-            'groupex/donne-chall.php'
-                                => $this->make_hook('chall',      AUTH_PUBLIC),
-            'groupex/export-econfiance.php'
-                                => $this->make_hook('econf',      AUTH_PUBLIC, 'user', NO_HTTPS),
-
-            'webservices/manageurs.php'
-                                => $this->make_hook('manageurs',  AUTH_PUBLIC, 'user', NO_HTTPS),
-
-            'auth-redirect.php' => $this->make_hook('redirect',   AUTH_COOKIE),
-            'auth-groupex.php'  => $this->make_hook('groupex_old',    AUTH_COOKIE),
-            'auth-groupex'      => $this->make_hook('groupex',    AUTH_COOKIE),
-            'admin/auth-groupes-x'         => $this->make_hook('admin_authgroupesx', AUTH_MDP, 'admin'),
+            'groupex/donne-chall.php'       => $this->make_hook('chall',              AUTH_PUBLIC),
+            'groupex/export-econfiance.php' => $this->make_hook('econf',              AUTH_PUBLIC, 'user', NO_HTTPS),
+
+            'webservices/manageurs.php'     => $this->make_hook('manageurs',          AUTH_PUBLIC, 'user', NO_HTTPS),
+
+            'auth-redirect.php'             => $this->make_hook('redirect',           AUTH_COOKIE),
+            'auth-groupex.php'              => $this->make_hook('groupex_old',        AUTH_COOKIE),
+            'auth-groupex'                  => $this->make_hook('groupex',            AUTH_COOKIE),
+            'admin/auth-groupes-x'          => $this->make_hook('admin_authgroupesx', AUTH_MDP,    'admin'),
         );
     }
 
@@ -125,34 +122,39 @@ class AuthModule extends PLModule
             $gpex_url .= "&PHPSESSID=" . $_GET["session"];
         }
 
-        /* a-t-on besoin d'ajouter le http:// ? */
+        // Normalize the return URL.
         if (!preg_match("/^(http|https):\/\/.*/",$gpex_url)) {
             $gpex_url = "http://$gpex_url";
         }
         $gpex_challenge = $_GET["challenge"];
 
-        // mise à jour de l'heure et de la machine de dernier login sauf quand on est en suid
+        // Update the last login information (unless the user is in SUID).
         $uid = S::i('uid');
         if (!S::suid()) {
             global $platal;
             S::logger($uid)->log('connexion_auth_ext', $platal->path);
         }
 
-        /* on parcourt les entrees de groupes_auth */
+        // Iterate over the auth token to find which one did sign the request.
         $res = XDB::iterRow('SELECT privkey, name, datafields, returnurls FROM groupesx_auth');
-
         while (list($privkey,$name,$datafields,$returnurls) = $res->next()) {
             if (md5($gpex_challenge.$privkey) == $gpex_pass) {
                 $returnurls = trim($returnurls);
+                // We check that the return url matches a per-key regexp to prevent
+                // replay attacks (more exactly to force replay attacks to redirect
+                // the user to the real GroupeX website, which defeats the attack).
                 if (empty($returnurls) || @preg_match($returnurls, $gpex_url)) {
                     $returl = $gpex_url . gpex_make_params($gpex_challenge, $privkey, $datafields, $charset);
                     http_redirect($returl);
+                } else if (S::admin()) {
+                    $page->kill("La requête d'authentification a échouée (url de retour invalide).");
                 }
             }
         }
 
-        /* si on n'a pas trouvé, on renvoit sur x.org */
-        http_redirect('https://www.polytechnique.org/');
+        // Otherwise (if no valid request was found, or if the return URL is not
+        // acceptable), the user is redirected back to our homepage.
+        pl_redirect('/');
     }
 
     function handler_admin_authgroupesx(&$page, $action = 'list', $id = null)
index c158ff2..6febc2c 100644 (file)
@@ -50,7 +50,7 @@ function gpex_make($chlg, $privkey, $datafields, $charset)
     foreach ($fieldarr as $val) {
         // Determine the requested value, and add it to the answer.
         if ($val == 'perms') {
-            $params .= gpex_prepare_param($val, S::has_perms() ? 'admin' : 'user', $tohash, $charset);
+            $params .= gpex_prepare_param($val, S::admin() ? 'admin' : 'user', $tohash, $charset);
         } else if ($val == 'forlife') {
             $params .= gpex_prepare_param($val, S::v('hruid'), $tohash, $charset);
         } else if (S::has($val)) {
@@ -74,7 +74,7 @@ function gpex_make($chlg, $privkey, $datafields, $charset)
                 $perms = $res->fetchOneCell();
             } else {
                 // if no group asked, return main rights
-                $perms = S::has_perms() ? 'admin' : 'membre';
+                $perms = S::admin() ? 'admin' : 'membre';
             }
             $params .= gpex_prepare_param($val, $perms, $tohash, $charset);
         } else {
index 91d96f0..1d695fd 100644 (file)
@@ -24,13 +24,13 @@ class AXLetterModule extends PLModule
     function handlers()
     {
         return array(
-            'ax'             => $this->make_hook('index',        AUTH_COOKIE),
+            'ax'             => $this->make_hook('index',  AUTH_COOKIE),
             'ax/out'         => $this->make_hook('out',    AUTH_PUBLIC),
             'ax/show'        => $this->make_hook('show',   AUTH_COOKIE),
             'ax/edit'        => $this->make_hook('submit', AUTH_MDP),
             'ax/edit/cancel' => $this->make_hook('cancel', AUTH_MDP),
             'ax/edit/valid'  => $this->make_hook('valid',  AUTH_MDP),
-            'admin/axletter' => $this->make_hook('admin', AUTH_MDP, 'admin'),
+            'admin/axletter' => $this->make_hook('admin',  AUTH_MDP, 'admin'),
         );
     }
 
@@ -90,6 +90,8 @@ class AXLetterModule extends PLModule
         $signature  = trim(Post::v('signature'));
         $promo_min  = Post::i('promo_min');
         $promo_max  = Post::i('promo_max');
+        $subset_to  = preg_split("/[ ,;\:\n\r]+/", Post::v('subset_to'), -1, PREG_SPLIT_NO_EMPTY);
+        $subset     = (count($subset_to) > 0);
         $echeance   = Post::has('echeance_date') ?
               preg_replace('/^(\d\d\d\d)(\d\d)(\d\d)$/', '\1-\2-\3', Post::v('echeance_date')) . ' ' . Post::v('echeance_time')
             : Post::v('echeance');
@@ -100,6 +102,8 @@ class AXLetterModule extends PLModule
             $res = XDB::query("SELECT * FROM axletter WHERE FIND_IN_SET('new', bits)");
             if ($res->numRows()) {
                 extract($res->fetchOneAssoc(), EXTR_OVERWRITE);
+                $subset_to = explode("\n", $subset);
+                $subset = (count($subset_to) > 0);
                 $saved = true;
             } else  {
                 XDB::execute("INSERT INTO axletter SET id = NULL");
@@ -151,15 +155,15 @@ class AXLetterModule extends PLModule
               case 'Aperçu':
                 $this->load('axletter.inc.php');
                 $al = new AXLetter(array($id, $short_name, $subject, $title, $body, $signature,
-                                         $promo_min, $promo_max, $echeance, 0, 'new'));
+                                         $promo_min, $promo_max, $subset, $echeance, 0, 'new'));
                 $al->toHtml($page, S::v('prenom'), S::v('nom'), S::v('femme'));
                 break;
 
               case 'Confirmer':
                 XDB::execute("REPLACE INTO  axletter
                                        SET  id = {?}, short_name = {?}, subject = {?}, title = {?}, body = {?},
-                                            signature = {?}, promo_min = {?}, promo_max = {?}, echeance = {?}",
-                             $id, $short_name, $subject, $title, $body, $signature, $promo_min, $promo_max, $echeance);
+                                            signature = {?}, promo_min = {?}, promo_max = {?}, echeance = {?}, subset = {?}",
+                             $id, $short_name, $subject, $title, $body, $signature, $promo_min, $promo_max, $echeance, $subset ? implode("\n", $subset_to): null);
                 if (!$saved) {
                     global $globals;
                     $mailer = new PlMailer();
@@ -197,12 +201,14 @@ class AXLetterModule extends PLModule
         $page->assign('signature', $signature);
         $page->assign('promo_min', $promo_min);
         $page->assign('promo_max', $promo_max);
+        $page->assign('subset_to', implode("\n", $subset_to));
+        $page->assign('subset', $subset);
         $page->assign('echeance', $echeance);
         $page->assign('echeance_date', $echeance_date);
         $page->assign('echeance_time', $echeance_time);
         $page->assign('saved', $saved);
         $page->assign('new', $new);
-        $page->assign('is_xorg', S::has_perms());
+        $page->assign('is_xorg', S::admin());
 
         if (!$saved) {
             $select = '';
@@ -316,7 +322,7 @@ class AXLetterModule extends PLModule
         $importer->apply($page, "admin/axletter", array('user_id', 'email', 'prenom', 'nom', 'promo', 'flag', 'hash'));
     }
 
-    function idFromMail($line, $key)
+    function idFromMail($line, $key, $relation = null)
     {
         static $field;
         global $globals;
@@ -334,7 +340,7 @@ class AXLetterModule extends PLModule
         return count($id) == 1 ? $id[0] : 0;
     }
 
-    function createHash($line, $partial_result, $key)
+    function createHash($line, $key, $relation)
     {
         $hash = implode(time(), $line) . rand();
         $hash = md5($hash);
index 7cf486e..d13985e 100644 (file)
@@ -27,6 +27,8 @@ class AXLetter extends MassMailer
     public $_signature;
     public $_promo_min;
     public $_promo_max;
+    public $_subset;
+    public $_subset_to;
     public $_echeance;
     public $_date;
     public $_bits;
@@ -54,10 +56,12 @@ class AXLetter extends MassMailer
         }
         list($this->_id, $this->_shortname, $this->_title_mail, $this->_title,
              $this->_body, $this->_signature, $this->_promo_min, $this->_promo_max,
-             $this->_echeance, $this->_date, $this->_bits) = $id;
+             $this->_subset_to, $this->_echeance, $this->_date, $this->_bits) = $id;
         if ($this->_date == '0000-00-00') {
             $this->_date = 0;
         }
+        $this->_subset_to = explode("\n", $this->_subset_to);
+        $this->_subset = (count($this->_subset_to) > 0);
     }
 
     protected function assignData(&$smarty)
@@ -132,13 +136,13 @@ class AXLetter extends MassMailer
 
     static public function hasPerms()
     {
-        if (S::has_perms()) {
+        if (S::admin()) {
             return true;
         }
-        $res = XDB::query("SELECT  1
+        $res = XDB::query("SELECT  COUNT(*)
                              FROM  axletter_rights
                             WHERE  user_id = {?}", S::i('uid'));
-        return $res->fetchOneCell();
+        return ($res->fetchOneCell() > 0);
     }
 
     static public function grantPerms($uid)
@@ -167,7 +171,7 @@ class AXLetter extends MassMailer
 
     protected function subscriptionWhere()
     {
-        if (!$this->_promo_min && !$this->_promo_max) {
+        if (!$this->_promo_min && !$this->_promo_max && !$this->_subset) {
             return '1';
         }
         $where = array();
@@ -177,6 +181,17 @@ class AXLetter extends MassMailer
         if ($this->_promo_max) {
             $where[] = "((ni.user_id = 0 AND ni.promo <= {$this->_promo_max}) OR (ni.user_id != 0 AND u.promo <= {$this->_promo_max}))";
         }
+        if ($this->_subset) {
+            require_once("emails.inc.php");
+            $ids = ids_from_mails($this->_subset_to);
+            $ids_list = implode(',', $ids);
+            if(count($ids_list) > 0) {
+                $where[] = "ni.user_id IN ($ids_list)";
+            } else {
+                // No valid email
+                $where[] = "0";
+            }
+        }
         return implode(' AND ', $where);
     }
 
index e9835fd..4a226ac 100644 (file)
@@ -24,9 +24,9 @@ class BandeauModule extends PLModule
     function handlers()
     {
         return array(
-            'bandeau/icone.png'  => $this->make_hook('icone',AUTH_PUBLIC, 'user', NO_HTTPS),
-            'bandeau'            => $this->make_hook('html', AUTH_PUBLIC, 'user', NO_HTTPS),
-            'bandeau.css'                               => $this->make_hook('css', AUTH_PUBLIC, 'user', NO_HTTPS),
+            'bandeau/icone.png'  => $this->make_hook('icone', AUTH_PUBLIC, 'user', NO_HTTPS),
+            'bandeau'            => $this->make_hook('html',  AUTH_PUBLIC, 'user', NO_HTTPS),
+            'bandeau.css'                               => $this->make_hook('css',   AUTH_PUBLIC, 'user', NO_HTTPS),
         );
     }
 
index 8109acb..f3b1ebd 100644 (file)
@@ -29,9 +29,9 @@ class CarnetModule extends PLModule
             'carnet/notifs'         => $this->make_hook('notifs',   AUTH_COOKIE),
 
             'carnet/contacts'       => $this->make_hook('contacts', AUTH_COOKIE),
-            'carnet/contacts/pdf'   => $this->make_hook('pdf',      AUTH_COOKIE, 'user', NO_HTTPS),
+            'carnet/contacts/pdf'   => $this->make_hook('pdf',      AUTH_COOKIE),
+            'carnet/contacts/vcard' => $this->make_hook('vcard',    AUTH_COOKIE),
             'carnet/contacts/ical'  => $this->make_hook('ical',     AUTH_PUBLIC, 'user', NO_HTTPS),
-            'carnet/contacts/vcard' => $this->make_hook('vcard',    AUTH_COOKIE, 'user', NO_HTTPS),
 
             'carnet/rss'            => $this->make_hook('rss',      AUTH_PUBLIC, 'user', NO_HTTPS),
         );
index a255b7f..b7a2fa6 100644 (file)
@@ -24,23 +24,23 @@ class EmailModule extends PLModule
     function handlers()
     {
         return array(
-            'emails' => $this->make_hook('emails', AUTH_COOKIE),
-            'emails/alias'    => $this->make_hook('alias', AUTH_MDP),
-            'emails/antispam' => $this->make_hook('antispam', AUTH_MDP),
-            'emails/broken'   => $this->make_hook('broken', AUTH_COOKIE),
-            'emails/redirect' => $this->make_hook('redirect', AUTH_MDP),
-            'emails/send'     => $this->make_hook('send', AUTH_MDP),
-            'emails/antispam/submit'  => $this->make_hook('submit', AUTH_COOKIE),
-            'emails/test'     => $this->make_hook('test', AUTH_COOKIE, 'user', NO_AUTH),
-
-            'emails/rewrite/in' => $this->make_hook('rewrite_in', AUTH_PUBLIC),
-            'emails/rewrite/out' => $this->make_hook('rewrite_out', AUTH_PUBLIC),
-
-            'emails/imap/in'  => $this->make_hook('imap_in', AUTH_PUBLIC),
-
-            'admin/emails/duplicated' => $this->make_hook('duplicated', AUTH_MDP, 'admin'),
-            'admin/emails/watch'      => $this->make_hook('duplicated', AUTH_MDP, 'admin'),
-            'admin/emails/lost'       => $this->make_hook('lost', AUTH_MDP, 'admin'),
+            'emails'                  => $this->make_hook('emails',      AUTH_COOKIE),
+            'emails/alias'            => $this->make_hook('alias',       AUTH_MDP),
+            'emails/antispam'         => $this->make_hook('antispam',    AUTH_MDP),
+            'emails/broken'           => $this->make_hook('broken',      AUTH_COOKIE),
+            'emails/redirect'         => $this->make_hook('redirect',    AUTH_MDP),
+            'emails/send'             => $this->make_hook('send',        AUTH_MDP),
+            'emails/antispam/submit'  => $this->make_hook('submit',      AUTH_COOKIE),
+            'emails/test'             => $this->make_hook('test',        AUTH_COOKIE, 'user', NO_AUTH),
+
+            'emails/rewrite/in'       => $this->make_hook('rewrite_in',  AUTH_PUBLIC),
+            'emails/rewrite/out'      => $this->make_hook('rewrite_out', AUTH_PUBLIC),
+
+            'emails/imap/in'          => $this->make_hook('imap_in',     AUTH_PUBLIC),
+
+            'admin/emails/duplicated' => $this->make_hook('duplicated',  AUTH_MDP,    'admin'),
+            'admin/emails/watch'      => $this->make_hook('duplicated',  AUTH_MDP,    'admin'),
+            'admin/emails/lost'       => $this->make_hook('lost',        AUTH_MDP,    'admin'),
         );
     }
 
@@ -490,7 +490,7 @@ class EmailModule extends PLModule
         }
 
         // Retrieves the User object for the test email recipient.
-        if (S::has_perms() && $hruid) {
+        if (S::admin() && $hruid) {
             $user = User::getSilent($hruid);
         } else {
             $user = S::user();
index 0a16d14..6cd7771 100644 (file)
@@ -24,15 +24,15 @@ class EventsModule extends PLModule
     function handlers()
     {
         return array(
-            'events'         => $this->make_hook('ev',        AUTH_COOKIE),
-            'rss'            => $this->make_hook('rss', AUTH_PUBLIC, 'user', NO_HTTPS),
-            'events/preview' => $this->make_hook('preview', AUTH_PUBLIC, 'user', NO_AUTH),
-            'events/photo'   => $this->make_hook('photo', AUTH_PUBLIC),
-            'events/submit'  => $this->make_hook('ev_submit', AUTH_MDP),
-            'admin/events'   => $this->make_hook('admin_events',     AUTH_MDP, 'admin'),
-
-            'ajax/tips'      => $this->make_hook('tips',      AUTH_COOKIE, 'user', NO_AUTH),
-            'admin/tips'     => $this->make_hook('admin_tips', AUTH_MDP, 'admin'),
+            'events'         => $this->make_hook('ev',           AUTH_COOKIE),
+            'rss'            => $this->make_hook('rss',          AUTH_PUBLIC, 'user', NO_HTTPS),
+            'events/preview' => $this->make_hook('preview',      AUTH_PUBLIC, 'user', NO_AUTH),
+            'events/photo'   => $this->make_hook('photo',        AUTH_PUBLIC),
+            'events/submit'  => $this->make_hook('ev_submit',    AUTH_MDP),
+            'admin/events'   => $this->make_hook('admin_events', AUTH_MDP,    'admin'),
+
+            'ajax/tips'      => $this->make_hook('tips',         AUTH_COOKIE, 'user', NO_AUTH),
+            'admin/tips'     => $this->make_hook('admin_tips',   AUTH_MDP,    'admin'),
         );
     }
 
@@ -106,14 +106,16 @@ class EventsModule extends PLModule
         $page->addJsLink('ajax.js');
         $page->assign('tips', $this->get_tips());
 
-        // Profile update (appears when profile is > 400d old), and birthday
-        // oneboxes.
+        // Adds a reminder onebox to the page.
         $user = S::user();
+        require_once 'reminder.inc.php';
+        if (($reminder = Reminder::GetCandidateReminder($user))) {
+            $reminder->Prepare($page);
+        }
+
+        // Wishes "Happy birthday" when required
         $profile = $user->profile();
         if (!is_null($profile)) {
-            if (strtotime($profile->last_change) < time() - (400 * 86400)) {
-                $page->assign('fiche_incitation', $profile->last_change);
-            }
             if ($profile->next_birthday == date('Y-m-d')) {
                 $birthyear = (int)date('Y', strtotime($profile->birthdate));
                 $curyear   = (int)date('Y');
@@ -121,17 +123,6 @@ class EventsModule extends PLModule
             }
         }
 
-        // No-photo onebox.
-        $res = XDB::query("SELECT  COUNT(*)
-                             FROM  photo
-                            WHERE  uid = {?}",
-                          S::user()->id());
-        $page->assign('photo_incitation', $res->fetchOneCell() == 0);
-
-        // Geo-location onebox.
-        require_once "geocoding.inc.php";
-        $page->assign('geoloc_incitation', Geocoder::countNonGeocoded(S::user()->id()));
-
         // Direct link to the RSS feed, when available.
         if (S::hasAuthToken()) {
             $page->setRssLink('Polytechnique.org :: News',
index 7a7a3fc..975ac43 100644 (file)
@@ -24,9 +24,9 @@ class ForumsModule extends PLModule
     function handlers()
     {
         return array(
-            'banana'         => $this->make_hook('banana', AUTH_COOKIE),
-            'banana/rss'     => $this->make_hook('rss', AUTH_PUBLIC, 'user', NO_HTTPS),
-            'admin/forums'   => $this->make_hook('forums_bans', AUTH_MDP, 'admin'),
+            'banana'         => $this->make_hook('banana',      AUTH_COOKIE),
+            'banana/rss'     => $this->make_hook('rss',         AUTH_PUBLIC, 'user', NO_HTTPS),
+            'admin/forums'   => $this->make_hook('forums_bans', AUTH_MDP,    'admin'),
         );
     }
 
index ede101f..b02b686 100644 (file)
@@ -25,9 +25,9 @@ class GadgetsModule extends PLModule
     {
         return array(
             'gadgets/ig-events.xml' => $this->make_hook('ig_events_xml', AUTH_PUBLIC, 'user', NO_HTTPS),
-            'gadgets/ig-events'     => $this->make_hook('ig_events', AUTH_PUBLIC),
+            'gadgets/ig-events'     => $this->make_hook('ig_events',     AUTH_PUBLIC),
             'gadgets/ig-search.xml' => $this->make_hook('ig_search_xml', AUTH_PUBLIC, 'user', NO_HTTPS),
-            'gadgets/ig-search'     => $this->make_hook('ig_search', AUTH_PUBLIC),
+            'gadgets/ig-search'     => $this->make_hook('ig_search',     AUTH_PUBLIC),
         );
     }
 
index f7796e2..b2ec0ab 100644 (file)
@@ -29,9 +29,9 @@ class GoogleAppsModule extends PLModule
         }
 
         return array(
-            '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'),
+            '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'),
         );
     }
index fa3232b..7a2584e 100644 (file)
@@ -27,7 +27,7 @@ class ListsModule extends PLModule
     {
         return array(
             'lists'           => $this->make_hook('lists',     AUTH_MDP),
-            'lists/ajax'      => $this->make_hook('ajax',      AUTH_MDP, 'user', NO_AUTH),
+            'lists/ajax'      => $this->make_hook('ajax',      AUTH_MDP,    'user', NO_AUTH),
             'lists/create'    => $this->make_hook('create',    AUTH_MDP),
 
             'lists/members'   => $this->make_hook('members',   AUTH_COOKIE),
@@ -43,7 +43,7 @@ class ListsModule extends PLModule
 
             'lists/soptions'  => $this->make_hook('soptions',  AUTH_MDP),
             'lists/check'     => $this->make_hook('check',     AUTH_MDP),
-            'admin/lists'     => $this->make_hook('admin_all', AUTH_MDP, 'admin'),
+            'admin/lists'     => $this->make_hook('admin_all', AUTH_MDP,    'admin'),
         );
     }
 
@@ -544,6 +544,21 @@ class ListsModule extends PLModule
                 $msg = str_replace("%(listname)s",  $liste, $msg);
                 $page->assign('msg', $msg);
                 return;
+            } elseif (Get::has('mid') && Env::has('mok')) {
+                $page->changeTpl('lists/moderate_mail.tpl');
+                require_once('banana/moderate.inc.php');
+                $params = array('listname' => $liste, 'domain' => $domain,
+                                'artid' => Get::i('mid'), 'part' => Get::v('part'), 'action' => Get::v('action'));
+                $params['client'] = $this->client;
+                run_banana($page, 'ModerationBanana', $params);
+
+                $msg = file_get_contents('/etc/mailman/fr/accept.txt');
+                $msg = str_replace("%(adminaddr)s", "$liste-owner@{$domain}", $msg);
+                $msg = str_replace("%(request)s",   "<< SUJET DU MAIL >>",    $msg);
+                $msg = str_replace("%(reason)s",    "<< TON EXPLICATION >>",  $msg);
+                $msg = str_replace("%(listname)s",  $liste, $msg);
+                $page->assign('msg', $msg);
+                return;
             }
 
             $mail = $this->moderate_mail($domain, $liste, Env::i('mid'));
diff --git a/modules/lists/mail_templates/accept.txt b/modules/lists/mail_templates/accept.txt
new file mode 100644 (file)
index 0000000..f80227b
--- /dev/null
@@ -0,0 +1,13 @@
+Vous avez envoyé un message à la liste de diffusion {{{LIST}}} :
+
+    %(request)s 
+
+Le modérateur a souhaité diffuser votre message vers les abonnés à
+la liste.
+
+    "%(reason)s" 
+
+Toute question ou commentaire doit être adressé aux modérateurs de la
+liste à cette adresse :
+
+    {{{ALIST}}}
index 6ef0cbb..c69e216 100644 (file)
@@ -24,11 +24,11 @@ class NewsletterModule extends PLModule
     function handlers()
     {
         return array(
-            'nl'             => $this->make_hook('nl',        AUTH_COOKIE),
-            'nl/show'        => $this->make_hook('nl_show',   AUTH_COOKIE),
-            'nl/submit'      => $this->make_hook('nl_submit', AUTH_MDP),
-            'admin/newsletter'             => $this->make_hook('admin_nl', AUTH_MDP, 'admin'),
-            'admin/newsletter/categories'  => $this->make_hook('admin_nl_cat', AUTH_MDP, 'admin'),
+            'nl'                           => $this->make_hook('nl',            AUTH_COOKIE),
+            'nl/show'                      => $this->make_hook('nl_show',       AUTH_COOKIE),
+            'nl/submit'                    => $this->make_hook('nl_submit',     AUTH_MDP),
+            'admin/newsletter'             => $this->make_hook('admin_nl',      AUTH_MDP, 'admin'),
+            'admin/newsletter/categories'  => $this->make_hook('admin_nl_cat',  AUTH_MDP, 'admin'),
             'admin/newsletter/edit'        => $this->make_hook('admin_nl_edit', AUTH_MDP, 'admin'),
         );
     }
index bdae55f..6b8f031 100644 (file)
@@ -61,144 +61,147 @@ class OpenidModule extends PLModule
     function handlers()
     {
         return array(
-            'openid'            => $this->make_hook('openid', AUTH_PUBLIC),
-            'openid/trust'      => $this->make_hook('trust', AUTH_COOKIE),
-            'openid/trusted'    => $this->make_hook('trusted', AUTH_MDP),
-            'admin/openid/trusted'  => $this->make_hook('admin_trusted', AUTH_MDP),
-            'openid/idp_xrds'   => $this->make_hook('idp_xrds', AUTH_PUBLIC),
-            'openid/user_xrds'  => $this->make_hook('user_xrds', AUTH_PUBLIC),
-            'openid/melix'      => $this->make_hook('melix', AUTH_PUBLIC),
+            'openid'                => $this->make_hook('openid', AUTH_PUBLIC),
+            'openid/melix'          => $this->make_hook('melix', AUTH_PUBLIC),
+            'openid/xrds'           => $this->make_hook('xrds', AUTH_PUBLIC),
+            'openid/trust'          => $this->make_hook('trust', AUTH_MDP),
+            'openid/trusted'        => $this->make_hook('trusted', AUTH_MDP),
+            'admin/openid/trusted'  => $this->make_hook('admin_trusted', AUTH_MDP, 'admin'),
         );
     }
 
-    function handler_openid(&$page, $x = null)
+    function handler_openid(&$page, $login = null)
     {
         $this->load('openid.inc.php');
+        $requested_user = User::getSilent($login);
+        $server = new OpenId();
 
         // Spec §4.1.2: if "openid.mode" is absent, we SHOULD assume that
-        // the request is not an OpenId message
-        if (!array_key_exists('openid_mode', $_REQUEST)) {
-            return $this->render_discovery_page($page, get_user($x));
+        // the request is not an OpenId message.
+        if (!$server->IsOpenIdRequest()) {
+            if ($requested_user) {
+                $server->RenderDiscoveryPage($page, $requested_user);
+                return;
+            } else {
+                pl_redirect('Xorg/OpenId');
+            }
+            exit;
         }
 
-        // Now, deal with the OpenId message
-        $server = init_openid_server();
-        $request = $server->decodeRequest();
-
-        // In modes 'checkid_immediate' and 'checkid_setup', the request
-        // needs some logic and can not be automatically answered by the server
-
-        // Immediate mode
-        if ($request->mode == 'checkid_immediate') {
+        // Initializes the OpenId environment from the request.
+        $server->Initialize();
+
+        // In modes 'checkid_immediate' and 'checkid_setup', we need to check
+        // by ourselves that we want to allow the user to be authenticated.
+        // Otherwise it can simply be forwarded to the Server object.
+        if ($server->IsAuthorizationRequest()) {
+            $authorized = S::logged() &&
+                $server->IsUserAuthorized(S::user()) &&
+                $server->IsEndpointTrusted(S::user());
+
+            if ($authorized) {
+                // TODO(vzanotti): SReg requests are currently not honored if
+                // the website is already trusted. We may want to redirect SReg
+                // requests to /openid/trust, to allow the user to choose.
+                $server->AnswerRequest(true);
+            } else if ($server->IsImmediateRequest()) {
+                $server->AnswerRequest(false);
+            } else {
+                // The user is currently not authorized to get her authorization
+                // request approved. Two possibilities:
+                //  * the endpoint is not yet trusted => redirect to openid/trust
+                //  * the user is not logged in => log in the user.
+                //
+                // The second case requires a special handling when the request
+                // was POSTed, as our current log in mechanism does not preserve
+                // POST arguments.
+                $openid_args = $server->GetQueryStringForRequest();
+                if (S::logged()) {
+                    pl_redirect('openid/trust', $openid_args);
+                } else if (Post::has('openid_mode')) {
+                    pl_redirect('openid', $openid_args);
+                } else {
+                    return PL_DO_AUTH;
+                }
+            }
+        } else {
+            $server->HandleRequest();
+        }
 
-            // We deny immediate requests, unless:
-            //   - the user identifier is known by the RP
-            //   - the user is logged in
-            //   - the user identifier matches the user logged in
-            //   - the user has whitelisted the site
-            $answer = !$request->idSelect()
-                      && S::logged()
-                      && $request->identity == S::user()->login()
-                      && is_trusted_site(S::user(), $request->trust_root);
-            $response =& $request->answer($answer);
+        // All requests should have been answered at this point. The best here
+        // is to get the user back to a safe page.
+        pl_redirect('');
+    }
 
-        // Setup mode
-        } else if ($request->mode == 'checkid_setup') {
+    function handler_melix(&$page, $login = null)
+    {
+        $this->load('openid.inc.php');
 
-            // We redirect to a page where the user will authenticate
-            // and confirm the use of his/her OpenId
-            $request_id = uniqid('openid-');
-            S::set($request_id, serialize($request));
-            $query = 'request_id=' . urlencode($request_id);
-            pl_redirect('openid/trust', $query);
-            return;
+        global $globals;
+        $melix = ($login ? $login . '@' . $globals->mail->alias_dom : null);
 
-        // Other requests can be automatically handled by the server
+        if ($melix && ($requested_user = User::getSilent($melix))) {
+            $server = new OpenId();
+            $server->RenderDiscoveryPage($page, $requested_user);
         } else {
-            $response =& $server->handleRequest($request);
+            pl_redirect('Xorg/OpenId');
         }
-
-        $webresponse =& $server->encodeResponse($response);
-        $this->render_openid_response($webresponse);
     }
 
-    function handler_trust(&$page, $x = null)
+    function handler_xrds(&$page, $login = null)
     {
         $this->load('openid.inc.php');
+        $requested_user = User::getSilent($login);
+        $server = new OpenId();
 
-        // Recover request in session
-        $request_id = $_GET['request_id'];
-        if (is_null($request_id) || !isset($_SESSION[$request_id])) {
-            // There is no authentication information, something went wrong
-            pl_redirect('/');
-            return;
+        if (!$login) {
+            $server->RenderMainXrdsPage($page);
+        } else if ($requested_user) {
+            $server->RenderUserXrdsPage($page, $requested_user);
+        } else {
+            return PL_NOT_FOUND;
         }
+    }
 
-        require_once 'Auth/OpenID/Server.php';
-        $request = unserialize($_SESSION[$request_id]);
-
-        $server = init_openid_server();
+    function handler_trust(&$page)
+    {
+        $this->load('openid.inc.php');
+        $server = new OpenId();
         $user = S::user();
-        $identity = null;
-        $claimed_id = null;
 
-        // Set the identity to the user currently logged in
-        // if an OP Identifier was initially used
-        if ($request->identity == Auth_OpenID_IDENTIFIER_SELECT) {
-            $identity = $user->hruid;
-            $claimed_id = get_user_openid_url($user);
-        // Check that the identity matches the user currently logged in
-        // if an User Identifier was initially used
-        } else if ($request->identity != $user->hruid) {
-            $response =& $request->answer(false);
-            $webresponse =& $server->encodeResponse($response);
-            $this->render_openid_response($webresponse);
-            return;
+        // Initializes the OpenId environment from the request.
+        if (!$server->Initialize() || !$server->IsAuthorizationRequest()) {
+            $page->kill("Ta requête OpenID a échoué, merci de réessayer.");
         }
 
-        // Prepare Simple Registration response fields
-        require_once 'Auth/OpenID/SReg.php';
-        $sreg_request = Auth_OpenID_SRegRequest::fromOpenIDRequest($request);
-        $sreg_response = Auth_OpenID_SRegResponse::extractResponse($sreg_request, get_sreg_data($user));
+        // Prepares the SREG data, if any is required.
+        $sreg_response = $server->GetSRegDataForRequest($user);
 
-        $whitelisted = is_trusted_site($user, $request->trust_root);
-
-        // Ask the user for confirmation
-        $from_trust_page = $_SERVER['REQUEST_METHOD'] == 'POST'
-                           && (isset($_POST['openid_trust']) || isset($_POST['openid_cancel']));
-        if (!$whitelisted && !$from_trust_page) {
+        // Asks the user about her trust level of the current request, if not
+        // done yet.
+        if (!Post::has('trust_accept') && !Post::has('trust_cancel')) {
             $page->changeTpl('openid/trust.tpl');
-            $page->assign('relying_party', $request->trust_root);
-            $page->assign_by_ref('sreg_data', $sreg_response->data);
-            $query = 'request_id=' . urlencode($request_id);
-            $page->assign('query', $query);
-            return;
-        }
-
-        // If this point is reached, the user has just validated the form on the 'trust' page
+            $page->assign('openid_query', $server->GetQueryStringForRequest());
+            $page->assign('relying_party', $server->GetEndpoint());
+            $page->assign('sreg_data', $sreg_response->contents());
 
-        // Remove the request from session since an answer will be sent
-        S::kill($request_id);
-
-        // Add 'always trusted' sites to whitelist
-        if (isset($_POST['openid_trust']) && @$_POST['openid_always']) {
-            add_trusted_site($user, $request->trust_root);
+            return;
         }
 
-        // Answer to the Relying Party
-        if ($whitelisted || isset($_POST['openid_trust'])) {
-            $response =& $request->answer(true, null, $identity, $claimed_id);
-
-            // Add the simple registration response values to the OpenID
-            // response message.
-            $sreg_response->toMessage($response->fields);
-
-        } else { // !$whitelisted && isset($_POST['openid_cancel'])
-            $response =& $request->answer(false);
+        // Interprets the form results, and updates the user whitelist.
+        S::assert_xsrf_token();
+        $trusted = $server->UpdateEndpointTrust(
+            $user,
+            Post::b('trust_accept') && !Post::b('trust_cancel'),
+            Post::b('trust_always'));
+
+        // Finally answers the request.
+        if ($server->IsUserAuthorized($user) && $trusted) {
+            $server->AnswerRequest(
+                true, $user, Post::b('trust_sreg') ? $sreg_response : null);
+        } else {
+            $server->AnswerRequest(false);
         }
-
-        $webresponse =& $server->encodeResponse($response);
-        $this->render_openid_response($webresponse);
     }
 
     function handler_trusted(&$page, $action = 'list', $id = null)
@@ -224,92 +227,7 @@ class OpenidModule extends PLModule
         $page->assign('readonly', true);
         $table_editor->apply($page, $action, $id);
     }
-
-    function handler_idp_xrds(&$page)
-    {
-        $this->load('openid.inc.php');
-        header('Content-type: application/xrds+xml');
-        $page->changeTpl('openid/idp_xrds.tpl', NO_SKIN);
-        $page->assign('type2', Auth_OpenID_TYPE_2_0_IDP);
-        $page->assign('sreg', Auth_OpenID_SREG_URI);
-        $page->assign('provider', get_openid_url());
-    }
-
-    function handler_user_xrds(&$page, $x = null)
-    {
-        $this->load('openid.inc.php');
-
-        $user = get_user($x);
-        if (is_null($user)) {
-            return PL_NOT_FOUND;
-        }
-
-        header('Content-type: application/xrds+xml');
-        $page->changeTpl('openid/user_xrds.tpl', NO_SKIN);
-        $page->assign('type2', Auth_OpenID_TYPE_2_0);
-        $page->assign('type1', Auth_OpenID_TYPE_1_1);
-        $page->assign('sreg', Auth_OpenID_SREG_URI);
-        $page->assign('provider', get_openid_url());
-        $page->assign('local_id', $user->hruid);
-    }
-
-    function handler_melix(&$page, $x = null)
-    {
-        $this->load('openid.inc.php');
-        $user = get_user_by_alias($x);
-
-        // This will redirect to the canonic URL, which was not used
-        // if this hook was triggered
-        return $this->render_discovery_page(&$page, $user);
-    }
-
-    //--------------------------------------------------------------------//
-
-    function render_discovery_page(&$page, $user)
-    {
-
-        // Show the documentation if this is not the OpenId page of an user
-        if (is_null($user)) {
-            pl_redirect('Xorg/OpenId');
-        }
-
-        // Redirect to the canonic URL if we are using an alias
-        // There might be a risk of redirection loop here
-        // if $_SERVER was not exactly what we expect
-        $current_url = 'http' . (empty($_SERVER['HTTPS']) ? '' : 's') . '://'
-                       . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
-        $canonic_url = get_user_openid_url($user);
-        if ($current_url != $canonic_url) {
-            http_redirect($canonic_url);
-        }
-
-        // Include X-XRDS-Location response-header for Yadis discovery
-        header('X-XRDS-Location: ' . get_user_xrds_url($user));
-
-        $page->changeTpl('openid/openid.tpl');
-        $page->setTitle($user->fullName());
-        // Set the <link> tags for HTML-Based Discovery
-        $page->addLink('openid.server openid2.provider', get_openid_url());
-        $page->addLink('openid.delegate openid2.local_id', $user->hruid);
-        $page->assign_by_ref('user', $user);
-
-        return;
-    }
-
-    function render_openid_response($webresponse)
-    {
-        if ($webresponse->code != AUTH_OPENID_HTTP_OK) {
-            header(sprintf("HTTP/1.1 %d ", $webresponse->code),
-                   true, $webresponse->code);
-        }
-        foreach ($webresponse->headers as $k => $v) {
-            header("$k: $v");
-        }
-        header('Connection: close');
-        print $webresponse->body;
-        exit;
-    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
-?>
\ No newline at end of file
+?>
index d5f7c5c..455e9df 100644 (file)
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
  ***************************************************************************/
 
-require_once "Auth/OpenID/Discover.php";
+require_once 'Auth/OpenID/Discover.php';
 
-function init_openid_server()
+// An helper class for using plat/al as an OpenId Identity Provider.
+class OpenId
 {
-    // Initialize a filesystem-based store
-    $store_location = dirname(__FILE__) . '/../../spool/openid/store';
-    require_once "Auth/OpenID/FileStore.php";
-    $store = new Auth_OpenID_FileStore($store_location);
-
-    // Create an OpenId server
-    require_once 'Auth/OpenID/Server.php';
-    return new Auth_OpenID_Server($store, get_openid_url());
-}
+    private $base_url;        // Base url for all OpenId operations.
+    private $spool_store;     // Location of the spool storage for OpenID.
 
-function get_openid_url()
-{
-    global $globals;
-    return $globals->baseurl . '/openid';
-}
+    private $server = null;   // Auth::OpenId::Server object.
+    private $request = null;  // Request extracted by the Server object.
+
+    public function __construct()
+    {
+        global $globals;
 
-function get_user($x) {
-    if (is_null($x)) {
-        return null;
+        $this->base_url = $globals->baseurl . '/openid';
+        $this->spool_store = $globals->spoolroot . '/spool/openid/store';
     }
-    $user = User::getSilent($x);
-    return $user ? $user : null;
 
-}
+    // Initializes an OpenId Server object; it will use a defined spool-based
+    // directory to store OpenID secrets. Returns true on success.
+    public function Initialize()
+    {
+        require_once 'Auth/OpenID/FileStore.php';
+        require_once 'Auth/OpenID/Server.php';
+
+        $store = new Auth_OpenID_FileStore($this->spool_store);
+        $this->server = new Auth_OpenID_Server($store, $this->base_url);
+        $this->request = $this->server->decodeRequest();
 
-function get_user_by_alias($x) {
-    if (is_null($x)) {
-        return null;
+        return !is_a($this->request, 'Auth_OpenID_ServerError');
     }
-    global $globals;
-    // Should we check the publicity of the alias?
-    $user = User::getSilent($x . '@' . $globals->mail->alias_dom);
-    return $user ? $user : null;
 
-}
+    // Authorization logic helpers ---------------------------------------------
 
-function get_user_openid_url($user)
-{
-    if (is_null($user)) {
-        return null;
+    // Returns true iff the current request is a valid openid request.
+    public function IsOpenIdRequest()
+    {
+        return Env::has('openid_mode');
     }
-    global $globals;
-    return $globals->baseurl . '/openid/' . $user->hruid;
-}
 
-function get_idp_xrds_url()
-{
-    global $globals;
-    return $globals->baseurl . '/openid/idp_xrds';
-}
+    // Returns true iff the request needs to be handled directly by the calling
+    // code (ie. the current user needs to be authorized).
+    public function IsAuthorizationRequest()
+    {
+        return $this->request->mode == 'checkid_immediate' ||
+               $this->request->mode == 'checkid_setup';
+    }
 
-function get_user_xrds_url($user)
-{
-    if (is_null($user)) {
-        return null;
+    // Returns true iff the request requires an immediate answer (no user
+    // interaction is allowed).
+    public function IsImmediateRequest()
+    {
+        return $this->request->mode == 'checkid_immediate';
     }
-    global $globals;
-    return $globals->baseurl . '/openid/user_xrds/' . $user->hruid;
-}
 
-function get_sreg_data($user)
-{
-    if (is_null($user)) {
-        return null;
-    }
-    return array('fullname' => $user->fullName(),
-                 'nickname' => $user->displayName(),
-                 'dob' => null,
-                 'email' => $user->bestEmail(),
-                 'gender' => $user->isFemale() ? 'F' : 'M',
-                 'postcode' => null,
-                 'country' => null,
-                 'language' => null,
-                 'timezone' => null);
-}
+    // Returns true iff the logged-in user is authorized for the current request.
+    // It checks that the user is logged in, and has the authorization to use
+    // that identity.
+    public function IsUserAuthorized(User $user)
+    {
+        return $user && ($user->login() == $this->request->identity ||
+            $this->request->idSelect());
+    }
 
-function is_trusted_site($user, $url)
-{
-    $res = XDB::query('SELECT  COUNT(*)
-                         FROM  openid_trusted
-                        WHERE  (user_id = {?} OR user_id IS NULL)
-                          AND  url = {?}',
-                               $user->id(), $url);
-    return $res->fetchOneCell() > 0;
-}
+    // SimpleRegistration helpers ----------------------------------------------
 
-function add_trusted_site($user, $url)
-{
-    XDB::execute("INSERT IGNORE INTO openid_trusted
-                      SET user_id={?}, url={?}",
-                  $user->id(), $url);
+    // Determines which SREG data are requested by the endpoint, and returns them.
+    public function GetSRegDataForRequest(User &$user)
+    {
+        require_once 'Auth/OpenID/SReg.php';
+
+        // Other common SReg fields we could fill are:
+        //   dob, country, language, timezone.
+        $sreg_request = Auth_OpenID_SRegRequest::fromOpenIDRequest($this->request);
+        return Auth_OpenID_SRegResponse::extractResponse($sreg_request, array(
+            'fullname' => $user->fullName(),
+            'nickname' => $user->displayName(),
+            'email'    => $user->bestEmail(),
+            'gender'   => $user->isFemale() ? 'F' : 'M',
+        ));
+    }
+
+    // Handling and answering helpers ------------------------------------------
+
+    // Answers the current request, and renders the response. Appends the |sreg|
+    // data when not null.
+    public function AnswerRequest($is_authorized, $user = null, $sreg_data = null)
+    {
+        // Creates the response.
+        if ($is_authorized && $this->request->idSelect() && $user) {
+            $response = $this->request->answer(
+                $is_authorized, null, $user->login(), $this->GetUserUrl($user));
+        } else {
+            $response = $this->request->answer($is_authorized);
+        }
+
+        // Clobbers response, and get it back to the Relaying Party.
+        if ($sreg_data) {
+            $sreg_data->toMessage($response->fields);
+        }
+        $this->RenderResponse($response);
+    }
+
+    // Automatically handles the request without any user interaction.
+    public function HandleRequest()
+    {
+        $response = $this->server->handleRequest($this->request);
+        $this->RenderResponse($response);
+    }
+
+    // Trust management helpers ------------------------------------------------
+
+    // Returns true iff the current endpoint is currently trusted by |user|.
+    public function IsEndpointTrusted(User $user)
+    {
+        $res = XDB::query(
+            "SELECT  COUNT(*)
+               FROM  openid_trusted
+              WHERE  (user_id = {?} OR user_id IS NULL) AND url = {?}",
+            $user->id(), $this->request->trust_root);
+        return ($res->fetchOneCell() > 0);
+    }
+
+    // Updates the trust level for the given endpoint, based on the value pf
+    // |trusted| and |permanent_trust| (the latter is ignored when the former
+    // value is false). Returns true iff the current endpoint is trusted.
+    public function UpdateEndpointTrust(User &$user, $trusted, $permanent_trust) {
+        $initial_trust = $this->IsEndpointTrusted($user);
+        if (!$initial_trust && $trusted && $permanent_trust) {
+            XDB::execute(
+                "INSERT IGNORE INTO  openid_trusted
+                                SET  user_id = {?}, url = {?}",
+                $user->id(), $this->request->trust_root);
+        }
+
+        return ($initial_trust || $trusted);
+    }
+
+    // Page renderers ----------------------------------------------------------
+
+    // Renders the OpenId discovery page for |user|.
+    public function RenderDiscoveryPage(&$page, User &$user)
+    {
+        $page->changeTpl('openid/openid.tpl');
+        $page->setTitle($user->fullName());
+        $page->addLink('openid.server openid2.provider', $this->base_url);
+        $page->addLink('openid.delegate openid2.local_id', $user->login());
+        $page->assign_by_ref('user', $user);
+
+        // Include the X-XRDS-Location header for Yadis discovery.
+        header('X-XRDS-Location: ' . $this->GetUserXrdsUrl($user));
+    }
+
+    // Renders the main XRDS page.
+    public function RenderMainXrdsPage(&$page)
+    {
+        header('Content-type: application/xrds+xml');
+        $page->changeTpl('openid/idp_xrds.tpl', NO_SKIN);
+        $page->assign('type2', Auth_OpenID_TYPE_2_0_IDP);
+        $page->assign('sreg', Auth_OpenID_SREG_URI);
+        $page->assign('provider', $this->base_url);
+    }
+
+    // Renders the XRDS page of |user|.
+    public function RenderUserXrdsPage(&$page, User &$user)
+    {
+        header('Content-type: application/xrds+xml');
+        $page->changeTpl('openid/user_xrds.tpl', NO_SKIN);
+        $page->assign('type2', Auth_OpenID_TYPE_2_0);
+        $page->assign('type1', Auth_OpenID_TYPE_1_1);
+        $page->assign('sreg', Auth_OpenID_SREG_URI);
+        $page->assign('provider', $this->base_url);
+        $page->assign('local_id', $user->login());
+    }
+
+    // Renders the OpenId response for the HTTP client.
+    public function RenderResponse($response)
+    {
+        if ($response) {
+            $web_response = $this->server->encodeResponse($response);
+            header(sprintf('%s %d', $_SERVER['SERVER_PROTOCOL'], $web_response->code),
+                   true, $web_response->code);
+
+            foreach ($web_response->headers as $key => $value) {
+                header(sprintf('%s: %s', $key, $value));
+            }
+
+            header('Connection: close');
+            print $web_response->body;
+        }
+        exit;
+    }
+
+    // URL providers -----------------------------------------------------------
+
+    // Returns the OpenId identity URL of the requested user.
+    private function GetUserUrl(User &$user)
+    {
+        return $this->base_url . '/' . $user->login();
+    }
+
+    // Returns the private XRDS page of a user.
+    private function GetUserXrdsUrl(User &$user)
+    {
+        return $this->base_url . '/xrds/' . $user->login();
+    }
+
+    // Returns the endpoint in the current request.
+    public function GetEndpoint()
+    {
+        return $this->request->trust_root;
+    }
+
+    // Extracts the OpenId arguments available in the current request, and
+    // builds a query string with them.
+    public function GetQueryStringForRequest()
+    {
+        foreach (Auth_OpenID::getQuery() as $key => $value) {
+            if (strpos($key, 'openid.') === 0) {
+                $args[$key] = $value;
+            }
+        }
+
+        return http_build_query($args);
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 9324e08..13c853c 100644 (file)
@@ -88,14 +88,14 @@ class PaymentModule extends PLModule
     function handlers()
     {
         return array(
-            'payment'               => $this->make_hook('payment', AUTH_MDP),
-            'payment/cyber_return'  => $this->make_hook('cyber_return',  AUTH_PUBLIC, 'user', NO_HTTPS),
-            'payment/paypal_return' => $this->make_hook('paypal_return',  AUTH_PUBLIC, 'user', NO_HTTPS),
-            '%grp/paiement'              => $this->make_hook('xnet_payment', AUTH_MDP),
-            '%grp/payment'               => $this->make_hook('xnet_payment', AUTH_MDP),
-            '%grp/payment/cyber_return'  => $this->make_hook('cyber_return', AUTH_PUBLIC, 'user', NO_HTTPS),
+            'payment'                    => $this->make_hook('payment',       AUTH_MDP),
+            'payment/cyber_return'       => $this->make_hook('cyber_return',  AUTH_PUBLIC, 'user', NO_HTTPS),
+            'payment/paypal_return'      => $this->make_hook('paypal_return', AUTH_PUBLIC, 'user', NO_HTTPS),
+            '%grp/paiement'              => $this->make_hook('xnet_payment',  AUTH_MDP),
+            '%grp/payment'               => $this->make_hook('xnet_payment',  AUTH_MDP),
+            '%grp/payment/cyber_return'  => $this->make_hook('cyber_return',  AUTH_PUBLIC, 'user', NO_HTTPS),
             '%grp/payment/paypal_return' => $this->make_hook('paypal_return', AUTH_PUBLIC, 'user', NO_HTTPS),
-            'admin/payments'        => $this->make_hook('admin', AUTH_MDP, 'admin'),
+            'admin/payments'             => $this->make_hook('admin',         AUTH_MDP,    'admin'),
 
         );
     }
@@ -218,10 +218,11 @@ class PaymentModule extends PLModule
                      $champ901, $user->id(), $ref, $champ200, $montant, $champ905, Env::v('comment'));
 
         /* on genere le mail de confirmation */
-        $conf_text = str_replace(array('<prenom>', '<nom>', '<promo>', '<montant>', '<salutation>', '<cher>'),
-                                 array($user->firstName(), $user->lastName(), $user->promo(), $montant,
-                                       $user->isFemale() ? 'Chère' : 'Cher',
-                                       $user->isFemale() ? 'Chère' : 'Cher'), $conf_text);
+        $conf_text = str_replace(
+            array('<prenom>', '<nom>', '<promo>', '<montant>', '<salutation>', '<cher>', 'comment>'),
+            array($user->firstName(), $user->lastName(), $user->promo(), $montant,
+                  $user->isFemale() ? 'Chère' : 'Cher', $user->isFemale() ? 'Chère' : 'Cher',
+                  Env::v('comment')), $conf_text);
 
         global $globals;
         $mymail = new PlMailer();
index f123ba7..94a4077 100644 (file)
@@ -38,25 +38,24 @@ class PlatalModule extends PLModule
     function handlers()
     {
         return array(
-            'index'       => $this->make_hook('index',     AUTH_PUBLIC),
-            'cacert.pem'  => $this->make_hook('cacert',    AUTH_PUBLIC),
-            'changelog'   => $this->make_hook('changelog', AUTH_PUBLIC),
+            'index'             => $this->make_hook('index',     AUTH_PUBLIC),
+            'cacert.pem'        => $this->make_hook('cacert',    AUTH_PUBLIC),
+            'changelog'         => $this->make_hook('changelog', AUTH_PUBLIC),
 
             // Preferences thingies
-            'prefs'       => $this->make_hook('prefs',     AUTH_COOKIE),
-            'prefs/rss'   => $this->make_hook('prefs_rss', AUTH_COOKIE),
-            'prefs/webredirect'
-                          => $this->make_hook('webredir',  AUTH_MDP),
-            'prefs/skin'  => $this->make_hook('skin',      AUTH_COOKIE),
+            'prefs'             => $this->make_hook('prefs',     AUTH_COOKIE),
+            'prefs/rss'         => $this->make_hook('prefs_rss', AUTH_COOKIE),
+            'prefs/webredirect' => $this->make_hook('webredir',  AUTH_MDP),
+            'prefs/skin'        => $this->make_hook('skin',      AUTH_COOKIE),
 
             // password related thingies
-            'password'      => $this->make_hook('password',  AUTH_MDP),
-            'tmpPWD'        => $this->make_hook('tmpPWD',    AUTH_PUBLIC),
-            'password/smtp' => $this->make_hook('smtppass',  AUTH_MDP),
-            'recovery'      => $this->make_hook('recovery',  AUTH_PUBLIC),
-            'exit'          => $this->make_hook('exit', AUTH_PUBLIC),
-            'review'        => $this->make_hook('review', AUTH_PUBLIC),
-            'deconnexion.php' => $this->make_hook('exit', AUTH_PUBLIC),
+            'password'          => $this->make_hook('password',  AUTH_MDP),
+            'tmpPWD'            => $this->make_hook('tmpPWD',    AUTH_PUBLIC),
+            'password/smtp'     => $this->make_hook('smtppass',  AUTH_MDP),
+            'recovery'          => $this->make_hook('recovery',  AUTH_PUBLIC),
+            'exit'              => $this->make_hook('exit',      AUTH_PUBLIC),
+            'review'            => $this->make_hook('review',    AUTH_PUBLIC),
+            'deconnexion.php'   => $this->make_hook('exit',      AUTH_PUBLIC),
         );
     }
 
@@ -64,7 +63,7 @@ class PlatalModule extends PLModule
     {
         // Include X-XRDS-Location response-header for Yadis discovery
         global $globals;
-        header('X-XRDS-Location: ' . $globals->baseurl . '/openid/idp_xrds');
+        header('X-XRDS-Location: ' . $globals->baseurl . '/openid/xrds');
 
         // Redirect to the suitable page
         if (S::logged()) {
@@ -464,7 +463,7 @@ Adresse de secours : " . Post::v('email') : ""));
     {
         // Include X-XRDS-Location response-header for Yadis discovery
         global $globals;
-        header('X-XRDS-Location: ' . $globals->baseurl . '/openid/idp_xrds');
+        header('X-XRDS-Location: ' . $globals->baseurl . '/openid/xrds');
 
         $this->load('review.inc.php');
         $dom = 'Review';
index 15d1f83..a9b3430 100644 (file)
@@ -25,7 +25,8 @@ class ReviewPage implements PlWizardPage
 {
     public function __construct(PlWizard &$wiz) { }
     public function template() { return 'platal/review.tpl'; }
-    public function process() { }
+    public function process(&$success) { }
+    public function success() { }
 
     public function prepare(PlPage &$page, $id)
     {
index abfbefa..38e6dc8 100644 (file)
@@ -72,7 +72,6 @@ class ProfileModule extends PLModule
             'admin/corps_enum'           => $this->make_hook('admin_corps_enum',           AUTH_MDP, 'admin'),
             'admin/corps_rank'           => $this->make_hook('admin_corps_rank',           AUTH_MDP, 'admin'),
             'admin/names'                => $this->make_hook('admin_names',                AUTH_MDP, 'admin'),
-
         );
     }
 
@@ -339,7 +338,7 @@ class ProfileModule extends PLModule
         http_redirect("http://www.polytechniciens.com/?page=AX_FICHE_ANCIEN&anc_id=" . $user->ax_id);
     }
 
-    function handler_p_edit(&$page, $user = null, $opened_tab = null, $mode = null)
+    function handler_p_edit(&$page, $user = null, $opened_tab = null, $mode = null, $success = null)
     {
         global $globals;
 
@@ -384,6 +383,9 @@ class ProfileModule extends PLModule
         }
 
        $page->setTitle('Mon Profil');
+       if (isset($success) && $success) {
+           $page->trigSuccess('Ton profil a bien été mis à jour.');
+       }
     }
 
     function handler_education_js(&$page)
index 2744aa8..11220b4 100644 (file)
@@ -144,7 +144,7 @@ class ProfileAddresses extends ProfilePage
     {
         $res = XDB::query("SELECT  id, accuracy, text, postalText,
                                    postalCode, localityId, subAdministrativeAreaId, administrativeAreaId,
-                                   countryId, latitude, longitude, pub, comment, updateTime,
+                                   countryId, latitude, longitude, pub, comment, UNIX_TIMESTAMP(updateTime) AS updateTime,
                                    north, south, east, west,
                                    FIND_IN_SET('current', flags) AS current,
                                    FIND_IN_SET('temporary', flags) AS temporary,
@@ -187,9 +187,18 @@ class ProfileAddresses extends ProfilePage
         }
         foreach ($this->values['addresses'] as $id => &$address) {
             if (!isset($address['tel'])) {
-                $address['tel'] = array();
+                $address['tel'] = array(
+                                 0 => array(
+                                     'type'    => 'fixed',
+                                     'tel'     => '',
+                                     'pub'     => 'private',
+                                     'comment' => '',
+                                     )
+                                 );
             }
             unset($address['id']);
+            $address['changed'] = 0;
+            $address['removed'] = 0;
         }
     }
 }
index 9856dc8..4884303 100644 (file)
@@ -57,6 +57,7 @@ class ProfileSearchNames implements ProfileSetting
     {
         $success     = true;
         $success_tmp = true;
+
         if (is_null($value)) {
             $sn_all = XDB::iterator("SELECT  CONCAT(sn.particle, sn.name) AS name,
                                              sn.particle, sn.typeid, e.type, e.name AS type_name,
@@ -85,12 +86,14 @@ class ProfileSearchNames implements ProfileSetting
                         $sn = $sn_all->next();
                     }
                 } else {
-                    $value[] = array('typeid'    => $sn_type['id'],
-                                     'type'      => $sn_type['type'],
-                                     'type_name' => $sn_type['name'],
-                                     'pub'       => 1,
+                    $value[] = array('name'             => '',
+                                     'particle'         => '',
+                                     'typeid'           => $sn_type['id'],
+                                     'type'             => $sn_type['type'],
+                                     'type_name'        => $sn_type['name'],
                                      'has_particle'     => $sn_type['has_particle'],
-                                     'always_displayed' => 1);
+                                     'always_displayed' => 1,
+                                     'pub'              => 1);
                 }
             }
             if ($sn) {
@@ -162,6 +165,7 @@ class ProfileSearchNames implements ProfileSetting
             Platal::page()->assign('public_name', $public_name);
             Platal::page()->assign('private_name', $private_name);
         }
+
         return $value;
     }
 
@@ -180,7 +184,7 @@ class ProfileSearchNames implements ProfileSetting
         if ($has_new) {
             $new_names = new NamesReq(S::user(), $this->search_names, $this->private_name_end);
             $new_names->submit();
-            Platal::page()->trigWarning("La demande de modification de tes noms a bien été prises en compte." .
+            Platal::page()->trigWarning("La demande de modification de tes noms a bien été prise en compte." .
                                         " Tu recevras un email dès que ces changements auront été effectués.");
         } else {
             $display_names = array();
@@ -368,8 +372,6 @@ class ProfileGeneral extends ProfilePage
                                   = $this->settings['yourself']
                                   = $this->settings['promo']
                                   = null;
-        $this->settings['synchro_ax']
-                                  = new ProfileBool();
         $this->settings['email_directory']
                                   = new ProfileEmail();
         $this->settings['email_directory_new']
@@ -390,7 +392,7 @@ class ProfileGeneral extends ProfilePage
                                    pr.nationality1, pr.nationality2, pr.nationality3, pr.birthdate,
                                    t.display_tel as mobile, t.pub as mobile_pub,
                                    d.email_directory as email_directory,
-                                   pr.freetext, pr.freetext_pub as freetext_pub
+                                   pr.freetext, pr.freetext_pub, pr.ax_id AS matricule_ax, p.yourself
                              FROM  profiles              AS pr
                        INNER JOIN  profile_display       AS p ON (p.pid = pr.pid)
                        INNER JOIN  profile_education     AS e ON (e.uid = pr.pid AND FIND_IN_SET('primary', e.flags))
@@ -446,11 +448,10 @@ class ProfileGeneral extends ProfilePage
             XDB::execute("UPDATE  profiles
                              SET  nationality1 = {?}, nationality2 = {?}, nationality3 = {?}, birthdate = {?},
                                   freetext = {?}, freetext_pub = {?}
-                           WHERE  user_id = {?}",
+                           WHERE  pid = {?}",
                           $this->values['nationality1'], $this->values['nationality2'], $this->values['nationality3'],
                           preg_replace('@(\d{2})/(\d{2})/(\d{4})@', '\3-\2-\1', $this->values['birthdate']),
-                          $this->values['freetext'], $this->values['freetext_pub'],
-                          $this->pid());
+                          $this->values['freetext'], $this->values['freetext_pub'], $this->pid());
         }
         if ($this->changed['email_directory']) {
             $new_email = ($this->values['email_directory'] == "new@example.org") ?
index 424de8e..18a8f6a 100644 (file)
@@ -42,6 +42,77 @@ class ProfileJob extends ProfileGeocoding
                              );
     }
 
+    public function emptyJob()
+    {
+        return array(
+            'id'               => '0',
+            'jobid'            => '',
+            'pub'              => 'private',
+            'name'             => '',
+            'hq_acronym'       => '',
+            'hq_url'           => '',
+            'hq_email'         => '',
+            'hq_address'       => array(
+                'text'                    => '',
+                'accuracy'                => '',
+                'postalText'              => '',
+                'postalCode'              => '',
+                'administrativeAreaId'    => '',
+                'subAdministrativeAreaId' => '',
+                'localityId'              => '',
+                'countryId'               => '',
+                'latitude'                => '',
+                'longitude'               => '',
+                'north'                   => '',
+                'south'                   => '',
+                'east'                    => '',
+                'west'                    => '',
+                'cedex'                   => '',
+                'updateTime'              => '',
+                'changed'                 => '0',
+                'removed'                 => '0',
+            ),
+            'hq_phone'         => '',
+            'hq_fax'           => '',
+            'subSubSectorName' => null,
+            'sector'           => '0',
+            'subSector'        => '0',
+            'subSubSector'     => '0',
+            'description'      => '',
+            'w_url'            => '',
+            'w_address'        => array(
+                'pub'                     => 'private',
+                'text'                    => '',
+                'accuracy'                => '',
+                'postalText'              => '',
+                'postalCode'              => '',
+                'administrativeAreaId'    => '',
+                'subAdministrativeAreaId' => '',
+                'localityId'              => '',
+                'countryId'               => '',
+                'latitude'                => '',
+                'longitude'               => '',
+                'north'                   => '',
+                'south'                   => '',
+                'east'                    => '',
+                'west'                    => '',
+                'cedex'                   => '',
+                'updateTime'              => '',
+                'changed'                 => '0',
+                'removed'                 => '0',
+            ),
+            'w_email'          => '',
+            'w_email_pub'      => 'private',
+            'w_email_new'      => '',
+            'w_phone'          => array(0 => array(
+                'type'    => 'fixed',
+                'tel'     => '',
+                'pub'     => 'private',
+                'comment' => '',
+            )),
+        );
+    }
+
     private function cleanJob(ProfilePage &$page, $jobid, array &$job, &$success)
     {
         $success = true;
@@ -102,6 +173,7 @@ class ProfileJob extends ProfileGeocoding
         }
         $profiletel = new ProfilePhones('pro', $jobid);
         $job['w_phone'] = $profiletel->value($page, 'tel', $job['w_phone'], $s);
+
         unset($job['removed']);
         unset($job['new']);
     }
@@ -120,7 +192,7 @@ class ProfileJob extends ProfileGeocoding
         $success = true;
         foreach ($value as $key=>&$job) {
             $job['name'] = trim($job['name']);
-            if (!$job['name']) {
+            if (!$job['name'] && $entreprise) {
                 $job['tmp_name'] = $entreprise[$entr_val]->name;
                 $entr_val ++;
             }
@@ -143,6 +215,8 @@ class ProfileJob extends ProfileGeocoding
 
     public function save(ProfilePage &$page, $field, $value)
     {
+        // TODO: use address and phone classes to update profile_job_enum and profile_phones once they are done.
+
         require_once('profil.func.inc.php');
         require_once('validations.inc.php');
 
@@ -156,23 +230,25 @@ class ProfileJob extends ProfileGeocoding
                             WHERE  uid = {?} AND link_type = 'pro'",
                      S::i('uid'));
         foreach ($value as $id=>&$job) {
-            if ($job['jobid']) {
-                XDB::execute("INSERT INTO  profile_job (uid, id, description, sectorid, subsectorid,
-                                                        subsubsectorid, email, url, pub, email_pub, jobid)
-                                   VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})",
-                             S::i('uid'), $id, $job['description'], $job['sector'], $job['subSector'],
-                             $job['subSubSector'], $job['w_email'], $job['w_url'], $job['pub'], $job['w_email_pub'], $job['jobid']);
-            } else {
-                XDB::execute("INSERT INTO  profile_job (uid, id, description, sectorid, subsectorid,
-                                                        subsubsectorid, email, url, pub, email_pub)
-                                   VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})",
-                             S::i('uid'), $id, $job['description'], $job['sector'], $job['subSector'],
-                             $job['subSubSector'], $job['w_email'], $job['w_url'], $job['pub'], $job['w_email_pub']);
+            if (isset($job['name']) && $job['name']) {
+                if (isset($job['jobid']) && $job['jobid']) {
+                    XDB::execute("INSERT INTO  profile_job (uid, id, description, sectorid, subsectorid,
+                                                            subsubsectorid, email, url, pub, email_pub, jobid)
+                                       VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})",
+                                 S::i('uid'), $id, $job['description'], $job['sector'], $job['subSector'],
+                                 $job['subSubSector'], $job['w_email'], $job['w_url'], $job['pub'], $job['w_email_pub'], $job['jobid']);
+                } else {
+                    XDB::execute("INSERT INTO  profile_job (uid, id, description, sectorid, subsectorid,
+                                                            subsubsectorid, email, url, pub, email_pub)
+                                       VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})",
+                                 S::i('uid'), $id, $job['description'], $job['sector'], $job['subSector'],
+                                 $job['subSubSector'], $job['w_email'], $job['w_url'], $job['pub'], $job['w_email_pub']);
+                }
+                $address = new ProfileAddress();
+                $address->saveAddress($id, $job['w_address'], 'job');
+                $profiletel = new ProfilePhones('pro', $id);
+                $profiletel->saveTels('tel', $job['w_phone']);
             }
-            $address = new ProfileAddress();
-            $address->saveAddress($id, $job['w_address'], 'job');
-            $profiletel = new ProfilePhones('pro', $id);
-            $profiletel->saveTels('tel', $job['w_phone']);
         }
     }
 }
@@ -229,97 +305,148 @@ class ProfileJobs extends ProfilePage
                            ORDER BY  j.id",
                             $this->pid());
         $this->values['jobs'] = array();
-        while (list($id, $jobid, $name, $sector, $subSector, $subSubSector,
-                    $subSubSectorName, $description, $w_email, $w_emailPub, $w_url, $pub,
-                    $hq_acronym, $hq_url, $hq_email,
-                    $w_accuracy, $w_text, $w_postalText, $w_postalCode, $w_localityId,
-                    $w_subAdministrativeAreaId, $w_administrativeAreaId, $w_countryId,
-                    $w_latitude, $w_longitude, $w_pub, $w_updateTime,
-                    $w_north, $w_south, $w_east, $w_west,
-                    $hq_accuracy, $hq_text, $hq_postalText, $hq_postalCode, $hq_localityId,
-                    $hq_subAdministrativeAreaId, $hq_administrativeAreaId, $hq_countryId,
-                    $hq_latitude, $hq_longitude, $hq_pub, $hq_updateTime,
-                    $hq_north, $hq_south, $hq_east, $hq_west,
-                   ) = $res->next()) {
-            $this->values['jobs'][] = array('id'               => $id,
-                                            'jobid'            => $jobid,
-                                            'name'             => $name,
-                                            'sector'           => $sector,
-                                            'subSector'        => $subSector,
-                                            'subSubSector'     => $subSubSector,
-                                            'subSubSectorName' => $subSubSectorName,
-                                            'description'      => $description,
-                                            'pub'              => $pub,
-                                            'w_email'          => $w_email,
-                                            'w_email_pub'      => $w_email_pub,
-                                            'w_url'            => $w_url,
-                                            'hq_acronym'       => $hq_acronym,
-                                            'hq_url'           => $hq_url,
-                                            'hq_email'         => $hq_email,
-                                            'w_address'        => array('accuracy'                => $w_accuracy,
-                                                                        'text'                    => $w_text,
-                                                                        'postalText'              => $w_postalText,
-                                                                        'postalCode'              => $w_postalCode,
-                                                                        'localityId'              => $w_localityId,
-                                                                        'subAdministrativeAreaId' => $w_subAdministrativeAreaId,
-                                                                        'administrativeAreaId'    => $w_administrativeAreaId,
-                                                                        'countryId'               => $w_countryId,
-                                                                        'latitude'                => $w_latitude,
-                                                                        'longitude'               => $w_longitude,
-                                                                        'pub'                     => $w_pub,
-                                                                        'updateTime'              => $w_update,
-                                                                        'north'                   => $w_north,
-                                                                        'south'                   => $w_south,
-                                                                        'east'                    => $w_east,
-                                                                        'west'                    => $w_west,
-                                                                       ),
-                                            'hq_address'       => array('accuracy'                => $hq_accuracy,
-                                                                        'text'                    => $hq_text,
-                                                                        'postalText'              => $hq_postalText,
-                                                                        'postalCode'              => $hq_postalCode,
-                                                                        'localityId'              => $hq_localityId,
-                                                                        'subAdministrativeAreaId' => $hq_subAdministrativeAreaId,
-                                                                        'administrativeAreaId'    => $hq_administrativeAreaId,
-                                                                        'countryId'               => $hq_countryId,
-                                                                        'latitude'                => $hq_latitude,
-                                                                        'longitude'               => $hq_longitude,
-                                                                        'pub'                     => $hq_pub,
-                                                                        'updateTime'              => $hq_update,
-                                                                        'north'                   => $hq_north,
-                                                                        'south'                   => $hq_south,
-                                                                        'east'                    => $hq_east,
-                                                                        'west'                    => $hq_west,
-                                                                       ),
-                                           );
-        }
 
-        $res = XDB::iterator("SELECT  link_id AS jobid, tel_type AS type, pub, display_tel AS tel, comment
-                                FROM  profile_phones
-                               WHERE  uid = {?} AND link_type = 'pro'
-                            ORDER BY  link_id",
-                             $this->pid());
-        $i = 0;
-        $jobNb = count($this->values['jobs']);
-        while ($phone = $res->next()) {
-            $jobid = $phone['jobid'];
-            while ($i < $jobNb && $this->values['jobs'][$i]['id'] < $jobid) {
-                $i++;
+        if ($res->numRows() > 0) {
+            while (list($id, $jobid, $name, $sector, $subSector, $subSubSector,
+                        $subSubSectorName, $description, $w_email, $w_emailPub, $w_url, $pub,
+                        $hq_acronym, $hq_url, $hq_email,
+                        $w_accuracy, $w_text, $w_postalText, $w_postalCode, $w_localityId,
+                        $w_subAdministrativeAreaId, $w_administrativeAreaId, $w_countryId,
+                        $w_latitude, $w_longitude, $w_pub, $w_updateTime,
+                        $w_north, $w_south, $w_east, $w_west,
+                        $hq_accuracy, $hq_text, $hq_postalText, $hq_postalCode, $hq_localityId,
+                        $hq_subAdministrativeAreaId, $hq_administrativeAreaId, $hq_countryId,
+                        $hq_latitude, $hq_longitude, $hq_pub, $hq_updateTime,
+                        $hq_north, $hq_south, $hq_east, $hq_west,
+                       ) = $res->next()) {
+                $this->values['jobs'][] = array(
+                    'id'               => $id,
+                    'jobid'            => $jobid,
+                    'name'             => $name,
+                    'sector'           => $sector,
+                    'subSector'        => $subSector,
+                    'subSubSector'     => $subSubSector,
+                    'subSubSectorName' => $subSubSectorName,
+                    'description'      => $description,
+                    'pub'              => $pub,
+                    'w_email'          => $w_email,
+                    'w_email_pub'      => $w_emailPub,
+                    'w_url'            => $w_url,
+                    'hq_acronym'       => $hq_acronym,
+                    'hq_url'           => $hq_url,
+                    'hq_email'         => $hq_email,
+                    'w_address'        => array(
+                        'accuracy'                => $w_accuracy,
+                        'text'                    => $w_text,
+                        'postalText'              => $w_postalText,
+                        'postalCode'              => $w_postalCode,
+                        'localityId'              => $w_localityId,
+                        'subAdministrativeAreaId' => $w_subAdministrativeAreaId,
+                        'administrativeAreaId'    => $w_administrativeAreaId,
+                        'countryId'               => $w_countryId,
+                        'latitude'                => $w_latitude,
+                        'longitude'               => $w_longitude,
+                        'pub'                     => $w_pub,
+                        'updateTime'              => $w_updateTime,
+                        'north'                   => $w_north,
+                        'south'                   => $w_south,
+                        'east'                    => $w_east,
+                        'west'                    => $w_west,
+                    ),
+                    'hq_address'       => array(
+                        'accuracy'                => $hq_accuracy,
+                        'text'                    => $hq_text,
+                        'postalText'              => $hq_postalText,
+                        'postalCode'              => $hq_postalCode,
+                        'localityId'              => $hq_localityId,
+                        'subAdministrativeAreaId' => $hq_subAdministrativeAreaId,
+                        'administrativeAreaId'    => $hq_administrativeAreaId,
+                        'countryId'               => $hq_countryId,
+                        'latitude'                => $hq_latitude,
+                        'longitude'               => $hq_longitude,
+                        'pub'                     => $hq_pub,
+                        'updateTime'              => $hq_updateTime,
+                        'north'                   => $hq_north,
+                        'south'                   => $hq_south,
+                        'east'                    => $hq_east,
+                        'west'                    => $hq_west,
+                    ),
+                );
+            }
+
+            $res = XDB::iterator("SELECT  link_id AS jobid, tel_type AS type, pub, display_tel AS tel, comment
+                                    FROM  profile_phones
+                                   WHERE  uid = {?} AND link_type = 'pro'
+                                ORDER BY  link_id",
+                                 S::i('uid'));
+            $i = 0;
+            $jobNb = count($this->values['jobs']);
+            while ($phone = $res->next()) {
+                $jobid = $phone['jobid'];
+                while ($i < $jobNb && $this->values['jobs'][$i]['id'] < $jobid) {
+                    $i++;
+                }
+                if ($i >= $jobNb) {
+                    break;
+                }
+                $job =& $this->values['jobs'][$i];
+                if (!isset($job['w_phone'])) {
+                    $job['w_phone'] = array();
+                }
+                if ($job['id'] == $jobid) {
+                    $job['w_phone'][] = $phone;
+                }
             }
-            if ($i >= $jobNb) {
-                break;
+            foreach ($this->values['jobs'] as $id => &$job) {
+                if (!isset($job['w_phone'])) {
+                    $job['w_phone'] = array(
+                        0 => array(
+                            'type'    => 'fixed',
+                            'tel'     => '',
+                            'pub'     => 'private',
+                            'comment' => '',
+                        )
+                    );
+                }
             }
-            $job =& $this->values['jobs'][$i];
-            if (!isset($job['w_phone'])) {
-                $job['w_phone'] = array();
+            $job['w_email_new'] = '';
+            if (!isset($job['hq_phone'])) {
+                $job['hq_phone'] = '';
             }
-            if ($job['id'] == $jobid) {
-                $job['w_phone'][] = $phone;
+            if (!isset($job['hq_fax'])) {
+                $job['hq_fax'] = '';
             }
-        }
-        foreach ($this->values['jobs'] as $id => &$job) {
-            if (!isset($job['w_phone'])) {
-                $job['w_phone'] = array();
+            if (!isset($job['w_email_pub'])) {
+                $job['w_email_pub'] = 'private';
             }
+            if (!$job['hq_address']['text']) {
+                $job['hq_address'] = array(
+                    'text'                    => '',
+                    'accuracy'                => '',
+                    'postalText'              => '',
+                    'postalCode'              => '',
+                    'administrativeAreaId'    => '',
+                    'subAdministrativeAreaId' => '',
+                    'localityId'              => '',
+                    'countryId'               => '',
+                    'latitude'                => '',
+                    'longitude'               => '',
+                    'north'                   => '',
+                    'south'                   => '',
+                    'east'                    => '',
+                    'west'                    => '',
+                    'cedex'                   => '',
+                    'updateTime'              => '',
+                    'changed'                 => '0',
+                    'removed'                 => '0',
+                );
+            }
+            $job['w_address']['cedex'] = '';
+            $job['w_address']['changed'] = '0';
+            $job['w_address']['removed'] = '0';
+        } else {
+            $this->values['jobs'][] = $this->settings['jobs']->emptyJob();
         }
     }
 
index 67fcbe7..1aaf2c2 100644 (file)
@@ -133,17 +133,28 @@ class ProfilePhones implements ProfileSetting
     public function value(ProfilePage &$page, $field, $value, &$success)
     {
         $success = true;
-        if (is_null($value) || !is_array($value)) {
+        if (is_null($value)) {
             $value = array();
             $res = XDB::iterator("SELECT  t.display_tel AS tel, t.tel_type AS type, t.pub, t.comment
                                     FROM  profile_phones AS t
                                    WHERE  t.uid = {?} AND t.link_type = {?}
                                 ORDER BY  t.tel_id",
-                                 $page->pid(), $this->link_type);
-            $value = $res->fetchAllAssoc();
+                                 $this->id, $this->link_type);
+            if ($res->numRows() > 0) {
+                $value = $res->fetchAllAssoc();
+            } else {
+                $value = array(
+                        0 => array(
+                            'type'    => 'fixed',
+                            'tel'     => '',
+                            'pub'     => 'private',
+                            'comment' => '',
+                            )
+                        );
+            }
         }
         foreach ($value as $key=>&$phone) {
-            if (@$phone['removed']) {
+            if (isset($phone['removed']) && $phone['removed']) {
                 unset($value[$key]);
             } else {
                 unset($phone['removed']);
@@ -254,7 +265,7 @@ abstract class ProfileGeocoding implements ProfileSetting
     {
         require_once 'geocoding.inc.php';
         $success = true;
-        if ($address['changed'] == 1) {
+        if (isset($address['changed']) && $address['changed'] == 1) {
             $gmapsGeocoder = new GMapsGeocoder();
             $address = $gmapsGeocoder->getGeocodedAddress($address);
             if (isset($address['geoloc'])) {
@@ -399,7 +410,7 @@ abstract class ProfilePage implements PlWizardPage
         $page->assign('errors', $this->errors);
     }
 
-    public function process()
+    public function process(&$global_success)
     {
         $global_success = true;
         $this->fetchData();
@@ -422,9 +433,14 @@ abstract class ProfilePage implements PlWizardPage
             return Post::has('next_page') ? PlWizard::NEXT_PAGE : PlWizard::CURRENT_PAGE;
         }
         Platal::page()->trigError("Certains champs n'ont pas pu être validés, merci de corriger les informations "
-                                . "de ton profil et de revalider ta demande");
+                                . "de ton profil et de revalider ta demande.");
         return PlWizard::CURRENT_PAGE;
     }
+
+    public function success()
+    {
+        return 'Ton profil a bien été mis à jour.';
+    }
 }
 
 require_once dirname(__FILE__) . '/general.inc.php';
index ba1ab62..7a64e32 100644 (file)
@@ -26,9 +26,6 @@ class RegisterModule extends PLModule
         return array(
             'register'         => $this->make_hook('register', AUTH_PUBLIC),
             'register/end'     => $this->make_hook('end',      AUTH_PUBLIC),
-            'register/end.php' => $this->make_hook('end_old',  AUTH_PUBLIC),
-            'register/success' => $this->make_hook('success',  AUTH_MDP),
-            'register/save'    => $this->make_hook('save',     AUTH_MDP),
         );
     }
 
@@ -48,15 +45,10 @@ class RegisterModule extends PLModule
             unset($state['backs']);
             $sub_state['backs'][] = $state;
             if (count($sub_state['backs']) == 3) {
-                $alert .= "Tentative d'inscription tres hesitante - ";
+                $alert .= "Tentative d'inscription très hésitante - ";
             }
         }
 
-        // Compatibility with old sources, keep it atm
-        if (!$hash && Env::has('hash')) {
-            $hash = Env::v('hash');
-        }
-
         if ($hash) {
             $res = XDB::query(
                     "SELECT  m.uid, u.promo, u.nom, u.prenom, u.matricule, u.naissance_ini, FIND_IN_SET('watch', u.flags)
@@ -104,7 +96,7 @@ class RegisterModule extends PLModule
                                                AND promo = {?}",
                                       $promo);
                     if (!$res->fetchOneCell()) {
-                        $err = "La promotion saisie est incorrecte ou tous les camardes de cette promo sont inscrits !";
+                        $err = "La promotion saisie est incorrecte ou tous les camarades de cette promotion sont inscrits !";
                     } else {
                         $sub_state['step']  = 2;
                         $sub_state['promo'] = $promo;
@@ -137,13 +129,17 @@ class RegisterModule extends PLModule
             case 3:
                 if (count($_POST)) {
                     $this->load('register.inc.php');
+
+                    // Validate the email address format and domain.
                     require_once 'emails.inc.php';
                     if (!isvalid_email(Post::v('email'))) {
-                        $err[] = "Le champ 'E-mail' n'est pas valide.";
+                        $err[] = "Le champ 'Email' n'est pas valide.";
                     } elseif (!isvalid_email_redirection(Post::v('email'))) {
                         $err[] = $sub_state['forlife']." doit renvoyer vers un email existant ".
                             "valide, en particulier, il ne peut pas être renvoyé vers lui-même.";
                     }
+
+                    // Validate the birthday format and range.
                     $birth = trim(Env::v('naissance'));
                     if (!preg_match('@^[0-3]?\d/[01]?\d/(19|20)?\d{2}$@', $birth)) {
                         $err[] = "La 'Date de naissance' n'est pas correcte.";
@@ -156,12 +152,17 @@ class RegisterModule extends PLModule
                         $promo = (int)$sub_state['promo'];
                         if ($year > $promo - 15 || $year < $promo - 30) {
                             $err[] = "La 'Date de naissance' n'est pas correcte.";
-                            $alert = "Date de naissance incorrecte a l'inscription - ";
+                            $alert = "Date de naissance incorrecte à l'inscription - ";
                             $sub_state['wrong_naissance'] = $birth;
                         }
                     }
 
-                    // Check if the given email is known as dangerous
+                    // Validate the password.
+                    if (!Post::v('response2', false)) {
+                        $err[] = "Le mot de passe n'est pas valide.";
+                    }
+
+                    // Check if the given email is known as dangerous.
                     $res = XDB::query("SELECT  w.state, w.description
                                          FROM  emails_watch AS w
                                         WHERE  w.email = {?} AND w.state != 'safe'",
@@ -169,7 +170,7 @@ class RegisterModule extends PLModule
                     $email_banned = false;
                     if ($res->numRows()) {
                         list($state, $description) = $res->fetchOneRow();
-                        $alert .= "Email surveille propose a l'inscription - ";
+                        $alert .= "Email surveillé proposé à l'inscription - ";
                         $sub_state['email_desc'] = $description;
                         if ($state == 'dangerous') {
                             $email_banned = true;
@@ -179,7 +180,7 @@ class RegisterModule extends PLModule
                         $alert .= "Inscription d'un utilisateur surveillé - ";
                     }
 
-                    if (check_ip('unsafe')) {
+                    if (($ip_banned = check_ip('unsafe'))) {
                         unset($err);
                     }
 
@@ -188,14 +189,19 @@ class RegisterModule extends PLModule
                     } else {
                         $sub_state['naissance'] = sprintf("%04d-%02d-%02d",
                                                           intval($birth[2]), intval($birth[1]), intval($birth[0]));
+                        $sub_state['email']     = Post::v('email');
+                        $sub_state['password']  = Post::v('response2');
+
+                        // Update the current alert if the birthdate is incorrect,
+                        // or if the IP address of the user has been banned.
                         if ($sub_state['naissance_ini'] != '0000-00-00' && $sub_state['naissance'] != $sub_state['naissance_ini']) {
                             $alert .= "Date de naissance incorrecte à l'inscription - ";
                         }
-                        $sub_state['email']     = Post::v('email');
-                        $ip_banned = check_ip('unsafe');
                         if ($ip_banned) {
-                            $alert .= "Tentative d'inscription depuis une IP surveillee";
+                            $alert .= "Tentative d'inscription depuis une IP surveillée";
                         }
+
+                        // Prevent banned user from actually registering; save the current state for others.
                         if ($email_banned || $ip_banned) {
                             global $globals;
                             $err = "Une erreur s'est produite lors de l'inscription."
@@ -218,34 +224,32 @@ class RegisterModule extends PLModule
         if (!empty($alert)) {
             send_warning_mail($alert);
         }
+
         $page->changeTpl('register/step'.intval($sub_state['step']).'.tpl');
+        $page->addJsLink('motdepasse.js');
         if (isset($err)) {
             $page->trigError($err);
         }
     }
 
-    function handler_end_old(&$page)
-    {
-        return $this->handler_end($page, Env::v('hash'));
-    }
-
     function handler_end(&$page, $hash = null)
     {
         global $globals;
-
-
-        $page->changeTpl('register/end.tpl');
         $_SESSION['sub_state'] = array('step' => 5);
 
+        // Reject registration requests from unsafe IP addresses (and remove the
+        // registration information from the database, to prevent IP changes).
         if (check_ip('unsafe')) {
             send_warning_mail('Une IP surveillée a tenté de finaliser son inscription');
-            XDB::execute('DELETE FROM  register_pending
-                                WHERE  hash = {?} AND hash != \'INSCRIT\'', $hash);
+            XDB::execute("DELETE FROM  register_pending
+                                WHERE  hash = {?} AND hash != 'INSCRIT'", $hash);
             return PL_FORBIDDEN;
         }
 
         require_once('user.func.inc.php');
 
+        // Retrieve the pre-registration information using the url-provided
+        // authentication token.
         if ($hash) {
             $res = XDB::query(
                     "SELECT  r.uid, r.forlife, r.bestalias, r.mailorg2,
@@ -253,19 +257,16 @@ class RegisterModule extends PLModule
                              u.promo, FIND_IN_SET('femme', u.flags), u.naissance_ini
                        FROM  register_pending AS r
                  INNER JOIN  auth_user_md5    AS u ON r.uid = u.user_id
-                      WHERE  hash={?} AND hash!='INSCRIT'", $hash);
+                      WHERE  hash = {?} AND hash != 'INSCRIT'", $hash);
         }
-
-        if (!$hash || !list($uid, $forlife, $bestalias, $mailorg2, $password, $email,
-                            $naissance, $nom, $prenom, $promo, $femme, $naiss_ini) = $res->fetchOneRow())
-        {
+        if (!$hash || $res->numRows() == 0) {
             $page->kill("<p>Cette adresse n'existe pas, ou plus, sur le serveur.</p>
-                         <p>Causes probables :</p>
+                         <p>Causes probables&nbsp;:</p>
                          <ol>
                            <li>Vérifie que tu visites l'adresse du dernier
-                               e-mail reçu s'il y en a eu plusieurs.</li>
+                               email reçu s'il y en a eu plusieurs.</li>
                            <li>Tu as peut-être mal copié l'adresse reçue par
-                               mail, vérifie-la à la main.</li>
+                               email, vérifie-la à la main.</li>
                            <li>Tu as peut-être attendu trop longtemps pour
                                confirmer.  Les pré-inscriptions sont annulées
                                tous les 30 jours.</li>
@@ -273,67 +274,91 @@ class RegisterModule extends PLModule
                         </ol>");
         }
 
+        list($uid, $forlife, $bestalias, $mailorg2, $password, $email,
+             $naissance, $nom, $prenom, $promo, $femme, $naiss_ini) = $res->fetchOneRow();
 
+        // Prepare the template for display.
+        $page->changeTpl('register/end.tpl');
+        $page->addJsLink('do_challenge_response_logged.js');
+        $page->assign('forlife', $forlife);
+        $page->assign('prenom', $prenom);
+        $page->assign('femme', $femme);
+
+        // Check if the user did enter a valid password; if not (or if none is found),
+        // get her an information page.
+        if (Env::has('response')) {
+            require_once 'secure_hash.inc.php';
+            $expected_response = hash_encrypt("$forlife:$password:" . S::v('challenge'));
+            if (Env::v('response') != $expected_response) {
+                $page->trigError("Mot de passe invalide.");
+                S::logger($uid)->log('auth_fail', 'bad password (register/end)');
+                return;
+            }
+        } else {
+            return;
+        }
 
-        /***********************************************************/
-        /****************** REALLY CREATE ACCOUNT ******************/
-        /***********************************************************/
-
-        XDB::execute('UPDATE  auth_user_md5
-                                   SET  password={?}, perms="user",
-                                        date=NOW(), naissance={?}, date_ins = NOW()
-                                 WHERE  user_id={?}', $password, $naissance, $uid);
-        XDB::execute('REPLACE INTO auth_user_quick (user_id) VALUES ({?})', $uid);
-        XDB::execute('INSERT INTO aliases (id,alias,type)
-                                     VALUES ({?}, {?}, "a_vie")', $uid,
-                                     $forlife);
-        XDB::execute('INSERT INTO aliases (id,alias,type,flags)
-                                     VALUES ({?}, {?}, "alias", "bestalias")',
-                                     $uid, $bestalias);
+        //
+        // Create the user account.
+        //
+        XDB::execute("UPDATE  auth_user_md5
+                         SET  password = {?}, perms = 'user',
+                              date = NOW(), naissance = {?}, date_ins = NOW()
+                       WHERE  user_id = {?}", $password, $naissance, $uid);
+        XDB::execute("REPLACE INTO auth_user_quick (user_id) VALUES ({?})", $uid);
+        XDB::execute("INSERT INTO  aliases (id, alias, type)
+                           VALUES  ({?}, {?}, 'a_vie')", $uid, $forlife);
+        XDB::execute("INSERT INTO  aliases (id, alias, type, flags)
+                           VALUES  ({?}, {?}, 'alias', 'bestalias')", $uid, $bestalias);
         if ($mailorg2) {
-            XDB::execute('INSERT INTO aliases (id,alias,type)
-                                         VALUES ({?}, {?}, "alias")', $uid,
-                                         $mailorg2);
+            XDB::execute("INSERT INTO  aliases (id, alias, type)
+                               VALUES  ({?}, {?}, 'alias')", $uid, $mailorg2);
         }
 
+        // Add the registration email address as first and only redirection.
         require_once('emails.inc.php');
         $user = User::getSilent($uid);
         $redirect = new Redirect($user);
         $redirect->add_email($email);
 
-        // on cree un objet logger et on log l'inscription
+        // Log the registration in the user session.
         S::logger($uid)->log('inscription', $email);
-        XDB::execute('UPDATE register_pending SET hash="INSCRIT" WHERE uid={?}', $uid);
-
+        XDB::execute("UPDATE  register_pending
+                         SET  hash = 'INSCRIT'
+                       WHERE  uid = {?}", $uid);
 
+        // Congratulate our newly registered user by email.
         $mymail = new PlMailer('register/inscription.reussie.tpl');
         $mymail->assign('forlife', $forlife);
         $mymail->assign('prenom', $prenom);
         $mymail->send();
 
-        // Enable search on the user
+        // Index the user, to allow her to appear in searches.
         require_once('user.func.inc.php');
         user_reindex($uid);
 
-        // Add notification for people looking for this registration
+        // Notify other users which were watching for her arrival.
         require_once 'notifs.inc.php';
         register_watch_op($uid, WATCH_INSCR);
         inscription_notifs_base($uid);
 
-        // Default registration on forums
-        $p_for = 'xorg.promo.x' . $promo;
-        $cible = array('xorg.general', 'xorg.pa.divers', 'xorg.pa.logements', $p_for);
-        foreach ($cible as $val) {
-            XDB::execute('INSERT INTO  forum_subs (fid,uid)
+        // Forcibly register the new user on default forums.
+        $promo_forum = 'xorg.promo.x' . $promo;
+        $registered_forums = array('xorg.general', 'xorg.pa.divers', 'xorg.pa.logements', $promo_forum);
+        foreach ($registered_forums as $forum) {
+            XDB::execute("INSERT INTO  forums.abos (fid,uid)
                                SELECT  fid, {?}
-                                 FROM  forum
-                                WHERE  name = {?}', $uid, $val);
-            if (XDB::affectedRows() == 0 && $val == $p_for) {
+                                 FROM  forums.list
+                                WHERE  nom = {?}",
+                                $uid, $val);
+
+            // Notify the newsgroup admin of the promotion forum needs be created.
+            if (XDB::affectedRows() == 0 && $forum == $promo_forum) {
                 $res = XDB::query("SELECT  SUM(perms IN ('admin','user') AND deces = 0), COUNT(*)
                                      FROM  auth_user_md5
                                     WHERE  promo = {?}", $promo);
-                list($effau, $effid) = $res->fetchOneRow();
-                if (5 * $effau > $effid) { // + 
+                list($promo_registered_count, $promo_count) = $res->fetchOneRow();
+                if ($promo_registered_count > 0.2 * $promo_count) {
                     $mymail = new PlMailer('admin/forums-promo.mail.tpl');
                     $mymail->assign('promo', $promo);
                     $mymail->send();
@@ -341,28 +366,32 @@ class RegisterModule extends PLModule
             }
         }
 
-        // update number of subscribers (perms has changed)
+        // Update the global registration count stats.
         $globals->updateNbIns();
 
-        if (!Platal::session()->startWeakSession($uid)) {
-            return PL_FORBIDDEN;
-        }
+        // Try to start a session (so the user don't have to log in); we will use
+        // the password available in Post:: to authenticate the user.
+        Platal::session()->start(AUTH_MDP);
+
+        //
+        // Update collateral data sources, and inform watchers by email.
+        //
 
-        /***********************************************************/
-        /************* envoi d'un mail au démarcheur ***************/
-        /***********************************************************/
+        // Email the referrer(s) of this new user.
         $res = XDB::iterRow(
                 "SELECT  sa.alias, IF(s.nom_usage,s.nom_usage,s.nom) AS nom,
                          s.prenom, FIND_IN_SET('femme', s.flags) AS femme,
                          GROUP_CONCAT(m.email SEPARATOR ', ') AS mails, MAX(m.last) AS dateDernier
                    FROM  register_marketing AS m
-             INNER JOIN  auth_user_md5      AS s  ON ( m.sender = s.user_id )
-             INNER JOIN  aliases            AS sa ON ( sa.id = m.sender
-                                                       AND FIND_IN_SET('bestalias', sa.flags) )
+             INNER JOIN  auth_user_md5      AS s  ON (m.sender = s.user_id)
+             INNER JOIN  aliases            AS sa ON (sa.id = m.sender
+                                                      AND FIND_IN_SET('bestalias', sa.flags))
                   WHERE  m.uid = {?}
                GROUP BY  m.sender
                ORDER BY  dateDernier DESC", $uid);
-        XDB::execute("UPDATE register_mstats SET success=NOW() WHERE uid={?}", $uid);
+        XDB::execute("UPDATE  register_mstats
+                         SET  success = NOW()
+                       WHERE  uid = {?}", $uid);
 
         $market = array();
         while (list($salias, $snom, $sprenom, $sfemme, $mails, $dateDernier) = $res->next()) {
@@ -377,12 +406,13 @@ class RegisterModule extends PLModule
                  . "vient à l'instant de terminer son inscription.\n\n"
                  . "Merci de ta participation active à la reconnaissance de ce site !!!\n\n"
                  . "Bien cordialement,\n"
+                 . "-- \n"
                  . "L'équipe Polytechnique.org";
             $mymail->setTxtBody(wordwrap($msg, 72));
             $mymail->send();
         }
 
-        /**** send a mail to X.org administrators ****/
+        // Email the plat/al administrators about the registration.
         if ($globals->register->notif) {
             $mymail = new PlMailer();
             $mymail->setSubject("Inscription de $prenom $nom (X$promo)");
@@ -410,111 +440,9 @@ class RegisterModule extends PLModule
             $mymail->send();
         }
 
+        // Remove old pending marketing requests for the new user.
         Marketing::clear($uid);
 
-        pl_redirect('register/success');
-        $page->assign('uid', $uid);
-    }
-
-    function handler_success(&$page)
-    {
-        global $globals;
-        $page->changeTpl('register/success.tpl');
-        $page->assign('user', S::user());
-
-        $_SESSION['sub_state'] = array('step' => 5);
-        if (Env::has('response2'))  {
-            $_SESSION['password'] = $password = Post::v('response2');
-
-            XDB::execute('UPDATE auth_user_md5 SET password={?}
-                                     WHERE user_id={?}', $password,
-                                   S::v('uid'));
-
-            // If GoogleApps is enabled, and the user did choose to use synchronized passwords,
-            // and if the (stupid) user has decided to use /register/success another time,
-            // updates the Google Apps password as well.
-            if ($globals->mailstorage->googleapps_domain) {
-                require_once 'googleapps.inc.php';
-                $account = new GoogleAppsAccount(S::user());
-                if ($account->active() && $account->sync_password) {
-                    $account->set_password($password);
-                }
-            }
-
-            S::logger()->log('passwd');
-            Platal::session()->setAccessCookie(true);
-
-            $page->assign('mdpok', true);
-        }
-
-        $res = XDB::iterRow("SELECT  sub, domain
-                               FROM  register_subs
-                              WHERE  uid = {?} AND type = 'list'
-                           ORDER BY  domain",
-                            S::i('uid'));
-        $current_domain = null;
-        $lists = array();
-        while (list($sub, $domain) = $res->next()) {
-            if ($current_domain != $domain) {
-                $current_domain = $domain;
-                $client = new MMList(S::v('uid'), S::v('password'), $domain);
-            }
-            list($details, ) = $client->get_members($sub);
-            $lists["$sub@$domain"] = $details;
-        }
-        $page->assign_by_ref('lists', $lists);
-
-        $page->addJsLink('motdepasse.js');
-    }
-
-    function handler_save(&$page)
-    {
-        global $globals;
-
-        // Finish registration procedure
-        if (Post::v('register_from_ax_question')) {
-            XDB::execute('UPDATE auth_user_quick
-                                     SET profile_from_ax = 1
-                                   WHERE user_id = {?}',
-                                 S::v('uid'));
-        }
-        if (Post::v('add_to_nl')) {
-            require_once 'newsletter.inc.php';
-            NewsLetter::subscribe();
-        }
-        if (Post::v('add_to_ax')) {
-            Platal::load('axletter', 'axletter.inc.php');
-            AXLetter::subscribe();
-        }
-        if (Post::v('add_to_promo')) {
-            $r = XDB::query('SELECT id FROM groupex.asso WHERE diminutif = {?}',
-                S::v('promo'));
-            $asso_id = $r->fetchOneCell();
-            XDB::execute('REPLACE INTO groupex.membres (uid,asso_id)
-                                     VALUES ({?}, {?})',
-                                 S::v('uid'), $asso_id);
-            $mmlist = new MMList(S::v('uid'), S::v('password'));
-            $mmlist->subscribe("promo".S::v('promo'));
-        }
-        if (Post::v('sub_ml')) {
-            $subs = array_keys(Post::v('sub_ml'));
-            $current_domain = null;
-            foreach ($subs as $list) {
-                list($sub, $domain) = explode('@', $list);
-                if ($domain != $current_domain) {
-                    $current_domain = $domain;
-                    $client = new MMList(S::v('uid'), S::v('password'), $domain);
-                }
-                $client->subscribe($sub);
-            }
-        }
-        if (Post::v('imap')) {
-            require_once 'emails.inc.php';
-            $user = S::user();
-            $storage = new EmailStorage($user, 'imap');
-            $storage->activate();
-        }
-
         pl_redirect('profile/edit');
     }
 }
index 6ac78ad..4d220c6 100644 (file)
@@ -44,7 +44,7 @@ function user_cmp($prenom, $nom, $_prenom, $_nom)
 // }}}
 // {{{ function check_mat
 
-function check_mat($promo, $mat, $nom, $prenom, &$ourmat, &$ourid, &$watch, &$naiss)
+function check_mat($promo, $mat, &$nom, &$prenom, &$ourmat, &$ourid, &$watch, &$naiss)
 {
     if (!preg_match('/^[0-9][0-9][0-9][0-9][0-9][0-9]$/', $mat)) {
         return "Le matricule doit comporter 6 chiffres.";
@@ -71,6 +71,8 @@ function check_mat($promo, $mat, $nom, $prenom, &$ourmat, &$ourid, &$watch, &$na
         return "erreur dans l'identification.  Réessaie, il y a une erreur quelque part !";
     }
 
+    $nom = $_nom;
+    $prenom = $_prenom;
     $ourid = $uid;
     return true;
 }
@@ -78,7 +80,7 @@ function check_mat($promo, $mat, $nom, $prenom, &$ourmat, &$ourid, &$watch, &$na
 // }}}
 // {{{ function check_old_mat
 
-function check_old_mat($promo, $mat, $nom, $prenom, &$ourmat, &$ourid, &$watch, &$naiss)
+function check_old_mat($promo, $mat, &$nom, &$prenom, &$ourmat, &$ourid, &$watch, &$naiss)
 {
     $res = XDB::iterRow(
             'SELECT  user_id, nom, prenom, matricule, FIND_IN_SET(\'watch\', flags), naissance_ini
@@ -86,6 +88,8 @@ function check_old_mat($promo, $mat, $nom, $prenom, &$ourmat, &$ourid, &$watch,
               WHERE  promo={?} AND deces=0 AND perms="pending"', $promo);
     while (list($_uid, $_nom, $_prenom, $_mat, $watch, $naiss) = $res->next()) {
         if (user_cmp($prenom, $nom, $_prenom, $_nom)) {
+            $nom = $_nom;
+            $prenom = $_prenom;
             $ourid  = $_uid;
             $ourmat = $_mat;
             return true;
@@ -152,7 +156,7 @@ function create_aliases (&$sub)
     $mailorg = make_username($prenom, $nom);
     $mailorg2 = $mailorg.sprintf(".%02u", ($promo%100));
 
-    $res = XDB::query("SELECT hruid FROM auth_user_md5 WHERE user_id = {?}", $uid);
+    $res = XDB::query("SELECT hruid FROM auth_user_md5 WHERE user_id = {?} AND hruid != ''", $uid);
     if ($res->numRows() == 0) {
         return "Tu n'as pas d'adresse à vie pré-attribuée.<br />"
             . "Envoie un mail à <a href=\"mailto:support@{$globals->mail->domain}</a>\">"
@@ -226,21 +230,19 @@ function finish_ins($sub_state)
     global $globals;
     extract($sub_state);
 
-    $pass     = rand_pass();
-    $pass_encrypted = sha1($pass);
-    $hash     = rand_url_id(12);
-
-    XDB::execute('UPDATE auth_user_md5 SET last_known_email={?} WHERE matricule = {?}', $email, $mat);
-
+    $hash = rand_url_id(12);
+    XDB::execute(
+            "UPDATE  auth_user_md5
+                SET  last_known_email = {?}
+              WHERE  matricule = {?}", $email, $mat);
     XDB::execute(
             "REPLACE INTO  register_pending (uid, forlife, bestalias, mailorg2, password, email, date, relance, naissance, hash)
                    VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, NOW(), 0, {?}, {?})",
-            $uid, $forlife, $bestalias, $mailorg2, $pass_encrypted, $email, $naissance, $hash);
+            $uid, $forlife, $bestalias, $mailorg2, $password, $email, $naissance, $hash);
 
     $mymail = new PlMailer('register/inscrire.mail.tpl');
     $mymail->assign('mailorg', $bestalias);
     $mymail->assign('lemail',  $email);
-    $mymail->assign('pass',    $pass);
     $mymail->assign('baseurl', $globals->baseurl);
     $mymail->assign('hash',    $hash);
     $mymail->assign('subj',    $bestalias."@" . $globals->mail->domain);
diff --git a/modules/reminder.php b/modules/reminder.php
new file mode 100644 (file)
index 0000000..2d68ef0
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2009 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                *
+ ***************************************************************************/
+
+class ReminderModule extends PLModule
+{
+    function handlers()
+    {
+        return array(
+            'ajax/reminder' => $this->make_hook('reminder', AUTH_COOKIE),
+        );
+    }
+
+    function handler_reminder(&$page, $reminder_name = null, $action = null)
+    {
+        require_once 'reminder.inc.php';
+        $user = S::user();
+
+        // If no reminder name was passed, or if we don't know that reminder name,
+        // just drop the request.
+        if (!$reminder_name ||
+            !($reminder = Reminder::GetByName($user, $reminder_name))) {
+            return PL_NOT_FOUND;
+        }
+
+        // Otherwise, the request is dispatched, and a new reminder, if any, is
+        // displayed.
+        $reminder->HandleAction($action);
+
+        $previous_reminder = $reminder->title();
+
+        if (($new_reminder = Reminder::GetCandidateReminder($user))) {
+            $new_reminder->DisplayStandalone($page, $previous_reminder);
+        } else {
+            $reminder->NotifiesAction($page);
+        }
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
index 06f1f8a..902f9f1 100644 (file)
@@ -86,7 +86,7 @@ class SearchModule extends PLModule
                 S::logger()->log('search', 'quick=' . $quick);
             }
             $list = 'profile|prf|fiche|fic|referent|ref|mentor';
-            if (S::has_perms()) {
+            if (S::admin()) {
                 $list .= '|admin|adm|ax';
             }
             if (preg_match('/^(' . $list . '):([-a-z]+(\.[-a-z]+(\.\d{2,4})?)?)$/', replace_accent($quick), $matches)) {
index 3d90887..f1c095c 100644 (file)
@@ -267,9 +267,9 @@ class QuickSearch extends SField
         $s = replace_accent(trim($this->value));
         $r = $s = str_replace('*','%',$s);
 
-        if (S::has_perms() && strpos($s, '@') !== false) {
+        if (S::admin() && strpos($s, '@') !== false) {
             $this->email = $s;
-        } else if (S::has_perms() && preg_match('/[0-9]+\.([0-9]+|%)\.([0-9]+|%)\.([0-9]+|%)/', $s)) {
+        } else if (S::admin() && preg_match('/[0-9]+\.([0-9]+|%)\.([0-9]+|%)\.([0-9]+|%)/', $s)) {
             $this->ip = $s;
         }
         if ($this->email || $this->ip) {
index 2304aaa..38ed64c 100644 (file)
@@ -36,15 +36,14 @@ class StatsModule extends PLModule
     function handlers()
     {
         return array(
-            'stats'           => $this->make_hook('stats',     AUTH_COOKIE),
-            'stats/evolution' => $this->make_hook('evolution', AUTH_COOKIE),
-            'stats/graph'     => $this->make_hook('graph',     AUTH_COOKIE),
-            '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),
+            'stats'                 => $this->make_hook('stats',     AUTH_COOKIE),
+            'stats/evolution'       => $this->make_hook('evolution', AUTH_COOKIE),
+            'stats/graph'           => $this->make_hook('graph',     AUTH_COOKIE),
+            '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),
         );
     }
 
index b28aea7..3ce8541 100644 (file)
@@ -25,15 +25,15 @@ class SurveyModule extends PLModule
     function handlers()
     {
         return array(
-            'survey'              => $this->make_hook('index', AUTH_PUBLIC),
-            'survey/vote'         => $this->make_hook('vote', AUTH_PUBLIC),
-            'survey/result'       => $this->make_hook('result', AUTH_PUBLIC),
-            'survey/edit'         => $this->make_hook('edit', AUTH_COOKIE),
-            'survey/ajax'         => $this->make_hook('ajax', AUTH_COOKIE),
-            'survey/admin'        => $this->make_hook('admin', AUTH_MDP, 'admin'),
-            'survey/admin/edit'   => $this->make_hook('adminEdit', AUTH_MDP, 'admin'),
+            'survey'              => $this->make_hook('index',         AUTH_PUBLIC),
+            'survey/vote'         => $this->make_hook('vote',          AUTH_PUBLIC),
+            'survey/result'       => $this->make_hook('result',        AUTH_PUBLIC),
+            'survey/edit'         => $this->make_hook('edit',          AUTH_COOKIE),
+            'survey/ajax'         => $this->make_hook('ajax',          AUTH_COOKIE),
+            'survey/admin'        => $this->make_hook('admin',         AUTH_MDP, 'admin'),
+            'survey/admin/edit'   => $this->make_hook('adminEdit',     AUTH_MDP, 'admin'),
             'survey/admin/valid'  => $this->make_hook('adminValidate', AUTH_MDP, 'admin'),
-            'survey/admin/del'    => $this->make_hook('adminDelete', AUTH_MDP, 'admin'),
+            'survey/admin/del'    => $this->make_hook('adminDelete',   AUTH_MDP, 'admin'),
         );
     }
     // }}}
index 195d4bb..2c04835 100644 (file)
@@ -24,15 +24,15 @@ class XnetModule extends PLModule
     function handlers()
     {
         return array(
-            'index'     => $this->make_hook('index',     AUTH_PUBLIC),
-            'exit'      => $this->make_hook('exit',      AUTH_PUBLIC),
-
-            'admin'     => $this->make_hook('admin',     AUTH_MDP, 'admin'),
-            'groups'    => $this->make_hook('groups',    AUTH_PUBLIC),
-            'groupes.php' => $this->make_hook('groups2', AUTH_PUBLIC),
-            'plan'      => $this->make_hook('plan',      AUTH_PUBLIC),
-            'photo'     => $this->make_hook('photo',     AUTH_MDP),
-            'autologin' => $this->make_hook('autologin', AUTH_MDP),
+            'index'       => $this->make_hook('index',     AUTH_PUBLIC),
+            'exit'        => $this->make_hook('exit',      AUTH_PUBLIC),
+
+            'admin'       => $this->make_hook('admin',     AUTH_MDP, 'admin'),
+            'groups'      => $this->make_hook('groups',    AUTH_PUBLIC),
+            'groupes.php' => $this->make_hook('groups2',   AUTH_PUBLIC),
+            'plan'        => $this->make_hook('plan',      AUTH_PUBLIC),
+            'photo'       => $this->make_hook('photo',     AUTH_MDP),
+            'autologin'   => $this->make_hook('autologin', AUTH_MDP),
         );
     }
 
@@ -114,12 +114,24 @@ class XnetModule extends PLModule
         if (Post::has('diminutif')) {
             S::assert_xsrf_token();
 
-            XDB::query('INSERT INTO groupex.asso (id,diminutif)
-                                 VALUES(NULL,{?})', Post::v('diminutif'));
-            pl_redirect('../'.Post::v('diminutif').'/edit');
+            $res = XDB::query('SELECT  COUNT(*)
+                                 FROM  groupex.asso
+                                WHERE  diminutif = {?}',
+                              Post::v('diminutif'));
+
+            if ($res->fetchOneCell() == 0) {
+                XDB::execute('INSERT INTO  groupex.asso (id, diminutif)
+                                   VALUES  (NULL, {?})',
+                             Post::v('diminutif'));
+                pl_redirect('../' . Post::v('diminutif') . '/edit');
+            } else {
+                $page->trigError('Le diminutif demandé est déjà pris.');
+            }
         }
 
-        $res = XDB::query('SELECT nom,diminutif FROM groupex.asso ORDER by NOM');
+        $res = XDB::query('SELECT  nom, diminutif
+                             FROM  groupex.asso
+                         ORDER BY  nom');
         $page->assign('assos', $res->fetchAllAssoc());
     }
 
index 938a6a6..bb1cda1 100644 (file)
@@ -25,41 +25,34 @@ class XnetGrpModule extends PLModule
     function handlers()
     {
         return array(
-            '%grp'                => $this->make_hook('index',     AUTH_PUBLIC),
-            '%grp/asso.php'       => $this->make_hook('index',     AUTH_PUBLIC),
-            '%grp/logo'           => $this->make_hook('logo',      AUTH_PUBLIC),
-            '%grp/site'           => $this->make_hook('site',      AUTH_PUBLIC),
-            '%grp/edit'           => $this->make_hook('edit',      AUTH_MDP, 'groupadmin'),
-            '%grp/mail'           => $this->make_hook('mail',      AUTH_MDP, 'groupadmin'),
-            '%grp/forum'          => $this->make_hook('forum',     AUTH_MDP, 'groupmember'),
-            '%grp/annuaire'       => $this->make_hook('annuaire',  AUTH_MDP, 'groupannu'),
-            '%grp/annuaire/vcard' => $this->make_hook('vcard',     AUTH_MDP, 'groupmember:groupannu'),
-            '%grp/annuaire/csv'   => $this->make_hook('csv',       AUTH_MDP, 'groupmember:groupannu'),
-            '%grp/trombi'         => $this->make_hook('trombi',    AUTH_MDP, 'groupannu'),
-            '%grp/geoloc'         => $this->make_hook('geoloc',    AUTH_MDP, 'groupannu'),
-            '%grp/subscribe'      => $this->make_hook('subscribe', AUTH_MDP),
-            '%grp/subscribe/valid' => $this->make_hook('subscribe_valid', AUTH_MDP, 'groupadmin'),
-            '%grp/unsubscribe'    => $this->make_hook('unsubscribe', AUTH_MDP, 'groupmember'),
-
-            '%grp/change_rights'  => $this->make_hook('change_rights', AUTH_MDP),
-
-            '%grp/admin/annuaire'
-                 => $this->make_hook('admin_annuaire', AUTH_MDP, 'groupadmin'),
-
-            '%grp/member'
-                 => $this->make_hook('admin_member', AUTH_MDP, 'groupadmin'),
-            '%grp/member/new'
-                 => $this->make_hook('admin_member_new', AUTH_MDP, 'groupadmin'),
-            '%grp/member/new/ajax'
-                 => $this->make_hook('admin_member_new_ajax', AUTH_MDP, 'user', NO_AUTH),
-            '%grp/member/del'
-                 => $this->make_hook('admin_member_del', AUTH_MDP, 'groupadmin'),
-
-            '%grp/rss'             => $this->make_hook('rss', AUTH_PUBLIC, 'user', NO_HTTPS),
-            '%grp/announce/new'    => $this->make_hook('edit_announce', AUTH_MDP,  'groupadmin'),
-            '%grp/announce/edit'   => $this->make_hook('edit_announce', AUTH_MDP,  'groupadmin'),
-            '%grp/announce/photo'  => $this->make_hook('photo_announce', AUTH_PUBLIC),
-            '%grp/admin/announces' => $this->make_hook('admin_announce', AUTH_MDP, 'groupadmin'),
+            '%grp'                 => $this->make_hook('index',                 AUTH_PUBLIC),
+            '%grp/asso.php'        => $this->make_hook('index',                 AUTH_PUBLIC),
+            '%grp/logo'            => $this->make_hook('logo',                  AUTH_PUBLIC),
+            '%grp/site'            => $this->make_hook('site',                  AUTH_PUBLIC),
+            '%grp/edit'            => $this->make_hook('edit',                  AUTH_MDP,    'groupadmin'),
+            '%grp/mail'            => $this->make_hook('mail',                  AUTH_MDP,    'groupadmin'),
+            '%grp/forum'           => $this->make_hook('forum',                 AUTH_MDP,    'groupmember'),
+            '%grp/annuaire'        => $this->make_hook('annuaire',              AUTH_MDP,    'groupannu'),
+            '%grp/annuaire/vcard'  => $this->make_hook('vcard',                 AUTH_MDP,    'groupmember:groupannu'),
+            '%grp/annuaire/csv'    => $this->make_hook('csv',                   AUTH_MDP,    'groupmember:groupannu'),
+            '%grp/trombi'          => $this->make_hook('trombi',                AUTH_MDP,    'groupannu'),
+            '%grp/geoloc'          => $this->make_hook('geoloc',                AUTH_MDP,    'groupannu'),
+            '%grp/subscribe'       => $this->make_hook('subscribe',             AUTH_MDP),
+            '%grp/subscribe/valid' => $this->make_hook('subscribe_valid',       AUTH_MDP,    'groupadmin'),
+            '%grp/unsubscribe'     => $this->make_hook('unsubscribe',           AUTH_MDP,    'groupmember'),
+
+            '%grp/change_rights'   => $this->make_hook('change_rights',         AUTH_MDP),
+            '%grp/admin/annuaire'  => $this->make_hook('admin_annuaire',        AUTH_MDP,    'groupadmin'),
+            '%grp/member'          => $this->make_hook('admin_member',          AUTH_MDP,    'groupadmin'),
+            '%grp/member/new'      => $this->make_hook('admin_member_new',      AUTH_MDP,    'groupadmin'),
+            '%grp/member/new/ajax' => $this->make_hook('admin_member_new_ajax', AUTH_MDP,    'user', NO_AUTH),
+            '%grp/member/del'      => $this->make_hook('admin_member_del',      AUTH_MDP,    'groupadmin'),
+
+            '%grp/rss'             => $this->make_hook('rss',                   AUTH_PUBLIC, 'user', NO_HTTPS),
+            '%grp/announce/new'    => $this->make_hook('edit_announce',         AUTH_MDP,    'groupadmin'),
+            '%grp/announce/edit'   => $this->make_hook('edit_announce',         AUTH_MDP,    'groupadmin'),
+            '%grp/announce/photo'  => $this->make_hook('photo_announce',        AUTH_PUBLIC),
+            '%grp/admin/announces' => $this->make_hook('admin_announce',        AUTH_MDP,    'groupadmin'),
         );
     }
 
@@ -189,8 +182,8 @@ class XnetGrpModule extends PLModule
                 $site = "";
             }
             if (S::has_perms()) {
-                if (strstr(Post::v('mail_domain'), '.') === false) {
-                    $page->trigError("le domaine doit être un FQDN (aucune modif effectuée) !!!");
+                if (Post::v('mail_domain') && (strstr(Post::v('mail_domain'), '.') === false)) {
+                    $page->trigError("Le domaine doit être un FQDN (aucune modification effectuée) !!!");
                     return;
                 }
                 XDB::execute(
@@ -217,13 +210,12 @@ class XnetGrpModule extends PLModule
                 XDB::execute(
                     "UPDATE  groupex.asso
                         SET  descr={?}, site={?}, mail={?}, resp={?},
-                             forum={?}, ax={?}, pub= {?}, sub_url={?},
+                             forum={?}, pub= {?}, sub_url={?},
                              unsub_url={?},flags={?}
                       WHERE  id={?}",
                       Post::v('descr'), $site,
                       Post::v('mail'), Post::v('resp'),
-                      Post::v('forum'), Post::has('ax'),
-                      Post::v('pub'),
+                      Post::v('forum'), Post::v('pub'),
                       Post::v('sub_url'), Post::v('unsub_url'),
                       $flags, $globals->asso('id'));
             }
@@ -245,7 +237,7 @@ class XnetGrpModule extends PLModule
             pl_redirect('../'.Post::v('diminutif', $globals->asso('diminutif')).'/edit');
         }
 
-        if (S::has_perms()) {
+        if (S::admin()) {
             $dom = XDB::iterator('SELECT * FROM groupex.dom ORDER BY nom');
             $page->assign('dom', $dom);
             $page->assign('super', true);
@@ -280,7 +272,13 @@ class XnetGrpModule extends PLModule
             $this->load('mail.inc.php');
             set_time_limit(120);
             $tos = get_all_redirects($mbr,  $mls, $mmlist);
+
             $upload = PlUpload::get($_FILES['uploaded'], S::user()->login(), 'xnet.emails', true);
+            if (!$upload && @$_FILES['uploaded']['name'] && PlUpload::$lastError != null) {
+                $page->trigError(PlUpload::$lastError);
+                return;
+            }
+
             send_xnet_mails($from, $sujet, $body, Env::v('wiki'), $tos, Post::v('replyto'), $upload, @$_FILES['uploaded']['name']);
             if ($upload) {
                 $upload->rm();
@@ -465,7 +463,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 de {$user->fullName()} a bien été refusée.");
+                $page->killSuccess("La demande de {$user->fullName()} a bien été refusée.");
             } else {
                 $page->assign('show_form', true);
                 $page->assign('reason', $reason);
@@ -516,7 +514,8 @@ class XnetGrpModule extends PLModule
                     . "à l'adresse : support@polytechnique.org\n";
 
             if (!$to) {
-                $to = $globals->asso("mail").", support@polytechnique.org";
+                $to = ($globals->asso('mail') != '') ? $globals->asso('mail') . ', ' : '';
+                $to .= 'support@polytechnique.org';
                 $append = "\n-- \nLe groupe ".$globals->asso("nom")
                         ." n'a pas d'administrateur, l'équipe de"
                         ." Polytechnique.org a été prévenue et va rapidement"
index 1c59e10..8442956 100644 (file)
@@ -28,29 +28,29 @@ class XnetListsModule extends ListsModule
     function handlers()
     {
         return array(
-            '%grp/lists'           => $this->make_hook('lists',     AUTH_MDP, 'groupmember'),
-            '%grp/lists/create'    => $this->make_hook('create',    AUTH_MDP, 'groupmember'),
+            '%grp/lists'              => $this->make_hook('lists',    AUTH_MDP, 'groupmember'),
+            '%grp/lists/create'       => $this->make_hook('create',   AUTH_MDP, 'groupmember'),
 
-            '%grp/lists/members'   => $this->make_hook('members',   AUTH_COOKIE),
-            '%grp/lists/csv'       => $this->make_hook('csv',       AUTH_COOKIE),
-            '%grp/lists/annu'      => $this->make_hook('annu',      AUTH_COOKIE),
-            '%grp/lists/archives'  => $this->make_hook('archives',  AUTH_COOKIE),
-            '%grp/lists/archives/rss' => $this->make_hook('rss',    AUTH_PUBLIC),
+            '%grp/lists/members'      => $this->make_hook('members',  AUTH_COOKIE),
+            '%grp/lists/csv'          => $this->make_hook('csv',      AUTH_COOKIE),
+            '%grp/lists/annu'         => $this->make_hook('annu',     AUTH_COOKIE),
+            '%grp/lists/archives'     => $this->make_hook('archives', AUTH_COOKIE),
+            '%grp/lists/archives/rss' => $this->make_hook('rss',      AUTH_PUBLIC),
 
-            '%grp/lists/moderate'  => $this->make_hook('moderate',  AUTH_MDP),
-            '%grp/lists/admin'     => $this->make_hook('admin',     AUTH_MDP),
-            '%grp/lists/options'   => $this->make_hook('options',   AUTH_MDP),
-            '%grp/lists/delete'    => $this->make_hook('delete',    AUTH_MDP),
+            '%grp/lists/moderate'     => $this->make_hook('moderate', AUTH_MDP),
+            '%grp/lists/admin'        => $this->make_hook('admin',    AUTH_MDP),
+            '%grp/lists/options'      => $this->make_hook('options',  AUTH_MDP),
+            '%grp/lists/delete'       => $this->make_hook('delete',   AUTH_MDP),
 
-            '%grp/lists/soptions'  => $this->make_hook('soptions',  AUTH_MDP),
-            '%grp/lists/check'     => $this->make_hook('check',     AUTH_MDP),
-            '%grp/lists/sync'      => $this->make_hook('sync',      AUTH_MDP),
+            '%grp/lists/soptions'     => $this->make_hook('soptions', AUTH_MDP),
+            '%grp/lists/check'        => $this->make_hook('check',    AUTH_MDP),
+            '%grp/lists/sync'         => $this->make_hook('sync',     AUTH_MDP),
 
-            '%grp/alias/admin'     => $this->make_hook('aadmin',    AUTH_MDP, 'groupadmin'),
-            '%grp/alias/create'    => $this->make_hook('acreate',   AUTH_MDP, 'groupadmin'),
+            '%grp/alias/admin'        => $this->make_hook('aadmin',   AUTH_MDP, 'groupadmin'),
+            '%grp/alias/create'       => $this->make_hook('acreate',  AUTH_MDP, 'groupadmin'),
 
             /* hack: lists uses that */
-            'profile' => $this->make_hook('profile', AUTH_PUBLIC),
+            'profile'                 => $this->make_hook('profile',  AUTH_PUBLIC),
         );
     }
 
@@ -106,7 +106,7 @@ class XnetListsModule extends ListsModule
         }
 
         $listes = $this->client->get_lists();
-        $page->assign('listes',$listes);
+        $page->assign('listes', $listes);
 
         $alias  = XDB::iterator(
                 'SELECT  alias,type
@@ -117,6 +117,13 @@ class XnetListsModule extends ListsModule
         $page->assign('alias', $alias);
 
         $page->assign('may_update', may_update());
+
+        if (count($listes) > 0 && !$globals->asso('has_ml')) {
+            XDB::execute("UPDATE  groupex.asso
+                             SET  flags = CONCAT_WS(',', IF(flags = '', NULL, flags), 'has_ml')
+                           WHERE  id = {?}",
+                         $globals->asso('id'));
+        }
     }
 
     function handler_create(&$page)
@@ -183,6 +190,12 @@ class XnetListsModule extends ListsModule
                                     VALUES ({?}, {?})', XDB::insertId(),
                                    $red . $mdir . '@listes.polytechnique.org');
         }
+
+        XDB::execute("UPDATE  groupex.asso
+                         SET  flags = CONCAT_WS(',', IF(flags = '', NULL, flags), 'has_ml')
+                       WHERE  id = {?}",
+                     $globals->asso('id'));
+
         pl_redirect('lists/admin/'.$liste);
     }
 
index b9589b2..b676d50 100644 (file)
@@ -24,18 +24,19 @@ function smarty_function_display_phones($param, &$smarty)
     $txthtml = "";
     if (count($param['tels'])) {
         foreach ($param['tels'] as $tel) {
+            $tel_type = ($param['dcd'] ? 'Dernier ' : '');
             switch ($tel['tel_type']) {
-            case 'fixed':
-                $tel_type = 'Tél';
+              case 'fixed':
+                $tel_type .= 'Tél';
                 break;
-            case 'fax':
-                $tel_type = 'Fax';
+              case 'fax':
+                $tel_type .= 'Fax';
                 break;
-            case 'mobile':
-                $tel_type = 'Mob';
+              case 'mobile':
+                $tel_type .= 'Mob';
                 break;
-            default:
-                $tel_type = $tel['tel_type'];
+              default:
+                $tel_type .= $tel['tel_type'];
             }
             $txthtml .= "<div>\n<em>" . $tel_type . "&nbsp;: </em>\n<strong>" . $tel['tel'] . "</strong>\n";
             $comment = "";
index bd7af29..47e6251 100644 (file)
@@ -31,20 +31,20 @@ function smarty_insert_getUsername()
     }
 
     if (Cookie::v('domain', 'login') != 'alias') {
-       $res = XDB::query("SELECT  alias FROM aliases
-                                     WHERE  id={?} AND (type IN ('a_vie','alias') AND FIND_IN_SET('bestalias', flags))", $id);
-       return $res->fetchOneCell();
+        $res = XDB::query("SELECT  alias FROM aliases
+                            WHERE  id={?} AND (type IN ('a_vie','alias') AND FIND_IN_SET('bestalias', flags))", $id);
+        return $res->fetchOneCell();
     } else {
-       $res = XDB::query("
-               SELECT v.alias
-                 FROM virtual AS v
-           INNER JOIN virtual_redirect USING(vid)
-           INNER JOIN aliases AS a ON(id={?} AND a.type='a_vie')
-                 WHERE redirect = CONCAT(a.alias, {?})
-                      OR redirect = CONCAT(a.alias, {?})",
-               $id, "@".$globals->mail->domain, "@".$globals->mail->domain2);
-       $alias = $res->fetchOneCell();
-       return substr($alias, 0, strpos($alias, "@"));
+        $res = XDB::query("
+            SELECT  v.alias
+              FROM  virtual AS v
+        INNER JOIN  virtual_redirect USING(vid)
+        INNER JOIN  aliases AS a ON(id={?} AND a.type='a_vie')
+             WHERE  redirect = CONCAT(a.alias, {?})
+                    OR redirect = CONCAT(a.alias, {?})",
+            $id, "@".$globals->mail->domain, "@".$globals->mail->domain2);
+        $alias = $res->fetchOneCell();
+        return substr($alias, 0, strpos($alias, "@"));
      }
 
      return $login;
index 5c8b4f2..64dee3a 100644 (file)
@@ -23,7 +23,7 @@
 
 
 <form action="admin/deaths" method="post">
-  <table class="tinybicol">
+  <table class="bicol">
     <tr>
       <td>
         Promotion&nbsp;:
index 02e5787..fe5c7ed 100644 (file)
       <td>{$selectedJob.holdingAcronym}</td>
     </tr>
     <tr>
+      <td>Adresse</td>
+      <td<textarea cols="30" rows="4" name="address">{$selectedJob.address}</textarea></td>
+    </tr>
+    <tr>
+      <td>Téléphone</td>
+      <td><input type="text" name="tel" value="{$selectedJob.tel}" /></td>
+    </tr>
+    <tr>
+      <td>Fax</td>
+      <td><input type="text" name="fax" value="{$selectedJob.fax}" /></td>
+    </tr>
+    <tr>
       <td>Remplacer par l'entreprise n°</td>
       <td><input type="text" name="newJobId" /></td>
     </tr>
index cf0beb8..e3fec0c 100644 (file)
@@ -26,7 +26,7 @@
   {xsrf_token_field}
   <div class="center">
     <input type="hidden" name="user_id" value="{$smarty.request.user_id}" />
-    Confirmer la suppression de {$smarty.request.user_id}&nbsp;&nbsp;
+    Confirmer la suppression de l'utilisateur {$smarty.request.user_id} ({$mr.prenom} {$mr.nom} - X{$mr.promo})&nbsp;&nbsp;
     <input type="submit" name="u_kill" value="continuer" />
   </div>
 </form>
index a07ea86..6b2e016 100644 (file)
       </td>
     </tr>
     {include file="include/field.promo.tpl" prefix=""}
+    <tr>
+      <td class="titre">Envoyer à une liste d'adresses</td>
+      <td><textarea name="subset_to" rows="7" cols="78">{$subset_to}</textarea><br />
+      <span class="smaller">Indiquez une liste d'adresses emails : la lettre sera envoyée uniquement aux personnes des promotions sélectionnées, dont l'adresse figure dans la liste, et qui souhaitent recevoir les emails de l'AX.</span>
+      </td>
+    </tr>
     {if !$saved}
     <tr>
       <td class="titre">Echéance d'envoi</td>
index 4ffb699..720a82e 100644 (file)
@@ -53,9 +53,8 @@
         <input type="text" name="username" size="20" maxlength="50" value="{insert name="getUserName"}" />&nbsp;@&nbsp;<select name="domain">
           <option value="login">{#globals.mail.domain#} / {#globals.mail.domain2#}</option>
           <option value="alias" {if $smarty.cookies.ORGdomain eq alias}selected="selected"{/if}>
-          {#globals.mail.alias_dom#} / {#globals.mail.alias_dom2#}
+            {#globals.mail.alias_dom#} / {#globals.mail.alias_dom2#}
           </option>
-          {$smarty.cookies.domain}
         </select>
       </td>
     </tr>
index 7839ae9..ef2f060 100644 (file)
@@ -64,8 +64,7 @@
   <div>
     {xsrf_token_field}
     <input type="hidden" name="challenge" value="{$smarty.session.challenge}" />
-    <input type="hidden" name="username"  value="{$smarty.cookies.ORGuid}" />
-    <input type="hidden" name="xorpass"  value="" />
+    <input type="hidden" name="username"  value="{$smarty.session.uid}" />
     <input type="hidden" name="remember"  value="" />
     <input type="hidden" name="response"  value="" />
   </div>
index 283e10b..29ab6bc 100644 (file)
@@ -35,7 +35,7 @@ En effet, il faut nous donner l'adresse qui se cache derrière l'adresse polytec
 correspondant si tu veux que nous puissions te répondre.
 </p>
 {elseif $x && $x.nb_mails}
-<h2>Patte Cassée</h2>
+<h2>Patte cassée</h2>
   <p>
     Ton correspondant a à l'heure actuelle <span class="erreur">{$x.nb_mails} adresse(s) email(s) de redirection active(s)
     en dehors de celle que tu nous as communiquée</span>. Cela ne veut pas forcément dire qu'il les avait
@@ -47,7 +47,7 @@ correspondant si tu veux que nous puissions te répondre.
     <a href="emails/broken/warn/{$email}?token={xsrf_token}">clique sur ce lien</a>.
   </p>
 {elseif $x}
-<h2>Patte Cassée</h2>
+<h2>Patte cassée</h2>
   <p>
     Désolé, mais ton correspondant, {$x.user->fullName()},
     n'a actuellement <span class="erreur">aucune adresse email de redirection 
index 634b18f..501139f 100644 (file)
         return function() {
                   if (!allow) {
                       if (box.value != '') {
-                          alert("Un mail de validation vient d'être envoyer sur " + mail
+                          alert("Un mail de validation vient d'être envoyé sur " + mail
                                + ". La réécriture ne sera active que lorsque tu auras cliqué sur le lien indiqué dans ce mail.");
                       }
                   }
     </table>
     <script type="text/javascript">showRemove(); activeEnable();</script>
   </div>
+<p class="smaller center">
+  Légende&nbsp;: {icon name=cross title="Supprimer"} Supprimer la redirection
+  - {icon name=information title="Plus d'informations"} Plus d'informations
+</p>
 {if $panne}
 <p class="smaller">
   <strong>
index 3e9bc0e..d7dad61 100644 (file)
@@ -41,65 +41,12 @@ Bienvenue {$smarty.session.display_name}{if $birthday}
 </div>
 {/if}
 
-{if $smarty.session.no_redirect}
-<div class="errors">
-  <ul>
-    <li>
-      Tu n'as plus de redirection valide ce qui rend ton adresse Polytechnique.org
-      inutilisable. Rends-toi au plus vite sur <a href="emails/redirect">la page de 
-      gestion des emails</a> pour corriger ce problème.
-    </li>
-  </ul>
-</div>
-{/if}
-
-{if $smarty.session.mx_failures|@count}
-<div class="warnings">
-  {icon name=error} Des problèmes sont actuellement recontrés sur tes redirections suivantes :
-  <ul>
-    {foreach from=$smarty.session.mx_failures item=mail}
-    <li>
-      <span class="erreur">{$mail.mail}</span> :
-      <span class="explication">{$mail.text}</span>
-    </li>
-    {/foreach}
-  </ul>
-  <div style="text-align: center"><a href="emails/redirect">Gérer mes adresses de redirection</a></div>
-</div>
-{/if}
-
-{if $fiche_incitation || $photo_incitation || ($geoloc_incitation > 0)}
-<div class="warnings">
-  <ul>
-{if $fiche_incitation}
-  <li>
-    La dernière mise à jour de ta
-    <a href="profile/{$smarty.session.hruid}" class="popup2">fiche</a>
-    date du {$fiche_incitation|date_format}.
-    Il est possible qu'elle ne soit pas à jour.
-    Si tu souhaites la modifier, <a href="profile/edit">clique ici !</a>
-  </li>
-{/if}
-
-{if $photo_incitation}
-  <li>
-    Tu n'as pas mis de photo de toi sur ta fiche, c'est dommage.
-    Clique <a href="photo/change">ici</a> si tu souhaites en ajouter une.
-  </li>
-{/if}
-
-{if $geoloc_incitation > 0}
-  <li>
-    Parmi tes adresses, il y en a {$geoloc_incitation} que nous n'avons pas pu localiser.
-    Clique <a href="profile/edit/adresses">ici</a> pour rectifier.
-  </li>
-{/if}
-  </ul>
-</div>
+{if $reminder}
+{include file="reminder/base.tpl"}
+{else}
+{include file="include/tips.tpl" full=true}
 {/if}
 
-{include file="include/tips.tpl" full=true}
-  
   <table class="tinybicol" id="menu-evts">
     {foreach from=$events name=events key=category item=evenement}
     <tr class="pair" style="height: 18px">
@@ -177,7 +124,7 @@ Bienvenue {$smarty.session.display_name}{if $birthday}
   -->
   {/literal}
   </script>
+
   {foreach from=$events key=category item=evenement}
   {foreach item=ev from=$evenement}
   {if $ev.nonlu}
index 0e899f5..4135749 100644 (file)
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
     <link rel="stylesheet" type="text/css" href="css/base.css" media="all"/>
     <link rel="stylesheet" type="text/css" href="css/igoogle.css" media="all"/>
-    <script type="text/javascript" src="javascript/ajax.js"></script>
-    <script type="text/javascript" src="javascript/base.js"></script>
-    <script type="text/javascript" src="javascript/igoogle.js"></script>
-    <script type="text/javascript" src="javascript/xorg.js"></script>
+    <script type="text/javascript">var platal_baseurl = "{$globals->baseurl}/";</script>
+    {javascript name=jquery}
+    {javascript name=ajax}
+    {javascript name=xorg}
+    {javascript name=igoogle}
     {foreach from=$gadget_js item=js}
     <script type="text/javascript" src="{$js}"></script>
     {/foreach}
-    <script type="text/javascript">var platal_baseurl = "{$globals->baseurl}/";</script>
   </head>
   <body onload="igOnLoadHandler();">
 {if $gadget_tpl}{include file=$gadget_tpl}{/if}
index 50ecdf3..229d1e8 100644 (file)
 <input type="hidden" name="{$prefname}[geocodedPostalText]" value="{$address.geocodedPostalText}" />
 <input type="hidden" name="{$prefname}[updateTime]" value="{$address.updateTime}" />
 {/if}
-<input type="hidden" name="{$prefname}[type]" value="{$address.type}" />
 <input type="hidden" name="{$prefname}[accuracy]" value="{$address.accuracy}" />
-<input type="hidden" name="{$prefname}[postalAddress]" value="{$address.postalAddress}" />
 <input type="hidden" name="{$prefname}[postalText]" value="{$address.postalText}" />
-<input type="hidden" name="{$prefname}[line1]" value="{$address.line1}" />
-<input type="hidden" name="{$prefname}[line2]" value="{$address.line2}" />
-<input type="hidden" name="{$prefname}[line3]" value="{$address.line3}" />
 <input type="hidden" name="{$prefname}[postalCode]" value="{$address.postalCode}" />
 <input type="hidden" name="{$prefname}[administrativeAreaId]" value="{$address.administrativeAreaId}" />
 <input type="hidden" name="{$prefname}[subAdministrativeAreaId]" value="{$address.subAdministrativeAreaId}" />
-<input type="hidden" name="{$prefname}[locality]" value="{$address.locality}" />
-<input type="hidden" name="{$prefname}[administrativeArea]" value="{$address.administrativeArea}" />
-<input type="hidden" name="{$prefname}[subAdministrativeArea]" value="{$address.subAdministrativeArea}" />
 <input type="hidden" name="{$prefname}[localityId]" value="{$address.localityId}" />
 <input type="hidden" name="{$prefname}[countryId]" value="{$address.countryId}" />
 <input type="hidden" name="{$prefname}[latitude]" value="{$address.latitude}" />
index 1663dbf..69b591a 100644 (file)
   <tr class="pair">
     <td class="titre">Utilisation du quota d'emails</td><td>{$a->r_disk_usage/1024/1024|string_format:"%.2f"}MB</td>
   </tr>
+
+  <tr class="impair">
+    <td class="titre">Alias email du compte</td>
+    <td>{foreach from=$a->nicknames() item=nickname}{$nickname}<br />{/foreach}{$a->g_account_name}</td>
+  </tr>
 </table><br />
 
 <form action="admin/googleapps/user/{$a->g_account_name}" method="post">
index a2091ca..fd2dd33 100644 (file)
     </tr>
 
     <tr class="impair">
-      <td colspan="2"><b>Création du compte :</b></td>
+      <td colspan="2"><b>Création du compte&nbsp;:</b></td>
     </tr>
     <tr class="impair">
       <td></td>
-      <td>La mise en place du compte Google Apps prends quelques minutes. Tu recevras un email explicatif dès l'opération terminée.</td>
+      <td>La mise en place du compte Google Apps prend quelques minutes. Tu recevras un email explicatif dès l'opération terminée.</td>
     </tr>
     <tr class="impair">
       <td colspan="2" style="text-align:center">
index 09457df..16308bf 100644 (file)
@@ -34,6 +34,8 @@
 <input type="text" name="NAF_code" size="25" maxlength="200" value="{$valid->NAF_code}" /><br />
 <strong>Code AX&nbsp;:</strong>
 <input type="text" name="AX_code" size="25" maxlength="200" value="{$valid->AX_code}" /><br />
+<strong>Adresse&nbsp;:</strong>
+<textarea cols="30" rows="4" name="address">{$valid->address}</textarea><br />
 <strong>Téléphone&nbsp;:</strong>
 <input type="text" name="tel" size="25" maxlength="200" value="{$valid->tel}" /><br />
 <strong>Fax&nbsp;:</strong>
index 6ed7534..5396880 100644 (file)
   <td>{$valid->AX_code}</td>
 </tr>
 <tr class="pair">
+  <td class="titre">Adresse&nbsp;:</td>
+  <td>{$valid->address}</td>
+</tr>
+<tr class="pair">
   <td class="titre">Téléphone&nbsp;:</td>
   <td>{$valid->tel}</td>
 </tr>
index d4c4741..6b8a357 100644 (file)
 
 <tr class="impair">
   <td class="titre">Promotion&nbsp;:</td>
-  <td>{$valid->user->promo()}</td>
+  <td>{$valid->entryYear}</td>
 </tr>
 <tr class="impair">
   <td class="titre">Année de sortie&nbsp;:</td>
-  <td>{$valid->promo_sortie} au lieu de {math equation="a + b" a=$valid->user->promo() b=3}</td>
+  <td>{$valid->newGradYear} au lieu de {$valid->oldGradYear}</td>
 </tr>
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 735b25e..53f7d6b 100644 (file)
         <td class="rt"><a href="{$web}">{$web}</a></td>
       </tr>
       {/if}
-      {if $address.country}
+      {if $address.country && !$c.dcd}
       <tr>
         <td class="lt">Géographie&nbsp;:</td>
         <td class="rt">{if $address.locality}{$address.locality}, {/if}{$address.country}</td>
index 1baaca4..912a581 100644 (file)
@@ -60,9 +60,43 @@ Soit un pourcentage d'inscrites de&nbsp;: {$stats.inse_rate} % <br />
 
 <p>
 Nombre d'<a href="marketing/this_week">inscrits ces 7 derniers jours</a>&nbsp;: {$nbInsSem}<br />
-Nombre d'<a href="marketing/relance">inscriptions en cours</a> (2ème phase non terminée)&nbsp;: {$nbInsEnCours} <br />
-Nombre d'envois marketing effectués n'ayant pas abouti&nbsp;: {$nbInsMarket}<br />
-Nombre d'envois marketing ayant abouti cette semaine&nbsp;: {$nbInsMarkOK}
+Nombre d'<a href="marketing/relance">inscriptions en cours</a> (2ème phase non terminée)&nbsp;: {$nbInsEnCours}
 </p>
 
+<table class="bicol">
+  <tr>
+    <th colspan="4">Marketings</th>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+    <td class="titre">Abouti</td>
+    <td class="titre">Non abouti</td>
+    <td class="titre">Total</td>
+  </tr>
+  <tr>
+    <td>Personnel</td>
+    <td>{$nbInsMarketOkPerso}</td>
+    <td>{$nbInsMarketNoPerso}</td>
+    <td>{$nbInsMarketOkPerso+$nbInsMarketNoPerso}</td>
+  </tr>
+  <tr>
+    <td>Par Polytechnique.org</td>
+    <td>{$nbInsMarketOkXorg}</td>
+    <td>{$nbInsMarketNoXorg}</td>
+    <td>{$nbInsMarketOkXorg+$nbInsMarketNoXorg}</td>
+  </tr>
+  <tr>
+    <td>Cette semaine</td>
+    <td>{$nbInsMarketOkWeek}</td>
+    <td>{$nbInsMarketNoWeek}</td>
+    <td>{$nbInsMarketOkWeek+$nbInsMarketNoWeek}</td>
+  </tr>
+  <tr>
+    <td class="titre">Total</td>
+    <td>{$nbInsMarketOkPerso+$nbInsMarketOkXorg}</td>
+    <td>{$nbInsMarketNoPerso+$nbInsMarketNoXorg}</td>
+    <td>{$nbInsMarketOkPerso+$nbInsMarketOkXorg+$nbInsMarketNoPerso+$nbInsMarketNoXorg}</td>
+  </tr>
+</table>
+
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 1c9f5dd..477b6af 100644 (file)
@@ -39,13 +39,13 @@ Cet utilisateur a une inscription en cours depuis le {$pending|date_format}.
 </p>
 <p>
 {if $relance eq '0000-00-00'}
-il n'a jamais été relancé.
+Il n'a jamais été relancé.
 {else}
-sa dernière relance date du {$relance|date_format}
+Sa dernière relance date du {$relance|date_format}.
 {/if}
 </p>
 
-<p>[<a href='{$path}/insrel?token={xsrf_token}'>le relancer</a>]</p>
+<p>[<a href='{$path}/insrel?token={xsrf_token}'>Le relancer</a>]</p>
 
 {/if}
 
index 6e273c5..600439e 100644 (file)
@@ -1,3 +1,25 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2009 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
 <?xml version="1.0" encoding="UTF-8"?>
 <xrds:XRDS
     xmlns:xrds="xri://$xrds"
@@ -11,3 +33,5 @@
     </Service>
   </XRD>
 </xrds:XRDS>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index d09c242..f47cce0 100644 (file)
 
 <h1>Page d'identité OpenId de {$user->fullName()}</h1>
 
-<p>OpenID est un système d'authentification décentralisé. Cette page permet 
-à des sites web tiers d'identifier {$user->displayName()}, grâce à son compte 
+<p>OpenID est un système d'authentification décentralisé. Cette page permet
+à des sites web tiers d'identifier {$user->displayName()}, grâce à son compte
 Polytechnique.org.<p>
 
-<p><a href="Xorg/OpenId">En savoir plus sur OpenId</a></p>
\ No newline at end of file
+<p><a href="Xorg/OpenId">En savoir plus sur OpenId</a></p>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 5ba2ce8..438fa7b 100644 (file)
 
 <h1>Demande d'identification OpenId</h1>
 
-<p>Le site <strong>{$relying_party}</strong> demande à confirmer votre identité.</p>
+<p>Un site tiers demande à confirmer ton identité OpenId.
+  {if $sreg_data}
+    De plus, il a demandé à recevoir un certain nombre d'informations
+    te concernant.
+  {/if}
+  Merci de nous indiquer ton choix.
+</p><br />
 
-{if $sreg_data neq null}
-<p>Les informations suivantes lui seront transmises :</p>
-<ul>
-{foreach from=$sreg_data key=field item=value}
-<li><i>{$field}</i> : {$value}</li>
-{/foreach}
-</ul>
-{/if}
+<form method="POST" action="openid/trust?{$openid_query}">
+  {xsrf_token_field}
+  <table class="bicol">
+    <tr><th colspan="2">Souhaitez-vous confirmer votre identité ?</th></tr>
 
+    <tr class="impair">
+      <td>Adresse du site&nbsp;:</td>
+      <td><strong>{$relying_party}</strong></td>
+    </tr>
+    {if $sreg_data}
+    <tr class="impair">
+      <td>Informations demandées&nbsp;:</td>
+      <td><ul style="margin-top: 0">
+        {foreach from=$sreg_data key=field item=value}
+        <li><strong>{$field}</strong> ({$value})</li>
+        {/foreach}
+      </ul></td>
+    </tr>
+    {/if}
 
-<p><strong>Souhaitez-vous confirmer votre identité ?</strong></p>
+    <tr class="pair">
+      <td></td>
+      <td>
+        <label><input type="checkbox" name="trust_always" />
+          Toujours faire confiance à ce site.</label><br />
+        {if $sreg_data}
+        <label><input type="checkbox" checked="checked" name="trust_sreg" />
+          Envoyer les données ci-dessus au site.</label><br />
+        {/if}
+      </td>
+    </tr>
+    <tr class="impair center"><td colspan="2">
+      <input type="submit" name="trust_accept" value="Confirmer" />
+      <input type="submit" name="trust_cancel" value="Annuler" />
+    </td></tr>
+  </table>
+</form>
 
-<div class="form">
-  <form method="post" action="openid/trust?{$query}">
-    <input type="checkbox" name="openid_always" /> Toujours faire confiance à ce site<br />
-    <input type="submit" name="openid_trust" value="Confirmer" />
-    <input type="submit" name="openid_cancel" value="Annuler" />
-  </form>
-</div>
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 323f515..6b07054 100644 (file)
@@ -1,3 +1,25 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2009 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
 <?xml version="1.0" encoding="UTF-8"?>
 <xrds:XRDS
     xmlns:xrds="xri://$xrds"
@@ -18,3 +40,5 @@
     </Service>
   </XRD>
 </xrds:XRDS>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 6f593b6..b424d98 100644 (file)
@@ -32,5 +32,5 @@ réception de ton paiement.</p>
 
 <p>{$texte|nl2br}</p>
 {/if}
-<p>[<a href='payment'>retour aux Télépaiements</a>]</p>
+<p>[<a href="https://www.polytechnique.org/payment">retour aux Télépaiements</a>]</p>
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 3eec463..a89e9c5 100644 (file)
@@ -43,7 +43,7 @@ Voici la liste des paiements en ligne possible pour le groupe {$asso->nom} :
     Tu es inscrit à cet événements.
       {if $ev.topay > $ev.paid}
       <a href="{$platal->ns}payment/{$p.id}?montant={math equation="a-b" a=$ev.topay b=$ev.paid}">
-        Tu dois encore payer {math equation="a-b" a=$ev.topay b=$ev.paid}&euro;
+        Tu dois encore payer {math equation="a-b" a=$ev.topay b=$ev.paid}&euro;.
       </a>
       {elseif $ev.topay eq $ev.paid}
       Tu as déjà réglé l'intégralité de ton inscription ({$ev.topay}&euro;).
index 89649b7..e7c2735 100644 (file)
       {if $sn.error} class="error"{/if} size="25" onkeyup="updateNameDisplay();"/>
   </td>
   <td>
-    {if $sn.has_particle}<input name="search_names[{$i}][particle]" type="checkbox"
-      title="Coche cette case si ton nom commence par une particle."
-      {if $sn.particle neq ''} checked="checked"{/if} onchange="updateNameDisplay();"/>
-    {else}
-      <input type="hidden"  name="search_names[{$i}][particle]" value=""/>{/if}
+    {if $sn.has_particle}<input type="checkbox"{if $sn.particle neq ''} checked="checked"{/if}
+      title="Coche cette case si ton nom commence par une particle." onchange="toggleParticle({$i});"/>
+    {/if}
+    <input type="hidden"  name="search_names[{$i}][particle]" value="{$sn.particle}"/>
     {if !$sn.always_displayed}<a href="javascript:removeSearchName({$i})">
       {icon name=cross title="Supprimer ce nom"}
     </a>{/if}
index 45e4f54..6f44217 100644 (file)
     <td colspan="2" class="smaller">
       <div class="titre">Signification des symboles&nbsp;:</div>
       {if $grp_public}{icon name=error} L'annuaire du groupe est à visibilité restreinte et ce groupe n'apparaîtra pas sur ta
-      fiche{/if}
+      fiche.{/if}
       {if $grp_public && $grp_admin}<br />{/if}
-      {if $grp_admin}{icon name=wrench} Tu es administrateur du groupe{/if}
+      {if $grp_admin}{icon name=wrench} Tu es administrateur du groupe.{/if}
     </td>
   </tr>
   {/if}
index 7489ede..3cb051e 100644 (file)
@@ -28,6 +28,8 @@
 <div id="{$jobid}">
   <input type="hidden" name="{$jobpref}[removed]" value="0" />
   <input type="hidden" name="{$jobpref}[new]" value="{if $new}1{else}0{/if}" />
+  <input type="hidden" name="{$jobpref}[id]" value="{$i}" />
+  <input type="hidden" name="{$jobpref}[jobid]" value="{$job.jobid}" />
   <table id="{$jobid}_grayed" class="bicol" style="display: none; margin-bottom: 1em">
     <tr>
       <th class="grayed">
@@ -38,6 +40,7 @@
       </th>
     </tr>
   </table>
+
   <table id="{$jobid}_cont" class="bicol" summary="Entreprise n°{$i+1}" style="margin-bottom: 1em">
     <tr>
       <th colspan="2" style="text-align: right">
@@ -54,7 +57,7 @@
         </a>
       </th>
     </tr>
-    {if !$job.tmp_name}
+    {if !$job.tmp_name && !$job.name}
     <tr class="{$entreprise}">
       <td class="center" colspan="2">
         <small>Si ton entreprise ne figure pas dans la liste,
       <td class="titre" rowspan="4">Secteur&nbsp;d'activité</td>
       <td>
         <select name="{$jobpref}[sector]" onchange="updateJobSector({$i}, '')">
-          <option value="">&nbsp;</option>
+          <option value="0">&nbsp;</option>
           {foreach from=$sectors item=item}
           <option value="{$item.id}" {if $item.id eq $job.sector}selected="selected"{/if}>
             {$item.label}
     </tr>
     <tr class="pair {$sector}" style="display: none">
       <td id="{$jobid}_subSector">
-        <input type="hidden" name="{$jobpref}[subSector]" value="{$job.subSector|default:'-1'}" />
+        <input type="hidden" name="{$jobpref}[subSector]" value="{$job.subSector|default:0}" />
       </td>
     </tr>
     <tr class="pair {$sector}" style="display: none">
       <td id="{$jobid}_subSubSector">
-        <input type="hidden" name="{$jobpref}[subSubSector]" value="{$job.subSubSector|default:'-1'}" />
+        <input type="hidden" name="{$jobpref}[subSubSector]" value="{$job.subSubSector|default:0}" />
       </td>
     </tr>
     <tr class="pair {$sector}" style="display: none">
index 4dcf488..56154a8 100644 (file)
@@ -22,7 +22,7 @@
 
 <?xml version="1.0" encoding="utf-8"?>
 <select name="jobs[{$id}][subSector]" {if ($change)}onchange="updateJobSubSector({$id}, '')"{/if}>
-  <option value=""></option>
+  <option value="0"></option>
   {iterate from=$subSectors item=subSector}
   {if $subSector.optgroup}
   {if $gp}
index 2415b47..99fb20b 100644 (file)
@@ -22,7 +22,7 @@
 
 <?xml version="1.0" encoding="utf-8"?>
 <select name="jobs[{$id}][subSubSector]" onchange="updateJobAlternates({$id})">
-  <option value=""></option>
+  <option value="0"></option>
   {iterate from=$subSubSectors item=subSubSector}
   <option value="{$subSubSector.id}" {if $subSubSector.id eq $sel}selected="selected"{/if}>{$subSubSector.name}</option>
   {/iterate}
index 7aa9c0c..9487465 100644 (file)
@@ -125,7 +125,7 @@ function chgMainWinLoc(strPage)
       </div>
       {/if}
       {if $x.tels}
-        {display_phones tels=$x.tels}
+        {display_phones tels=$x.tels dcd=$x.dcd}
       {/if}
       <div class='spacer'></div>
     </div>
@@ -160,6 +160,11 @@ function chgMainWinLoc(strPage)
   {if $x.adr}
   <div class="part">
     <h2>Contact&nbsp;: </h2>
+    {if $x.dcd}
+      {assign var=address_name value="Dernière adresse"}
+    {else}
+      {assign var=address_name value="Adresse"}
+    {/if}
     {foreach from=$x.adr item="address" name=adresses}
       {if $smarty.foreach.adresses.iteration is even}
         {assign var=pos value="right"}
@@ -167,13 +172,13 @@ function chgMainWinLoc(strPage)
         {assign var=pos value="left"}
       {/if}
       {if $address.active}
-      {include file="geoloc/address.tpl" address=$address titre_div=true titre="Mon adresse actuelle&nbsp;:"
+      {include file="geoloc/address.tpl" address=$address titre_div=true titre=$address_name|@cat:" actuelle&nbsp;:"
                for="`$x.prenom` `$x.nom`" pos=$pos}
       {elseif $address.secondaire}
-      {include file="geoloc/address.tpl" address=$address titre_div=true titre="Adresse secondaire&nbsp;:"
+      {include file="geoloc/address.tpl" address=$address titre_div=true titre=$address_name|@cat:" secondaire&nbsp;:"
                for="`$x.prenom` `$x.nom`" pos=$pos}
       {else}
-      {include file="geoloc/address.tpl" address=$address titre_div=true titre="Adresse principale&nbsp;:"
+      {include file="geoloc/address.tpl" address=$address titre_div=true titre=$address_name|@cat:" principale&nbsp;:"
                for="`$x.prenom` `$x.nom`" pos=$pos}
       {/if}
       {if $smarty.foreach.adresses.iteration is even}<div class="spacer"></div>{/if}
index c0147d5..12449a2 100644 (file)
 
 {include file="register/breadcrumb.tpl"}
 
-<h1>:'(</h1>
+<h1>Confirmation de ton inscription</h1>
 
-<p class="erreur">
-Une erreur est survenue lors de ton inscription...
-</p>
-<p>
-Contacte nous au plus vite, en nous indiquant ce nombre&nbsp;: {$uid} à l'adresse 
-<a href="mailto:support@{#globals.mail.domain#}">support@{#globals.mail.domain#}</a>
-</p>
+<p>Merci {$prenom} d'avoir choisi de t'inscrire. Pour finaliser ton inscription,
+il te suffit de taper ton mot de passe ci-dessous. Tu pourras ensuite librement
+accéder au site, et à notre annuaire en ligne !</p>
+
+<form action="{$smarty.server.REQUEST_URI}" method="post" id="login" onsubmit='doChallengeResponse(); return false;'>
+  <table class="bicol">
+    <tr>
+      <td class="titre">Nom d'utilisateur&nbsp;:</td>
+      <td>{$forlife}</td>
+    </tr>
+    <tr>
+      <td class="titre">Mot de passe&nbsp;:</td>
+      <td><input type="password" name="password" size="10" maxlength="256" /></td>
+    </tr>
+    <tr>
+      <td {popup caption='Connexion permanente' width='300' text='Décoche cette case pour que le site oublie ce navigateur.<br />
+        Il est conseillé de décocher la case si cette machine n\'est pas <b>strictement</b> personnelle'} colspan="2">
+        <label><input type="checkbox" name="remember" checked="checked" />
+          Garder l'accès aux services après déconnexion.
+        </label>
+      </td>
+    </tr>
+    <tr>
+      <td></td>
+      <td><input  type="submit" name="submitbtn" value="Envoyer" /></td>
+    </tr>
+  </table>
+</form>
+
+<form action="{$smarty.server.REQUEST_URI}" method="post" id="loginsub">
+  <div>
+    <input type="hidden" name="challenge" value="{$smarty.session.challenge}" />
+    <input type="hidden" name="username" value="{$forlife}" />
+    <input type="hidden" name="remember" value="" />
+    <input type="hidden" name="response" value="" />
+  </div>
+</form>
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index fab01b3..15efcc1 100644 (file)
@@ -29,9 +29,6 @@
 
 {$prenom}, félicitations pour ton inscription !
 
-N'oublie pas de changer ton mot de passe sur le site. C'est très important
-si tu veux garder accès au site et ton email en fonction.
-
 Tu as maintenant accès à l'annuaire en ligne, aux services de listes de
 diffusion, aux infos promo, etc. N'oublie pas de mettre ta fiche-annuaire
 à jour.
index d2d594f..0a1fedc 100644 (file)
@@ -33,9 +33,7 @@ Ton inscription sur Polytechnique.org est presque terminée !
 Après activation, tes paramètres de connexion seront :
 
 identifiant  : {$mailorg}
-mot de passe : {$pass}
-
-Nous te proposerons de remplacer ce mot de passe temporaire par un mot de passe de ton choix.
+mot de passe : celui que tu as choisi
 
 Rends-toi maintenant sur la page web suivante afin d'activer ta pré-inscription :
 
@@ -46,6 +44,7 @@ Si en cliquant dessus tu n'y arrives pas, copie intégralement ce lien dans la b
 Nous espérons que tu profiteras pleinement des services en ligne de Polytechnique.org ; s'ils te convainquent, n'oublie pas d'en parler aux camarades autour de toi !
 
 Bien cordialement,
+-- 
 L'équipe de Polytechnique.org,
 Le portail des élèves et anciens élèves de l'École polytechnique
 {/if}
index 2f58d67..4a41294 100644 (file)
@@ -54,7 +54,7 @@
         {math equation="(promo % 100) + 100" promo=$promo}532)<br />
         {/if}
         Voir sur le GU ou un bulletin de solde pour trouver cette information<br /><br />
-        Pour les élèves étrangers voie 2, il est du type&nbsp;:
+        Pour les élèves étrangers voie 2, il peut être aussi du type&nbsp;:
         {if $promo < 1999}
         {math equation="(promo + 1) % 100" promo=$promo}0XXX
         {else}
index bc10f19..4a8c003 100644 (file)
 
 <h1>Formulaire de pré-inscription</h1>
 
-<form action="register" method="post">
+<form action="register" method="post" id="changepass2">
   {if $smarty.session.sub_state.mailorg2}
   <p>
   Tu n'as pour le moment aucun homonyme dans notre base de données. Nous allons
   donc te donner l'adresse <strong>{$smarty.session.sub_state.bestalias}@{#globals.mail.domain#}</strong>,
   en plus de ton adresse à vie <strong>{$smarty.session.sub_state.forlife}@{#globals.mail.domain#}</strong>.
   Note que tu pourrais perdre l'adresse <strong>{$smarty.session.sub_state.bestalias}@{#globals.mail.domain#}</strong> 
-  si un homonyme s'inscrivait &mdash; cela reste assez rare.
+  si un homonyme s'inscrivait, même si cela reste assez rare.
   </p>
   {else}
   <p>
   t'envoyer tes informations de connexion.
   </p>
 
+  <p>Nous te demandons également un <strong>mot de passe</strong>, qui te permettra de te reconnecter au site ultérieurement.
+  Pour une sécurité optimale, ton mot de passe ne circulera jamais en clair, et sera stocké sous une forme chiffrée
+  irréversiblement sur nos serveurs.
+  </p>
+
+
   <table class="bicol">
     <tr>
       <th colspan="2">
@@ -68,7 +74,7 @@
         <input type="text" size="35" maxlength="50" name="email" value="{$smarty.post.email}" />
       </td>
     </tr>
-    <tr>
+    <tr class="pair">
       <td class="titre">
         Date de naissance<br />
         <span class="smaller">jour/mois/année</span>
         (demandée si tu perds ton mot de passe)
       </td>
     </tr>
+    <tr class="impair">
+      <td class="titre">
+        Mot de passe<br />
+        <span class="smaller">au moins 6 caractères</span>
+      </td>
+      <td>
+        <input type="hidden" name="response2" />
+        <input type="password" size="10" maxlength="256" name="password" /><br/>
+        <input type="password" size="10" maxlength="256" name="password2" /> (retape ton mot de passe)<br />
+        {checkpasswd prompt="password" text="Terminer la pré-inscription"}
+      </td>
+    </tr>
     <tr>
       <td colspan="2" class="center">
-        <input type="submit" value="Terminer la pré-inscription" />
+        <input type="submit" name="submitn" value="Continuer" onclick="EncryptedResponseInNestedForm(); return false;" />
       </td>
     </tr>
   </table>
 </form>
-
+<form action="register" id="changepass">
+  <div>
+    <input type="hidden" name="nouveau" />
+    <input type="hidden" name="nouveau2" />
+  </div>
+</form>
 {/if}
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index a42c1d5..b9af58b 100644 (file)
@@ -28,8 +28,8 @@
 La pré-inscription que tu viens de soumettre a été enregistrée.
 </p>
 <p>
-Les instructions te permettant de valider ton inscription et ton mot de passe pour
-accéder au site viennent de t'être envoyés à l'adresse <strong>{$smarty.session.sub_state.email}</strong>.
+Les instructions te permettant de valider ton inscription viennent de t'être envoyés
+à l'adresse <strong>{$smarty.session.sub_state.email}</strong>.
 </p>
 <p>
 Tu n'as que quelques jours pour suivre ces instructions. Ensuite, la pré-inscription
diff --git a/templates/register/success.tpl b/templates/register/success.tpl
deleted file mode 100644 (file)
index 626d742..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-{**************************************************************************}
-{*                                                                        *}
-{*  Copyright (C) 2003-2009 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               *}
-{*                                                                        *}
-{**************************************************************************}
-
-{include file="register/breadcrumb.tpl"}
-
-<h1>Bravo !!!</h1>
-
-<p>
-Tu as maintenant accès au site !<br />
-Ton adresse électronique à vie <strong>{$user->forlifeEmail()}</strong> est déjà ouverte, essaie-la !
-</p>
-<p class="smaller">
-  <strong>Remarque&nbsp;:</strong> m4x.org est un domaine "discret" qui veut dire "mail for X" et
-  qui comporte exactement les mêmes adresses que le domaine polytechnique.org.
-</p>
-
-
-<h2>Mot de passe</h2>
-
-{if $mdpok}
-
-<p class="erreur">
-Ton mot de passe a bien été mis à jour !
-</p>
-
-{else}
-
-<p>
-  Tu as reçu un mot de passe par défaut, si tu souhaites en changer, tu peux le faire ici&nbsp;:<br />
-  <strong>Remarque&nbsp;:</strong> il doit faire au moins <strong>6 caractères</strong> et comporter deux types de
-  caractères parmi les suivants : lettres minuscules, lettres majuscules, chiffres, caractères spéciaux.
-</p>
-
-<form action="register/success" method="post" id="changepass">
-  <table class="tinybicol" cellpadding="3" cellspacing="0">
-    <tr>
-      <th colspan="2">
-        Saisie du nouveau mot de passe
-      </th>
-    </tr>
-    <tr>
-      <td class="titre">
-        Nouveau mot de passe&nbsp;:
-      </td>
-      <td>
-        <input type="password" size="10" maxlength="10" name="nouveau" />
-      </td>
-    </tr>
-    <tr>
-      <td class="titre">
-        Retape-le une fois&nbsp;:
-      </td>
-      <td>
-        <input type="password" size="10" maxlength="10" name="nouveau2" />
-      </td>
-    </tr>
-    <tr>
-      <td class="titre">Sécurité</td>
-      <td>{checkpasswd prompt="nouveau" submit="submitn"}</td>
-    </tr>
-    <tr>
-      <td colspan="2" class="center">
-        <input type="submit" value="Changer" name="submitn" onclick="EnCryptedResponse(); return false;" />
-      </td>
-    </tr>
-  </table>
-</form>
-
-<form action="register/success" method="post" id="changepass2">
-<div><input type="hidden" name="response2"  value="" /></div>
-</form>
-
-<p class="smaller">
-<strong>N'oublie pas&nbsp;:</strong> en cas de perte de ton mot de passe,
-il existe une procédure de récupération automatique ; mais elle nécessite
-que ton adresse email sur le site soit toujours valable. Dans le cas contraire,
-il te faudra contacter l'équipe support.
-</p>
-
-{/if}
-
-<h2>Rejoindre la communauté</h2>
-
-<form action='register/save' method='post'>
-  <p>
-  Pour rejoindre la communauté des X sur le web, nous t'invitons vivement à remplir ton profil !
-  </p>
-
-  <p>
-  Cet annuaire n'est pas redondant avec l'annuaire de l'AX ; il est synchronisé automatiquement,
-  d'une manière que tu choisis&nbsp;:
-  </p>
-
-  <dl>
-    <dt><input type="checkbox" value="1" checked="checked" name="send_to_ax" disabled="disabled" /> vers l'AX</dt>
-    <dd>
-      tu peux choisir dans ton profil sur Polytechnique.org de transmettre automatiquement à l'AX certains éléments de ta fiche,
-      au fur et à mesure que tu les modifies.
-      (Les données transmises seront <strong>uniquement</strong> celles que tu as décidé de transmettre).
-    </dd>
-    <dt><label><input type='checkbox' value='1' checked="checked" name='register_from_ax_question' /> depuis l'AX</label></dt>
-    <dd>
-    nous mettons à jour ta fiche depuis les données de l'annuaire de l'AX si tu le souhaites. <br/>
-    (si tu ne le souhaites pas, décoche la case ci-dessus)
-    </dd>
-  </dl>
-
-  <p>
-  Pour profiter pleinement de ta nouvelle inscription, nous te proposons
-  </p>
-
-  <dl>
-    <dt><label><input type='checkbox' value='1' checked="checked" name='add_to_nl' /> lettre mensuelle*</label></dt>
-    <dd>
-      de recevoir chaque mois la lettre mensuelle de Polytechnique.org contenant les activités et nouvelles de la communauté des X.
-    </dd>
-    <dt><label><input type="checkbox" value="1" checked="checked" name="add_to_ax" /> envois de l'AX*</label></dt>
-    <dd>
-      de recevoir les informations importantes de l'AX.
-    </dd>
-    <dt><label><input type='checkbox' value='1' checked="checked" name='add_to_promo' /> ta promo*</label></dt>
-    <dd>
-      de recevoir les informations plus spécifiques de ta promotion pour pouvoir participer plus facilement aux événements
-      qu'elle organise. Nous t'inscrivons donc dans le groupe de la promotion {$smarty.session.promo}.
-    </dd>
-    <dt><label><input type='checkbox' value='1' checked="checked" name='imap' /> sauvegarde des emails</label></dt>
-    <dd>
-      d'avoir un accès de secours aux 30 derniers jours d'emails reçus sur ton adresse Polytechnique.org.
-    </dd>
-  </dl>
-
-  {if $lists|@count neq 0}
-  <p>
-    Des camarades souhaitent que tu t'inscrives aux listes suivantes&nbsp;:
-  </p>
-
-  <dl>
-    {foreach from=$lists key=list item=details}
-    <dt><label><input type='checkbox' value='1' checked="checked" name="sub_ml[{$list}]" /> {$list}*&nbsp;: {$details.desc}</label></dt>
-    {if $details.info}
-    <dd>
-      {$details.info|nl2br}
-    </dd>
-    {/if}
-    {/foreach}
-  </dl>
-  {/if}
-
-  <p class="smaller">* décoche les cases si tu ne souhaites pas être inscrit à la liste de diffusion correspondante</p>
-
-  <div class="center">
-    <input type="submit" value="Rejoindre les X sur le Net !" class="erreur" style="background-color: #fff" />
-  </div>
-</form>
-
-{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/reminder/base.tpl b/templates/reminder/base.tpl
new file mode 100644 (file)
index 0000000..ef58a96
--- /dev/null
@@ -0,0 +1,58 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2009 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<div id="reminder">
+  {if $previous_reminder}
+    {include file="reminder/notification.tpl" previous_reminder=$previous_reminder}
+  {/if}
+
+  <fieldset class="warnings">
+    <legend>
+      {if $reminder->warning()}{icon name=error}{else}{icon name=information}{/if}
+      &nbsp;{$reminder->title()}
+    </legend>
+
+    {if $reminder->template()}
+      {include file=$reminder->template()}
+    {else}
+      <div style="margin-bottom: 0.5em">
+        {$reminder->text()}
+      </div>
+      <div class="center">
+        <a href="" onclick="Ajax.update_html('reminder', '{$reminder->baseurl()}/yes'); return false" style="text-decoration: none">
+          {icon name=add} M'inscrire
+        </a> -
+        <a href="" onclick="Ajax.update_html('reminder', '{$reminder->baseurl()}/no'); return false" style="text-decoration: none">
+          {icon name=delete} Ne pas m'inscrire
+        </a> -
+        <a href="" onclick="Ajax.update_html('reminder', '{$reminder->baseurl()}/dismiss'); return false" style="text-decoration: none">
+          {icon name=cross} Décider plus tard
+        </a>
+        {if $reminder->info()}
+          - <a class="popup2" style="text-decoration: none" href="{$reminder->info()}">{icon name=information} En savoir plus</a>
+        {/if}
+      </div>
+    {/if}
+  </fieldset>
+</div>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/reminder/email_warning.tpl b/templates/reminder/email_warning.tpl
new file mode 100644 (file)
index 0000000..cd04b2a
--- /dev/null
@@ -0,0 +1,34 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2009 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+Des problèmes sont actuellement recontrés sur tes redirections suivantes&nbsp;:
+<ul>
+  {foreach from=$smarty.session.mx_failures item=mail}
+  <li>
+    <span class="erreur">{$mail.mail}</span> :
+    <span class="explication">{$mail.text}</span>
+  </li>
+  {/foreach}
+</ul>
+<div style="text-align: center"><a href="emails/redirect">Gérer mes adresses de redirection</a></div>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/reminder/gapps.tpl b/templates/reminder/gapps.tpl
new file mode 100644 (file)
index 0000000..1320861
--- /dev/null
@@ -0,0 +1,42 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2009 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<div style="margin-bottom: 0.5em">
+  Polytechnique.org te fournit un compte Google Apps qui te permet
+  de disposer des applications web de Google (GMail, Google Calendar,
+  Google Docs, et bien d'autres) sur ton adresse Polytechnique.org
+  habituelle (en savoir plus).
+</div>
+<div class="center">
+  <a href="{$reminder->baseurl()}/yes" style="text-decoration: none">
+    {icon name=add} M'inscrire
+  </a> -
+  <a href="" onclick="Ajax.update_html('reminder', '{$reminder->baseurl()}/no'); return false" style="text-decoration: none">
+    {icon name=delete} Ne pas m'inscrire
+  </a> -
+  <a href="" onclick="Ajax.update_html('reminder', '{$reminder->baseurl()}/dismiss'); return false" style="text-decoration: none">
+    {icon name=cross} Décider plus tard
+  </a> -
+  <a class="popup2" style="text-decoration: none" href="Xorg/GoogleApps">{icon name=information} En savoir plus</a>
+</div>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/reminder/ml.tpl b/templates/reminder/ml.tpl
new file mode 100644 (file)
index 0000000..62270ae
--- /dev/null
@@ -0,0 +1,53 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2009 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<form action="{$reminder->baseurl()}/suscribe" method="post">
+  {xsrf_token_field}
+  Des camarades souhaitent que tu t'inscrives aux listes suivantes&nbsp;:
+  <dl>
+    {foreach from=$lists key=list item=details}
+    <dt>
+      <label>
+        <input type='checkbox' value='1' checked="checked" name="sub_ml[{$list}]" />
+        {$list}&nbsp;: {$details.desc}
+      </label>
+    </dt>
+    {if $details.info}
+    <dd>
+      {$details.info|nl2br}
+    </dd>
+    {/if}
+    {/foreach}
+  </dl>
+
+  <div class="center">
+    <input type="submit" value="M'inscrire aux listes" /> -
+    <a href="" onclick="Ajax.update_html('reminder', '{$reminder->baseurl()}/no'); return false" style="text-decoration: none">
+      {icon name=delete} Ne pas m'inscrire
+    </a> -
+    <a href="" onclick="Ajax.update_html('reminder', '{$reminder->baseurl()}/dismiss'); return false" style="text-decoration: none">
+      {icon name=cross} Décider plus tard
+    </a>
+  </div>
+</form>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/reminder/no_redirection.tpl b/templates/reminder/no_redirection.tpl
new file mode 100644 (file)
index 0000000..a07f2ea
--- /dev/null
@@ -0,0 +1,27 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2009 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+Tu n'as plus de redirection valide ce qui rend ton adresse Polytechnique.org
+inutilisable. Rends-toi au plus vite sur <a href="emails/redirect">la page de
+gestion des emails</a> pour corriger ce problème.
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/reminder/notification.tpl b/templates/reminder/notification.tpl
new file mode 100644 (file)
index 0000000..f7fc9b4
--- /dev/null
@@ -0,0 +1,32 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2009 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<div id="reminder">
+  <fieldset class="success">
+    <legend>
+      {icon name=information}&nbsp;{$previous_reminder}
+    </legend>
+    Ta demande a bien été prise en compte.
+  </fieldset>
+</div>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/reminder/profile_update.tpl b/templates/reminder/profile_update.tpl
new file mode 100644 (file)
index 0000000..497dc7e
--- /dev/null
@@ -0,0 +1,45 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2009 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+{if $profile_incitation}
+  La dernière mise à jour de ta <a href="profile/{$smarty.session.hruid}" class="popup2">fiche</a>
+  date du {$profile_last_update|date_format}. Il est possible qu'elle ne soit pas à jour.
+  Si tu souhaites la modifier,
+  <a href="{$reminder->baseurl()}/profile" style="text-decoration: none">
+  clique ici !</a>
+{elseif $photo_incitation}
+  Tu n'as pas mis de photo de toi sur ta fiche, c'est dommage.
+  <a href="{$reminder->baseurl()}/photo" style="text-decoration: none">
+  Clique ici</a> si tu souhaites en ajouter une.
+{elseif $geocoding_incitation > 0}
+  Parmi tes adresses, il y en a {$geocoding_incitation} que nous n'avons pas pu localiser.
+  <a href="{$reminder->baseurl()}/geoloc" style="text-decoration: none">
+  Clique ici</a> pour rectifier.
+{/if}
+
+<div class="right">
+  <a href="" onclick="Ajax.update_html('reminder', '{$reminder->baseurl()}/dismiss'); return false" style="text-decoration: none">
+    {icon name=cross} Mettre à jour plus tard
+  </a>
+</div>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 95eb62e..82fd654 100644 (file)
     });
 -->
 {/literal}</script>
+<p class="center">[<a href="search">Revenir à la recherche simple</a>]</p>
 <form id="recherche" action="search/adv" method="get">
   <table class="bicol" cellpadding="3" summary="Recherche">
     <tr>
       <th colspan="2">
-        Recherche avancée [<a href="search">Revenir à la Recherche simple</a>]
+        Recherche avancée
       </th>
     </tr>
     <tr>
index d6693ec..d04b0da 100644 (file)
       </td>
     </tr>
     <tr class="noprint">
-      <td style="width: 60%">
+      <td style="width: 70%">
         <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" {if $smarty.request.nonins}checked='checked'{/if} value='1' /> <label for="nonins">Chercher uniquement des non inscrits.</label>
       </td>
+      <td class="right">
+        <br /><input type="submit" value="Chercher" />
+      </td>
     {else}
     <tr class="noprint">
       <td style="width: 60%">
         <input type='text' name="quick" value="{$smarty.request.quick}" style="width: 98%" /><br />
       </td>
-    {/if}
       <td class="right">
-        [<a href="search/adv">Recherche avancée</a>]
-        <br /><br /><input type="submit" value="Chercher" />
+        <input type="submit" value="Chercher" />
       </td>
+    {/if}
     </tr>
   </table>
 </form>
-
-<br />
+{if $smarty.session.auth ge AUTH_COOKIE}
+<p class="center">[<a href="search/adv">Effectuer une recherche avancée</a>]</p>
+{/if}
 
 {if $show_js}
 {literal}
index ad75c91..78259bb 100644 (file)
                     <div>
                         <input type="text" size="20" name="quick" id="quick" class="quick_search"
                                value="{$smarty.request.quick|default:"Recherche dans l'annuaire"}"
-                               onfocus="if (this.value === 'Recherche dans l\'annuaire') this.value=''"
-                               onblur="if (this.value === '') this.value='{$smarty.request.quick|default:"Recherche dans l'annuaire"|escape:javascript}'"/>
-                        <button type="submit" onclick="if ($('#quick').val() === 'Recherche dans l\'annuaire') $('#quick').val('')">OK</button>
+                               onfocus="if (this.value === 'Recherche dans l\'annuaire') this.value='';
+                                        $('#quick_button').show()"
+                               onblur="if (this.value === '') this.value='{$smarty.request.quick|default:"Recherche dans l'annuaire"|escape:javascript}'"
+                               />
+                        <button id="quick_button" type="submit" style="display: none"
+                                onclick="if ($('#quick').val() === 'Recherche dans l\'annuaire') $('#quick').val('')">
+                          OK
+                        </button>
                     </div>
                 </form>
                 {if $smarty.session.auth gt AUTH_PUBLIC && $smarty.session.notifs}
index d6c2435..9b3f323 100644 (file)
       <td class="titre">Commentaire</td>
       <td><textarea name="survey_question[comment]" rows="5" cols="60">{$survey_current.comment}</textarea></td>
     </tr>
+    <tr>
+      <td></td>
+      <td class="smaller">
+        <a href="wiki_help/notitle" class="popup3">
+          {icon name=information title="Syntaxe wiki"} Voir la syntaxe wiki autorisée pour le commentaire d'une question
+        </a>
+      </td>
+    </tr>
     <script type="text/javascript">//<![CDATA[ 
       var id = new Array();
       id['choices'] = {$survey_current.choices|@count};
index 778f232..7e3fd89 100644 (file)
       <td><textarea name="survey_question[description]" rows="5" cols="60">{$survey_current.description}</textarea></td>
     </tr>
     <tr>
+      <td></td>
+      <td class="smaller">
+        <a href="wiki_help/notitle" class="popup3">
+          {icon name=information title="Syntaxe wiki"} Voir la syntaxe wiki autorisée pour le commentaire du sondage
+        </a>
+      </td>
+    </tr>
+    <tr>
       <td class="titre">Date de fin</td>
       <td>
         {valid_date name="survey_question[end]" value=$survey_current.end to=90}
@@ -60,6 +68,7 @@
           {/foreach}
         </select>
       </td>
+    </tr>
     <tr id="ln_promo">
       <td class="titre">Promotions</td>
       <td><input type="text" name="survey_question[promos]" size="50" maxlength="200" value="{$survey_current.promos}"/></td>
index a5f52fe..dce0105 100644 (file)
 {*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
 {*                                                                        *}
 {**************************************************************************}
-<h1>Sondage&nbsp;: {if $survey_type == 'root'}nouveau sondage{else}nouvelle question{/if}</h1>
+<h1>Sondage&nbsp;:
+  {if $survey_type == 'newsurvey'} créer un nouveau sondage
+  {elseif $survey_type == 'new'} ajouter une question
+  {elseif $survey_type == 'root'} modifier la description
+  {else} modifier une question
+  {/if}
+</h1>
 
 <form action="{$survey_formaction}" method="post">
   <input type="hidden" name="survey_action" value="{$survey_action}"/>
index 8748004..e8ece0a 100644 (file)
@@ -22,7 +22,7 @@
 
   <h2>{$squestion.question}</h2>
 {if $squestion.comment != ''}
-  {$squestion.comment}<br/>
+  {$squestion.comment|miniwiki|smarty:nodefaults}<br/>
 {/if}
 {assign var='squestion_type' value=$squestion.type}
 {include file="survey/show_$squestion_type.tpl"}
index 2ff3cd7..70e4cbd 100644 (file)
@@ -27,7 +27,7 @@
     <td>
     <table class="bicol">
       <tr class="pair">
-        <td colspan="2">{$survey.description}</td>
+        <td colspan="2">{$survey.description|miniwiki|smarty:nodefaults}</td>
       </tr>
       <tr>
         <td class="titre">Fin du sondage&nbsp;:</td>
index 661826a..8ce2eb1 100644 (file)
@@ -163,9 +163,9 @@ function deadlineChange(box)
       <td colspan="2">
         Il faut que tu définisses le texte de l'email de confirmation de paiement. Pour ceci, tu peux adapter le modèle qui suit&nbsp;:
         <ul>
-          <li><strong>Remplace les crochets</strong> ([...]) par le texte que tu désires y voir apparaître</li>
-          <li>&lt;salutation&gt;, &lt;prenom&gt;, &lt;nom&gt; et &lt;montant&gt; seront <strong>automatiquement</strong> remplacés par les informations adaptées</li>
-          <li><a href="wiki_help" class="popup3">{icon name=information} tu peux utiliser une syntaxe wiki pour formatter ton texte</a></li>
+          <li><strong>Remplace les crochets</strong> ([...]) par le texte que tu désires y voir apparaître.</li>
+          <li>&lt;salutation&gt;, &lt;prenom&gt;, &lt;nom&gt;, &lt;montant&gt; et &lt;comment&gt; seront <strong>automatiquement</strong> remplacés par les informations adaptées.</li>
+          <li><a href="wiki_help" class="popup3">{icon name=information} Tu peux utiliser une syntaxe wiki pour formatter ton texte.</a></li>
         </ul>
         {javascript name=ajax}
         <div id="pay_preview" style="display: none">
@@ -176,7 +176,9 @@ function deadlineChange(box)
         </div>
         <textarea name="confirmation" id="payment_text" rows="12" cols="65">{if $paiement_message}{$paiement_message}{else}&lt;salutation&gt; &lt;prenom&gt; &lt;nom&gt;,
 
-Ton inscription à [METS LE NOM DE L'EVENEMENT ICI] a bien été enregistrée et ton paiement de &lt;montant&gt; a bien été reçu.
+Ton inscription à [METS LE NOM DE L'EVENEMENT ICI] a bien été enregistrée et ton paiement de &lt;montant&gt; a bien
+été reçu avec le commentaire suivant&nbsp;:
+&lt;comment&gt;
 
 [COMPLETE EN PRECISANT LA DATE ET LA PERSONNE A CONTACTER]
 
@@ -184,7 +186,8 @@ Ton inscription à [METS LE NOM DE L'EVENEMENT ICI] a bien été enregistrée et
 
 -- 
 {$smarty.session.prenom} {$smarty.session.nom}{/if}</textarea><br />
-        Page internet de l'événement&nbsp;: <input size="40" name="site" value="{$paiement_site|default:$asso->site|default:$globals->baseurl|cat:'/'|cat:$platal->ns}" /><br />
+        {assign var='asso_url' value=$globals->baseurl|cat:'/'|cat:$platal->ns}
+        Page internet de l'événement&nbsp;: <input size="40" name="site" value="{$paiement_site|default:$asso.site|default:$asso_url}" /><br />
         Le nouveau paiement sera activé automatiquement après validation par le trésorier de Polytechnique.org,
         ce qui sera fait sous peu.
         <script type="text/javascript">//<![CDATA[
index 5d60921..9d0d235 100644 (file)
@@ -34,6 +34,7 @@ Le groupe {$asso->nom} compte {$nb_tot} membres&nbsp;:
       Ajouter un membre
     </a>
   </li>
+  {if $asso.has_ml}
   <li>
     <a href="{$platal->ns}admin/annuaire">
       {icon name=wand title="Synchroniser"} 
@@ -41,6 +42,7 @@ Le groupe {$asso->nom} compte {$nb_tot} membres&nbsp;:
     </a>
   </li>
   {/if}
+  {/if}
   <li>
     <a href="{$platal->ns}annuaire/csv/{$asso->diminutif}.csv">
       {icon name=page_excel title="Fichier Excel"} 
index 5f0277b..112026e 100644 (file)
         </select>
       </td>
     </tr>
+    <tr>
+      <td class="titre center" colspan="2">
+        <label><input type="checkbox" value="1" name="ax" {if $asso.ax}checked="checked"{/if} />
+        groupe agréé par l'AX</label>
+      </td>
+    </tr>
   </table>
   <p></p>
   {/if}
+
   <table cellpadding="0" cellspacing="0" class='tiny'>
     <tr>
       <td class="titre">
 
     <tr>
       <td class="titre center" colspan="2">
-        <label><input type="checkbox" value="1" name="ax" {if $asso->ax}checked="checked"{/if} />
-        groupe agréé par l'AX</label>
-      </td>
-    </tr>
-
-    <tr>
-      <td class="titre center" colspan="2">
         Diffusion de la liste des membres&nbsp;:
         <select name="pub">
           <option value="public" {if $asso->pub eq 'public'}selected="selected"{/if}>Publique</option>
index 01ddadf..b0e339d 100644 (file)
@@ -103,4 +103,10 @@ function searchX()
   </table>
 </form>
 
+{literal}
+<script type="text/javascript">
+  $("#email").focus();
+</script>
+{/literal}
+
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/upgrade/0.10.1/00_inscription.sql b/upgrade/0.10.1/00_inscription.sql
new file mode 100644 (file)
index 0000000..a23ef9e
--- /dev/null
@@ -0,0 +1,36 @@
+DROP TABLE IF EXISTS reminder_type;
+
+CREATE TABLE IF NOT EXISTS reminder_type (
+  type_id INT NOT NULL AUTO_INCREMENT,
+  name VARCHAR(255) NOT NULL,
+  weight INT NOT NULL,
+  remind_delay_yes INT NOT NULL DEFAULT 0,
+  remind_delay_no INT NOT NULL DEFAULT 0,
+  remind_delay_dismiss INT NOT NULL DEFAULT 0,
+  PRIMARY KEY(type_id),
+  UNIQUE KEY(name)
+) CHARSET=utf8;
+
+INSERT INTO  reminder_type (name, weight, remind_delay_yes, remind_delay_no, remind_delay_dismiss)
+     VALUES  ('email_warning', 100, 0, 0,   7),
+             ('no_redirection', 100, 0, 0,  1),
+             ('profile_update', 90, 0, 0,   2),
+             ('nl',             80, 0, 365, 7),
+             ('promotion_ml',   70, 0, 365, 7),
+             ('ml',             70, 0, 0,   7),
+             ('email_backup',   60, 0, 365, 7),
+             ('gapps',          50, 0, 365, 7),
+             ('ax_letter',      50, 0, 365, 14);
+
+DROP TABLE IF EXISTS reminder;
+
+CREATE TABLE IF NOT EXISTS reminder (
+  uid INT NOT NULL,
+  type_id INT NOT NULL,
+  status ENUM('yes', 'no', 'dismiss') NOT NULL,
+  remind_last TIMESTAMP NOT NULL,
+  remind_next TIMESTAMP NULL,
+  PRIMARY KEY(uid, type_id)
+) CHARSET=utf8;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/0.10.1/01_groupex.sql b/upgrade/0.10.1/01_groupex.sql
new file mode 100644 (file)
index 0000000..e52291e
--- /dev/null
@@ -0,0 +1,3 @@
+ALTER TABLE groupex.asso CHANGE COLUMN flags flags SET('wiki_desc', 'notif_unsub', 'has_ml') NOT NULL;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/0.10.1/02_axletter.sql b/upgrade/0.10.1/02_axletter.sql
new file mode 100644 (file)
index 0000000..524200e
--- /dev/null
@@ -0,0 +1,3 @@
+ALTER TABLE axletter ADD subset TEXT NULL DEFAULT NULL AFTER promo_max;
+
+-- vim:set syntax=mysql:
index 4e5eae2..f0b52d9 100644 (file)
@@ -41,4 +41,9 @@ UPDATE  profile_corps_enum
 DELETE FROM  profile_corps_enum
       WHERE  name = "Ancien élève étranger";
 
+
+ALTER TABLE watch_profile MODIFY field enum('nom', 'freetext', 'mobile', 'nationalite', 'nationalite2',
+                                            'nationalite3', 'nick', 'web', 'networking', 'edus', 'addresses',
+                                            'section', 'binets', 'medals', 'cv', 'jobs', 'photo', 'corps');
+
 --  vim:set syntax=mysql:
index 8baebda..04b3483 100644 (file)
@@ -1,13 +1,13 @@
 ALTER TABLE watch_profile MODIFY field enum('search_names', 'nom', 'freetext', 'mobile', 'nationalite',
                                             'nationalite2', 'nationalite3', 'nick', 'web', 'networking',
                                             'edus', 'addresses', 'section', 'binets', 'medals', 'cv',
-                                            'jobs', 'photo');
+                                            'jobs', 'photo', 'corps');
 
 UPDATE watch_profile SET field = 'search_names' WHERE field = 'nom' OR field = 'nick';
 
 ALTER TABLE watch_profile MODIFY field enum('search_names', 'freetext', 'mobile', 'nationalite',
                                             'nationalite2', 'nationalite3', 'web', 'networking','edus',
                                             'addresses', 'section', 'binets', 'medals', 'cv', 'jobs',
-                                            'photo');
+                                            'photo', 'corps');
 
 # vim:set syntax=mysql:
index d8f34ce..2311f47 100644 (file)
@@ -1,3 +1,5 @@
+DROP TABLE IF EXISTS profile_addresses;
+
 CREATE TABLE IF NOT EXISTS profile_addresses (
   pid INT(11) DEFAULT NULL,
   jobid INT(6) UNSIGNED DEFAULT NULL,
@@ -18,7 +20,7 @@ CREATE TABLE IF NOT EXISTS profile_addresses (
   south FLOAT(10,7) DEFAULT NULL,
   east FLOAT(10,7) DEFAULT NULL,
   west FLOAT(10,7) DEFAULT NULL,
-  updateTime DATE NOT NULL DEFAULT 0,
+  updateTime DATETIME NOT NULL DEFAULT 0,
   pub ENUM('public','ax','private') NOT NULL DEFAULT 'private',
   comment VARCHAR(255) DEFAULT NULL,
   PRIMARY KEY(pid, jobid, type, id),
@@ -32,6 +34,16 @@ CREATE TABLE IF NOT EXISTS profile_addresses (
   INDEX countryId (countryId)
 ) CHARSET=utf8;
 
+INSERT INTO  profile_addresses (pid, id, postalCode, updateTime, pub, comment, latitude, longitude, countryId,
+                                type, flags)
+     SELECT  uid, adrid, postcode, datemaj, pub, comment, glat, glng, country,
+             IF(FIND_IN_SET('pro', 'statut'), 'job', 'home'),
+             CONCAT(IF(FIND_IN_SET('res-secondaire', 'statut'), 'secondary,', ''),
+                    IF(FIND_IN_SET('courrier', 'statut'), 'mail,', ''),
+                    IF(FIND_IN_SET('active', 'statut'), 'current,', ''),
+                    IF(FIND_IN_SET('temporaire', 'statut'), 'temporary', ''))
+       FROM  adresses;
+
 CREATE TABLE IF NOT EXISTS geoloc_countries (
   iso_3166_1_a2 CHAR(2) NOT NULL,
   iso_3166_1_a3 CHAR(3) NOT NULL,
index 7fc2876..291c826 100644 (file)
@@ -2,3 +2,5 @@ Il faudra déplacer le yourself qui est mis dans profile_display dans le script
 
 Le 12_secteurs.sql est à faire avant le alternate_subsubsectors.php et pour que ce dernier fonctionne, il faut que le fichier
 arbo-UTF8.xml soit dans le même dossier.
+
+Le script addresses.php *doit* être lancé dans un screen - il prend plusieurs jours à tourner.
diff --git a/upgrade/newdirectory-0.0.1/addresses.php b/upgrade/newdirectory-0.0.1/addresses.php
new file mode 100755 (executable)
index 0000000..0b659e6
--- /dev/null
@@ -0,0 +1,136 @@
+#!/usr/bin/php5
+<?php
+require_once 'connect.db.inc.php';
+require_once 'geocoding.inc.php';
+
+$globals->debug = 0; // Do not store backtraces.
+
+$res = XDB::query('SELECT  MIN(user_id), MAX(user_id)
+                     FROM  auth_user_md5');
+
+$pids = $res->fetchOneRow();
+
+$minPid = $pids[0];
+$maxPid = $pids[1];
+
+echo "This will take a few minutes.\n".
+
+// Fills the 'text' field in profile_addresses.
+for ($pid = $minPid; $pid < $maxPid + 1; ++$pid) {
+    $res  = XDB::iterator("SELECT  a.adrid AS id, a.adr1, a.adr2, a.adr3,
+                                   UNIX_TIMESTAMP(a.datemaj) AS datemaj,
+                                   a.postcode, a.city, a.cityid, a.region, a.regiontxt,
+                                   a.pub, a.country, gp.pays AS countrytxt, gp.display,
+                                   FIND_IN_SET('coord-checked', a.statut) AS checked,
+                                   FIND_IN_SET('res-secondaire', a.statut) AS secondaire,
+                                   FIND_IN_SET('courrier', a.statut) AS mail,
+                                   FIND_IN_SET('temporaire', a.statut) AS temporary,
+                                   FIND_IN_SET('active', a.statut) AS current,
+                                   FIND_IN_SET('pro', a.statut) AS pro,
+                                   a.glat AS precise_lat, a.glng AS precise_lon
+                             FROM  adresses AS a
+                       INNER JOIN  geoloc_pays AS gp ON(gp.a2 = a.country)
+                            WHERE  uid = {?}
+                         ORDER BY  adrid",
+                           $pid);
+
+    while ($address = $res->next()) {
+        $text = get_address_text($address);
+        XDB::iterator('UPDATE  profile_addresses
+                          SET  text = {?}
+                        WHERE  pid = {?} AND type = {?} AND id = {?}',
+                      $text, $pid, $address['pro'] ? 'job' : 'home', $address['id']);
+    }
+}
+
+echo "Filling the 'text' filles is over. Geocoding will start now and will take a few days\n";
+
+// Tries to geocode all the addresses.
+for ($pid = $minPid; $pid < $maxPid + 1; ++$pid) {
+    $res = XDB::iterator('SELECT  *
+                            FROM  profile_addresses
+                           WHERE  pid = {?}',
+                         $pid);
+
+    while ($address = $res->next()) {
+        $updateTime = $address['updateTime'];
+        $gmapsGeocoder = new GMapsGeocoder();
+        $address = $gmapsGeocoder->getGeocodedAddress($address);
+
+        if (!isset($address['geoloc'])) {
+            // TODO: use address and phone classes to update profile_job_enum and profile_phones once they are done.
+
+            XDB::execute('DELETE FROM  profile_addresses
+                                WHERE  pid = {?} AND id = {?} AND type = {?}',
+                         $address['pid'], $address['id'], $address['type']);
+
+            Geocoder::getAreaId($address, 'administrativeArea');
+            Geocoder::getAreaId($address, 'subAdministrativeArea');
+            Geocoder::getAreaId($address, 'locality');
+            XDB::execute('INSERT INTO  profile_addresses (pid, type, id, flags, accuracy,
+                                                          text, postalText, postalCode, localityId,
+                                                          subAdministrativeAreaId, administrativeAreaId,
+                                                          countryId, latitude, longitude, updateTime, pub, comment,
+                                                          north, south, east, west)
+                               VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?},
+                                        {?}, {?}, FROM_UNIXTIME({?}), {?}, {?}, {?}, {?}, {?}, {?})',
+                         $address['pid'], $address['type'], $address['id'], $flags, $address['accuracy'],
+                         $address['text'], $address['postalText'], $address['postalCode'], $address['localityId'],
+                         $address['subAdministrativeAreaId'], $address['administrativeAreaId'],
+                         $address['countryId'], $address['latitude'], $address['longitude'],
+                         $updateTime, $address['pub'], $address['comment'],
+                         $address['north'], $address['south'], $address['east'], $address['west']);
+        } else {
+            XDB::execute('UPDATE  profile_addresses
+                             SET  postalText = {?}
+                           WHERE  pid = {?} AND id = {?} AND type = {?}',
+                         $address['postalText'], $address['pid'], $address['id'], $address['type']);
+        }
+
+        sleep(60); // So we don't get blacklisted by Google.
+    }
+}
+
+echo "Geocoding is over.\n";
+
+function get_address_text($adr)
+{
+    $t = "";
+    if (isset($adr['adr1']) && $adr['adr1']) $t.= $adr['adr1'];
+    if (isset($adr['adr2']) && $adr['adr2']) $t.= "\n".$adr['adr2'];
+    if (isset($adr['adr3']) && $adr['adr3']) $t.= "\n".$adr['adr3'];
+    $l = "";
+    if (isset($adr['display']) && $adr['display']) {
+        $keys = explode(' ', $adr['display']);
+        foreach ($keys as $key) {
+            if (isset($adr[$key])) {
+                $l .= " ".$adr[$key];
+            } else {
+                $l .= " ".$key;
+            }
+        }
+        if ($l) substr($l, 1);
+    } elseif ($adr['country'] == 'US' || $adr['country'] == 'CA' || $adr['country'] == 'GB') {
+        if ($adr['city']) $l .= $adr['city'].",\n";
+        if ($adr['region']) $l .= $adr['region']." ";
+        if ($adr['postcode']) $l .= $adr['postcode'];
+    } else {
+        if (isset($adr['postcode']) && $adr['postcode']) $l .= $adr['postcode']." ";
+        if (isset($adr['city']) && $adr['city']) $l .= $adr['city'];
+    }
+    if ($l) $t .= "\n".trim($l);
+    if ($adr['country'] != '00' && (!$adr['countrytxt'] || $adr['countrytxt'] == strtoupper($adr['countrytxt']))) {
+        $res = XDB::query('SELECT  pays
+                             FROM  geoloc_pays
+                            WHERE  a2 = {?}',
+                          $adr['country']);
+        $adr['countrytxt'] = $res->fetchOneCell();
+    }
+    if (isset($adr['countrytxt']) && $adr['countrytxt']) {
+        $t .= "\n".$adr['countrytxt'];
+    }
+    return trim($t);
+}
+
+/* vim:set et sw=4 sts=4 ts=4: */
+?>