Merge branch 'xorg/maint' into xorg/master
authorStéphane Jacob <sj@m4x.org>
Wed, 26 Oct 2011 13:29:59 +0000 (15:29 +0200)
committerStéphane Jacob <sj@m4x.org>
Wed, 26 Oct 2011 13:29:59 +0000 (15:29 +0200)
120 files changed:
ChangeLog
Makefile
banana
bin/cron/checkdb.php
bin/cron/cron_xnet_accounts.php
bin/formatAddresses.php
bin/lists.rpc.py
classes/address.php
classes/direnum.php
classes/phone.php
classes/profile.php
classes/user.php
classes/userfilter/conditions.inc.php
classes/xnetsession.php
classes/xorgsession.php
core
htdocs/css/base.css
htdocs/css/keynote.css
htdocs/javascript/jquery.autocomplete.js [deleted file]
htdocs/javascript/profile.js
htdocs/javascript/search.js
include/emails.inc.php
include/newsletter.inc.php
include/notifs.inc.php
include/profilefields.inc.php
include/ufbuilder.inc.php
include/userset.inc.php
include/validations/account.inc.php
include/validations/listes.inc.php
include/validations/medals.inc.php
include/validations/paiements.inc.php
modules/admin.php
modules/auth.php
modules/axletter.php
modules/carnet.php
modules/email.php
modules/epletter.php
modules/events.php
modules/forums.php
modules/fusionax.php
modules/fusionax/Anciens.sql
modules/googleapps.php
modules/lists.php
modules/marketing.php
modules/newsletter.php
modules/openid.php
modules/payment.php
modules/payment/money.inc.php
modules/payment/money/bplccyberplus.inc.php
modules/payment/money/paypal.inc.php
modules/platal.php
modules/profile.php
modules/profile/decos.inc.php
modules/profile/general.inc.php
modules/profile/mentor.inc.php
modules/profile/page.inc.php
modules/profile/skills.inc.php [deleted file]
modules/register.php
modules/search.php
modules/survey.php
modules/urlshortener.php
modules/xnet.php
modules/xnetevents.php
modules/xnetevents/xnetevents.inc.php
modules/xnetgrp.php
modules/xnetlists.php
modules/xnetnl.php
plugins/function.profile.php
templates/banana/index.tpl
templates/carnet/batch.tpl [new file with mode: 0644]
templates/carnet/index.tpl
templates/carnet/notif.mail.tpl
templates/carnet/notifs.tpl
templates/emails/alias.tpl
templates/emails/send.tpl
templates/include/form.valid.edit-paiements.tpl
templates/include/form.valid.paiements.tpl
templates/lists/admin.tpl
templates/lists/header_listes.tpl
templates/newsletter/admin_all.tpl
templates/newsletter/edit.tpl
templates/newsletter/index.tpl
templates/payment/payment.tpl [moved from templates/payment/index.tpl with 81% similarity]
templates/platal/email_preferences.tpl [new file with mode: 0644]
templates/platal/preferences.tpl
templates/profile/base.tpl
templates/profile/deco.medal.tpl
templates/profile/deco.tpl
templates/profile/fiche_referent.tpl
templates/profile/general.hobby.tpl [new file with mode: 0644]
templates/profile/general.private_name.tpl
templates/profile/general.public_names.tpl
templates/profile/general.tpl
templates/profile/jobs.job.tpl
templates/profile/mentor.tpl
templates/profile/profile.tpl
templates/profile/skill.tpl [deleted file]
templates/search/adv.form.tpl
templates/search/referent.tpl
templates/skin/common.footer.tpl
templates/skin/common.menu.tpl
templates/xnet/account.mail.tpl
templates/xnetevents/admin.tpl
templates/xnetevents/edit.tpl
templates/xnetgrp/annuaire.tpl
templates/xnetgrp/asso.tpl
templates/xnetgrp/edit.tpl
templates/xnetgrp/membres-edit.tpl
upgrade/1.0.1/merge.php
upgrade/1.1.4/01_payments.sql [new file with mode: 0644]
upgrade/1.1.4/02_newsletter_issues.sql [new file with mode: 0644]
upgrade/1.1.4/03_watch_group.sql [new file with mode: 0644]
upgrade/1.1.4/04_accounts.sql [new file with mode: 0644]
upgrade/1.1.4/05_medals.sql [new file with mode: 0644]
upgrade/1.1.4/06_hobby.sql [new file with mode: 0644]
upgrade/1.1.4/07_autocomplete.sql [new file with mode: 0644]
upgrade/1.1.4/08_ax_id.sql [new file with mode: 0644]
upgrade/1.1.4/09_title.sql [new file with mode: 0644]
upgrade/1.1.4/10_virtual_alias_pub.sql [new file with mode: 0644]
upgrade/1.1.4/README [new file with mode: 0644]

index 79f63da..f02824c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,62 @@
 ================================================================================
+VERSION 1.1.4                                                         XX XX XXXX
+
+New:
+
+    * Newsletter:
+        - Displays number of subscribers without any valid redirection     -JAC
+
+    * Search:
+        - Switches autocomplete to jQuery UI                               -JAC
+
+Bug/Wish:
+
+    * Carnet:
+        - #709: Adds multiple contacts, and markets those unregistered     -JAC
+        - #808: Enables watch of groups                                    -JAC
+        - #1528: Do not display birthday of deceased users in emails       -FUL
+
+    * Core:
+        - #1523: Rename AUTH_MDP to AUTH_PASSWD                            -JAC
+        - #1534: Fixes birthday calendar downloading with IE               -JAC
+
+    * Email:
+        - #1529: Stores and uses preferences for sending emails from site  -JAC
+        - #1516: Enables @polytechnique.edu adresses for old promotions    -GLN
+        - #1549: Updates aliases and MLs on new redirection addition       -JAC
+
+    * Lists:
+        - #1543: Displays no member in directory view for empty lists      -JAC
+        - #1555: Ensures an email is given only once in mass subscription  -JAC
+
+    * Newsletter:
+        - #1509: Adds a Reply-To field for newsletters                     -GLN
+        - #1526: Shows user filter used after sending                      -GLN
+        - #1538: Improves display in main NL administration page       -FUL/JAC
+
+    * Payments:
+        - #1512: Allows payments for unlogged users                        -JAC
+        - #1537: Replaces payments page on main site by a donation page    -JAC
+
+    * Profile:
+        - #1381: Adds levels to medals                                     -JAC
+        - #1446: Adds field for sports and hobbies                         -JAC
+        - #1535: Moves and displays skills with mentoring informations     -JAC
+        - #1554: Allows admins to modify unregisterd users' ref birthdate  -JAC
+
+    * Search:
+        - #1284: If a country is chosen, only proposes its cities          -JAC
+
+    * XnetGrp:
+        - #1525: Fixes broken page on erroneous group page edition         -JAC
+        - #1530: Enables reminder for xnet accounts                        -JAC
+
+From 1.1.3 branch:
+
+    * Profile:
+        - #1545: Fixes link to profiles on IE7                             -FRU
+
+================================================================================
 VERSION 1.1.3                                                         10 09 2011
 
 New:
@@ -1781,6 +1839,8 @@ ACRONYMS:
     * CAT: Florian El Ahdab     (LeChat)    <florian.el-ahdab@m4x.org>
     * FAL: Raphaël Marichez     (Falco)     <raphael.marichez@m4x.org>
     * FRU: Florent Bruneau      (Fruneau)   <florent.bruneau@m4x.org>
+    * FUL: Thomas Minvielle     (Fulanor)   <thomas.minvielle@m4x.org>
+    * GLN: Brice Gelineau       (brice)     <brice.gelineau@m4x.org>
     * GUI: Guillaume Bandet     (GUI)       <guillaume.bandet@m4x.org>
     * JAC: Stéphane Jacob       (jacou)     <stephane.jacob@m4x.org>
     * JM : Jean-Marc Bécu                   <jean-marc.becu@m4x.org>
index 5b9c699..6a8a175 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -174,7 +174,7 @@ JQUERY_PLUGINS=color form
 JQUERY_PLUGINS_PATHES=$(addprefix htdocs/javascript/jquery.,$(addsuffix .js,$(JQUERY_PLUGINS)))
 
 JQUERY_UI_VERSION=1.8.10
-JQUERY_UI=core widget tabs datepicker
+JQUERY_UI=core widget tabs datepicker autocomplete position
 JQUERY_UI_PATHES=$(addprefix htdocs/javascript/jquery.ui.,$(addsuffix .js,$(JQUERY_UI)))
 
 JQUERY_TMPL_VERSION=vBeta1.0.0
@@ -183,12 +183,9 @@ JQUERY_TMPL_PATH=htdocs/javascript/jquery.tmpl.js
 JSTREE_VERSION=1.0rc2
 JSTREE_PATH=htdocs/javascript/jquery.jstree.js
 
-# TODO: jquery.autocomplete.js should rather be downloaded from an official source. The issue
-# is that the version we use is not available anymore on the Internet, and the latest version
-# we could use is not backward compatible with our current code.
 jquery: htdocs/javascript/jquery.xorg.js htdocs/javascript/jquery.ui.xorg.js $(JSTREE_PATH)
 
-htdocs/javascript/jquery.xorg.js: htdocs/javascript/jquery.js $(JQUERY_PLUGINS_PATHES) $(JQUERY_TMPL_PATH) htdocs/javascript/jquery.autocomplete.js
+htdocs/javascript/jquery.xorg.js: htdocs/javascript/jquery.js $(JQUERY_PLUGINS_PATHES) $(JQUERY_TMPL_PATH)
        cat $^ > $@
 
 htdocs/javascript/jquery.ui.xorg.js: $(JQUERY_UI_PATHES) htdocs/javascript/jquery.ui.datepicker-fr.js
diff --git a/banana b/banana
index 8575148..0e2d7b8 160000 (submodule)
--- a/banana
+++ b/banana
@@ -1 +1 @@
-Subproject commit 8575148f767c35d84122edf39f9a416010d9e532
+Subproject commit 0e2d7b8ec9a5c194f6eeed5f13e7acb69dea9089
index fee4057..b7cdcb3 100755 (executable)
@@ -217,6 +217,20 @@ check("SELECT  evd.name
         WHERE  evd2.id != evd2.aliasing",
       "Domaines aliasés de niveau 2 ou plus qui ne sont pas vu par postfix.");
 
+// Account viewing statistics
+info("SELECT  nb_profiles, hruid
+        FROM  (
+           SELECT  a.hruid AS hruid, COUNT(DISTINCT le.data) AS nb_profiles
+             FROM  log_events AS le
+        LEFT JOIN  log_sessions AS ls ON (ls.id = le.session)
+        LEFT JOIN  accounts AS a ON (a.uid = ls.uid)
+            WHERE  le.action = 30 AND ls.start >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
+         GROUP BY  a.hruid
+              ) AS profile_views
+       WHERE  nb_profiles >= 100
+    ORDER BY  nb_profiles DESC",
+     "Camarades ayant consulté plus de 100 fiches au cours des 7 derniers jours.");
+
 // Counts empty profile fields that should never be empty.
 infoCountEmpty('profile_addresses', 'type');
 infoCountEmpty('profile_phones', 'link_type');
index de935e0..6194f68 100755 (executable)
@@ -40,6 +40,7 @@ foreach ($users as $user) {
     $mailer->assign('email', $user['email']);
     $mailer->assign('group', $user['group_name']);
     $mailer->assign('sender_name', $user['sender_name']);
+    $mailer->assign('again', false);
     $mailer->send();
 
     XDB::execute('UPDATE  accounts
index 6b8a8dd..2e25835 100755 (executable)
@@ -24,17 +24,18 @@ require './connect.db.inc.php';
 require_once '../classes/address.php';
 require_once '../classes/geocoder.php';
 require_once '../classes/gmapsgeocoder.php';
+require_once '../classes/visibility.php';
 
 $globals->debug = 0; // Do not store backtraces
 
 $targets = array(
-    'g' => 'formatted_address',
-    'p' => 'postalText'
+    'g' => 'pa.formatted_address',
+    'p' => 'pa.postalText'
 );
 $ranges = array(
     'f' => ' != \'\'',
     'e' => ' = \'\'',
-    'a' => 'IS NOT NULL'
+    'a' => ' IS NOT NULL'
 );
 
 $options = getopt('g::t:r:h::', array('geocode::', 'target:', 'range:', 'help::'));
@@ -87,9 +88,10 @@ EOF;
 
 print "Formats addresses addresses.\n";
 
-$where = '';
 if ($range != 'a') {
-    $where = 'WHERE  ' . $targets[$target] . $ranges[$range];
+    $where = $targets[$target] . $ranges[$range];
+} else {
+    $where = null;
 }
 
 if ($geocoding_required) {
@@ -102,10 +104,7 @@ if ($geocoding_required) {
     $display_limit = 100;
 }
 
-$it = XDB::rawIterator('SELECT  *
-                          FROM  profile_addresses
-                        ' . $where . '
-                      ORDER BY  pid, jobid, type, id');
+$it = Address::iterate(array(), array(), array(), Visibility::get(Visibility::VIEW_PRIVATE), $where);
 
 $total = $it->total();
 $i = 0;
@@ -113,12 +112,11 @@ $j = 0;
 $skipped = 0;
 printf("\r%u / %u",  $i, $total);
 
-while ($item = $it->next()) {
-    $address = new Address($item);
+while ($address = $it->next()) {
     $address->changed = ($geocoding_required ? 1 : 0);
     $address->format();
     if ($address->delete()) {
-        $address->save();
+        $address->save(false);
     } else {
         ++$skipped;
     }
index 61aac8f..780b293 100755 (executable)
@@ -467,6 +467,8 @@ def mass_subscribe(userdesc, perms, mlist, users):
             @edit
             @admin
     """
+    if isinstance(users, dict):
+        users = users.values()
     if not isinstance(users, list):
         raise Exception("userlist must be a list")
     members = mlist.getRegularMemberKeys()
index 871526a..af0e2f0 100644 (file)
@@ -685,7 +685,7 @@ class Address
         return (!$this->text || $this->text == '');
     }
 
-    public function save()
+    public function save($notify_ungeocoded = true)
     {
         if (!$this->isEmpty()) {
             XDB::execute('INSERT IGNORE INTO  profile_addresses (pid, jobid, groupid, type, id, flags, text, postalText, pub, comment,
@@ -704,7 +704,7 @@ class Address
                                               VALUES  ({?}, {?}, {?}, {?}, {?}, {?})',
                                  $this->pid, $this->jobid, $this->groupid, $this->type, $this->id, $component_id);
                 }
-            } else {
+            } elseif ($notify_ungeocoded) {
                 // If the address was not geocoded, notifies it to the appropriate ML.
                 $mailer = new PlMailer('profile/no_geocoding.mail.tpl');
                 $mailer->assign('text', $this->text);
@@ -878,9 +878,9 @@ class Address
     }
 
     static public function iterate(array $pids = array(), array $types = array(),
-                                   array $jobids = array(), $visibility = null)
+                                   array $jobids = array(), $visibility = null, $where = null)
     {
-        return new AddressIterator($pids, $types, $jobids, $visibility);
+        return new AddressIterator($pids, $types, $jobids, $visibility, $where);
     }
 }
 
@@ -895,9 +895,12 @@ class AddressIterator implements PlIterator
 {
     private $dbiter;
 
-    public function __construct(array $pids, array $types, array $jobids, $visibility)
+    public function __construct(array $pids, array $types, array $jobids, $visibility, $_where)
     {
         $where = array();
+        if (!is_null($_where)) {
+            $where[] = $_where;
+        }
         if (count($pids) != 0) {
             $where[] = XDB::format('(pa.pid IN {?})', $pids);
         }
index 9d9a163..5176c4a 100644 (file)
@@ -119,16 +119,16 @@ class DirEnum
      * @param $text Text to autocomplete
      * @return PlIterator over the results
      */
-    static public function getAutoComplete($type, $text)
+    static public function getAutoComplete($type, $text, $sub_id = null)
     {
         if (!array_key_exists($type, self::$enumerations)) {
             self::init($type);
         }
         $obj = self::$enumerations[$type];
         if ($obj->capabilities & DirEnumeration::HAS_AUTOCOMP) {
-            return call_user_func(array($obj, 'getAutoComplete'), $text);
+            return call_user_func_array(array($obj, 'getAutoComplete'), array($text, $sub_id));
         } else {
-            return PlIteratorUtils::fromArray(array());
+            return array();
         }
     }
 
@@ -252,7 +252,7 @@ abstract class DirEnumeration
     /** Builds a list of query parts for searching @$text in @$field :
      * field LIKE 'text%', field LIKE '% text%', field LIKE '%-text%'
      */
-    private function mkTests($field, $text)
+    protected function mkTests($field, $text)
     {
         $tests = array();
         $tests[] = $field . XDB::formatWildcards(XDB::WILDCARD_PREFIX, $text);
@@ -276,7 +276,7 @@ abstract class DirEnumeration
     }
 
     // {{{ function getAutoComplete
-    public function getAutoComplete($text)
+    public function getAutoComplete($text, $sub_id = null)
     {
         $text = str_replace(array('%', '_'), '', $text);
 
@@ -293,15 +293,15 @@ abstract class DirEnumeration
 
         $where .= '(' . implode(' OR ', $tests) . ')';
 
-        return XDB::iterator('SELECT ' . $this->valfield . ' AS field'
-                                       . ($this->ac_distinct ? (', COUNT(DISTINCT ' . $this->ac_unique . ') AS nb') : '')
-                                       . ($this->ac_withid ? (', ' . $this->idfield . ' AS id') : '') . '
-                                FROM ' . $this->from . '
-                                     ' . $this->ac_join . '
-                               WHERE ' . $where . '
-                            GROUP BY ' . $this->valfield . '
-                            ORDER BY ' . ($this->ac_distinct ? 'nb DESC' : $this->valfield) . '
-                               LIMIT ' . self::AUTOCOMPLETE_LIMIT);
+        return XDB::fetchAllAssoc('SELECT ' . $this->valfield . ' AS field'
+                                            . ($this->ac_distinct ? (', COUNT(DISTINCT ' . $this->ac_unique . ') AS nb') : '')
+                                            . ($this->ac_withid ? (', ' . $this->idfield . ' AS id') : '') . '
+                                     FROM ' . $this->from . '
+                                          ' . $this->ac_join . '
+                                    WHERE ' . $where . '
+                                 GROUP BY ' . $this->valfield . '
+                                 ORDER BY ' . ($this->ac_distinct ? 'nb DESC' : $this->valfield) . '
+                                    LIMIT ' . self::AUTOCOMPLETE_LIMIT);
     }
     // }}}
 
@@ -421,15 +421,15 @@ abstract class DE_WithSuboption extends DirEnumeration
 
         $where .= '(' . implode(' OR ', $tests) . ')';
 
-        return XDB::iterator('SELECT ' . $this->valfield . ' AS field'
-                                       . ($this->ac_distinct ? (', COUNT(DISTINCT ' . $this->ac_unique . ') AS nb') : '')
-                                       . ($this->ac_withid ? (', ' . $this->idfield . ' AS id') : '') . '
-                                FROM ' . $this->from . '
-                                     ' . $this->ac_join . '
-                               WHERE ' . $where . '
-                            GROUP BY ' . $this->valfield . '
-                            ORDER BY ' . ($this->ac_distinct ? 'nb DESC' : $this->valfield) . '
-                               LIMIT ' . self::AUTOCOMPLETE_LIMIT);
+        return XDB::fetchAllAssoc('SELECT ' . $this->valfield . ' AS field'
+                                            . ($this->ac_distinct ? (', COUNT(DISTINCT ' . $this->ac_unique . ') AS nb') : '')
+                                            . ($this->ac_withid ? (', ' . $this->idfield . ' AS id') : '') . '
+                                     FROM ' . $this->from . '
+                                          ' . $this->ac_join . '
+                                    WHERE ' . $where . '
+                                 GROUP BY ' . $this->valfield . '
+                                 ORDER BY ' . ($this->ac_distinct ? 'nb DESC' : $this->valfield) . '
+                                    LIMIT ' . self::AUTOCOMPLETE_LIMIT);
     }
 }
 // }}}
@@ -609,6 +609,30 @@ class DE_Localities extends DE_AddressesComponents
 {
     protected $where = 'WHERE  FIND_IN_SET(\'locality\', profile_addresses_components_enum.types)';
     protected $ac_where  = 'profile_addresses_components.type = \'home\' AND FIND_IN_SET(\'locality\', profile_addresses_components_enum.types)';
+
+    // {{{ function getAutoComplete
+    public function getAutoComplete($text, $sub_id = null)
+    {
+        if (is_null($sub_id)) {
+            return parent::getAutoComplete($text);
+        } else {
+            $tests = $this->mkTests('pace1.long_name', $text);
+            $where .= '(' . implode(' OR ', $tests) . ')';
+            $query = "SELECT  pace1.id AS id, pace1.long_name AS field, COUNT(DISTINCT(pac1.pid)) AS nb
+                        FROM  profile_addresses_components_enum AS pace1
+                  INNER JOIN  profile_addresses_components      AS pac1  ON (pac1.component_id = pace1.id)
+                  INNER JOIN  profile_addresses_components      AS pac2  ON (pac1.pid = pac2.pid AND pac1.jobid = pac2.jobid AND pac1.id = pac2.id
+                                                                             AND pac1.groupid = pac2.groupid AND pac1.type = pac2.type)
+                  INNER JOIN  profile_addresses_components_enum AS pace2 ON (pac2.component_id = pace2.id AND FIND_IN_SET('country', pace2.types))
+                       WHERE  pace2.id = {?} AND FIND_IN_SET('locality', pace1.types) AND pac1.type = 'home' AND " . $where . "
+                    GROUP BY  pace1.long_name
+                    ORDER BY  nb DESC, field
+                       LIMIT  " . self::AUTOCOMPLETE_LIMIT;
+            return XDB::fetchAllAssoc($query, $sub_id);
+        }
+    }
+    // }}}
+
 }
 
 class DE_Sublocalities extends DE_AddressesComponents
@@ -659,21 +683,21 @@ class DE_JobTerms extends DirEnumeration
     protected $idfield = 'profile_job_term_enum.jtid';
 
     // {{{ function getAutoComplete
-    public function getAutoComplete($text)
+    public function getAutoComplete($text, $sub_id = null)
     {
         $tokens = JobTerms::tokenize($text.'%');
         if (count($tokens) == 0) {
-            return PlIteratorUtils::fromArray(array());
+            return array();
         }
         $token_join = JobTerms::token_join_query($tokens, 'e');
-        return XDB::iterator('SELECT  e.jtid AS id, e.full_name AS field, COUNT(DISTINCT p.pid) AS nb
-                                 FROM  profile_job_term_enum AS e
-                           INNER JOIN  profile_job_term_relation AS r ON (r.jtid_1 = e.jtid)
-                           INNER JOIN  profile_job_term AS p ON (r.jtid_2 = p.jtid)
-                           '.$token_join.'
-                             GROUP BY  e.jtid
-                             ORDER BY  nb DESC, field
-                                LIMIT ' . self::AUTOCOMPLETE_LIMIT);
+        return XDB::fetchAllAssoc('SELECT  e.jtid AS id, e.full_name AS field, COUNT(DISTINCT p.pid) AS nb
+                                     FROM  profile_job_term_enum AS e
+                               INNER JOIN  profile_job_term_relation AS r ON (r.jtid_1 = e.jtid)
+                               INNER JOIN  profile_job_term AS p ON (r.jtid_2 = p.jtid)
+                               '.$token_join.'
+                                 GROUP BY  e.jtid
+                                 ORDER BY  nb DESC, field
+                                    LIMIT ' . self::AUTOCOMPLETE_LIMIT);
     }
     // }}}
 }
index c709281..be6f3ad 100644 (file)
@@ -187,9 +187,10 @@ class Phone
         if ((!isset($format['phoneprf'])) || ($format['phoneprf'] == '')) {
             $res = XDB::query('SELECT  phonePrefix AS phoneprf, phoneFormat AS format
                                  FROM  geoloc_countries
-                                WHERE  phonePrefix = {?} OR phonePrefix = {?} OR phonePrefix = {?}
+                                WHERE  phonePrefix = SUBSTRING({?}, 1, LENGTH(phonePrefix))
+                             ORDER BY  LENGTH(phonePrefix) DESC
                                 LIMIT  1',
-                              substr($tel, 0, 1), substr($tel, 0, 2), substr($tel, 0, 3));
+                              $tel);
             if ($res->numRows() == 0) {
                 // No country found, does not format more than prepending a '+' sign.
                 $this->error = true;
index 6574d0a..d46b864 100644 (file)
@@ -111,10 +111,12 @@ class Profile implements PlExportable
     const FETCH_MENTOR_TERMS   = 0x000400;
     const FETCH_DELTATEN       = 0x000800;
     const FETCH_PARTNER        = 0x001000;
+    const FETCH_SKILL          = 0x002000;
+    const FETCH_LANGUAGE       = 0x004000;
 
     const FETCH_MINIFICHES   = 0x00012D; // FETCH_ADDRESSES | FETCH_EDU | FETCH_JOBS | FETCH_NETWORKING | FETCH_PHONES
 
-    const FETCH_ALL          = 0x001FFF; // OR of FETCH_*
+    const FETCH_ALL          = 0x007FFF; // OR of FETCH_*
 
     static public $descriptions = array(
         'search_names'    => 'Noms',
@@ -481,7 +483,7 @@ class Profile implements PlExportable
 
         XDB::execute("UPDATE  profiles
                          SET  cv = NULL, freetext = NULL, freetext_pub = 'private',
-                              medals_pub = 'private', alias_pub = 'private',
+                              medals_pub = 'private', alias_pub = 'hidden',
                               email_directory = NULL
                        WHERE  pid = {?}",
                      $this->id());
@@ -676,7 +678,10 @@ class Profile implements PlExportable
     public function getEducations($flags, $limit = null)
     {
         if ($this->educations == null && !$this->fetched(self::FETCH_EDU)) {
-            $this->setEducations($this->getProfileField(self::FETCH_EDU));
+            $educations = $this->getProfileField(self::FETCH_EDU);
+            if ($educations) {
+                $this->setEducations($educations);
+            }
         }
 
         if ($this->educations == null) {
@@ -701,7 +706,10 @@ class Profile implements PlExportable
     public function getCorps()
     {
         if ($this->corps == null && !$this->fetched(self::FETCH_CORPS)) {
-            $this->setCorps($this->getProfileField(self::FETCH_CORPS));
+            $corps = $this->getProfileField(self::FETCH_CORPS);
+            if ($corps) {
+                $this->setCorps($corps);
+            }
         }
         return $this->corps;
     }
@@ -796,7 +804,10 @@ class Profile implements PlExportable
     public function getMentoringCountries()
     {
         if ($this->mentor_countries == null && !$this->fetched(self::FETCH_MENTOR_COUNTRY)) {
-            $this->setMentoringCountries($this->getProfileField(self::FETCH_MENTOR_COUNTRY));
+            $countries = $this->getProfileField(self::FETCH_MENTOR_COUNTRY);
+            if ($countries) {
+                $this->setMentoringCountries($countries);
+            }
         }
 
         if ($this->mentor_countries == null) {
@@ -823,7 +834,10 @@ class Profile implements PlExportable
     public function getMentoringTerms()
     {
         if ($this->mentor_terms == null && !$this->fetched(self::FETCH_MENTOR_TERMS)) {
-            $this->setMentoringTerms($this->getProfileField(self::FETCH_MENTOR_TERMS));
+            $terms = $this->getProfileField(self::FETCH_MENTOR_TERMS);
+            if ($terms) {
+                $this->setMentoringTerms($terms);
+            }
         }
 
         if ($this->mentor_terms == null) {
@@ -833,6 +847,50 @@ class Profile implements PlExportable
         }
     }
 
+    /* Skills */
+    private $skills = null;
+    public function setSkills(ProfileSkills $skills)
+    {
+        $this->skills = $skills;
+    }
+    public function getSkills()
+    {
+        if ($this->skills == null && !$this->fetched(self::FETCH_SKILL)) {
+            $skills = $this->getProfileField(self::FETCH_SKILL);
+            if ($skills) {
+                $this->setSkills($skills);
+            }
+        }
+
+        if ($this->skills == null) {
+            return array();
+        } else {
+            return $this->skills->skills;
+        }
+    }
+
+    /* Languades */
+    private $languages = null;
+    public function setLanguages(ProfileLanguages $languages)
+    {
+        $this->languages = $languages;
+    }
+    public function getLanguages()
+    {
+        if ($this->languages == null && !$this->fetched(self::FETCH_LANGUAGE)) {
+            $languages = $this->getProfileField(self::FETCH_LANGUAGE);
+            if ($languages) {
+                $this->setLanguages($languages);
+            }
+        }
+
+        if ($this->languages == null) {
+            return array();
+        } else {
+            return $this->languages->languages;
+        }
+    }
+
     /** DeltaTen
      */
 
@@ -907,7 +965,10 @@ class Profile implements PlExportable
     public function getMedals()
     {
         if ($this->medals == null && !$this->fetched(self::FETCH_MEDALS)) {
-            $this->setMedals($this->getProfileField(self::FETCH_MEDALS));
+            $medals = $this->getProfileField(self::FETCH_MEDALS);
+            if ($medals) {
+                $this->setMedals($medals);
+            }
         }
         if ($this->medals == null) {
             return array();
@@ -926,7 +987,10 @@ class Profile implements PlExportable
     public function getPartnerSettings($partner_id)
     {
         if ($this->partners_settings === null && !$this->fetched(self::FETCH_PARTNER)) {
-            $this->setPartnersSettings($this->getProfileField(self::FETCH_PARTNER));
+            $settings = $this->getProfileField(self::FETCH_PARTNER);
+            if ($settings) {
+                $this->setPartnersSettings($settings);
+            }
         }
         if ($this->partners_settings === null) {
             return PartnerSettings::getEmpty($partner_id);
index eb3c855..bc9adc5 100644 (file)
@@ -306,7 +306,7 @@ class User extends PlUser
     public function firstName()
     {
         if (!$this->hasProfile()) {
-            return $this->displayName();
+            return $this->firstname;
         }
         return $this->profile()->firstName();
     }
@@ -314,7 +314,7 @@ class User extends PlUser
     public function lastName()
     {
         if (!$this->hasProfile()) {
-            return '';
+            return $this->lastname;
         }
         return $this->profile()->lastName();
     }
@@ -568,6 +568,10 @@ class User extends PlUser
         $watch['watch_promos'] = XDB::fetchColumn('SELECT  promo
                                                      FROM  watch_promo
                                                     WHERE  uid = {?}', $this->id());
+        $watch['watch_groups'] = XDB::fetchColumn("SELECT  w.groupid
+                                                     FROM  watch_group AS w
+                                               INNER JOIN  groups      AS g ON (w.groupid = g.id AND NOT FIND_IN_SET('private', pub))
+                                                    WHERE  w.uid = {?}", $this->id());
         $watch['watch_users'] = XDB::fetchColumn('SELECT  ni_id
                                                     FROM  watch_nonins
                                                    WHERE  uid = {?}', $this->id());
@@ -598,6 +602,12 @@ class User extends PlUser
         return $this->watch_promos;
     }
 
+    public function watchGroups()
+    {
+        $this->fetchWatchData();
+        return $this->watch_groups;
+    }
+
     public function watchUsers()
     {
         $this->fetchWatchData();
@@ -616,6 +626,7 @@ class User extends PlUser
         unset($this->watch_users);
         unset($this->watch_last);
         unset($this->watch_promos);
+        unset($this->watch_groups);
     }
 
 
@@ -708,7 +719,7 @@ class User extends PlUser
     /**
      * Clears a user.
      *  *always deletes in: account_lost_passwords, register_marketing,
-     *      register_pending, register_subs, watch_nonins, watch, watch_promo
+     *      register_pending, register_subs, watch_nonins, watch, watch_promo, watch_group,
      *  *always keeps in: account_types, accounts, email_virtual, carvas,
      *      group_members, homonyms_list, newsletter_ins, register_mstats, email_source_account
      *  *deletes if $clearAll: account_auth_openid, announce_read, contacts,
@@ -728,7 +739,7 @@ class User extends PlUser
     {
         $tables = array('account_lost_passwords', 'register_marketing',
                         'register_pending', 'register_subs', 'watch_nonins',
-                        'watch', 'watch_promo');
+                        'watch', 'watch_promo', 'watch_group');
 
         foreach ($tables as $t) {
             XDB::execute('DELETE FROM  ' . $t . '
index cb8f5de..2604a37 100644 (file)
@@ -966,7 +966,7 @@ class UFC_Email extends UserFilterCondition
         $cond    = array();
 
         if (count($this->emails) == 0) {
-            return PlFilterCondition::COND_TRUE;
+            return PlFilterCondition::COND_FALSE;
         }
 
         foreach ($this->emails as $entry) {
@@ -1582,6 +1582,27 @@ class UFC_WatchPromo extends UFC_UserRelated
     }
 }
 // }}}
+// {{{ class UFC_WatchGroup
+/** Filters users belonging to a group watched by selected user
+ * @param $user Selected user (the one watching group)
+ */
+class UFC_WatchGroup extends UFC_UserRelated
+{
+    public function buildCondition(PlFilter $uf)
+    {
+        $groups = $this->user->watchGroups();
+        if (count($groups) == 0) {
+            return PlFilterCondition::COND_FALSE;
+        }
+        $conditions = array();
+        foreach ($groups as $group) {
+            $sub = $uf->addGroupFilter($group);
+            $conditions[] = 'gpm' . $sub . '.perms IS NOT NULL';
+        }
+        return implode(' OR ', $conditions);
+    }
+}
+// }}}
 // {{{ class UFC_WatchContact
 /** Filters users watched by selected user
  */
index b6fe1f7..b7a8c1f 100644 (file)
@@ -29,7 +29,7 @@ class XnetSession extends XorgSession
     public function startAvailableAuth()
     {
         if (!S::logged() && Get::has('auth')) {
-            if (!$this->start(AUTH_MDP)) {
+            if (!$this->start(AUTH_PASSWD)) {
                 return false;
             }
         }
@@ -88,7 +88,7 @@ class XnetSession extends XorgSession
             return null;
         }
         Get::kill('auth');
-        S::set('auth', AUTH_MDP);
+        S::set('auth', AUTH_PASSWD);
         return User::getSilentWithValues(null, array('uid' => Get::i('uid')));
     }
 
@@ -100,7 +100,7 @@ class XnetSession extends XorgSession
         }
 
         if ($level == AUTH_SUID) {
-            S::set('auth', AUTH_MDP);
+            S::set('auth', AUTH_PASSWD);
         }
 
         S::set('uid', $user->uid);
index 84128af..af7cd9e 100644 (file)
@@ -138,16 +138,19 @@ class XorgSession extends PlSession
 
         $user = User::getSilent($login);
 
-        $success = $this->checkPassword($login, $user, Post::v('response'));
-
-        if (!is_null($user) && S::suid()) {
-            $success = (S::suid('uid') == $user->id());
+        if (is_null($user)) {
+            Platal::page()->trigError(self::TEXT_INVALID_LOGIN);
+            $success = false;
         } else {
-            $success = $this->checkPassword($login, $user, Post::v('response'));
+            if (S::suid()) {
+                $success = (S::suid('uid') == $user->id());
+            } else {
+                $success = $this->checkPassword($login, $user, Post::v('response'));
+            }
         }
 
         if ($success) {
-            S::set('auth', AUTH_MDP);
+            S::set('auth', AUTH_PASSWD);
             S::kill('challenge');
             S::logger($user->id())->log('auth_ok');
         }
@@ -163,7 +166,7 @@ class XorgSession extends PlSession
             return true;
         }
         if ($level == AUTH_SUID) {
-            S::set('auth', AUTH_MDP);
+            S::set('auth', AUTH_PASSWD);
         }
 
         // Loads uid and hruid into the session for developement conveniance.
@@ -303,7 +306,7 @@ class XorgSession extends PlSession
 
     public function sureLevel()
     {
-        return AUTH_MDP;
+        return AUTH_PASSWD;
     }
 
 
diff --git a/core b/core
index a552b53..7446ea5 160000 (submodule)
--- a/core
+++ b/core
@@ -1 +1 @@
-Subproject commit a552b53ac5b4e512720d77b457bfda823ed3e10b
+Subproject commit 7446ea512d015e4b6b07ed378bed4bb9fd5418ba
index d13d2f6..ed74318 100644 (file)
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
  ***************************************************************************/
 
-.ac_results {
-    background-color: window;
-    border: 1px solid;
-    overflow: hidden;
-    padding: 0px;
+.ui-autocomplete {
+    position: absolute;
+    cursor: pointer;
 }
 
-.ac_results ul {
-    padding:0px;
-    margin:0px;
-    width:100%;
+.ui-menu {
+    list-style: none;
+    padding: 0px;
+    margin: 0;
+    display: block;
+    border: 1px solid black;
+    background: white;
+    color: black;
 }
-
-.ac_results li {
-    display:block;
-    padding: 2px;
-    cursor:pointer;
-    font-size: 90%;
+.ui-menu .ui-menu-item {
+    margin: 0;
+    padding: 0;
+    width: 100%;
 }
-
-.ac_results iframe {
-    display:none;/*sorry for IE5*/
-    display/**/:block;/*sorry for IE5*/
-    position:absolute;
-    top:0;
-    left:0;
-    z-index:-1;
-    filter:mask();
-    width:3000px;
-    height:3000px;
+.ui-menu .ui-menu-item a {
+    text-decoration: none;
+    display: block;
+    padding: .2em .4em;
 }
 
-.ac_over {
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
     background: highlight;
     color: highlighttext;
 }
index f0dd75a..ac7e1b2 100644 (file)
@@ -748,8 +748,8 @@ div#content {
     font-size: 85%;
 }
 
-.ac_results {
-       color:  black;
+.ui-menu {
+       color: black;
 }
 
 /* vim: set et ts=4 sts=4 sw=4: */
diff --git a/htdocs/javascript/jquery.autocomplete.js b/htdocs/javascript/jquery.autocomplete.js
deleted file mode 100644 (file)
index 4e211a1..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * jQuery autocomplete plugin
- * Version 2.0.0  (2008-03-22)
- * @requires jQuery v1.1.1+
- *
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- * Dylan Verheul
- * http://www.dyve.net/jquery
- *
- */
-(function($) {
-       /**
-        * The autocompleter object
-        */
-       $.autocomplete = function(input, options) {
-
-               // Create a link to self
-               var me = this;
-               // Create jQuery object for input element
-               var $input = $(input).attr("autocomplete", "off");
-               // Apply inputClass if necessary
-               if (options.inputClass) {
-                       $input.addClass(options.inputClass);
-               }
-
-               // Create results
-               var results = document.createElement("div");
-
-               // Create jQuery object for results
-               // var $results = $(results);
-               var $results = $(results).hide().addClass(options.resultsClass).css("position", "absolute");
-               if( options.width > 0 ) {
-                       $results.css("width", options.width);
-               }
-
-               // Add to body element
-               $("body").append(results);
-
-               input.autocompleter = me;
-
-               var timeout = null;
-               var prev = "";
-               var active = -1;
-               var cache = {};
-               var keyb = false;
-               var hasFocus = false;
-               var lastKeyPressCode = null;
-               var mouseDownOnSelect = false;
-               var hidingResults = false;
-
-               // flush cache
-               function flushCache(){
-                       cache = {};
-                       cache.data = {};
-                       cache.length = 0;
-               };
-
-               // flush cache
-               flushCache();
-
-               // if there is a data array supplied
-               if( options.data != null ){
-                       var sFirstChar = "", stMatchSets = {}, row = [];
-
-                       // no url was specified, we need to adjust the cache length to make sure it fits the local data store
-                       if (typeof options.url != "string") {
-                               options.cacheLength = 1;
-                       }
-
-                       // loop through the array and create a lookup structure
-                       for( var i=0; i < options.data.length; i++ ){
-                               // if row is a string, make an array otherwise just reference the array
-                               row = ((typeof options.data[i] == "string") ? [options.data[i]] : options.data[i]);
-
-                               // if the length is zero, don't add to list
-                               if( row[0].length > 0 ){
-                                       // get the first character
-                                       sFirstChar = row[0].substring(0, 1).toLowerCase();
-                                       // if no lookup array for this character exists, look it up now
-                                       if( !stMatchSets[sFirstChar] ) stMatchSets[sFirstChar] = [];
-                                       // if the match is a string
-                                       stMatchSets[sFirstChar].push(row);
-                               }
-                       }
-
-                       // add the data items to the cache
-                       for (var k in stMatchSets) {
-                               // increase the cache size
-                               options.cacheLength++;
-                               // add to the cache
-                               addToCache(k, stMatchSets[k]);
-                       }
-               }
-
-               $input
-               .keydown(function(e) {
-                       // track last key pressed
-                       lastKeyPressCode = e.keyCode;
-                       switch(e.keyCode) {
-                               case 38: // up
-                                       e.preventDefault();
-                                       moveSelect(-1);
-                                       break;
-                               case 40: // down
-                                       e.preventDefault();
-                                       moveSelect(1);
-                                       break;
-                               case 9:  // tab
-                               case 13: // return
-                                       if( selectCurrent() ){
-                                               // make sure to blur off the current field
-                                               $input.blur();
-                                               e.preventDefault();
-                                               // give focus with a small timeout (weird behaviour in FF)
-                                               setTimeout(function() { $input.focus() }, 10);
-                                       }
-                                       break;
-                               default:
-                                       active = -1;
-                                       if (timeout) clearTimeout(timeout);
-                                       timeout = setTimeout(onChange, options.delay);
-                                       break;
-                       }
-               })
-               .focus(function(){
-                       // track whether the field has focus, we shouldn't process any results if the field no longer has focus
-                       hasFocus = true;
-               })
-               .blur(function() {
-                       // track whether the field has focus
-                       hasFocus = false;
-                       if (!mouseDownOnSelect) {
-                               hideResults();
-                       }
-               });
-
-               hideResultsNow();
-
-               function onChange() {
-                       // ignore if the following keys are pressed: [del] [shift] [capslock]
-                       if( lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32) ) return $results.hide();
-                       var v = $input.val();
-                       if (v == prev) return;
-                       prev = v;
-                       if (v.length >= options.minChars) {
-                               $input.addClass(options.loadingClass);
-                               requestData(v);
-                       } else {
-                               $input.removeClass(options.loadingClass);
-                               $results.hide();
-                       }
-               };
-
-               function moveSelect(step) {
-
-                       var lis = $("li", results);
-                       if (!lis) return;
-
-                       active += step;
-
-                       if (active < 0) {
-                               active = 0;
-                       } else if (active >= lis.size()) {
-                               active = lis.size() - 1;
-                       }
-
-                       lis.removeClass("ac_over");
-
-                       $(lis[active]).addClass("ac_over");
-
-                       // Weird behaviour in IE
-                       // if (lis[active] && lis[active].scrollIntoView) {
-                       //      lis[active].scrollIntoView(false);
-                       // }
-
-               };
-
-               function selectCurrent() {
-                       var li = $("li.ac_over", results)[0];
-                       if (!li) {
-                               var $li = $("li", results);
-                               if (options.selectOnly) {
-                                       if ($li.length == 1) li = $li[0];
-                               } else if (options.selectFirst) {
-                                       li = $li[0];
-                               }
-                       }
-                       if (li) {
-                               selectItem(li);
-                               return true;
-                       } else {
-                               return false;
-                       }
-               };
-
-               function selectItem(li) {
-                       if (!li) {
-                               li = document.createElement("li");
-                               li.extra = [];
-                               li.selectValue = "";
-                       }
-                       var v = $.trim(li.selectValue ? li.selectValue : li.innerHTML);
-                       input.lastSelected = v;
-                       prev = v;
-                       $results.html("");
-                       $input.val(v);
-                       hideResultsNow();
-                       if (options.onItemSelect) {
-                               setTimeout(function() { options.onItemSelect(li) }, 1);
-                       }
-               };
-
-               // selects a portion of the input string
-               function createSelection(start, end){
-                       // get a reference to the input element
-                       var field = $input.get(0);
-                       if( field.createTextRange ){
-                               var selRange = field.createTextRange();
-                               selRange.collapse(true);
-                               selRange.moveStart("character", start);
-                               selRange.moveEnd("character", end);
-                               selRange.select();
-                       } else if( field.setSelectionRange ){
-                               field.setSelectionRange(start, end);
-                       } else {
-                               if( field.selectionStart ){
-                                       field.selectionStart = start;
-                                       field.selectionEnd = end;
-                               }
-                       }
-                       field.focus();
-               };
-
-               // fills in the input box w/the first match (assumed to be the best match)
-               function autoFill(sValue){
-                       // if the last user key pressed was backspace, don't autofill
-                       if( lastKeyPressCode != 8 ){
-                               // fill in the value (keep the case the user has typed)
-                               $input.val($input.val() + sValue.substring(prev.length));
-                               // select the portion of the value not typed by the user (so the next character will erase)
-                               createSelection(prev.length, sValue.length);
-                       }
-               };
-
-               function showResults() {
-                       // get the position of the input field right now (in case the DOM is shifted)
-                       var pos = findPos(input);
-                       // either use the specified width, or autocalculate based on form element
-                       var iWidth = (options.width > 0) ? options.width : $input.width();
-                       // reposition
-                       $results.css({
-                               width: parseInt(iWidth) + "px",
-                               top: (pos.y + input.offsetHeight) + "px",
-                               left: pos.x + "px"
-                       }).show();
-               };
-
-               function hideResults() {
-                       if (timeout) clearTimeout(timeout);
-                       timeout = setTimeout(hideResultsNow, 200);
-               };
-
-               function hideResultsNow() {
-                       if (hidingResults) {
-                               return;
-                       }
-                       hidingResults = true;
-
-                       if (timeout) {
-                               clearTimeout(timeout);
-                       }
-
-                       var v = $input.removeClass(options.loadingClass).val();
-
-                       if ($results.is(":visible")) {
-                               $results.hide();
-                       }
-
-                       if (options.mustMatch) {
-                               if (!input.lastSelected || input.lastSelected != v) {
-                                       selectItem(null);
-                               }
-                       }
-
-                       hidingResults = false;
-               };
-
-               function receiveData(q, data) {
-                       if (data) {
-                               $input.removeClass(options.loadingClass);
-                               results.innerHTML = "";
-
-                               // if the field no longer has focus or if there are no matches, do not display the drop down
-                               if( !hasFocus || data.length == 0 ) return hideResultsNow();
-
-                               if ($.browser.msie) {
-                                       // we put a styled iframe behind the calendar so HTML SELECT elements don't show through
-                                       $results.append(document.createElement('iframe'));
-                               }
-                               results.appendChild(dataToDom(data));
-                               // autofill in the complete box w/the first match as long as the user hasn't entered in more data
-                               if( options.autoFill && ($input.val().toLowerCase() == q.toLowerCase()) ) autoFill(data[0][0]);
-                               showResults();
-                       } else {
-                               hideResultsNow();
-                       }
-               };
-
-               function parseData(data) {
-                       if (!data) return null;
-                       var parsed = [];
-                       var rows = data.split(options.lineSeparator);
-                       for (var i=0; i < rows.length; i++) {
-                               var row = $.trim(rows[i]);
-                               if (row) {
-                                       parsed[parsed.length] = row.split(options.cellSeparator);
-                               }
-                       }
-                       return parsed;
-               };
-
-               function dataToDom(data) {
-                       var ul = document.createElement("ul");
-                       var num = data.length;
-
-                       // limited results to a max number
-                       if( (options.maxItemsToShow > 0) && (options.maxItemsToShow < num) ) num = options.maxItemsToShow;
-
-                       for (var i=0; i < num; i++) {
-                               var row = data[i];
-                               if (!row) continue;
-                               var li = document.createElement("li");
-                               if (options.formatItem) {
-                                       li.innerHTML = options.formatItem(row, i, num);
-                                       li.selectValue = row[0];
-                               } else {
-                                       li.innerHTML = row[0];
-                                       li.selectValue = row[0];
-                               }
-                               var extra = null;
-                               if (row.length > 1) {
-                                       extra = [];
-                                       for (var j=1; j < row.length; j++) {
-                                               extra[extra.length] = row[j];
-                                       }
-                               }
-                               li.extra = extra;
-                               ul.appendChild(li);
-
-                               $(li).hover(
-                                       function() {
-                                               var $this = $(this);
-                                               active = $("li", ul).removeClass("ac_over").index($this[0]);
-                                               $this.addClass("ac_over");
-                                       },
-                                       function() {
-                                               $(this).removeClass("ac_over");
-                                       }
-                               ).click(function(e) {
-                                       e.preventDefault();
-                                       e.stopPropagation();
-                                       selectItem(this)
-                               });
-
-                       }
-                       $(ul).mousedown(function() {
-                               mouseDownOnSelect = true;
-                       }).mouseup(function() {
-                               mouseDownOnSelect = false;
-                       });
-                       return ul;
-               };
-
-               function requestData(q) {
-                       if (!options.matchCase) q = q.toLowerCase();
-                       var data = options.cacheLength ? loadFromCache(q) : null;
-                       // recieve the cached data
-                       if (data) {
-                               receiveData(q, data);
-                       // if an AJAX url has been supplied, try loading the data now
-                       } else if( (typeof options.url == "string") && (options.url.length > 0) ){
-                               $.get(makeUrl(q), function(data) {
-                                       data = parseData(data);
-                                       addToCache(q, data);
-                                       receiveData(q, data);
-                               });
-                       // if there's been no data found, remove the loading class
-                       } else {
-                               $input.removeClass(options.loadingClass);
-                       }
-               };
-
-               function makeUrl(q) {
-                       var sep = options.url.indexOf('?') == -1 ? '?' : '&';
-                       var url = options.url + sep + "q=" + encodeURI(q);
-                       for (var i in options.extraParams) {
-                               url += "&" + i + "=" + encodeURI(options.extraParams[i]);
-                       }
-                       return url;
-               };
-
-               function loadFromCache(q) {
-                       if (!q) return null;
-                       if (cache.data[q]) return cache.data[q];
-                       if (options.matchSubset) {
-                               for (var i = q.length - 1; i >= options.minChars; i--) {
-                                       var qs = q.substr(0, i);
-                                       var c = cache.data[qs];
-                                       if (c) {
-                                               var csub = [];
-                                               for (var j = 0; j < c.length; j++) {
-                                                       var x = c[j];
-                                                       var x0 = x[0];
-                                                       if (matchSubset(x0, q)) {
-                                                               csub[csub.length] = x;
-                                                       }
-                                               }
-                                               return csub;
-                                       }
-                               }
-                       }
-                       return null;
-               };
-
-               function matchSubset(s, sub) {
-                       if (!options.matchCase) s = s.toLowerCase();
-                       var i = s.indexOf(sub);
-                       if (i == -1) return false;
-                       return i == 0 || options.matchContains;
-               };
-
-               this.flushCache = function() {
-                       flushCache();
-               };
-
-               this.setExtraParams = function(p) {
-                       options.extraParams = p;
-               };
-
-               this.findValue = function(){
-                       var q = $input.val();
-
-                       if (!options.matchCase) q = q.toLowerCase();
-                       var data = options.cacheLength ? loadFromCache(q) : null;
-                       if (data) {
-                               findValueCallback(q, data);
-                       } else if( (typeof options.url == "string") && (options.url.length > 0) ){
-                               $.get(makeUrl(q), function(data) {
-                                       data = parseData(data)
-                                       addToCache(q, data);
-                                       findValueCallback(q, data);
-                               });
-                       } else {
-                               // no matches
-                               findValueCallback(q, null);
-                       }
-               }
-
-               function findValueCallback(q, data){
-                       if (data) $input.removeClass(options.loadingClass);
-
-                       var num = (data) ? data.length : 0;
-                       var li = null;
-
-                       for (var i=0; i < num; i++) {
-                               var row = data[i];
-
-                               if( row[0].toLowerCase() == q.toLowerCase() ){
-                                       li = document.createElement("li");
-                                       if (options.formatItem) {
-                                               li.innerHTML = options.formatItem(row, i, num);
-                                               li.selectValue = row[0];
-                                       } else {
-                                               li.innerHTML = row[0];
-                                               li.selectValue = row[0];
-                                       }
-                                       var extra = null;
-                                       if( row.length > 1 ){
-                                               extra = [];
-                                               for (var j=1; j < row.length; j++) {
-                                                       extra[extra.length] = row[j];
-                                               }
-                                       }
-                                       li.extra = extra;
-                               }
-                       }
-
-                       if( options.onFindValue ) setTimeout(function() { options.onFindValue(li) }, 1);
-               }
-
-               function addToCache(q, data) {
-                       if (!data || !q || !options.cacheLength) return;
-                       if (!cache.length || cache.length > options.cacheLength) {
-                               flushCache();
-                               cache.length++;
-                       } else if (!cache[q]) {
-                               cache.length++;
-                       }
-                       cache.data[q] = data;
-               };
-
-               function findPos(obj) {
-                       var curleft = obj.offsetLeft || 0;
-                       var curtop = obj.offsetTop || 0;
-                       while (obj = obj.offsetParent) {
-                               curleft += obj.offsetLeft
-                               curtop += obj.offsetTop
-                       }
-                       return {x:curleft,y:curtop};
-               }
-       }
-
-       /**
-        * The autocomplete plugin itself
-        */
-       $.fn.autocomplete = function(url, options, data) {
-
-               // Make sure options exists
-               options = options || {};
-               // Set url as option
-               options.url = url;
-               // set some bulk local data
-               options.data = ((typeof data == "object") && (data.constructor == Array)) ? data : null;
-
-               // Set default values for required options (set global defaults in $.fn.autocomplete.defaults)
-               options = $.extend({
-                       inputClass: "ac_input",
-                       resultsClass: "ac_results",
-                       lineSeparator: "\n",
-                       cellSeparator: "|",
-                       minChars: 1,
-                       delay: 400,
-                       matchCase: 0,
-                       matchSubset: 1,
-                       matchContains: 0,
-                       cacheLength: 1,
-                       mustMatch: 0,
-                       extraParams: {},
-                       loadingClass: "ac_loading",
-                       selectFirst: false,
-                       selectOnly: false,
-                       maxItemsToShow: -1,
-                       autoFill: false,
-                       width: 0
-               }, $.fn.autocomplete.defaults, options);
-
-               options.width = parseInt(options.width, 10);
-               
-               return this.each(function() {
-                       var input = this;
-                       new $.autocomplete(input, options);
-               });
-
-       }
-
-})(jQuery);
index b8b1c2c..97de167 100644 (file)
@@ -66,9 +66,12 @@ publicity['public']  = 2;
 
 // Names {{{1
 
-function toggleNamesAdvanced()
+function toggleNamesAdvanced(togglePrivate)
 {
-    $('.names_advanced').toggle();
+    $('.names_advanced_public').toggle();
+    if (togglePrivate) {
+        $('.names_advanced_private').toggle();
+    }
 }
 
 function addSearchName(isFemale)
@@ -261,6 +264,44 @@ function updateNetworking(i)
     $('#networking_' + i).find("[name='networking[" + i + "][name]']").val($('#networking_' + i).find('select option:selected').text());
 }
 
+// Hobby {{{1
+
+function addHobby()
+{
+    var i = 0;
+    while ($('#hobby_' + i).length != 0) {
+        ++i;
+    }
+    var html = '<tr id="hobby_' + i + '">'
+        + '  <td colspan="2">'
+        + '    <div style="float: left; width: 200px;">'
+        + '      <span class="flags">'
+        + '        <input type="checkbox" name="hobbies[' + i + '][pub]"/>'
+        + '        <img src="images/icons/flag_green.gif" alt="site public" title="site public">'
+        + '      </span>&nbsp;'
+        + '      <select name="hobbies[' + i + '][type]">'
+        + '        <option value="Sport">Sport</option>'
+        + '        <option value="Loisir">Loisir</option>'
+        + '        <option value="Hobby">Hobby</option>'
+        + '      </select>'
+        + '    </div>'
+        + '    <div style="float: left">'
+        + '      <input type="text" name="hobbies[' + i + '][text]" value="" size="30"/>'
+        + '      <a href="javascript:removeHobby(' + i + ')">'
+        + '        <img src="images/icons/cross.gif" alt="cross" title="Supprimer cet élément"/>'
+        + '      </a>'
+        + '    </div>'
+        + '  </td>'
+        + '</tr>';
+
+    $('#hobby').before(html);
+}
+
+function removeHobby(id)
+{
+    $('#hobby_' + id).remove();
+}
+
 // Addresses {{{1
 
 function toggleAddress(id, val)
@@ -619,44 +660,28 @@ function removeJobTerm()
 }
 
 /**
- * Prepare display for autocomplete suggestions in job terms
- * @param row an array of (title of term, id of term)
- * @return text to display
- * If id is negative, it is because there are too much terms to
- * be displayed.
- */
-function displayJobTerm(row)
-{
-    if (row[1] < 0) {
-        return '... <em>parcourir les résultats dans un arbre</em> ...';
-    }
-    return row[0];
-}
-
-/**
  * Function called when a job term has been selected from autocompletion
  * in search
  * @param li is the list item (<li>) that has been clicked
  * The context is the jsquery autocomplete object.
  */
-function selectJobTerm(li)
+function selectJobTerm(id, value, jobid)
 {
-    var jobid = this.extraParams.jobid;
-    if (li.extra[0] >= 0) {
-        addJobTerm(jobid,li.extra[0],$(li).text());
+    if (id >= 0) {
+        addJobTerm(jobid, id, value);
     }
     var search_input;
     if (jobid < 0) {
         search_input = $('.term_search')[0];
     } else {
-        search_input = $('#jobs_'+jobid+' .term_search')[0];
+        search_input = $('#jobs_' + jobid + ' .term_search')[0];
     }
-    if (li.extra[0] >= 0) {
+    if (id >= 0) {
         search_input.value = '';
         search_input.focus();
     } else {
-        search_input.value = li.selectValue.replace(/%$/,'');
-        toggleJobTermsTree(jobid, li.selectValue);
+        search_input.value = value.replace(/%$/, '');
+        toggleJobTermsTree(jobid, ''); // Use given value instead
     }
 }
 
@@ -728,31 +753,18 @@ function addCountry()
 
 function registerEnterpriseAutocomplete(id)
 {
-    $(".enterpriseName").each(
-      function() {
+    $('.enterprise_name').each(function() {
         if (id == -1 || this.name == "jobs[" + id + "][name]") {
-            $(this).autocomplete($.plURL("search/autocomplete/entreprise"),
-                                 {
-                                     selectOnly:1,
-                                     field:this.name,
-                                     matchSubset:0,
-                                     width:$(this).width()
-                                 });
+            $(this).autocomplete({
+                source: $.plURL('search/autocomplete/entreprise/') + this.name,
+                change: function(event, ui) {
+                    if (ui.item != null && ui.item.field != null) {
+                        $(this).val(ui.item.field);
+                    }
+                }
+            });
         }
-      });
-
-    $(".sectorName").each(
-      function() {
-        if (id == -1 || this.name == "jobs[" + id + "][subSubSectorName]") {
-            $(this).autocomplete($.plURL("search/autocomplete/subSubSector"),
-                                 {
-                                     selectOnly:1,
-                                     field:this.name,
-                                     matchSubset:0,
-                                     width:$(this).width()
-                                 });
-        }
-      });
+    });
 }
 
 // {{{1 Multiusage functions
index ddee7d9..52870ad 100644 (file)
 var baseurl = $.plURL('search/');
 var address_types = new Array('country', 'administrative_area_level_1', 'administrative_area_level_2', 'locality', 'postal_code');
 var address_types_count = address_types.length;
+var autocomplete_sub = {'country': 'locality_text'};
 
 function load_advanced_search(request)
 {
     $('.autocomplete_target').hide();
     $('.autocomplete').show().each(function() {
-        $(this).autocomplete(baseurl + 'autocomplete/' + this.name, {
-            selectOnly: 1,
-            formatItem: make_format_autocomplete(this),
-            field: this.name,
-            onItemSelect: select_autocomplete(this.name),
-            matchSubset: 0,
-            width: $(this).width()
+        $(this).autocomplete({
+            source: baseurl + 'autocomplete/' + this.name,
+            select: function(event, ui) {
+                select_autocomplete(this.name, ui.item.id);
+            },
+            change: function(event, ui) {
+                if (ui.item != null && ui.item.field != null) {
+                    $(this).val(ui.item.field);
+                }
+            }
         });
     });
 
@@ -148,25 +152,6 @@ function cleanForm(f, targeturl)
 // }}}
 // {{{ Autocomplete related functions.
 
-// display an autocomplete row : blabla (nb of found matches)
-function make_format_autocomplete(block)
-{
-    return function(row) {
-        regexp = new RegExp('(' + RegExp.escape(block.value) + ')', 'i');
-        name = row[0].htmlEntities().replace(regexp, '<strong>$1<\/strong>');
-
-        if (row[1] === '-1') {
-            return '&hellip;';
-        }
-        if (row[1] === '-2') {
-            return '<em>aucun camarade trouvé pour '+row[0].htmlEntities()+'<\/em>';
-        }
-
-        mate = (row[1] > 1) ? 'camarades' : 'camarade';
-        return name + '<em>&nbsp;&nbsp;-&nbsp;&nbsp;' + row[1].htmlEntities() + '&nbsp;' + mate + '<\/em>';
-    };
-}
-
 function cancel_autocomplete(field, realfield)
 {
     $(".autocomplete[name='" + field + "']").removeClass('hidden_valid').val('').focus();
@@ -177,46 +162,45 @@ function cancel_autocomplete(field, realfield)
 }
 
 // when choosing autocomplete from list, must validate
-function select_autocomplete(name)
+function select_autocomplete(name, id)
 {
     var field_name = name.replace(/_text$/, '');
+    if (autocomplete_sub[field_name] != null) {
+        $(".autocomplete[name='" + autocomplete_sub[field_name] + "']").autocomplete('option', 'source', baseurl + 'autocomplete/' + autocomplete_sub[field_name] + '/' + id);
+    }
 
     // just display field as valid if field is not a text field for a list
     if (field_name == name) {
-        return function(i) {
-            $(".autocomplete[name='" + name + "']").addClass('hidden_valid');
-        }
+        $(".autocomplete[name='" + name + "']").addClass('hidden_valid');
+        return;
     }
 
     // When changing country, locality or school, open next address component.
     if (field_name == 'country' || field_name == 'locality' || field_name == 'school') {
-        return function(i) {
-            if (i.extra[0] < 0) {
-                cancel_autocomplete(name, field_name);
-                i.extra[1] = '';
-            }
-
-            if (field_name == 'school') {
-                changeSchool(i.extra[1], '');
-            } else {
-                changeAddressComponents(field_name, i.extra[1]);
-            }
-
-            $(".autocomplete_target[name='" + field_name + "']").attr('value', i.extra[1]);
-            $(".autocomplete[name='" + name + "']").addClass('hidden_valid');
+        if (id < 0) {
+            cancel_autocomplete(name, field_name);
+            id = '';
         }
-    }
 
-    // change field in list and display text field as valid
-    return function(i) {
-        if (i.extra[0] < 0) {
-            cancel_autocomplete(this.field, field_name);
-            return;
+        if (field_name == 'school') {
+            changeSchool(id, '');
+        } else {
+            changeAddressComponents(field_name, id);
         }
 
-        $(".autocomplete_target[name='" + field_name + "']").attr('value', i.extra[1]);
+        $(".autocomplete_target[name='" + field_name + "']").attr('value', id);
         $(".autocomplete[name='" + name + "']").addClass('hidden_valid');
+        return;
     }
+
+    // change field in list and display text field as valid
+    if (id < 0) {
+        cancel_autocomplete(this.field, field_name);
+        return;
+    }
+
+    $(".autocomplete_target[name='" + field_name + "']").attr('value', id);
+    $(".autocomplete[name='" + name + "']").addClass('hidden_valid');
 }
 
 // }}}
@@ -260,6 +244,10 @@ function displayNextAddressComponent(i, j, value)
         $("select[name='locality_text']").attr('value', '');
     }
 
+    if (autocomplete_sub[prev_type] != null) {
+        $(".autocomplete[name='" + autocomplete_sub[prev_type] + "']").autocomplete('option', 'source', baseurl + 'autocomplete/' + autocomplete_sub[prev_type] + '/' + value);
+    }
+
     $('#' + next_list).load(baseurl + 'list/' + next_type, { previous:prev_type, value:value }, function() {
         $("select[name='" + next_type + "']").attr('value', '');
         if ($("select[name='" + next_type + "']").children('option').size() > 1) {
@@ -331,5 +319,14 @@ function searchForJobTerm(treeid, jtid, full_name)
     $("input[name='jobterm']").val(jtid);
 }
 
+function addressesDump()
+{
+    if ($('#addresses_dump:checked').length > 0) {
+        $('#recherche').attr('action', 'search/adv/addresses').attr('method', 'post').removeAttr('onsubmit');
+    } else {
+        $('#recherche').attr('action', 'search/adv').attr('method', 'get');
+    }
+}
+
 // }}}
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 1e32840..2cf14d8 100644 (file)
@@ -30,7 +30,20 @@ function require_email_update(User $user, $new_email)
 {
     Platal::assert(!is_null($user), 'User cannot be null.');
 
-    return !$user->checkPerms(User::PERM_MAIL) && strtolower($new_email) != strtolower($user->forlifeEmail());
+    $is_new = !$user->checkPerms(User::PERM_MAIL) && $new_email != strtolower($user->email);
+    if ($new_email && $is_new) {
+        $already = XDB::fetchOneCell('SELECT  hruid
+                                        FROM  accounts
+                                       WHERE  email = {?} AND uid != {?}',
+                                     $new_email, $user->id());
+        if ($already) {
+            Platal::page()->trigError("L'email ne peut pas être utilisé pour ce compte car il correspond déjà au compte : "
+                                      . $already . ". Si l'utilisateur courant et cette personne ne sont en fait qu'une "
+                                      . "seul et même personne, ou en cas de problème, contacter : contact@polytechnique.org");
+            return false;
+        }
+    }
+    return $is_new;
 }
 
 function format_email_alias($email)
@@ -298,11 +311,17 @@ function valide_email($str)
 // function isvalid_email_redirection() {{{1
 /** Checks if an email is a suitable redirection.
  * @param $email the email to check
+ * @param $user  the user asking for the redirection
  * @return BOOL
  */
-function isvalid_email_redirection($email)
+function isvalid_email_redirection($email, User $user)
 {
-    return isvalid_email($email) && !preg_match("/@polytechnique\.edu$/", $email) && User::isForeignEmailAddress($email);
+    $valid = isvalid_email($email) && User::isForeignEmailAddress($email);
+    if (!$user->hasProfile() || ($user->profile()->grad_year > date('Y') - 3)) {
+        return $valid && !preg_match("/@polytechnique\.edu$/", $email);
+    } else {
+        return $valid;
+    }
 }
 
 // function ids_from_mails() {{{1
@@ -785,7 +804,7 @@ class Redirect
         if (!isvalid_email($email_stripped)) {
             return ERROR_INVALID_EMAIL;
         }
-        if (!isvalid_email_redirection($email_stripped)) {
+        if (!isvalid_email_redirection($email_stripped, $this->user)) {
             return ERROR_LOOP_EMAIL;
         }
         // We first need to retrieve the value for the antispam filter: it is
@@ -797,6 +816,9 @@ class Redirect
         XDB::execute('REPLACE INTO  email_redirect_account (uid, redirect, flags, action)
                             VALUES  ({?}, {?}, \'active\', {?})',
                      $this->user->id(), $email, $filter);
+        $listClient = new MMList(S::user());
+        $listClient->change_user_email($this->user->forlifeEmail(), $new_email);
+        update_alias_user($this->user->forlifeEmail(), $new_email);
         if ($logger = S::v('log', null)) { // may be absent --> step4.php
             S::logger()->log('email_add', $email . ($this->user->id() != S::v('uid') ? " (admin on {$this->user->login()})" : ""));
         }
index 224d497..7f1975c 100644 (file)
@@ -105,15 +105,13 @@ class NewsLetter
     /** Retrieve all newsletters
      * @return An array of $id => NewsLetter objects
      */
-    public static function getAll()
+    public static function getAll($sort = 'id', $order = 'ASC')
     {
-        $res = XDB::query('SELECT  id
-                             FROM  newsletters');
-        $nls = array();
-        foreach ($res->fetchColumn() as $id) {
-            $nls[$id] = new NewsLetter($id);
-        }
-        return $nls;
+        $res = XDB::fetchAllAssoc('SELECT  n.id, g.nom AS group_name, n.name, n.custom_css, n.criteria, g.diminutif AS group_link
+                                     FROM  newsletters AS n
+                               INNER JOIN  groups      AS g ON (n.group_id = g.id)
+                                 ORDER BY  ' . $sort . ' ' . $order);
+        return $res;
     }
 
     // }}}
@@ -407,6 +405,20 @@ class NewsLetter
                                    WHERE  nlid = {?}', $this->id);
     }
 
+    /** Get the count of subscribers with non valid redirection.
+     */
+    public function lostSubscriberCount()
+    {
+        return XDB::fetchOneCell('SELECT  COUNT(DISTINCT(n.uid))
+                                    FROM  newsletter_ins         AS n
+                              INNER JOIN  accounts               AS a ON (n.uid = a.uid)
+                              INNER JOIN  account_types          AS t ON (t.type = a.type)
+                               LEFT JOIN  email_redirect_account AS r ON (r.uid = a.uid AND r.flags = \'active\' AND r.broken_level < 3
+                                                                          AND r.type != \'imap\' AND r.type != \'homonym\')
+                                   WHERE  n.nlid = {?} AND r.redirect IS NULL AND a.state = \'active\' AND FIND_IN_SET(\'mail\', t.perms)',
+                                 $this->id);
+    }
+
     /** Get the number of subscribers to the NL whose last received mailing was $last.
      * @p $last ID of the issue for which subscribers should be counted.
      * @return Number of subscribers
@@ -623,6 +635,7 @@ class NLIssue
     public $send_before;  // Date at which issue should be sent
     public $head;  // Foreword of the issue (or body for letters with no articles)
     public $signature;  // Signature of the letter
+    public $reply_to;  // Adress to reply to the message (can be empty)
     public $arts = array();  // Articles of the issue
 
     const BATCH_SIZE = 60;  // Number of emails to send every minute.
@@ -647,7 +660,7 @@ class NLIssue
     {
         // Load this issue
         $res = XDB::query('SELECT  nlid, short_name, date, send_before, state, sufb_json,
-                                   title, mail_title, head, signature
+                                   title, mail_title, head, signature, reply_to
                              FROM  newsletter_issues
                             WHERE  id = {?}',
                           $id);
@@ -670,6 +683,7 @@ class NLIssue
         $this->title_mail  = $issue['mail_title'];
         $this->head        = $issue['head'];
         $this->signature   = $issue['signature'];
+        $this->reply_to    = $issue['reply_to'];
         $this->sufb        = $this->importJSonStoredUFB($issue['sufb_json']);
 
         if ($fetch_articles) {
@@ -872,6 +886,7 @@ class NLIssue
     // }}}
     // {{{ Edition, articles
 
+    const ERROR_INVALID_REPLY_TO = 'invalid_reply_to';
     const ERROR_INVALID_SHORTNAME = 'invalid_shortname';
     const ERROR_INVALID_UFC = 'invalid_ufc';
     const ERROR_TOO_LONG_UFC = 'too_long_ufc';
@@ -891,6 +906,12 @@ class NLIssue
             'signature' => $this->signature,
         );
 
+        if (!empty($this->reply_to) && !isvalid_email($this->reply_to)) {
+            $errors[] = self::ERROR_INVALID_REPLY_TO ;
+        } else {
+            $fields['reply_to'] = $this->reply_to;
+        }
+
         if ($this->isEditable()) {
             $fields['date'] = $this->date;
             if (!preg_match('/^[-a-z0-9]+$/i', $this->shortname) || is_numeric($this->shortname)) {
@@ -1167,6 +1188,9 @@ class NLIssue
         $mailer->assign('user', $user);
         $mailer->assign('prefix',  null);
         $mailer->assign('hash',    $hash);
+        if (!empty($this->reply_to)) {
+            $mailer->addHeader('Reply-To', $this->reply_to);
+        }
         $mailer->sendTo($user);
     }
 
@@ -1205,7 +1229,7 @@ class NLIssue
                        $this->id);
 
         $ufc = new PFC_And($this->getRecipientsUFC(), new UFC_NLSubscribed($this->nl->id, $this->id), new UFC_HasValidEmail());
-        $uf = new UserFilter($ufc, array(new UFO_IsAdmin(), new UFO_Uid()));
+        $uf = new UserFilter($ufc, array(new UFO_IsAdmin(true), new UFO_Uid()));
         $limit = new PlLimit(self::BATCH_SIZE);
         $global_sent = array();
 
index d79de44..088c4a1 100644 (file)
@@ -130,7 +130,8 @@ class WatchRegistration extends WatchOperation
     {
         return new PFC_And(new UFC_Registered(false, '>', $watch->date()),
                            new PFC_Or($watch->contactCondition(),
-                                      $watch->promoCondition()));
+                                      $watch->promoCondition(),
+                                      $watch->groupCondition()));
     }
 
     public function getOrder()
@@ -158,7 +159,8 @@ class WatchDeath extends WatchOperation
     {
         return new PFC_And(new UFC_Dead('>', $watch->date(), true),
                            new PFC_Or($watch->contactCondition(),
-                                      $watch->promoCondition()));
+                                      $watch->promoCondition(),
+                                      $watch->groupCondition()));
     }
 
     public function getOrder()
@@ -205,7 +207,8 @@ class WatchBirthday extends WatchOperation
             $cond = new PFC_Or($cond,
                                new PFC_And($watch->promoCondition(),
                                            new UFC_Promo('>=', $profile->mainGrade(), $profile->yearpromo() - 1),
-                                           new UFC_Promo('<=', $profile->mainGrade(), $profile->yearpromo() + 1)));
+                                           new UFC_Promo('<=', $profile->mainGrade(), $profile->yearpromo() + 1)),
+                               $watch->groupCondition());
         }
         return new PFC_And($select_date, $cond);
     }
@@ -248,6 +251,7 @@ class Watch
     private $date = null;
     private $contactCond = null;
     private $promoCond = null;
+    private $groupCond = null;
 
     private $filters = array();
 
@@ -288,6 +292,14 @@ class Watch
         return $this->promoCond;
     }
 
+    public function groupCondition()
+    {
+        if (!$this->groupCond) {
+            $this->groupCond = new UFC_WatchGroup($this->user);
+        }
+        return $this->groupCond;
+    }
+
     private function fetchEventWatch($class)
     {
         if (!isset(self::$events[$class])) {
index c1dd074..ef574c0 100644 (file)
@@ -36,6 +36,8 @@ abstract class ProfileField
         Profile::FETCH_MENTOR_COUNTRY => 'ProfileMentoringCountries',
         Profile::FETCH_JOB_TERMS      => 'ProfileJobTerms',
         Profile::FETCH_MENTOR_TERMS   => 'ProfileMentoringTerms',
+        Profile::FETCH_SKILL          => 'ProfileSkills',
+        Profile::FETCH_LANGUAGE       => 'ProfileLanguages',
         Profile::FETCH_PARTNER        => 'ProfilePartnerSharing',
     );
 
@@ -374,7 +376,7 @@ class ProfileMedals extends ProfileField
 
     public static function fetchData(array $pids, Visibility $visibility)
     {
-        $data = XDB::iterator('SELECT  pm.pid, pm.mid, pm.gid, pme.text, pme.img, pmge.text AS grade
+        $data = XDB::iterator('SELECT  pm.pid, pm.mid, pm.gid, pme.text, pme.img, pmge.text AS grade, pm.level
                                  FROM  profile_medals AS pm
                             LEFT JOIN  profiles AS p ON (pm.pid = p.pid)
                             LEFT JOIN  profile_medal_enum AS pme ON (pme.id = pm.mid)
@@ -722,6 +724,66 @@ class ProfileMentoringTerms extends ProfileJobTerms
     }
 }
 // }}}
+// {{{ class ProfileSkills                                   [ Field ]
+class ProfileSkills extends ProfileField
+{
+    public $skills = array();
+
+    public function __construct(PlInnerSubIterator $it)
+    {
+        $this->pid = $it->value();
+        while ($skill = $it->next()) {
+            $this->skills[$skill['cid']] = $skill;
+        }
+    }
+
+    public static function fetchData(array $pids, Visibility $visibility)
+    {
+        $data = XDB::iterator('SELECT  ps.cid, pse.text_fr, ps.level, ps.pid
+                                 FROM  profile_skills          AS ps
+                           INNER JOIN  profile_skill_enum      AS pse ON (pse.id = ps.cid)
+                                WHERE  ps.pid IN {?}
+                             ORDER BY  ' . XDB::formatCustomOrder('ps.pid', $pids),
+                              $pids);
+        return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
+    }
+}
+// }}}
+// {{{ class ProfileLanguages                                [ Field ]
+class ProfileLanguages extends ProfileField
+{
+    public $languages = array();
+
+    public function __construct(PlInnerSubIterator $it)
+    {
+        static $levels = array(
+            1 => 'connaissance basique',
+            2 => 'maîtrise des bases',
+            3 => 'maîtrise limitée',
+            4 => 'maîtrise générale',
+            5 => 'bonne maîtrise',
+            6 => 'maîtrise complète'
+        );
+
+        $this->pid = $it->value();
+        while ($language = $it->next()) {
+            $this->languages[$language['lid']] = $language;
+            $this->languages[$language['lid']]['level'] = $levels[$language['level']];
+        }
+    }
+
+    public static function fetchData(array $pids, Visibility $visibility)
+    {
+        $data = XDB::iterator('SELECT  ps.lid, pse.language, ps.level, ps.pid
+                                 FROM  profile_langskills     AS ps
+                           INNER JOIN  profile_langskill_enum AS pse ON (pse.iso_639_2b = ps.lid)
+                                WHERE  ps.pid IN {?}
+                             ORDER BY  ' . XDB::formatCustomOrder('ps.pid', $pids),
+                              $pids);
+        return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
+    }
+}
+// }}}
 // {{{ class ProfilePartnerSharing                    [ Field ]
 class ProfilePartnerSharing extends ProfileField
 {
index 1543b15..5785ea7 100644 (file)
@@ -839,9 +839,10 @@ class UFBF_SchoolIds extends UFB_Field
         }
 
         $value = $ufb->t($this->envfield);
-        $values = explode("\r\n", $value);
+        $values = explode("\n", $value);
         $ids = array();
         foreach ($values as $val) {
+            $val = trim($val);
             if (preg_match('/^[0-9A-Z]{0,8}$/', $val)) {
                 $ids[] = $val;
             }
index 62b5a02..ca097b3 100644 (file)
@@ -425,17 +425,24 @@ class AddressesView implements PlView
     {
         $pids = $this->set->getIds(new PlLimit());
         $visibility = Visibility::defaultForRead(Visibility::VIEW_AX);
-        pl_cached_content_headers('text/x-csv', 1);
+        pl_cached_content_headers('text/x-csv', 'iso-8859-1', 1, 'adresses.csv');
 
         $csv = fopen('php://output', 'w');
-        fputcsv($csv, array('adresses'), ';');
-        $res = XDB::query('SELECT  pd.public_name, pa.postalText
-                             FROM  profile_addresses AS pa
-                       INNER JOIN  profile_display   AS pd ON (pd.pid = pa.pid)
-                            WHERE  pa.type = \'home\' AND pa.pub IN (\'public\', \'ax\') AND FIND_IN_SET(\'mail\', pa.flags) AND pa.pid IN {?}
-                         GROUP BY  pa.pid', $pids);
-        foreach ($res->fetchAllAssoc() as $item) {
-            fputcsv($csv, $item, ';');
+        fputcsv($csv,  array('PROMOTION', 'CIVILITE', 'NOM', 'SOCIETE', 'ADRESSE', 'EMAIL'), ';');
+        if (!empty($pids)) {
+            $res = XDB::query("SELECT  pd.promo, p.title, pd.short_name, UPPER(pje.name),
+                                       pa.postalText, p.email_directory
+                                 FROM  profile_addresses    AS pa
+                           INNER JOIN  profiles             AS p   ON (pa.pid = p.pid)
+                           INNER JOIN  profile_display      AS pd  ON (pd.pid = pa.pid)
+                            LEFT JOIN  profile_job          AS pj  ON (pj.pid = pa.pid)
+                            LEFT JOIN  profile_job_enum     AS pje ON (pj.jobid = pje.id)
+                                WHERE  pa.type = 'home' AND pa.pub IN ('public', 'ax') AND FIND_IN_SET('mail', pa.flags)
+                                       AND pa.pid IN {?}
+                             GROUP BY  pa.pid", $pids);
+            foreach ($res->fetchAllAssoc() as $item) {
+                fputcsv($csv, array_map('utf8_decode', $item), ';');
+            }
         }
         fclose($csv);
         exit();
index 68b10a5..f2154dd 100644 (file)
@@ -77,9 +77,9 @@ class AccountReq extends Validate
     protected function _mail_body($isok)
     {
         if ($isok) {
-            return "  Un email vient d'être envoyé à {$this->email} pour qu'il puisse activer son compte sur Polytechnique.net.";
+            return "  Un email vient d'être envoyé à {$this->email} pour que cette personne puisse activer son compte sur Polytechnique.net.";
         } else {
-            return "  Nous n'avons pas jugé bon d'envoyer d'email à {$this->email} pour qu'il puisse activer son compte sur Polytechnique.net.";
+            return "  Nous n'avons pas jugé bon d'envoyer d'email à {$this->email} pour que cette personne puisse activer son compte sur Polytechnique.net.";
         }
     }
 
index b5bcd15..ef19a21 100644 (file)
@@ -134,10 +134,19 @@ class ListeReq extends Validate
                 add_to_list_alias($member, $this->liste, $this->domain);
             }
         } else {
+            $members = User::getBulkForlifeEmails($this->members, true,
+                                                  array('ListsModule', 'no_login_callback'));
+            $owners = User::getBulkForlifeEmails($this->owners, true,
+                                                 array('ListsModule', 'no_login_callback'));
             $list = new MMList(S::user(), $this->domain);
+
+            // Make sure we send a list (array_values) of unique (array_unique)
+            // emails.
+            $owners = array_values(array_unique($owners));
+            $members = array_values(array_unique($members));
             $success = $list->create_list($this->liste, utf8_decode($this->desc), $this->advertise,
                                           $this->modlevel, $this->inslevel,
-                                          $this->owners, $this->members);
+                                          $owners, $members);
             if ($success) {
                 create_list($this->liste, $this->domain);
             }
index fc77918..09c2520 100644 (file)
@@ -27,18 +27,25 @@ class MedalReq extends ProfileValidate
 
     public $mid;
     public $gid;
+    public $level;
+    public $has_levels;
 
     // }}}
     // {{{ constructor
 
-    public function __construct(User $_user, Profile $_profile, $_idmedal, $_subidmedal, $_stamp = 0)
+    public function __construct(User $_user, Profile $_profile, $_idmedal, $_subidmedal, $_level, $has_levels, $_stamp = 0)
     {
         parent::__construct($_user, $_profile, false, 'medal', $_stamp);
         $this->mid = $_idmedal;
         $this->gid = $_subidmedal;
+        $this->level = $_level;
+        $this->has_levels = $has_levels;
         if (is_null($this->gid)) {
             $this->gid = 0;
         }
+        if (!$this->has_levels) {
+            $this->level = '';
+        }
     }
 
     // }}}
@@ -107,21 +114,21 @@ class MedalReq extends ProfileValidate
 
     public function commit ()
     {
-        return XDB::execute('INSERT INTO  profile_medals (pid, mid, gid)
-                                  VALUES  ({?}, {?}, {?})
+        return XDB::execute('INSERT INTO  profile_medals (pid, mid, gid, level)
+                                  VALUES  ({?}, {?}, {?}, {?})
                  ON DUPLICATE KEY UPDATE  gid = VALUES(gid)',
                             $this->profile->id(), $this->mid,
-                            is_null($this->gid) ? 0 : $this->gid);
+                            is_null($this->gid) ? 0 : $this->gid, $this->level);
     }
 
     // }}}
     // {{{ function get_request($medal)
 
-    static public function get_request($pid, $type, $grade)
+    static public function get_request($pid, $type, $grade, $level)
     {
         $reqs = parent::get_typed_requests($pid, 'medal');
         foreach ($reqs as &$req) {
-            if ($req->mid == $type && $req->gid == $grade) {
+            if ($req->mid == $type && $req->gid == $grade && $req->level == $level) {
                 return $req;
             }
         }
index 2509806..0214520 100644 (file)
@@ -37,7 +37,7 @@ class PayReq extends Validate
     public $asso;
     public $evt;
     public $evt_intitule;
-    public $donation;
+    public $public;
 
     public $rules = "Vérifier que les balises &lt;salutation&gt;, &lt;prenom&gt;, &lt;nom&gt;,  &lt;montant&gt; et &lt;comment&gt; n'ont pas été modifiées.
 Vérifier que le demandeur n'a pas laissé les crochets [].
@@ -47,7 +47,7 @@ Si le télépaiement n'est pas lié à un groupe ou supérieur à 51 euros, lais
 
     public function __construct(User $_user, $_intitule, $_site, $_montant, $_msg,
                                 $_montantmin=0, $_montantmax=999, $_asso_id = 0,
-                                $_evt = 0, $_donation = false, $_stamp=0)
+                                $_evt = 0, $_public = false, $_stamp = 0)
     {
         parent::__construct($_user, false, 'paiements', $_stamp);
 
@@ -56,10 +56,10 @@ Si le télépaiement n'est pas lié à un groupe ou supérieur à 51 euros, lais
         $this->msg_reponse  = $_msg;
         $this->asso_id      = (string)$_asso_id;
         $this->evt          = (string)$_evt;
-        $this->donation     = $_donation;
         $this->montant      = $_montant;
         $this->montant_min  = $_montantmin;
         $this->montant_max  = $_montantmax;
+        $this->public       = $_public;
 
         if ($_asso_id) {
             $res = XDB::query("SELECT nom FROM groups WHERE id = {?}", $_asso_id);
@@ -89,7 +89,7 @@ Si le télépaiement n'est pas lié à un groupe ou supérieur à 51 euros, lais
     public function accept()
     {
         // no text [AI JMIAJM IJA MIJ]
-        if (preg_match('/\[[-\'"A-Z ]+\]/', $this->msg_reponse)) {
+        if (preg_match('/\[[-\'"a-zA-Z ]+\]/', replace_accent($this->msg_reponse))) {
             $this->trigError("La demande de paiement n'est pas valide. Merci de compléter le texte avant de la soumettre");
             return false;
         }
@@ -139,6 +139,7 @@ Si le télépaiement n'est pas lié à un groupe ou supérieur à 51 euros, lais
         $this->montant_min = Env::i('pay_montant_min');
         $this->montant_max = Env::i('pay_montant_max');
         $this->msg_reponse = Env::v('pay_msg_reponse');
+        $this->public      = (Env::v('pay_public') == 'yes');
         return true;
     }
 
@@ -169,11 +170,11 @@ Si le télépaiement n'est pas lié à un groupe ou supérieur à 51 euros, lais
     {
         $res = XDB::query("SELECT MAX(id) FROM payments");
         $id = $res->fetchOneCell()+1;
-        $flags = ($this->donation ? 'donation' : '');
-        $ret = XDB::execute('INSERT INTO  payments (id, text, url, flags, amount_def, amount_min, amount_max, mail, confirmation, asso_id)
+        $ret = XDB::execute('INSERT INTO  payments (id, text, url, amount_def, amount_min, amount_max, mail, confirmation, asso_id, flags)
                                   VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
-                            $id, $this->titre, $this->site, $flags, $this->montant, $this->montant_min,
-                            $this->montant_max, $this->user->bestEmail(), $this->msg_reponse, $this->asso_id);
+                            $id, $this->titre, $this->site, $this->montant, $this->montant_min,
+                            $this->montant_max, $this->user->bestEmail(), $this->msg_reponse, $this->asso_id,
+                            ($this->public ? 'public' : ''));
         if ($this->asso_id && $this->evt) {
             XDB::execute("UPDATE  group_events
                              SET  paiement_id = {?}
index ad07d0e..a2d5d59 100644 (file)
@@ -24,38 +24,38 @@ class AdminModule extends PLModule
     function handlers()
     {
         return array(
-            'phpinfo'                      => $this->make_hook('phpinfo',                AUTH_MDP,    'admin'),
+            'phpinfo'                      => $this->make_hook('phpinfo',                AUTH_PASSWD, 'admin'),
             'get_rights'                   => $this->make_hook('get_rights',             AUTH_COOKIE, 'admin'),
             'set_skin'                     => $this->make_hook('set_skin',               AUTH_COOKIE, 'admin'),
-            'admin'                        => $this->make_hook('default',                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/user'                   => $this->make_hook('user',                   AUTH_MDP,    'admin'),
-            'admin/add_accounts'           => $this->make_hook('add_accounts',           AUTH_MDP,    'admin'),
-            'admin/validate'               => $this->make_hook('validate',               AUTH_MDP,    'admin,edit_directory'),
-            '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/geocoding'              => $this->make_hook('geocoding',              AUTH_MDP,    'admin'),
-            'admin/accounts'               => $this->make_hook('accounts',               AUTH_MDP,    'admin'),
-            'admin/account/watch'          => $this->make_hook('account_watch',          AUTH_MDP,    'admin'),
-            'admin/account/types'          => $this->make_hook('account_types',          AUTH_MDP,    'admin'),
-            'admin/xnet_without_group'     => $this->make_hook('xnet_without_group',     AUTH_MDP,    'admin'),
-            'admin/jobs'                   => $this->make_hook('jobs',                   AUTH_MDP,    'admin,edit_directory'),
-            'admin/profile'                => $this->make_hook('profile',                AUTH_MDP,    'admin,edit_directory'),
-            'admin/phd'                    => $this->make_hook('phd',                    AUTH_MDP,    'admin'),
-            'admin/add_secondary_edu'      => $this->make_hook('add_secondary_edu',      AUTH_MDP,    'admin')
+            'admin'                        => $this->make_hook('default',                AUTH_PASSWD, 'admin'),
+            'admin/dead-but-active'        => $this->make_hook('dead_but_active',        AUTH_PASSWD, 'admin'),
+            'admin/deaths'                 => $this->make_hook('deaths',                 AUTH_PASSWD, 'admin'),
+            'admin/downtime'               => $this->make_hook('downtime',               AUTH_PASSWD, 'admin'),
+            'admin/homonyms'               => $this->make_hook('homonyms',               AUTH_PASSWD, 'admin'),
+            'admin/logger'                 => $this->make_hook('logger',                 AUTH_PASSWD, 'admin'),
+            'admin/logger/actions'         => $this->make_hook('logger_actions',         AUTH_PASSWD, 'admin'),
+            'admin/postfix/blacklist'      => $this->make_hook('postfix_blacklist',      AUTH_PASSWD, 'admin'),
+            'admin/postfix/delayed'        => $this->make_hook('postfix_delayed',        AUTH_PASSWD, 'admin'),
+            'admin/postfix/regexp_bounces' => $this->make_hook('postfix_regexpsbounces', AUTH_PASSWD, 'admin'),
+            'admin/postfix/whitelist'      => $this->make_hook('postfix_whitelist',      AUTH_PASSWD, 'admin'),
+            'admin/mx/broken'              => $this->make_hook('mx_broken',              AUTH_PASSWD, 'admin'),
+            'admin/skins'                  => $this->make_hook('skins',                  AUTH_PASSWD, 'admin'),
+            'admin/user'                   => $this->make_hook('user',                   AUTH_PASSWD, 'admin'),
+            'admin/add_accounts'           => $this->make_hook('add_accounts',           AUTH_PASSWD, 'admin'),
+            'admin/validate'               => $this->make_hook('validate',               AUTH_PASSWD, 'admin,edit_directory'),
+            'admin/validate/answers'       => $this->make_hook('validate_answers',       AUTH_PASSWD, 'admin'),
+            'admin/wiki'                   => $this->make_hook('wiki',                   AUTH_PASSWD, 'admin'),
+            'admin/ipwatch'                => $this->make_hook('ipwatch',                AUTH_PASSWD, 'admin'),
+            'admin/icons'                  => $this->make_hook('icons',                  AUTH_PASSWD, 'admin'),
+            'admin/geocoding'              => $this->make_hook('geocoding',              AUTH_PASSWD, 'admin'),
+            'admin/accounts'               => $this->make_hook('accounts',               AUTH_PASSWD, 'admin'),
+            'admin/account/watch'          => $this->make_hook('account_watch',          AUTH_PASSWD, 'admin'),
+            'admin/account/types'          => $this->make_hook('account_types',          AUTH_PASSWD, 'admin'),
+            'admin/xnet_without_group'     => $this->make_hook('xnet_without_group',     AUTH_PASSWD, 'admin'),
+            'admin/jobs'                   => $this->make_hook('jobs',                   AUTH_PASSWD, 'admin,edit_directory'),
+            'admin/profile'                => $this->make_hook('profile',                AUTH_PASSWD, 'admin,edit_directory'),
+            'admin/phd'                    => $this->make_hook('phd',                    AUTH_PASSWD, 'admin'),
+            'admin/add_secondary_edu'      => $this->make_hook('add_secondary_edu',      AUTH_PASSWD, 'admin')
         );
     }
 
@@ -518,10 +518,11 @@ class AdminModule extends PLModule
             if (Post::t('comment') != $user->comment) {
                 $to_update['comment'] = Post::blank('comment') ? null : Post::t('comment');
             }
-            if (require_email_update($user, Post::t('email'))) {
-                $to_update['email'] = Post::t('email');
-                $listClient->change_user_email($user->forlifeEmail(), Post::t('email'));
-                update_alias_user($user->forlifeEmail(), Post::t('email'));
+            $new_email = strtolower(Post::t('email'));
+            if (require_email_update($user, $new_email)) {
+                $to_update['email'] = $new_email;
+                $listClient->change_user_email($user->forlifeEmail(), $new_email);
+                update_alias_user($user->forlifeEmail(), $new_email);
             }
         }
         if (!empty($to_update)) {
@@ -592,7 +593,7 @@ class AdminModule extends PLModule
         $redirect = ($registered ? new Redirect($user) : null);
         if (Post::has('add_fwd')) {
             $email = Post::t('email');
-            if (!isvalid_email_redirection($email)) {
+            if (!isvalid_email_redirection($email, $user)) {
                 $page->trigError("Email non valide: $email");
             } else {
                 $redirect->add_email($email);
@@ -814,6 +815,7 @@ class AdminModule extends PLModule
         $page->changeTpl('admin/add_accounts.tpl');
 
         if (Env::has('add_type') && Env::has('people')) {
+            static $titles = array('male' => 'M', 'female' => 'MLLE');
             $lines = explode("\n", Env::t('people'));
             $separator = Env::t('separator');
             $promotion = Env::i('promotion');
@@ -872,9 +874,10 @@ class AdminModule extends PLModule
                                 continue;
                             }
 
-                            XDB::execute('INSERT INTO  profiles (hrpid, xorg_id, ax_id, birthdate_ref, sex)
-                                               VALUES  ({?}, {?}, {?}, {?}, {?})',
-                                         $infos['hrid'], $xorgId, (isset($infos[5]) ? $infos[5] : null), $birthDate, $sex);
+                            XDB::execute('INSERT INTO  profiles (hrpid, xorg_id, ax_id, birthdate_ref, sex, title)
+                                               VALUES  ({?}, {?}, {?}, {?}, {?}, {?})',
+                                         $infos['hrid'], $xorgId, (isset($infos[5]) ? $infos[5] : null),
+                                         $birthDate, $sex, $titles[$sex]);
                             $pid = XDB::insertId();
                             XDB::execute('INSERT INTO  profile_public_names (pid, lastname_initial, lastname_main, firstname_initial, firstname_main)
                                                VALUES  ({?}, {?}, {?}, {?}, {?})',
index a86313e..688c5c5 100644 (file)
@@ -32,7 +32,7 @@ class AuthModule extends PLModule
             'auth-redirect.php'             => $this->make_hook('redirect',           AUTH_COOKIE, 'user'),
             'auth-groupex.php'              => $this->make_hook('groupex_old',        AUTH_COOKIE, ''),
             'auth-groupex'                  => $this->make_hook('groupex',            AUTH_PUBLIC, ''),
-            'admin/auth-groupes-x'          => $this->make_hook('admin_authgroupesx', AUTH_MDP,    'admin'),
+            'admin/auth-groupes-x'          => $this->make_hook('admin_authgroupesx', AUTH_PASSWD, 'admin'),
         );
     }
 
index d6a63be..4ebf134 100644 (file)
@@ -30,12 +30,12 @@ class AXLetterModule extends NewsletterModule
             'ax/out'               => $this->make_hook('out',             AUTH_PUBLIC),
             'ax/show'              => $this->make_hook('nl_show',         AUTH_COOKIE, 'user'),
             'ax/search'            => $this->make_hook('nl_search',       AUTH_COOKIE, 'user'),
-            'ax/admin'             => $this->make_hook('admin_nl',        AUTH_MDP,    'user'),
-            'ax/admin/edit'        => $this->make_hook('admin_nl_edit',   AUTH_MDP,    'user'),
-            'ax/admin/edit/valid'  => $this->make_hook('admin_nl_valid',  AUTH_MDP,    'user'),
-            'ax/admin/edit/cancel' => $this->make_hook('admin_nl_cancel', AUTH_MDP,    'user'),
-            'ax/admin/edit/delete' => $this->make_hook('admin_nl_delete', AUTH_MDP,    'user'),
-            'ax/admin/categories'  => $this->make_hook('admin_nl_cat',    AUTH_MDP,    'user'),
+            'ax/admin'             => $this->make_hook('admin_nl',        AUTH_PASSWD, 'user'),
+            'ax/admin/edit'        => $this->make_hook('admin_nl_edit',   AUTH_PASSWD, 'user'),
+            'ax/admin/edit/valid'  => $this->make_hook('admin_nl_valid',  AUTH_PASSWD, 'user'),
+            'ax/admin/edit/cancel' => $this->make_hook('admin_nl_cancel', AUTH_PASSWD, 'user'),
+            'ax/admin/edit/delete' => $this->make_hook('admin_nl_delete', AUTH_PASSWD, 'user'),
+            'ax/admin/categories'  => $this->make_hook('admin_nl_cat',    AUTH_PASSWD, 'user'),
         );
     }
 
index 8db0fc2..5139bb0 100644 (file)
@@ -34,6 +34,7 @@ class CarnetModule extends PLModule
             'carnet/contacts/ical'         => $this->make_token_hook('ical',         AUTH_COOKIE, 'directory_private'),
             'carnet/contacts/csv'          => $this->make_token_hook('csv',          AUTH_COOKIE, 'directory_private'),
             'carnet/contacts/csv/birthday' => $this->make_token_hook('csv_birthday', AUTH_COOKIE, 'directory_private'),
+            'carnet/batch'                 => $this->make_hook('batch',              AUTH_COOKIE, 'directory_private'),
 
             'carnet/rss'                   => $this->make_token_hook('rss',          AUTH_COOKIE, 'directory_private'),
         );
@@ -152,12 +153,62 @@ class CarnetModule extends PLModule
         Platal::session()->updateNbNotifs();
     }
 
+    private function getGroup(PlPage $page, $group)
+    {
+        $groupid = XDB::fetchOneCell("SELECT  id
+                                        FROM  groups
+                                       WHERE  (nom = {?} OR diminutif = {?}) AND NOT FIND_IN_SET('private', pub)",
+                                     $group, $group);
+        if (is_null($groupid)) {
+            $search = XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $group);
+            $res = XDB::query('SELECT  id
+                                 FROM  groups
+                                WHERE  (nom ' . $search . ' OR diminutif ' . $search . ") AND NOT FIND_IN_SET('private', pub)",
+                              $search, $search);
+            if ($res->numRows() == 1) {
+                $groupid = $res->fetchOneCell();
+            }
+        }
+        return $groupid;
+    }
+
+    private function addGroup(PlPage $page, $group)
+    {
+        $groupid = $this->getGroup($page, $group);
+        if (is_null($groupid)) {
+            return;
+        }
+        XDB::execute('INSERT IGNORE INTO  watch_group (uid, groupid)
+                                  VALUES  ({?}, {?})',
+                     S::i('uid'), $groupid);
+        S::user()->invalidWatchCache();
+        Platal::session()->updateNbNotifs();
+    }
+
+    private function delGroup(PlPage $page, $group)
+    {
+        $groupid = $this->getGroup($page, $group);
+        if (is_null($groupid)) {
+            return;
+        }
+        XDB::execute('DELETE FROM  watch_group
+                            WHERE  uid = {?} AND groupid = {?}',
+                     S::i('uid'), $groupid);
+        S::user()->invalidWatchCache();
+        Platal::session()->updateNbNotifs();
+    }
+
     public function addNonRegistered(PlPage $page, PlUser $user)
     {
         XDB::execute('INSERT IGNORE INTO  watch_nonins (uid, ni_id)
                                   VALUES  ({?}, {?})', S::i('uid'), $user->id());
-        S::user()->invalidWatchCache();
-        Platal::session()->updateNbNotifs();
+        if (XDB::affectedRows() > 0) {
+            S::user()->invalidWatchCache();
+            Platal::session()->updateNbNotifs();
+            $page->trigSuccess('Contact ajouté&nbsp;: ' . $user->fullName(true));
+        } else {
+            $page->trigWarning('Contact déjà dans la liste&nbsp;: ' . $user->fullName(true));
+        }
     }
 
     public function delNonRegistered(PlPage $page, PlUser $user)
@@ -169,6 +220,33 @@ class CarnetModule extends PLModule
         Platal::session()->updateNbNotifs();
     }
 
+    public function addRegistered(PlPage $page, Profile $profile)
+    {
+        XDB::execute('INSERT IGNORE INTO  contacts (uid, contact)
+                                  VALUES  ({?}, {?})',
+                     S::i('uid'), $profile->id());
+        if (XDB::affectedRows() > 0) {
+            S::user()->invalidWatchCache();
+            Platal::session()->updateNbNotifs();
+            $page->trigSuccess('Contact ajouté&nbsp;: ' . $profile->fullName(true));
+        } else {
+            $page->trigWarning('Contact déjà dans la liste&nbsp;: ' . $profile->fullName(true));
+        }
+    }
+
+    public function delRegistered(PlPage $page, Profile $profile)
+    {
+        XDB::execute('DELETE FROM  contacts
+                            WHERE  uid = {?} AND contact = {?}',
+                     S::i('uid'), $profile->id());
+        if (XDB::affectedRows() > 0) {
+            S::user()->invalidWatchCache();
+            Platal::session()->updateNbNotifs();
+            $page->trigSuccess("Contact retiré&nbsp;!");
+        }
+
+    }
+
     public function handler_notifs($page, $action = null, $arg = null)
     {
         $page->changeTpl('carnet/notifs.tpl');
@@ -184,6 +262,14 @@ class CarnetModule extends PLModule
                 $this->delPromo($page, $arg);
                 break;
 
+              case 'add_group':
+                $this->addGroup($page, $arg);
+                break;
+
+              case 'del_group':
+                $this->delGroup($page, $arg);
+                break;
+
               case 'del_nonins':
                 $user = User::get($arg);
                 if ($user) {
@@ -256,6 +342,14 @@ class CarnetModule extends PLModule
         $page->assign('promo_ranges', $ranges);
         $page->assign('nonins', $nonins->getUsers());
 
+        $groups = XDB::fetchColumn('SELECT  g.nom
+                                      FROM  watch_group AS w
+                                INNER JOIN  groups      AS g ON (g.id = w.groupid)
+                                     WHERE  w.uid = {?}
+                                  ORDER BY  g.nom',
+                                   S::i('uid'));
+        $page->assign('groups', $groups);
+        $page->assign('groups_count', count($groups));
         list($flags, $actions) = XDB::fetchOneRow('SELECT  flags, actions
                                                      FROM  watch
                                                     WHERE  uid = {?}', S::i('uid'));
@@ -270,9 +364,6 @@ class CarnetModule extends PLModule
         $page->setTitle('Mes contacts');
         $this->_add_rss_link($page);
 
-        $uid  = S::i('uid');
-        $user = S::user();
-
         // For XSRF protection, checks both the normal xsrf token, and the special RSS token.
         // It allows direct linking to contact adding in the RSS feed.
         if (Env::v('action') && Env::v('token') !== S::user()->token) {
@@ -281,31 +372,19 @@ class CarnetModule extends PLModule
         switch (Env::v('action')) {
             case 'retirer':
                 if (($contact = Profile::get(Env::v('user')))) {
-                    if (XDB::execute("DELETE FROM  contacts
-                                            WHERE  uid = {?} AND contact = {?}",
-                                     $uid, $contact->id())) {
-                        Platal::session()->updateNbNotifs();
-                        $page->trigSuccess("Contact retiré&nbsp;!");
-                    }
+                    $this->delRegistered($page, $contact);
                 }
                 break;
 
             case 'ajouter':
                 if (($contact = Profile::get(Env::v('user')))) {
-                    XDB::execute('INSERT IGNORE INTO  contacts (uid, contact)
-                                              VALUES  ({?}, {?})',
-                                 $uid, $contact->id());
-                    if (XDB::affectedRows() > 0) {
-                        Platal::session()->updateNbNotifs();
-                        $page->trigSuccess('Contact ajouté&nbsp;!');
-                    } else {
-                        $page->trigWarning('Contact déjà dans la liste&nbsp;!');
-                    }
+                    $this->addRegistered($page, $contact);
                 }
                 break;
         }
 
         $search = false;
+        $user = S::user();
 
         require_once 'userset.inc.php';
 
@@ -396,7 +475,7 @@ class CarnetModule extends PLModule
         } else {
             $encoding = 'utf-8';
         }
-        pl_content_headers("text/comma-separated-values;charset=".$encoding);
+        pl_cached_content_headers('text/comma-separated-values; charset=' . $encoding, 1);
     }
 
     function handler_ical(PlPage $page, PlUser $user)
@@ -409,7 +488,7 @@ class CarnetModule extends PLModule
         $profiles = $filter->iterProfiles();
         $page->assign('events', PlIteratorUtils::map($profiles, array($this, 'buildBirthRef')));
 
-        pl_content_headers("text/calendar");
+        pl_cached_content_headers('text/calendar', 1);
     }
 
     function handler_vcard($page, $photos = null)
@@ -427,6 +506,85 @@ class CarnetModule extends PLModule
         require_once 'carnet/outlook.inc.php';
         Outlook::output_profiles($pf->getProfiles(), 'fr');
     }
+
+    function handler_batch($page)
+    {
+        $page->changeTpl('carnet/batch.tpl');
+        $errors = false;
+        $incomplete = array();
+
+        if (Post::has('add')) {
+            S::assert_xsrf_token();
+            require_once 'userset.inc.php';
+            require_once 'emails.inc.php';
+            require_once 'marketing.inc.php';
+
+            $list = explode("\n", Post::v('list'));
+            $origin = Post::v('origin');
+
+            foreach ($list as $item) {
+                if ($item = trim($item)) {
+                    $elements = preg_split("/\s/", $item);
+                    $email = array_pop($elements);
+                    if (!isvalid_email($email)) {
+                        $page->trigError('Email invalide&nbsp;: ' . $email);
+                        $incomplete[] = $item;
+                        $errors = true;
+                        continue;
+                    }
+
+                    $user = User::getSilent($email);
+                    if (is_null($user)) {
+                        $details = implode(' ', $elements);
+                        $promo = trim(array_pop($elements));
+                        $cond = new PFC_And();
+                        if (preg_match('/^[MDX]\d{4}$/', $promo)) {
+                            $cond->addChild(new UFC_Promo('=', UserFilter::DISPLAY, $promo));
+                        } else {
+                            $cond->addChild(new UFC_NameTokens($promo));
+                        }
+                        foreach ($elements as $element) {
+                            $cond->addChild(new UFC_NameTokens($element));
+                        }
+                        $uf = new UserFilter($cond);
+                        $count = $uf->getTotalCount();
+                        if ($count == 0) {
+                            $page->trigError('Les informations : « ' . $item . ' » ne correspondent à aucun camarade.');
+                            $incomplete[] = $item;
+                            $errors = true;
+                            continue;
+                        } elseif ($count > 1) {
+                            $page->trigError('Les informations : « ' . $item . ' » sont ambigues et correspondent à plusieurs camarades.');
+                            $incomplete[] = $item;
+                            $errors = true;
+                            continue;
+                        } else {
+                            $user = $uf->getUser();
+                        }
+                    }
+
+                    if ($user->state == 'active') {
+                        $this->addRegistered($page, $user->profile());
+                    } else {
+                        if (!User::isForeignEmailAddress($email)) {
+                            $page->trigError('Email pas encore attribué&nbsp;: ' . $email);
+                            $incomplete[] = $item;
+                            $errors = true;
+                        } else {
+                            $this->addNonRegistered($page, $user);
+                            if (!Marketing::get($user->id(), $email, true)) {
+                                check_email($email, "Une adresse surveillée est proposée au marketing par " . S::user()->login());
+                                $market = new Marketing($user->id(), $email, 'default', null, $origin, S::v('uid'), null);
+                                $market->add();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        $page->assign('errors', $errors);
+        $page->assign('incomplete', $incomplete);
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index e5049c5..331eacf 100644 (file)
@@ -25,11 +25,11 @@ class EmailModule extends PLModule
     {
         return array(
             'emails'                  => $this->make_hook('emails',      AUTH_COOKIE, 'mail'),
-            'emails/alias'            => $this->make_hook('alias',       AUTH_MDP,    'mail'),
-            'emails/antispam'         => $this->make_hook('antispam',    AUTH_MDP,    'mail'),
+            'emails/alias'            => $this->make_hook('alias',       AUTH_PASSWD, 'mail'),
+            'emails/antispam'         => $this->make_hook('antispam',    AUTH_PASSWD, 'mail'),
             'emails/broken'           => $this->make_hook('broken',      AUTH_COOKIE, 'user'),
-            'emails/redirect'         => $this->make_hook('redirect',    AUTH_MDP,    'mail'),
-            'emails/send'             => $this->make_hook('send',        AUTH_MDP,    'mail'),
+            'emails/redirect'         => $this->make_hook('redirect',    AUTH_PASSWD, 'mail'),
+            'emails/send'             => $this->make_hook('send',        AUTH_PASSWD, 'mail'),
             'emails/antispam/submit'  => $this->make_hook('submit',      AUTH_COOKIE, 'user'),
             'emails/test'             => $this->make_hook('test',        AUTH_COOKIE, 'mail', NO_AUTH),
 
@@ -38,10 +38,10 @@ class EmailModule extends PLModule
 
             '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'),
-            'admin/emails/broken'     => $this->make_hook('broken_addr', AUTH_MDP,    'admin'),
+            'admin/emails/duplicated' => $this->make_hook('duplicated',  AUTH_PASSWD, 'admin'),
+            'admin/emails/watch'      => $this->make_hook('duplicated',  AUTH_PASSWD, 'admin'),
+            'admin/emails/lost'       => $this->make_hook('lost',        AUTH_PASSWD, 'admin'),
+            'admin/emails/broken'     => $this->make_hook('broken_addr', AUTH_PASSWD, 'admin'),
         );
     }
 
@@ -152,7 +152,7 @@ class EmailModule extends PLModule
                                                  INNER JOIN  email_virtual_domains AS d ON (s.domain = d.id)
                                                       WHERE  s.uid = {?} AND s.type = \'alias_aux\'',
                                                     $user->id());
-        $visibility = $user->hasProfile() && ($user->profile(true)->alias_pub == 'public');
+        $visibility = $user->hasProfile() && $user->profile()->isVisible($user->profile()->alias_pub);
         $page->assign('current', $alias);
         $page->assign('user', $user);
         $page->assign('mail_public', $visibility);
@@ -163,20 +163,21 @@ class EmailModule extends PLModule
             // Retrieves user request.
             $new_alias  = Env::v('alias');
             $reason = Env::v('reason');
-            $public = (Env::v('public', 'off') == 'on') ? 'public' : 'private';
+            $public = (Env::v('public', 'off') == 'on') ? 'private' : 'hidden';
 
             $page->assign('r_alias', $new_alias);
             $page->assign('r_reason', $reason);
-            if ($public == 'public') {
+            if ($public == 'private') {
                 $page->assign('r_public', true);
             }
 
             // Checks special charaters in alias.
-            if (!preg_match("/^[a-zA-Z0-9\-.]{3,20}$/", $new_alias)) {
+            if (!preg_match("/^[a-zA-Z0-9\-.]{2,19}[a-zA-Z0-9\-]$/", $new_alias)) {
                 $page->trigError("L'adresse demandée n'est pas valide."
                             . " Vérifie qu'elle comporte entre 3 et 20 caractères"
                             . " et qu'elle ne contient que des lettres non accentuées,"
-                            . " des chiffres ou les caractères - et .");
+                            . " des chiffres ou les caractères '-' et '.'. De plus, elle ne"
+                            . " peut pas se terminer par un point.");
                 return;
             } else {
                 // Checks if the alias has already been given.
@@ -463,7 +464,7 @@ class EmailModule extends PLModule
                     foreach ($files as $name=>&$upload) {
                         $mymail->addUploadAttachment($upload, $name);
                     }
-                    if (Env::v('nowiki')) {
+                    if (Env::v('wiki') == 'text') {
                         $mymail->setTxtBody(wordwrap($txt, 78, "\n"));
                     } else {
                         $mymail->setWikiBody($txt);
@@ -498,6 +499,14 @@ class EmailModule extends PLModule
         $page->assign('contacts', $contacts);
         $page->assign('maxsize', ini_get('upload_max_filesize') . 'o');
         $page->assign('user', S::user());
+        $preferences = XDB::fetchOneAssoc('SELECT  from_email, from_format
+                                             FROM  accounts
+                                            WHERE  uid = {?}',
+                                          S::user()->id());
+        if ($preferences['from_email'] == '') {
+            $preferences['from_email'] = '"' . S::user()->fullName() . '" <' . S::user()->bestEmail() . '>';
+        }
+        $page->assign('preferences', $preferences);
     }
 
     function handler_test($page, $hruid = null)
index b914893..f3667d3 100644 (file)
@@ -30,12 +30,12 @@ class EPLetterModule extends NewsletterModule
             'epletter/out'               => $this->make_hook('out',             AUTH_PUBLIC),
             'epletter/show'              => $this->make_hook('nl_show',         AUTH_COOKIE, 'user'),
             'epletter/search'            => $this->make_hook('nl_search',       AUTH_COOKIE, 'user'),
-            'epletter/admin'             => $this->make_hook('admin_nl',        AUTH_MDP,    'user'),
-            'epletter/admin/edit'        => $this->make_hook('admin_nl_edit',   AUTH_MDP,    'user'),
-            'epletter/admin/edit/valid'  => $this->make_hook('admin_nl_valid',  AUTH_MDP,    'user'),
-            'epletter/admin/edit/cancel' => $this->make_hook('admin_nl_cancel', AUTH_MDP,    'user'),
-            'epletter/admin/edit/delete' => $this->make_hook('admin_nl_delete', AUTH_MDP,    'user'),
-            'epletter/admin/categories'  => $this->make_hook('admin_nl_cat',    AUTH_MDP,    'user'),
+            'epletter/admin'             => $this->make_hook('admin_nl',        AUTH_PASSWD, 'user'),
+            'epletter/admin/edit'        => $this->make_hook('admin_nl_edit',   AUTH_PASSWD, 'user'),
+            'epletter/admin/edit/valid'  => $this->make_hook('admin_nl_valid',  AUTH_PASSWD, 'user'),
+            'epletter/admin/edit/cancel' => $this->make_hook('admin_nl_cancel', AUTH_PASSWD, 'user'),
+            'epletter/admin/edit/delete' => $this->make_hook('admin_nl_delete', AUTH_PASSWD, 'user'),
+            'epletter/admin/categories'  => $this->make_hook('admin_nl_cat',    AUTH_PASSWD, 'user'),
         );
     }
 
index b1f6482..7395568 100644 (file)
@@ -27,12 +27,12 @@ class EventsModule extends PLModule
             'events'         => $this->make_hook('ev',           AUTH_COOKIE, 'user'),
             '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,    'user'),
-            'admin/events'   => $this->make_hook('admin_events', AUTH_MDP,    'admin'),
+            'events/submit'  => $this->make_hook('ev_submit',    AUTH_PASSWD, 'user'),
+            'admin/events'   => $this->make_hook('admin_events', AUTH_PASSWD, 'admin'),
             'rss'            => $this->make_token_hook('rss',    AUTH_COOKIE, 'user'),
 
             'ajax/tips'      => $this->make_hook('tips',         AUTH_COOKIE, 'user', NO_AUTH),
-            'admin/tips'     => $this->make_hook('admin_tips',   AUTH_MDP,    'admin'),
+            'admin/tips'     => $this->make_hook('admin_tips',   AUTH_PASSWD, 'admin'),
         );
     }
 
index 28ea1c8..22604b1 100644 (file)
@@ -26,7 +26,7 @@ class ForumsModule extends PLModule
         return array(
             'banana'       => $this->make_hook('banana',      AUTH_COOKIE, 'forums'),
             'banana/rss'   => $this->make_hook('rss',         AUTH_PUBLIC, 'forums', NO_HTTPS),
-            'admin/forums' => $this->make_hook('forums_bans', AUTH_MDP,    'admin'),
+            'admin/forums' => $this->make_hook('forums_bans', AUTH_PASSWD, 'admin'),
         );
     }
 
index 65a692b..b30fcb4 100644 (file)
@@ -35,22 +35,22 @@ class FusionAxModule extends PLModule
     {
         if (Platal::globals()->merge->state == 'pending') {
             return array(
-                'fusionax'                  => $this->make_hook('index',    AUTH_MDP, 'admin'),
-                'fusionax/import'           => $this->make_hook('import',   AUTH_MDP, 'admin'),
-                'fusionax/view'             => $this->make_hook('view',     AUTH_MDP, 'admin'),
-                'fusionax/ids'              => $this->make_hook('ids',      AUTH_MDP, 'admin'),
-                'fusionax/deceased'         => $this->make_hook('deceased', AUTH_MDP, 'admin'),
-                'fusionax/promo'            => $this->make_hook('promo',    AUTH_MDP, 'admin'),
-                'fusionax/names'            => $this->make_hook('names',    AUTH_MDP, 'admin'),
-                'fusionax/edu'              => $this->make_hook('edu',      AUTH_MDP, 'admin'),
-                'fusionax/corps'            => $this->make_hook('corps',    AUTH_MDP, 'admin')
+                'fusionax'                  => $this->make_hook('index',    AUTH_PASSWD, 'admin'),
+                'fusionax/import'           => $this->make_hook('import',   AUTH_PASSWD, 'admin'),
+                'fusionax/view'             => $this->make_hook('view',     AUTH_PASSWD, 'admin'),
+                'fusionax/ids'              => $this->make_hook('ids',      AUTH_PASSWD, 'admin'),
+                'fusionax/deceased'         => $this->make_hook('deceased', AUTH_PASSWD, 'admin'),
+                'fusionax/promo'            => $this->make_hook('promo',    AUTH_PASSWD, 'admin'),
+                'fusionax/names'            => $this->make_hook('names',    AUTH_PASSWD, 'admin'),
+                'fusionax/edu'              => $this->make_hook('edu',      AUTH_PASSWD, 'admin'),
+                'fusionax/corps'            => $this->make_hook('corps',    AUTH_PASSWD, 'admin')
             );
         } elseif (Platal::globals()->merge->state == 'done') {
             return array(
-                'fusionax'                  => $this->make_hook('index',            AUTH_MDP, 'admin,edit_directory'),
-                'fusionax/issues'           => $this->make_hook('issues',           AUTH_MDP, 'admin,edit_directory'),
-                'fusionax/issues/deathdate' => $this->make_hook('issues_deathdate', AUTH_MDP, 'admin,edit_directory'),
-                'fusionax/issues/promo'     => $this->make_hook('issues_promo',     AUTH_MDP, 'admin,edit_directory'),
+                'fusionax'                  => $this->make_hook('index',            AUTH_PASSWD, 'admin,edit_directory'),
+                'fusionax/issues'           => $this->make_hook('issues',           AUTH_PASSWD, 'admin,edit_directory'),
+                'fusionax/issues/deathdate' => $this->make_hook('issues_deathdate', AUTH_PASSWD, 'admin,edit_directory'),
+                'fusionax/issues/promo'     => $this->make_hook('issues_promo',     AUTH_PASSWD, 'admin,edit_directory'),
             );
         }
     }
index 0501616..52aa274 100644 (file)
@@ -13,6 +13,7 @@ CREATE TABLE IF NOT EXISTS fusionax_anciens (
   Nom_usuel VARCHAR(255) NOT NULL COMMENT 'Nom usuel (nom marital par exemple) sans la particule',
   partic_nom VARCHAR(5) NOT NULL COMMENT 'Particule du nom usuel',
   Nom_complet VARCHAR(255) NOT NULL COMMENT 'Nom patronymique complet (avec la particule)',
+  Civilité ENUM('M', 'MLLE', 'MME') NOT NULL DEFAULT 'M',
   Code_nationalite CHAR(4) NOT NULL COMMENT 'Nationalité (code)',
   corps_sortie VARCHAR(50) NOT NULL COMMENT 'Corps de sortie (ou D si aucun)',
   Date_deces DATE COMMENT 'Date de décès',
@@ -29,7 +30,7 @@ CREATE TABLE IF NOT EXISTS fusionax_anciens (
 
 LOAD DATA LOCAL INFILE '{?}Anciens.txt' INTO TABLE `fusionax_anciens` CHARACTER SET utf8 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\r\n'
 (AN, ax_id, @login, @password, promotion_etude, groupe_promo, Nom_patronymique, partic_patro, prenom, Nom_usuel, partic_nom,
-  Nom_complet, @civilite, Code_nationalite, @type, corps_sortie, @StringDate_deces, grade, Mel_usage, Mel_publiable, @xxx, Mob_publiable,
+  Nom_complet, Civilite, Code_nationalite, @type, corps_sortie, @StringDate_deces, grade, Mel_usage, Mel_publiable, @xxx, Mob_publiable,
   tel_mobile, @xxx, @xxx, @xxx, @xxx, @xxx, @xxx, @xxx, @X_M_D, @xxx, @xxx, @xxx, @xxx, @xxx, @xxx, @Type_adr,
   @Ligne1, @Ligne2, @Ligne3, @code_postal, @ville, @zip_cedex, @etat_distr, @pays, @tel, @fax, @StringDate_maj)
 SET
index b4900b9..bad3836 100644 (file)
@@ -29,10 +29,10 @@ class GoogleAppsModule extends PLModule
         }
 
         return array(
-            'googleapps'            => $this->make_hook('index',      AUTH_MDP, 'gapps'),
-            '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'),
+            'googleapps'            => $this->make_hook('index',      AUTH_PASSWD, 'gapps'),
+            'admin/googleapps'      => $this->make_hook('admin',      AUTH_PASSWD, 'admin'),
+            'admin/googleapps/job'  => $this->make_hook('admin_job',  AUTH_PASSWD, 'admin'),
+            'admin/googleapps/user' => $this->make_hook('admin_user', AUTH_PASSWD, 'admin'),
         );
     }
 
index 688b0b0..e53ea7a 100644 (file)
@@ -26,9 +26,9 @@ class ListsModule extends PLModule
     function handlers()
     {
         return array(
-            'lists'              => $this->make_hook('lists',     AUTH_MDP,    'user'),
-            'lists/ajax'         => $this->make_hook('ajax',      AUTH_MDP,    'user', NO_AUTH),
-            'lists/create'       => $this->make_hook('create',    AUTH_MDP,    'lists'),
+            'lists'              => $this->make_hook('lists',     AUTH_PASSWD, 'user'),
+            'lists/ajax'         => $this->make_hook('ajax',      AUTH_PASSWD, 'user', NO_AUTH),
+            'lists/create'       => $this->make_hook('create',    AUTH_PASSWD, 'lists'),
 
             'lists/members'      => $this->make_hook('members',   AUTH_COOKIE, 'user'),
             'lists/csv'          => $this->make_hook('csv',       AUTH_COOKIE, 'user'),
@@ -36,15 +36,15 @@ class ListsModule extends PLModule
             'lists/archives'     => $this->make_hook('archives',  AUTH_COOKIE, 'user'),
             'lists/archives/rss' => $this->make_hook('rss',       AUTH_PUBLIC, 'user', NO_HTTPS),
 
-            'lists/moderate'     => $this->make_hook('moderate',  AUTH_MDP,    'user'),
-            'lists/admin'        => $this->make_hook('admin',     AUTH_MDP,    'user'),
-            'lists/options'      => $this->make_hook('options',   AUTH_MDP,    'user'),
-            'lists/delete'       => $this->make_hook('delete',    AUTH_MDP,    'user'),
+            'lists/moderate'     => $this->make_hook('moderate',  AUTH_PASSWD, 'user'),
+            'lists/admin'        => $this->make_hook('admin',     AUTH_PASSWD, 'user'),
+            'lists/options'      => $this->make_hook('options',   AUTH_PASSWD, 'user'),
+            'lists/delete'       => $this->make_hook('delete',    AUTH_PASSWD, 'user'),
 
-            'lists/soptions'     => $this->make_hook('soptions',  AUTH_MDP,    'user'),
-            'lists/check'        => $this->make_hook('check',     AUTH_MDP,    'user'),
-            'admin/lists'        => $this->make_hook('admin_all', AUTH_MDP,    'admin'),
-            'admin/aliases'      => $this->make_hook('aaliases',  AUTH_MDP,    'admin')
+            'lists/soptions'     => $this->make_hook('soptions',  AUTH_PASSWD, 'user'),
+            'lists/check'        => $this->make_hook('check',     AUTH_PASSWD, 'user'),
+            'admin/lists'        => $this->make_hook('admin_all', AUTH_PASSWD, 'admin'),
+            'admin/aliases'      => $this->make_hook('aaliases',  AUTH_PASSWD, 'admin')
         );
     }
 
@@ -618,8 +618,9 @@ class ListsModule extends PLModule
 
                   case 'marketu': case 'markets':
                     require_once 'emails.inc.php';
+                    $user = User::get($uids[$key]);
                     $mail = valide_email($mails[$key]);
-                    if (isvalid_email_redirection($mail)) {
+                    if (isvalid_email_redirection($mail, $user)) {
                         $from = ($action == 'marketu') ? 'user' : 'staff';
                         $market = Marketing::get($uids[$key], $mail);
                         if (!$market) {
@@ -643,6 +644,10 @@ class ListsModule extends PLModule
             $members = User::getBulkForlifeEmails(Env::v('add_member'),
                                                   true,
                                                   array('ListsModule', 'no_login_callback'));
+            // Make sure we send a list (array_values) of unique (array_unique)
+            // emails.
+            $members = array_values(array_unique($members));
+
             $arr = $this->client->mass_subscribe($liste, $members);
             if (is_array($arr)) {
                 foreach($arr as $addr) {
@@ -661,6 +666,10 @@ class ListsModule extends PLModule
                 $members = User::getBulkForlifeEmails($upload->getContents(),
                                                       true,
                                                       array('ListsModule', 'no_login_callback'));
+                // Make sure we send a list (array_values) of unique (array_unique)
+                // emails.
+                $members = array_values(array_unique($members));
+
                 $arr = $this->client->mass_subscribe($liste, $members);
                 if (is_array($arr)) {
                     foreach($arr as $addr) {
index 5086e96..ac5cff5 100644 (file)
@@ -24,13 +24,13 @@ class MarketingModule extends PLModule
     function handlers()
     {
         return array(
-            'marketing'            => $this->make_hook('marketing',  AUTH_MDP,    'admin'),
-            'marketing/promo'      => $this->make_hook('promo',      AUTH_MDP,    'admin'),
-            'marketing/relance'    => $this->make_hook('relance',    AUTH_MDP,    'admin'),
-            'marketing/this_week'  => $this->make_hook('week',       AUTH_MDP,    'admin'),
-            'marketing/volontaire' => $this->make_hook('volontaire', AUTH_MDP,    'admin'),
+            'marketing'            => $this->make_hook('marketing',  AUTH_PASSWD, 'admin'),
+            'marketing/promo'      => $this->make_hook('promo',      AUTH_PASSWD, 'admin'),
+            'marketing/relance'    => $this->make_hook('relance',    AUTH_PASSWD, 'admin'),
+            'marketing/this_week'  => $this->make_hook('week',       AUTH_PASSWD, 'admin'),
+            'marketing/volontaire' => $this->make_hook('volontaire', AUTH_PASSWD, 'admin'),
 
-            'marketing/private'    => $this->make_hook('private',    AUTH_MDP,    'admin'),
+            'marketing/private'    => $this->make_hook('private',    AUTH_PASSWD, 'admin'),
             'marketing/public'     => $this->make_hook('public',     AUTH_COOKIE, 'user'),
             'marketing/broken'     => $this->make_hook('broken',     AUTH_COOKIE, 'user'),
         );
@@ -237,7 +237,7 @@ class MarketingModule extends PLModule
         if (Post::has('mail')) {
             $email = valide_email(Post::v('mail'));
         }
-        if (Post::has('valide') && isvalid_email_redirection($email)) {
+        if (Post::has('valide') && isvalid_email_redirection($email, $user)) {
             S::assert_xsrf_token();
 
             // security stuff
@@ -303,7 +303,7 @@ class MarketingModule extends PLModule
             $email = trim(Post::v('mail'));
 
             require_once 'emails.inc.php';
-            if (!isvalid_email_redirection($email)) {
+            if (!isvalid_email_redirection($email, $user)) {
                 $page->trigError('Email invalide&nbsp;!');
             } else {
                 // On cherche les marketings précédents sur cette adresse
index 6603bc8..809caef 100644 (file)
@@ -27,16 +27,16 @@ class NewsletterModule extends PLModule
             'nl'                           => $this->make_hook('nl',              AUTH_COOKIE, 'user'),
             'nl/show'                      => $this->make_hook('nl_show',         AUTH_COOKIE, 'user'),
             'nl/search'                    => $this->make_hook('nl_search',       AUTH_COOKIE, 'user'),
-            'nl/submit'                    => $this->make_hook('nl_submit',       AUTH_MDP,    'user'),
-            'nl/remaining'                 => $this->make_hook('nl_remaining',    AUTH_MDP,    'user'),
-            'admin/nls'                    => $this->make_hook('admin_nl_groups', AUTH_MDP,    'admin'),
-            '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'),
-            'admin/newsletter/edit/delete' => $this->make_hook('admin_nl_delete', AUTH_MDP,    'admin'),
+            'nl/submit'                    => $this->make_hook('nl_submit',       AUTH_PASSWD, 'user'),
+            'nl/remaining'                 => $this->make_hook('nl_remaining',    AUTH_PASSWD, 'user'),
+            'admin/nls'                    => $this->make_hook('admin_nl_groups', AUTH_PASSWD, 'admin'),
+            'admin/newsletter'             => $this->make_hook('admin_nl',        AUTH_PASSWD, 'admin'),
+            'admin/newsletter/categories'  => $this->make_hook('admin_nl_cat',    AUTH_PASSWD, 'admin'),
+            'admin/newsletter/edit'        => $this->make_hook('admin_nl_edit',   AUTH_PASSWD, 'admin'),
+            'admin/newsletter/edit/delete' => $this->make_hook('admin_nl_delete', AUTH_PASSWD, 'admin'),
             // Automatic mailing is disabled for X.org NL
-//            'admin/newsletter/edit/cancel' => $this->make_hook('cancel', AUTH_MDP, 'admin'),
-//            'admin/newsletter/edit/valid'  => $this->make_hook('valid',  AUTH_MDP, 'admin'),
+//            'admin/newsletter/edit/cancel' => $this->make_hook('cancel', AUTH_PASSWD, 'admin'),
+//            'admin/newsletter/edit/valid'  => $this->make_hook('valid',  AUTH_PASSWD, 'admin'),
         );
     }
 
@@ -216,14 +216,36 @@ class NewsletterModule extends PLModule
         $page->assign('nl_list', $nl->listAllIssues());
     }
 
-    function handler_admin_nl_groups($page)
+    function handler_admin_nl_groups($page, $sort = 'id', $order = 'ASC')
     {
         require_once 'newsletter.inc.php';
 
+        static $titles = array(
+            'id'         => 'Id',
+            'group_name' => 'Groupe',
+            'name'       => 'Titre',
+            'custom_css' => 'CSS spécifique',
+            'criteria'   => 'Critères actifs'
+        );
+        static $next_orders = array(
+            'ASC'  => 'DESC',
+            'DESC' => 'ASC'
+        );
+
+        if (!array_key_exists($sort, $titles)) {
+            $sort = 'id';
+        }
+        if (!in_array($order, array('ASC', 'DESC'))) {
+            $order = 'ASC';
+        }
+
         $page->changeTpl('newsletter/admin_all.tpl');
         $page->setTitle('Administration - Newsletters : Liste des Newsletters');
-
-        $page->assign('nls', Newsletter::getAll());
+        $page->assign('nls', Newsletter::getAll($sort, $order));
+        $page->assign('sort', $sort);
+        $page->assign('order', $order);
+        $page->assign('next_order', $next_orders[$order]);
+        $page->assign('titles', $titles);
     }
 
     function handler_admin_nl_edit($page, $nid = 'last', $aid = null, $action = 'edit') {
@@ -247,6 +269,7 @@ class NewsletterModule extends PLModule
 
         // Convert NLIssue error messages to human-readable errors
         $error_msgs = array(
+            NLIssue::ERROR_INVALID_REPLY_TO => "L'adresse de réponse est invalide.",
             NLIssue::ERROR_INVALID_SHORTNAME => "Le nom court est invalide ou vide.",
             NLIssue::ERROR_INVALID_UFC => "Le filtre des destinataires est invalide.",
             NLIssue::ERROR_TOO_LONG_UFC => "Le nombre de matricules AX renseigné est trop élevé.",
@@ -261,6 +284,7 @@ class NewsletterModule extends PLModule
             $issue->title_mail = Post::s('title_mail');
             $issue->head       = Post::s('head');
             $issue->signature  = Post::s('signature');
+            $issue->reply_to   = Post::s('reply_to');
 
             if ($issue->isEditable()) {
                 // Date and shortname may only be modified for pending NLs, otherwise all links get broken.
index fa4c1d5..826c78c 100644 (file)
@@ -64,9 +64,9 @@ class OpenidModule extends PLModule
             '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, 'user'),
-            'openid/trusted'       => $this->make_hook('trusted',       AUTH_MDP, 'user'),
-            'admin/openid/trusted' => $this->make_hook('admin_trusted', AUTH_MDP, 'admin'),
+            'openid/trust'         => $this->make_hook('trust',         AUTH_PASSWD, 'user'),
+            'openid/trusted'       => $this->make_hook('trusted',       AUTH_PASSWD, 'user'),
+            'admin/openid/trusted' => $this->make_hook('admin_trusted', AUTH_PASSWD, 'admin'),
         );
     }
 
index ef0ed1a..4a28ef3 100644 (file)
@@ -105,104 +105,116 @@ class PaymentModule extends PLModule
     function handlers()
     {
         return array(
-            'payment'                      => $this->make_hook('payment',          AUTH_MDP,    'payment'),
+            'payment'                      => $this->make_hook('payment',          AUTH_PUBLIC, 'user'),
             'payment/cyber2_return'        => $this->make_hook('cyber2_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,    'user'),
-            '%grp/payment'                 => $this->make_hook('xnet_payment',     AUTH_MDP,    'user'),
-            '%grp/payment/csv'             => $this->make_hook('payment_csv',      AUTH_MDP,    'groupadmin'),
+            '%grp/paiement'                => $this->make_hook('xnet_payment',     AUTH_PUBLIC, 'user'),
+            '%grp/payment'                 => $this->make_hook('xnet_payment',     AUTH_PUBLIC, 'user'),
+            '%grp/payment/csv'             => $this->make_hook('payment_csv',      AUTH_PASSWD, 'groupadmin'),
             '%grp/payment/cyber2_return'   => $this->make_hook('cyber2_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/methods'       => $this->make_hook('adm_methods',      AUTH_MDP,    'admin'),
-            'admin/payments/transactions'  => $this->make_hook('adm_transactions', AUTH_MDP,    'admin'),
-            'admin/reconcile'              => $this->make_hook('adm_reconcile',    AUTH_MDP,    'admin'),
-            'admin/reconcile/importlogs'   => $this->make_hook('adm_importlogs',   AUTH_MDP,    'admin'),
-            'admin/reconcile/transfers'    => $this->make_hook('adm_transfers',    AUTH_MDP,    'admin'),
-            'admin/reconcile/bankaccounts' => $this->make_hook('adm_bankaccounts', AUTH_MDP,    'admin'),
+            'admin/payments'               => $this->make_hook('admin',            AUTH_PASSWD, 'admin'),
+            'admin/payments/methods'       => $this->make_hook('adm_methods',      AUTH_PASSWD, 'admin'),
+            'admin/payments/transactions'  => $this->make_hook('adm_transactions', AUTH_PASSWD, 'admin'),
+            'admin/reconcile'              => $this->make_hook('adm_reconcile',    AUTH_PASSWD, 'admin'),
+            'admin/reconcile/importlogs'   => $this->make_hook('adm_importlogs',   AUTH_PASSWD, 'admin'),
+            'admin/reconcile/transfers'    => $this->make_hook('adm_transfers',    AUTH_PASSWD, 'admin'),
+            'admin/reconcile/bankaccounts' => $this->make_hook('adm_bankaccounts', AUTH_PASSWD, 'admin'),
         );
     }
 
     function handler_payment($page, $ref = -1)
     {
-        global $globals;
-
+        $page->changeTpl('payment/payment.tpl');
+        $page->setTitle('Télépaiement');
         $this->load('money.inc.php');
 
-        if (!empty($GLOBALS['IS_XNET_SITE'])) {
-            if (!$globals->asso('id')) {
-                return PL_NOT_FOUND;
-            }
-            $res = XDB::query('SELECT  asso_id
-                                 FROM  payments
-                                WHERE  asso_id = {?} AND id = {?}',
-                              $globals->asso('id'), $ref);
-            if (!$res->numRows()) {
-                return PL_FORBIDDEN;
-            }
-        }
-        $page->changeTpl('payment/index.tpl');
-        $page->setTitle('Télépaiements');
-
-        // initialisation
-        $op   = Env::v('op', 'select');
         $meth = new PayMethod(Env::i('methode', -1));
         $pay  = new Payment($ref);
 
-        if($pay->flags->hasflag('old')){
-            $page->trigError("La transaction selectionnée est périmée.");
-            $pay = new Payment();
+        if (!$pay->flags->hasflag('public') && (!S::user() || !S::logged())) {
+            $page->kill("Vous n'avez pas les permissions nécessaires pour accéder à cette page.");
+        } else {
+            $page->assign('public', true);
         }
-        $val = Env::v('montant') != 0 ? Env::v('montant') : $pay->amount_def;
 
-        if (($e = $pay->check($val)) !== true) {
-            $page->trigError($e);
+        if ($pay->flags->hasflag('old')) {
+            $page->kill('La transaction selectionnée est périmée.');
         }
 
-        if ($op == 'submit') {
-            $pay->init($val, $meth);
-            $pay->prepareform($pay);
-        } else {
+        $val = (Post::v('amount') != 0) ? Post::v('amount') : $pay->amount_def;
+
+        if (($error = $pay->check($val)) !== true) {
+            $page->trigError($error);
+        }
+
+        if (Post::has('op') && Post::v('op', 'select') == 'submit') {
+            if (S::logged()) {
+                $user = S::user();
+            } else {
+                $user = User::getSilent(Post::t('login'));
+            }
+
+            if (is_null($user)) {
+                $page->trigError("L'identifiant est erroné.");
+                $page->assign('login_error', true);
+                $page->assign('login', Post::t('login'));
+            } else {
+                $pay->init($val, $meth);
+                $pay->prepareform($user);
+                $page->assign('full_name', $user->fullName(true));
+                $page->assign('sex', $user->isFemale());
+            }
+        } elseif (S::logged()) {
             $res = XDB::iterator('SELECT  ts_confirmed, amount
                                     FROM  payment_transactions
                                    WHERE  uid = {?} AND ref = {?}
                                 ORDER BY  ts_confirmed DESC',
-                                 S::v('uid', -1), $ref);
+                                 S::v('uid', -1), $pay->id);
 
             if ($res->total()) {
                 $page->assign('transactions', $res);
             }
 
-            if ($pay->flags->hasflag('donation')) {
-                $donations = XDB::fetchAllAssoc('SELECT  IF(p.display,
-                                                            IF(ap.pid IS NOT NULL, CONCAT(a.full_name, \' (\', pd.promo, \')\'), a.full_name),
-                                                            \'XXXX\') AS name, p.amount
-                                                   FROM  payment_transactions AS p
-                                             INNER JOIN  accounts             AS a  ON (a.uid = p.uid)
-                                              LEFT JOIN  account_profiles     AS ap ON (a.uid = ap.uid AND FIND_IN_SET(\'owner\', ap.perms))
-                                              LEFT JOIN  profile_display      AS pd ON (ap.pid = pd.pid)
-                                                  WHERE  p.ref = {?}
-                                               ORDER BY  LENGTH(p.amount) DESC, p.amount DESC, name',
-                                                $ref);
-                $sum = 0;
-                foreach ($donations as $d) {
-                    $sum += $d['amount'];
-                }
-
+            // Only if $id = -1, meaning only for donation the site's association
+            if ($ref == -1) {
+                $biggest_donations = XDB::fetchAllAssoc('SELECT  IF(p.display,
+                                                                    IF(ap.pid IS NOT NULL, CONCAT(a.full_name, \' (\', pd.promo, \')\'), a.full_name),
+                                                                    \'XXXX\') AS name, p.amount, p.ts_confirmed
+                                                           FROM  payment_transactions AS p
+                                                     INNER JOIN  accounts             AS a  ON (a.uid = p.uid)
+                                                      LEFT JOIN  account_profiles     AS ap ON (a.uid = ap.uid AND FIND_IN_SET(\'owner\', ap.perms))
+                                                      LEFT JOIN  profile_display      AS pd ON (ap.pid = pd.pid)
+                                                          WHERE  p.ref = {?}
+                                                       ORDER BY  LENGTH(p.amount) DESC, p.amount DESC, name
+                                                          LIMIT  10',
+                                                        $pay->id);
+
+                $donations = XDB::fetchAllAssoc('(SELECT  SUM(amount) AS amount, YEAR(ts_confirmed) AS year, MONTH(ts_confirmed) AS month, ts_confirmed
+                                                    FROM  payment_transactions
+                                                   WHERE  ref = {?} AND YEAR(ts_confirmed) = YEAR(CURDATE())
+                                                GROUP BY  month)
+                                                 UNION
+                                                 (SELECT  SUM(amount) AS amount, YEAR(ts_confirmed) AS year, 0 AS month, ts_confirmed
+                                                    FROM  payment_transactions
+                                                   WHERE  ref = {?} AND YEAR(ts_confirmed) < YEAR(CURDATE())
+                                                GROUP BY  year)
+                                                ORDER BY  year DESC, month DESC',
+                                                $pay->id, $pay->id);
+
+                $page->assign('biggest_donations', $biggest_donations);
                 $page->assign('donations', $donations);
-                $page->assign('sum', strtr($sum, '.', ','));
+                $page->assign('donation', true);
             }
         }
 
-        $val = floor($val*100)/100;
-        $page->assign('montant', $val);
+        $val = floor($val * 100) / 100;
+        $page->assign('amount', $val);
         $page->assign('comment', Env::v('comment'));
 
         $page->assign('meth', $meth);
         $page->assign('pay', $pay);
         $page->assign('evtlink', $pay->event());
-        $page->assign('sex', S::user()->isFemale());
-        $page->assign('donation', $pay->flags->hasflag('donation'));
     }
 
     function handler_cyber2_return($page, $uid = null)
@@ -266,7 +278,7 @@ class PaymentModule extends PLModule
             list($eid, $asso_id) = $res->fetchOneRow();
             require_once dirname(__FILE__) . '/xnetevents/xnetevents.inc.php';
             $evt = get_event_detail($eid, false, $asso_id);
-            subscribe_lists_event($user->id(), $evt['short_name'], 1, $amount, true);
+            subscribe_lists_event($user->id(), $evt['short_name'], 1, $montant, true);
         }
 
         /* on genere le mail de confirmation */
@@ -357,12 +369,13 @@ class PaymentModule extends PLModule
                     $no_transaction, $user->id(), $ref, $fullref, $montant, $clef, Env::v('comment'), Get::i('display'));
 
         // We check if it is an Xnet payment and then update the related ML.
-        $res = XDB::query('SELECT  eid
+        $res = XDB::query('SELECT  eid, asso_id
                              FROM  group_events
                             WHERE  paiement_id = {?}', $ref);
-        if ($eid = $res->fetchOneCell()) {
+        if ($res->numRows() == 1) {
+            list($eid, $asso_id) = $res->fetchOneRow();
             require_once dirname(__FILE__) . '/xnetevents/xnetevents.inc.php';
-            $evt = get_event_detail($eid);
+            $evt = get_event_detail($eid, false, $asso_id);
             subscribe_lists_event($user->id(), $evt['short_name'], 1, $montant, true);
         }
 
@@ -404,7 +417,7 @@ class PaymentModule extends PLModule
         global $globals;
 
         $perms = S::v('perms');
-        if (!$perms->hasFlag('groupmember')) {
+        if (!(S::identified() && $perms->hasFlag('groupmember'))) {
             if (is_null($pid)) {
                 return PL_FORBIDDEN;
             }
@@ -413,7 +426,12 @@ class PaymentModule extends PLModule
                            INNER JOIN  group_event_participants AS ep ON (ep.eid = e.eid AND ep.uid = {?})
                                 WHERE  e.paiement_id = {?} AND e.asso_id = {?}",
                               S::i('uid'), $pid, $globals->asso('id'));
-            if ($res->numRows() == 0) {
+            $public = XDB::query("SELECT  1
+                                    FROM  payments     AS p
+                              INNER JOIN  group_events AS g ON (g.paiement_id = p.id)
+                                   WHERE  g.asso_id = {?} AND p.id = {?} AND FIND_IN_SET('public', p.flags)",
+                                 $globals->asso('id'), $pid);
+            if ($res->numRows() == 0 && $public->numRows() == 0) {
                 return PL_FORBIDDEN;
             }
         }
@@ -434,7 +452,7 @@ class PaymentModule extends PLModule
         $trans = array();
         $event = array();
         if (may_update()) {
-            static $orders = array('timestamp' => 'p', 'directory_name' => 'a', 'promo' => 'pd', 'comment' => 'p', 'amount' => 'p');
+            static $orders = array('ts_confirmed' => 'p', 'directory_name' => 'a', 'promo' => 'pd', 'comment' => 'p', 'amount' => 'p');
 
             if (Get::has('order_id') && Get::has('order') && array_key_exists(Get::v('order'), $orders)) {
                 $order_id = Get::i('order_id');
@@ -925,7 +943,7 @@ class PaymentLogsImporter extends CSVImporter {
             // convert date
             $a['date'] = preg_replace('/([0-9]{2})\/([0-9]{2})\/([0-9]{4}).*/', '\3-\2-\1', $a['date']);
             $a['date'] = preg_replace('/T.*/','', $a['date']);
-            
+
             // convert money
             $a['amount'] = str_replace(',', '.', $a['amount']);
             $a['commission'] = str_replace(',', '.', $a['commission']);
index 83b21db..ecd49f5 100644 (file)
 
 class Payment
 {
-    // {{{ properties
-
-    var $id;
-    var $text;
-    var $url;
-    var $flags;
-    var $mail;
-    var $amount_min;
-    var $amount_max;
-    var $amount_def;
-    var $asso_id;
-
-    var $api = null;
-
-    // }}}
-    // {{{ constructor
-
-    function Payment($ref=-1)
+    public $id;
+    public $text;
+    public $url;
+    public $flags;
+    public $mvarail;
+    public $amount_min;
+    public $amount_max;
+    public $amount_def;
+    public $asso_id;
+
+    public $api = null;
+
+    function Payment($ref = -1)
     {
         global $globals;
-        $r   = $ref==-1 ? $globals->money->mpay_def_id : $ref;
-        $res = XDB::query("SELECT  id, text, url, flags, mail, amount_min, amount_max, amount_def, asso_id
-                             FROM  payments WHERE id={?}", $r);
+
+        $r   = ($ref == -1) ? $globals->money->mpay_def_id : $ref;
+        $res = XDB::query('SELECT  id, text, url, flags, mail, amount_min, amount_max, amount_def, asso_id
+                             FROM  payments
+                            WHERE  id = {?}', $r);
         list($this->id, $this->text, $this->url, $flags, $this->mail,
              $this->amount_min, $this->amount_max, $this->amount_def, $this->asso_id) = $res->fetchOneRow();
 
         $this->amount_min = (float)$this->amount_min;
         $this->amount_max = (float)$this->amount_max;
-        $this->flags       = new PlFlagSet($flags);
+        $this->flags      = new PlFlagSet($flags);
     }
 
-    // }}}
-    // {{{ function check()
-
     function check($value)
     {
         $v = (float)strtr($value, ',', '.');
@@ -67,21 +61,15 @@ class Payment
         }
     }
 
-    // }}}
-    // {{{ function init()
-
     function init($val, $meth)
     {
-        require_once dirname(__FILE__).'/money/'.$meth->inc;
+        require_once dirname(__FILE__) . '/money/' . $meth->inc;
         $this->api = new $api($val);
     }
 
-    // }}}
-    // {{{ function prepareform()
-
-    function prepareform()
+    function prepareform(User $user)
     {
-        return $this->api->prepareform($this);
+        return $this->api->prepareform($this, $user);
     }
 
     function event()
@@ -98,34 +86,25 @@ class Payment
         }
         return null;
     }
-    // }}}
 }
 
-// {{{ class PayMethod
-
 class PayMethod
 {
-    // {{{ properties
-
-    var $id;
-    var $text;
-    var $inc;
-
-    // }}}
-    // {{{ constructor
+    public $id;
+    public $text;
+    public $inc;
 
-    function PayMethod($id=-1)
+    function PayMethod($id = -1)
     {
         global $globals;
-        $i   = $id==-1 ? $globals->money->mpay_def_meth : $id;
-        $res = XDB::query("SELECT id,text,include FROM payment_methods WHERE id={?}", $i);
+
+        $i   = ($id == -1) ? $globals->money->mpay_def_meth : $id;
+        $res = XDB::query('SELECT  id, text, include
+                             FROM  payment_methods
+                            WHERE  id = {?}', $i);
         list($this->id, $this->text, $this->inc) = $res->fetchOneRow();
     }
-
-    // }}}
 }
 
-// }}}
-
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
 ?>
index f0b40e4..e82fb8f 100644 (file)
@@ -60,7 +60,7 @@ class BPLCCyberPlus
         return trim(preg_replace('/\s\s+/', ' ', preg_replace('/[^a-zA-Z0-9]/', ' ', $string)));
     }
 
-    function prepareform($pay)
+    function prepareform($pay, $user)
     {
         global $globals, $platal;
         $log = S::v('log');
@@ -79,9 +79,9 @@ class BPLCCyberPlus
             'vads_return_mode' => 'NONE',
             'vads_url_return' => $pay->url ? $pay->url : $globals->baseurl . '/' . $platal->ns);
         $this->infos['client'] = Array(
-            'vads_cust_email' => S::user()->bestEmail(),
+            'vads_cust_email' => $user->bestEmail(),
             'vads_cust_id' => S::v('uid'),
-            'vads_cust_name' => substr(self::replaceNonAlpha(replace_accent(S::user()->shortName())), 0, 127));
+            'vads_cust_name' => substr(self::replaceNonAlpha(replace_accent($user->shortName())), 0, 127));
         $this->infos['commande'] = Array(
             'vads_amount' => $this->val,
             'vads_currency' => '978', # Euro
index 41fbb6c..3ea2c63 100644 (file)
@@ -33,7 +33,7 @@ class PayPal
         $this->val_number = $val;
     }
 
-    function prepareform($pay)
+    function prepareform($pay, $user)
     {
         // Documentation:
         // https://www.paypal.com/developer
@@ -43,7 +43,6 @@ class PayPal
         global $globals, $platal;
 
         $this->urlform = 'https://' . $globals->money->paypal_site . '/cgi-bin/webscr';
-        $user = S::user();
 
         $roboturl = str_replace("https://","http://",$globals->baseurl)
                   . '/' . $platal->ns . "payment/paypal_return/" . S::v('uid')
index c9fd3d9..baa18b1 100644 (file)
@@ -38,26 +38,27 @@ 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, 'user,groups'),
-            'prefs/rss'         => $this->make_hook('prefs_rss', AUTH_COOKIE, 'user'),
-            'prefs/webredirect' => $this->make_hook('webredir',  AUTH_MDP,    'mail'),
-            'prefs/skin'        => $this->make_hook('skin',      AUTH_COOKIE, 'user'),
+            'prefs'             => $this->make_hook('prefs',        AUTH_COOKIE, 'user,groups'),
+            'prefs/rss'         => $this->make_hook('prefs_rss',    AUTH_COOKIE, 'user'),
+            'prefs/webredirect' => $this->make_hook('webredir',     AUTH_PASSWD, 'mail'),
+            'prefs/skin'        => $this->make_hook('skin',         AUTH_COOKIE, 'user'),
+            'prefs/email'       => $this->make_hook('prefs_email',  AUTH_COOKIE, 'mail'),
 
             // password related thingies
-            'password'          => $this->make_hook('password',  AUTH_MDP,    'user,groups'),
-            'tmpPWD'            => $this->make_hook('tmpPWD',    AUTH_PUBLIC),
-            'password/smtp'     => $this->make_hook('smtppass',  AUTH_MDP,    'mail'),
-            'recovery'          => $this->make_hook('recovery',  AUTH_PUBLIC),
+            'password'          => $this->make_hook('password',     AUTH_PASSWD, 'user,groups'),
+            'password/smtp'     => $this->make_hook('smtppass',     AUTH_PASSWD, 'mail'),
+            'tmpPWD'            => $this->make_hook('tmpPWD',       AUTH_PUBLIC),
+            'recovery'          => $this->make_hook('recovery',     AUTH_PUBLIC),
             'recovery/ext'      => $this->make_hook('recovery_ext', AUTH_PUBLIC),
             'register/ext'      => $this->make_hook('register_ext', AUTH_PUBLIC),
-            'exit'              => $this->make_hook('exit',      AUTH_PUBLIC),
-            'review'            => $this->make_hook('review',    AUTH_PUBLIC),
-            'deconnexion.php'   => $this->make_hook('exit',      AUTH_PUBLIC),
+            'exit'              => $this->make_hook('exit',         AUTH_PUBLIC),
+            'review'            => $this->make_hook('review',       AUTH_PUBLIC),
+            'deconnexion.php'   => $this->make_hook('exit',         AUTH_PUBLIC),
         );
     }
 
@@ -199,6 +200,47 @@ class PlatalModule extends PLModule
         }
     }
 
+    function handler_prefs_email($page)
+    {
+        $page->changeTpl('platal/email_preferences.tpl');
+
+        if (Post::has('submit')) {
+            S::assert_xsrf_token();
+
+            $from_email = Post::t('from_email');
+            $from_format = Post::v('from_format');
+
+            // Checks email.
+            $email_regex = '/^[a-z0-9.\-+_\$]+@([\-.+_]?[a-z0-9])+$/i';
+            if (!preg_match($email_regex, $from_email)) {
+                $full_regex = '/^[^<]*<[a-z0-9.\-+_\$]+@([\-.+_]?[a-z0-9])+>$/i';
+                if (!preg_match($full_regex, $from_email)) {
+                    $page->trigError("L'adresse email est erronée.");
+                    $error = true;
+                    $page->assign('from_email', $from_email);
+                    $page->assign('from_format', $from_format);
+                    $page->assign('error', true);
+                    return;
+                }
+            }
+
+            // Saves data.
+            XDB::execute('UPDATE  accounts
+                             SET  from_email = {?}, from_format = {?}
+                           WHERE  uid = {?}',
+                         $from_email, ($from_format == 'html' ? 'html' : 'text'), S::user()->id());
+            $page->trigSuccess('Données enregistrées.');
+        }
+
+        $data = XDB::fetchOneAssoc('SELECT  from_email, from_format
+                                      FROM  accounts
+                                     WHERE  uid = {?}',
+                                   S::user()->id());
+        $page->assign('from_email', $data['from_email']);
+        $page->assign('from_format', $data['from_format']);
+        $page->assign('error', false);
+    }
+
     function handler_password($page)
     {
         global $globals;
@@ -375,7 +417,7 @@ Adresse de secours : ' . $to));
                      $user->id(), $hash);
 
         $mymail = new PlMailer('platal/password_recovery_xnet.mail.tpl');
-        $mymail->addTo($user);
+        $mymail->setTo($user);
         $mymail->assign('hash', $hash);
         $mymail->assign('email', Post::t('login'));
         $mymail->send();
@@ -389,23 +431,18 @@ Adresse de secours : ' . $to));
         XDB::execute('DELETE FROM  account_lost_passwords
                             WHERE  DATE_SUB(NOW(), INTERVAL 380 MINUTE) > created');
 
-        $res = XDB::query('SELECT  uid
-                             FROM  account_lost_passwords WHERE certificat={?}', $certif);
-        $ligne = $res->fetchOneAssoc();
-        if (!$ligne) {
-            $page->changeTpl('platal/index.tpl');
-            $page->kill("Cette adresse n'existe pas ou n'existe plus sur le serveur.");
-        }
-
-        $uid = $ligne["uid"];
         if (Post::has('pwhash') && Post::t('pwhash')) {
+            $uid = XDB::fetchOneCell('SELECT  uid
+                                        FROM  accounts
+                                       WHERE  hruid = {?}',
+                                     Post::t('username'));
             $password = Post::t('pwhash');
             XDB::query('UPDATE  accounts
-                           SET  password={?}
+                           SET  password = {?}
                          WHERE  uid = {?} AND state = \'active\'',
                        $password, $uid);
             XDB::query('DELETE FROM  account_lost_passwords
-                              WHERE  certificat={?}', $certif);
+                              WHERE  certificat = {?}', $certif);
 
             // If GoogleApps is enabled, and the user did choose to use synchronized passwords,
             // updates the Google Apps password as well.
@@ -421,14 +458,23 @@ Adresse de secours : ' . $to));
 
             // 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);
+            Platal::session()->start(AUTH_PASSWD);
 
             $page->changeTpl('platal/tmpPWD.success.tpl');
         } else {
+            $res = XDB::query('SELECT  uid
+                                 FROM  account_lost_passwords
+                                WHERE  certificat = {?}', $certif);
+            $ligne = $res->fetchOneAssoc();
+            if (!$ligne) {
+                $page->changeTpl('platal/index.tpl');
+                $page->kill("Cette adresse n'existe pas ou n'existe plus sur le serveur.");
+            }
+
             $hruid = XDB::fetchOneCell('SELECT  hruid
                                           FROM  accounts
                                          WHERE  uid = {?}',
-                                       $uid);
+                                       $ligne['uid']);
             $page->changeTpl('platal/password.tpl');
             $page->assign('hruid', $hruid);
             $page->assign('do_auth', 1);
index 7428f14..6714c4e 100644 (file)
@@ -25,15 +25,15 @@ class ProfileModule extends PLModule
     {
         return array(
             'photo'                      => $this->make_hook('photo',                      AUTH_PUBLIC),
-            'photo/change'               => $this->make_hook('photo_change',               AUTH_MDP,    'user'),
+            'photo/change'               => $this->make_hook('photo_change',               AUTH_PASSWD, 'user'),
 
             'fiche.php'                  => $this->make_hook('fiche',                      AUTH_PUBLIC),
             'profile'                    => $this->make_hook('profile',                    AUTH_PUBLIC),
             'profile/private'            => $this->make_hook('profile',                    AUTH_COOKIE, 'user'),
             'profile/ax'                 => $this->make_hook('ax',                         AUTH_COOKIE, 'admin,edit_directory'),
-            'profile/edit'               => $this->make_hook('p_edit',                     AUTH_MDP,    'user'),
+            'profile/edit'               => $this->make_hook('p_edit',                     AUTH_PASSWD, 'user'),
             'profile/ajax/address'       => $this->make_hook('ajax_address',               AUTH_COOKIE, 'user', NO_AUTH),
-            'profile/ajax/address/del'   => $this->make_hook('ajax_address_del',           AUTH_MDP,    'user'),
+            'profile/ajax/address/del'   => $this->make_hook('ajax_address_del',           AUTH_PASSWD, 'user'),
             'profile/ajax/tel'           => $this->make_hook('ajax_tel',                   AUTH_COOKIE, 'user', NO_AUTH),
             'profile/ajax/edu'           => $this->make_hook('ajax_edu',                   AUTH_COOKIE, 'user', NO_AUTH),
             'profile/ajax/medal'         => $this->make_hook('ajax_medal',                 AUTH_COOKIE, 'user', NO_AUTH),
@@ -57,17 +57,17 @@ class ProfileModule extends PLModule
             'groupes-x/logo'             => $this->make_hook('xnetlogo',                   AUTH_PUBLIC),
 
             'vcard'                      => $this->make_hook('vcard',                      AUTH_COOKIE, 'user', NO_HTTPS),
-            'admin/binets'               => $this->make_hook('admin_binets',               AUTH_MDP,    'admin'),
-            'admin/medals'               => $this->make_hook('admin_medals',               AUTH_MDP,    'admin'),
-            'admin/education'            => $this->make_hook('admin_education',            AUTH_MDP,    'admin'),
-            'admin/education_field'      => $this->make_hook('admin_education_field',      AUTH_MDP,    'admin'),
-            'admin/education_degree'     => $this->make_hook('admin_education_degree',     AUTH_MDP,    'admin'),
-            'admin/education_degree_set' => $this->make_hook('admin_education_degree_set', AUTH_MDP,    'admin'),
-            'admin/sections'             => $this->make_hook('admin_sections',             AUTH_MDP,    'admin'),
-            'admin/networking'           => $this->make_hook('admin_networking',           AUTH_MDP,    'admin'),
-            'admin/trombino'             => $this->make_hook('admin_trombino',             AUTH_MDP,    'admin'),
-            'admin/corps_enum'           => $this->make_hook('admin_corps_enum',           AUTH_MDP,    'admin'),
-            'admin/corps_rank'           => $this->make_hook('admin_corps_rank',           AUTH_MDP,    'admin'),
+            'admin/binets'               => $this->make_hook('admin_binets',               AUTH_PASSWD, 'admin'),
+            'admin/medals'               => $this->make_hook('admin_medals',               AUTH_PASSWD, 'admin'),
+            'admin/education'            => $this->make_hook('admin_education',            AUTH_PASSWD, 'admin'),
+            'admin/education_field'      => $this->make_hook('admin_education_field',      AUTH_PASSWD, 'admin'),
+            'admin/education_degree'     => $this->make_hook('admin_education_degree',     AUTH_PASSWD, 'admin'),
+            'admin/education_degree_set' => $this->make_hook('admin_education_degree_set', AUTH_PASSWD, 'admin'),
+            'admin/sections'             => $this->make_hook('admin_sections',             AUTH_PASSWD, 'admin'),
+            'admin/networking'           => $this->make_hook('admin_networking',           AUTH_PASSWD, 'admin'),
+            'admin/trombino'             => $this->make_hook('admin_trombino',             AUTH_PASSWD, 'admin'),
+            'admin/corps_enum'           => $this->make_hook('admin_corps_enum',           AUTH_PASSWD, 'admin'),
+            'admin/corps_rank'           => $this->make_hook('admin_corps_rank',           AUTH_PASSWD, 'admin'),
         );
     }
 
@@ -273,7 +273,7 @@ class ProfileModule extends PLModule
         $page->setTitle($profile->fullName());
 
         // Determines and displays the virtual alias.
-        if (!is_null($owner) && $profile->alias_pub == 'public') {
+        if (!is_null($owner) && $profile->isVisible($profile->alias_pub)) {
             $page->assign('virtualalias', $owner->emailAlias());
         }
 
@@ -301,7 +301,7 @@ class ProfileModule extends PLModule
     {
         global $globals;
 
-        if (in_array($hrpid, array('general', 'adresses', 'emploi', 'poly', 'deco', 'skill', 'mentor', 'deltaten'))) {
+        if (in_array($hrpid, array('general', 'adresses', 'emploi', 'poly', 'deco', 'mentor', 'deltaten'))) {
             $aux = $opened_tab;
             $opened_tab = $hrpid;
             $hrpid = $aux;
@@ -318,6 +318,7 @@ class ProfileModule extends PLModule
         }
 
         // Build the page
+        $page->addJsLink('jquery.ui.xorg.js');
         $page->addJsLink('education.js', true, false); /* dynamic content */
         $page->addJsLink('grades.js', true, false);    /* dynamic content */
         $page->addJsLink('profile.js');
@@ -328,15 +329,15 @@ class ProfileModule extends PLModule
         $wiz->addPage('ProfilePageGeneral', 'Général', 'general');
         $wiz->addPage('ProfilePageAddresses', 'Adresses personnelles', 'adresses');
         $wiz->addPage('ProfilePageJobs', 'Informations professionnelles', 'emploi');
-        if (S::user()->checkPerms(User::PERM_DIRECTORY_PRIVATE)) {
+        $viewPrivate = S::user()->checkPerms(User::PERM_DIRECTORY_PRIVATE);
+        if ($viewPrivate) {
             $wiz->addPage('ProfilePageGroups', 'Groupes X - Binets', 'poly');
         }
         $wiz->addPage('ProfilePageDecos', 'Décorations - Medailles', 'deco');
-        if (S::user()->checkPerms(User::PERM_DIRECTORY_PRIVATE)) {
-            $wiz->addPage('ProfilePageSkills', 'Compétences diverses', 'skill');
+        if ($viewPrivate) {
             $wiz->addPage('ProfilePageMentor', 'Mentoring', 'mentor');
         }
-        if (S::user()->checkPerms(User::PERM_DIRECTORY_PRIVATE) && $profile->isDeltatenEnabled(Profile::DELTATEN_OLD)) {
+        if ($viewPrivate && $profile->isDeltatenEnabled(Profile::DELTATEN_OLD)) {
             $wiz->addPage('ProfilePageDeltaten', 'Opération N N-10', 'deltaten');
         }
         $wiz->apply($page, 'profile/edit/' . $profile->hrid(), $opened_tab, $mode);
@@ -348,6 +349,8 @@ class ProfileModule extends PLModule
 
        $page->setTitle('Mon Profil');
        $page->assign('hrpid', $profile->hrid());
+       $page->assign('viewPrivate', $viewPrivate);
+       $page->assign('isMe', S::user()->isMyProfile($profile));
        if (isset($success) && $success) {
            $page->trigSuccess('Ton profil a bien été mis à jour.');
        }
@@ -427,8 +430,12 @@ class ProfileModule extends PLModule
     {
         pl_content_headers("text/html");
         $page->changeTpl('profile/deco.medal.tpl', NO_SKIN);
+        list($valid, $has_levels) = XDB::fetchOneRow("SELECT  NOT FIND_IN_SET('validation', flags), FIND_IN_SET('has_levels', flags)
+                                                        FROM  profile_medal_enum
+                                                       WHERE  id = {?}",
+                                                     $id);
         $page->assign('id', $i);
-        $page->assign('medal', array('id' => $id, 'grade' => 0, 'valid' => 0));
+        $page->assign('medal', array('id' => $id, 'grade' => 0, 'valid' => $valid, 'has_levels' => $has_levels));
     }
 
     function handler_ajax_job($page, $id, $pid)
@@ -557,7 +564,7 @@ class ProfileModule extends PLModule
     {
         pl_content_headers("text/plain");
 
-        $q = Env::v('q').'%';
+        $q = Env::v('term') . '%';
         $tokens = JobTerms::tokenize($q);
         if (count($tokens) == 0) {
             exit;
@@ -565,51 +572,79 @@ class ProfileModule extends PLModule
         sort($tokens);
         $q_normalized = implode(' ', $tokens);
 
-        // try to look in cached results
+        // Try to look in cached results.
+        $cached = false;
         $cache = XDB::query('SELECT  result
                                FROM  search_autocomplete
-                              WHERE  name = {?} AND
-                                     query = {?} AND
-                                     generated > NOW() - INTERVAL 1 DAY',
-                            $type, $q_normalized);
-        if ($res = $cache->fetchOneCell()) {
-            echo $res;
-            die();
-        }
-
-        $joins = JobTerms::token_join_query($tokens, 'e');
-        if ($type == 'mentor') {
-            $count = ', COUNT(DISTINCT pid) AS nb';
-            $countjoin = ' INNER JOIN  profile_job_term_relation AS r ON(r.jtid_1 = e.jtid) INNER JOIN  profile_mentor_term AS m ON(r.jtid_2 = m.jtid)';
-            $countorder = 'nb DESC, ';
+                              WHERE  name = {?} AND query = {?} AND generated > NOW() - INTERVAL 1 DAY',
+                             $type, $q_normalized);
+
+        if ($cache->numRows() > 0) {
+            $cached = true;
+            $data = explode("\n", $cache->fetchOneCell());
+            $list = array();
+            foreach ($data as $line) {
+                if ($line != '') {
+                    $aux = explode("\t", $line);
+                    if ($type == 'mentor') {
+                        $item = array(
+                            'field' => $aux[0],
+                            'nb'    => $aux[1],
+                            'id'    => $aux[2]
+                        );
+                        $item['value'] = SearchModule::format_autocomplete($item);
+                    } else {
+                        $item = array(
+                            'value' => $aux[0],
+                            'id'    => $aux[1]
+                        );
+                    }
+                    array_push($list, $item);
+                }
+            }
         } else {
-            $count = $countjoin = $countorder = '';
-        }
-        $list = XDB::iterator('SELECT  e.jtid AS id, e.full_name AS field'.$count.'
-                                 FROM  profile_job_term_enum AS e '.$joins.$countjoin.'
-                             GROUP BY  e.jtid
-                             ORDER BY  '.$countorder.'field
-                                LIMIT  11');
-        $nbResults = 0;
-        $res = '';
-        while ($result = $list->next()) {
-            $nbResults++;
-            if ($nbResults == 11) {
-                $res .= $q."|-1\n";
+            $joins = JobTerms::token_join_query($tokens, 'e');
+            if ($type == 'mentor') {
+                $count = ', COUNT(DISTINCT pid) AS nb';
+                $countjoin = ' INNER JOIN  profile_job_term_relation AS r ON(r.jtid_1 = e.jtid) INNER JOIN  profile_mentor_term AS m ON(r.jtid_2 = m.jtid)';
+                $countorder = 'nb DESC, ';
             } else {
-                $res .= $result['field'].'|';
-                if ($count) {
-                    $res .= $result['nb'].'|';
+                $count = $countjoin = $countorder = '';
+            }
+            $list = XDB::fetchAllAssoc('SELECT  e.jtid AS id, e.full_name AS field' . $count . '
+                                          FROM  profile_job_term_enum AS e ' . $joins . $countjoin . '
+                                      GROUP BY  e.jtid
+                                      ORDER BY  ' . $countorder . 'field
+                                         LIMIT  ' . DirEnumeration::AUTOCOMPLETE_LIMIT);
+            $to_cache = '';
+            if ($type == 'mentor') {
+                foreach ($list as &$item) {
+                    $to_cache .= $item['field'] . "\t" . $item['nb'] . "\t" . $item['id'] . "\n";
+                    $item['value'] = SearchModule::format_autocomplete($item);
+                }
+            } else {
+                foreach ($list as &$item) {
+                    $to_cache .= $item['field'] . "\t" . $item['id'] . "\n";
+                    $item['value'] = $item['field'];
                 }
-                $res .= $result['id'];
             }
-            $res .= "\n";
         }
-        XDB::query('INSERT INTO  search_autocomplete (name, query, result, generated)
-                         VALUES  ({?}, {?}, {?}, NOW())
-        ON DUPLICATE KEY UPDATE  result = VALUES(result), generated = VALUES(generated)',
-                    $type, $q_normalized, $res);
-        echo $res;
+
+        if (count($list) == DirEnumeration::AUTOCOMPLETE_LIMIT && $type == 'nomentor') {
+            $list[] = array(
+                'value' => '… parcourir les résultats dans un arbre …',
+                'field' => '',
+                'id'    => -1
+            );
+        }
+
+        if (!$cached) {
+            XDB::query('INSERT INTO  search_autocomplete (name, query, result, generated)
+                             VALUES  ({?}, {?}, {?}, NOW())
+            ON DUPLICATE KEY UPDATE  result = VALUES(result), generated = VALUES(generated)',
+                       $type, $q_normalized, $to_cache);
+        }
+        echo json_encode($list);
         exit();
     }
 
index 3adbafa..dcdffe5 100644 (file)
@@ -24,6 +24,9 @@ class ProfileSettingDeco implements ProfileSetting
     private static function compareMedals(array $a, array $b)
     {
         if ($a['id'] == $b['id']) {
+            if ($a['grade'] == $b['grade']) {
+                return $a['level'] > $b['level'];
+            }
             return $a['grade'] > $b['grade'];
         }
         return $a['id'] > $b['id'];
@@ -34,18 +37,21 @@ class ProfileSettingDeco implements ProfileSetting
         $success = true;
         if (is_null($value)) {
             // Fetch already attributed medals
-            $value = XDB::fetchAllAssoc('SELECT  mid AS id, gid AS grade, 1 AS valid
-                                           FROM  profile_medals
-                                          WHERE  pid = {?}',
+            $value = XDB::fetchAllAssoc("SELECT  m.mid AS id, m.gid AS grade, 1 AS valid, FIND_IN_SET('has_levels', e.flags) AS has_levels, m.level
+                                           FROM  profile_medals     AS m
+                                     INNER JOIN  profile_medal_enum AS e ON (m.mid = e.id)
+                                          WHERE  m.pid = {?}",
                                         $page->pid());
 
             // Fetch not yet validated medals
             $medals = ProfileValidate::get_typed_requests($page->pid(), 'medal');
             foreach ($medals as &$medal) {
                 $value[] = array(
-                    'id'    => $medal->mid,
-                    'grade' => $medal->gid,
-                    'valid' => '0'
+                    'id'         => $medal->mid,
+                    'grade'      => $medal->gid,
+                    'level'      => $medal->level,
+                    'has_levels' => $medal->has_levels,
+                    'valid'      => '0'
                 );
             }
         } elseif (!is_array($value)) {
@@ -65,7 +71,7 @@ class ProfileSettingDeco implements ProfileSetting
 
         while ($i < $total_original || $j < $total_value) {
             if (isset($value[$j]) && (!isset($original[$i]) || self::compareMedals($original[$i], $value[$j]))) {
-                $req = new MedalReq(S::user(), $page->profile, $value[$j]['id'], $value[$j]['grade']);
+                $req = new MedalReq(S::user(), $page->profile, $value[$j]['id'], $value[$j]['grade'], $value[$j]['level'], $value[$j]['has_levels']);
                 $req->submit();
                 sleep(1);
                 ++$j;
@@ -75,7 +81,7 @@ class ProfileSettingDeco implements ProfileSetting
                                         WHERE  pid = {?} AND mid = {?} AND gid = {?}',
                                  $page->pid(), $original[$i]['id'], $original[$i]['grade']);
                 } else {
-                    $req = MedalReq::get_request($page->pid(), $original[$i]['id'], $original[$i]['grade']);
+                    $req = MedalReq::get_request($page->pid(), $original[$i]['id'], $original[$i]['grade'], $value[$j]['level']);
                     if ($req) {
                         $req->clean();
                     }
index b235080..f382e7b 100644 (file)
@@ -96,10 +96,12 @@ class ProfileSettingSearchNames implements ProfileSetting
             foreach ($value['public_names'] as $key => $name) {
                 $value['public_names'][$key] = trim($name);
             }
-            foreach ($value['private_names'] as $key => $name) {
-                $value['private_names'][$key]['name'] = trim($name['name']);
-                if ($value['private_names'][$key]['name'] == '') {
-                    unset($value['private_names'][$key]);
+            if (isset($value['private_names'])) {
+                foreach ($value['private_names'] as $key => $name) {
+                    $value['private_names'][$key]['name'] = trim($name['name']);
+                    if ($value['private_names'][$key]['name'] == '') {
+                        unset($value['private_names'][$key]);
+                    }
                 }
             }
 
@@ -110,8 +112,13 @@ class ProfileSettingSearchNames implements ProfileSetting
 
         require_once 'name.func.inc.php';
         $public_name = build_first_name($value['public_names']) . ' ' . build_full_last_name($value['public_names'], $page->profile->isFemale());
-        $private_name_end = build_private_name($value['private_names']);
-        $private_name = $public_name . $private_name_end;
+        if (isset($value['private_names'])) {
+            $private_name_end = build_private_name($value['private_names']);
+            $private_name = $public_name . $private_name_end;
+        } else {
+            $value['private_names'] = array();
+            $private_name = $public_name;
+        }
 
         Platal::page()->assign('public_name', $public_name);
         Platal::page()->assign('private_name', $private_name);
@@ -142,8 +149,10 @@ class ProfileSettingSearchNames implements ProfileSetting
                      $page->pid());
         $values = array();
         $nickname = $lastname = $firstname = 0;
-        foreach ($value['private_names'] as $name) {
-            $values[] = XDB::format('({?}, {?}, {?}, {?})', $page->pid(), $name['type'], $$name['type']++, $name['name']);
+        if (isset($value['private_names'])) {
+            foreach ($value['private_names'] as $name) {
+                $values[] = XDB::format('({?}, {?}, {?}, {?})', $page->pid(), $name['type'], $$name['type']++, $name['name']);
+            }
         }
         if (count($values)) {
             XDB::rawExecute('INSERT INTO  profile_private_names (pid, type, id, name)
@@ -153,7 +162,8 @@ class ProfileSettingSearchNames implements ProfileSetting
         if ($has_diff) {
             update_display_names($page->profile, $old, $value['private_names']);
         } else {
-            update_display_names($page->profile, $value['public_names'], $value['private_names']);
+            update_display_names($page->profile,
+                                 $value['public_names'], (isset($value['private_names']) ? $value['private_names'] : null));
         }
     }
 
@@ -165,7 +175,7 @@ class ProfileSettingSearchNames implements ProfileSetting
             }
         }
 
-        if (count($value['private_names'])) {
+        if (isset($value['private_names']) && count($value['private_names'])) {
             $private_names = array();
             foreach ($value['private_names'] as $name) {
                 $private_names[] = $name['name'];
@@ -338,11 +348,11 @@ class ProfileSettingMainEdu implements ProfileSetting
         $educations = array();
         foreach ($value as $item) {
             $details = array($this->cycles[$item['degreeid']]);
-            if ($education['program']) {
-                $details[] = '« ' . $education['program'] . ' »';
+            if ($item['program']) {
+                $details[] = '« ' . $item['program'] . ' »';
             }
-            if ($education['fieldid']) {
-                $details[] = $fieldsList[$education['fieldid']];
+            if ($item['fieldid']) {
+                $details[] = $fieldsList[$item['fieldid']];
             }
         }
         return implode(', ', $educations);
@@ -460,6 +470,79 @@ class ProfileSettingNetworking implements ProfileSetting
     }
 }
 
+class ProfileSettingHobby implements ProfileSetting
+{
+    private $pub;
+    static private $type = array('Sport', 'Loisir', 'Hobby');
+
+    public function __construct()
+    {
+        $this->pub = new ProfileSettingPub();
+    }
+
+    public function value(ProfilePage $page, $field, $value, &$success)
+    {
+        $success = true;
+        if (is_null($value)) {
+            $value = XDB::fetchAllAssoc('SELECT  type, text, pub
+                                           FROM  profile_hobby
+                                          WHERE  pid = {?}',
+                                         $page->pid());
+        }
+        if (!is_array($value)) {
+            return array();
+        }
+        foreach($value as $i => &$hobby) {
+            $hobby['text'] = trim($hobby['text']);
+            if (!$hobby['text'] ||!in_array($hobby['type'], self::$type)) {
+                unset($value[$i]);
+            } else {
+                if (!isset($hobby['pub'])) {
+                    $hobby['pub'] = 'private';
+                }
+                $s = true;
+                $hobby['pub'] = $this->pub->value($page, 'pub', $hobby['pub'], $s);
+                $success = $success && $s;
+            }
+        }
+        return $value;
+    }
+
+    public function save(ProfilePage $page, $field, $value)
+    {
+        XDB::execute('DELETE FROM profile_hobby
+                            WHERE pid = {?}',
+                     $page->pid());
+        if (!count($value)) {
+            return;
+        }
+        foreach ($value as $id => $hobby) {
+            XDB::execute("INSERT INTO  profile_hobby (pid, id, type, text, pub)
+                               VALUES  ({?}, {?}, {?}, {?}, {?})",
+                         $page->pid(), $id, $hobby['type'], $hobby['text'], $hobby['pub']);
+        }
+    }
+
+    public function getText($value) {
+        static $pubs = array('public' => 'publique', 'private' => 'privé');
+        $hobbies = array();
+        foreach (self::$type as $type) {
+            $hobbies[$type] = array();
+        }
+        foreach ($value as $hobby) {
+            $hobbies[$hobby['type']][] = $hobby['text'] . ' (affichage ' . $pubs[$hobby['pub']] . ')';
+        }
+        $text = array();
+        foreach (self::$type as $type) {
+            if (!empty($hobbies[$type])) {
+                $text[] = $hobbies[$type] . ' : ' . implode(', ' , $hobbies[$type]);
+            }
+        }
+        return implode(', ' , $text);
+    }
+}
+
+
 class ProfileSettingPromo implements ProfileSetting
 {
     public function __construct(){}
@@ -546,26 +629,24 @@ class ProfilePageGeneral extends ProfilePage
     public function __construct(PlWizard $wiz)
     {
         parent::__construct($wiz);
-        $this->settings['search_names']
-                                  = new ProfileSettingSearchNames();
-        $this->settings['nationality1']
-                                  = $this->settings['nationality2']
-                                  = $this->settings['nationality3']
-                                  = $this->settings['promo_display']
-                                  = null;
-        $this->settings['email_directory']
-                                  = new ProfileSettingEmail();
-        $this->settings['email_directory_new']
-                                  = new ProfileSettingEmailDirectory();
-        $this->settings['networking'] = new ProfileSettingNetworking();
-        $this->settings['tels']   = new ProfileSettingPhones();
-        $this->settings['edus']   = new ProfileSettingEdu();
+        $this->settings['search_names'] = new ProfileSettingSearchNames();
+        $this->settings['nationality1'] = $this->settings['nationality2']
+                                        = $this->settings['nationality3']
+                                        = $this->settings['promo_display']
+                                        = $this->settings['profile_title']
+                                        = null;
+        $this->settings['email_directory'] = new ProfileSettingEmail();
+        $this->settings['email_directory_new'] = new ProfileSettingEmailDirectory();
+        $this->settings['tels'] = new ProfileSettingPhones();
+        $this->settings['edus'] = new ProfileSettingEdu();
         $this->settings['main_edus'] = new ProfileSettingMainEdu();
         $this->settings['promo']  = new ProfileSettingPromo();
-        $this->watched= array('tels' => true,
-                              'networking' => true, 'edus' => true,
-                              'nationality1' => true, 'nationality2' => true,
-                              'nationality3' => true, 'search_names' => true);
+        $this->settings['networking'] = new ProfileSettingNetworking();
+        $this->settings['hobbies'] = new ProfileSettingHobby();
+        $this->watched = array('tels' => true,
+                               'networking' => true, 'edus' => true,
+                               'nationality1' => true, 'nationality2' => true,
+                               'nationality3' => true, 'search_names' => true);
 
         /* Some fields editable under condition */
         if (!S::user()->isMe($this->owner)) {
@@ -579,12 +660,12 @@ class ProfilePageGeneral extends ProfilePage
         if (S::user()->checkPerms('directory_private')
             || S::user()->isMyProfile($this->owner)) {
             $this->settings['freetext'] = null;
-            $this->settings['freetext_pub']
-                                      = $this->settings['photo_pub']
-                                      = new ProfileSettingPub();
+            $this->settings['freetext_pub'] = $this->settings['photo_pub']
+                                            = new ProfileSettingPub();
             $this->watched['freetext'] = true;
         }
 
+        Platal::page()->assign('is_registered', ($this->owner->perms ? true : false));
     }
 
     protected function _fetchData()
@@ -593,7 +674,8 @@ class ProfilePageGeneral extends ProfilePage
         $res = XDB::query("SELECT  p.nationality1, p.nationality2, p.nationality3, IF(p.birthdate = 0, '', p.birthdate) AS birthdate,
                                    p.email_directory as email_directory, pd.promo AS promo_display,
                                    p.freetext, p.freetext_pub, p.ax_id AS matricule_ax, pd.yourself,
-                                   p.deathdate, IF(p.birthdate_ref = 0, '', p.birthdate_ref) AS birthdate_ref
+                                   p.deathdate, IF(p.birthdate_ref = 0, '', p.birthdate_ref) AS birthdate_ref,
+                                   p.title AS profile_title
                              FROM  profiles              AS p
                        INNER JOIN  profile_display       AS pd ON (pd.pid = p.pid)
                             WHERE  p.pid = {?}", $this->pid());
@@ -624,7 +706,7 @@ class ProfilePageGeneral extends ProfilePage
     {
         if ($this->changed['nationality1'] || $this->changed['nationality2'] || $this->changed['nationality3']
             || $this->changed['birthdate'] || $this->changed['freetext'] || $this->changed['freetext_pub']
-            || $this->changed['email_directory']) {
+            || $this->changed['email_directory'] || $this->changed['profile_title']) {
             if ($this->values['nationality3'] == "") {
                 $this->values['nationality3'] = NULL;
             }
@@ -657,11 +739,12 @@ class ProfilePageGeneral extends ProfilePage
 
             XDB::execute("UPDATE  profiles
                              SET  nationality1 = {?}, nationality2 = {?}, nationality3 = {?}, birthdate = {?},
-                                  freetext = {?}, freetext_pub = {?}, email_directory = {?}
+                                  freetext = {?}, freetext_pub = {?}, email_directory = {?}, title = {?}
                            WHERE  pid = {?}",
                           $this->values['nationality1'], $this->values['nationality2'], $this->values['nationality3'],
                           ProfileSettingDate::toSQLDate($this->values['birthdate']),
-                          $this->values['freetext'], $this->values['freetext_pub'], $new_email, $this->pid());
+                          $this->values['freetext'], $this->values['freetext_pub'], $new_email,
+                          $this->values['profile_title'], $this->pid());
         }
         if ($this->changed['photo_pub']) {
             XDB::execute("UPDATE  profile_photos
@@ -698,7 +781,7 @@ class ProfilePageGeneral extends ProfilePage
                 }
             }
         }
-        if ($this->orig['birthdate_ref'] == 0 && !S::user()->isMe($this->owner) && $this->changed['birthdate_ref']) {
+        if ($this->changed['birthdate_ref'] && S::admin() && !$this->owner->perms) {
             XDB::execute('UPDATE  profiles
                              SET  birthdate_ref = {?}
                            WHERE  pid = {?}',
index 7a14e2d..279a105 100644 (file)
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
  ***************************************************************************/
 
+class ProfileSettingSkill implements ProfileSetting
+{
+    private $table;
+    private $id;
+    private $skill_field;
+    private $text_field;
+
+    public function __construct($table, $id, $skill, $text)
+    {
+        $this->table = $table;
+        $this->id = $id;
+        $this->skill_field = $skill;
+        $this->text_field = $text;
+    }
+
+    public function value(ProfilePage $page, $field, $value, &$success)
+    {
+        if (is_null($value)) {
+            $value = array();
+            $res = XDB::iterRow("SELECT  s.{$this->id}, s.{$this->text_field}, i.level
+                                   FROM  profile_{$this->table}_enum AS s
+                             INNER JOIN  profile_{$this->table}s     AS i ON (s.{$this->id} = i.{$this->skill_field})
+                                  WHERE  i.pid = {?}",
+                                $page->pid());
+            while (list($sid, $text, $level) = $res->next()) {
+                $value[$sid] = array('text' => $text, 'level' => $level);
+            }
+        }
+        if (!is_array($value)) {
+            $value = array();
+        } else {
+            foreach ($value as $id=>&$skill) {
+                if (!isset($skill['text']) || empty($skill['text'])) {
+                    $res = XDB::query("SELECT  {$this->text_field}
+                                         FROM  profile_{$this->table}_enum
+                                        WHERE  {$this->id} = {?}", $id);
+                    $skill['text'] = $res->fetchOneCell();
+                }
+            }
+        }
+        ksort($value);
+        $success = true;
+        return $value;
+    }
+
+    public function save(ProfilePage $page, $field, $value)
+    {
+        XDB::execute("DELETE FROM  profile_{$this->table}s
+                            WHERE  pid = {?}",
+                     $page->pid());
+        if (!count($value)) {
+            return;
+        }
+        foreach ($value as $id=>&$skill) {
+            XDB::execute("INSERT INTO  profile_{$this->table}s (pid, {$this->skill_field}, level)
+                               VALUES  ({?}, {?}, {?})",
+                         $page->pid(), $id, $skill['level']);
+        }
+    }
+
+    public function getText($value) {
+        $skills = array();
+
+        if ($this->table == 'langskill') {
+            static $levels = array(
+                1 => 'connaissance basique',
+                2 => 'maîtrise des bases',
+                3 => 'maîtrise limitée',
+                4 => 'maîtrise générale',
+                5 => 'bonne maîtrise',
+                6 => 'maîtrise complète'
+            );
+            foreach ($value as $skill) {
+                $skills[] = $skill['text'] . ' (' . $levels[$skill['level']] . ')';
+            }
+        } else {
+            foreach ($value as $skill) {
+                $skills[] = $skill['text'] . ' (' . $skill['level'] . ')';
+            }
+        }
+
+        return implode(', ' , $skills);
+    }
+}
+
 /** Terms associated to profile mentoring */
 class ProfileSettingTerms implements ProfileSetting
 {
@@ -143,6 +228,8 @@ class ProfilePageMentor extends ProfilePage
         $this->settings['expertise'] = null;
         $this->settings['terms'] = new ProfileSettingTerms();
         $this->settings['countries'] = new ProfileSettingCountry();
+        $this->settings['competences'] = new ProfileSettingSkill('skill', 'id', 'cid', 'text_fr');
+        $this->settings['langues'] = new ProfileSettingSkill('langskill', 'iso_639_2b', 'lid', 'language');
     }
 
     protected function _fetchData()
@@ -179,6 +266,20 @@ class ProfilePageMentor extends ProfilePage
                                                       FROM  geoloc_countries
                                                   ORDER BY  country"));
         $page->assign('hrpid', $this->profile->hrpid);
+        $page->assign('comp_list', XDB::iterator("SELECT  id, text_fr, FIND_IN_SET('titre',flags) AS title
+                                                    FROM  profile_skill_enum"));
+        $page->assign('comp_level', array('initié' => 'initié',
+                                          'bonne connaissance' => 'bonne connaissance',
+                                          'expert' => 'expert'));
+        $page->assign('lang_list', XDB::iterator('SELECT  iso_639_2b, language
+                                                    FROM  profile_langskill_enum
+                                                ORDER BY  language'));
+        $page->assign('lang_level', array(1 => 'connaissance basique',
+                                          2 => 'maîtrise des bases',
+                                          3 => 'maîtrise limitée',
+                                          4 => 'maîtrise générale',
+                                          5 => 'bonne maîtrise',
+                                          6 => 'maîtrise complète'));
     }
 }
 
index c6eae36..f9e93a4 100644 (file)
@@ -108,7 +108,7 @@ class ProfileSettingPhones implements ProfileSetting
         $phones = array();
 
         if (is_null($value)) {
-            $it = Phone::iterate(array($page->pid()), array(Phone::LINK_PROFILE), array(0), Visibility::defaultForEdit());
+            $it = Phone::iterate(array($page->pid()), array(Phone::LINK_PROFILE), array(0));
             while ($phone = $it->next()) {
                 $success = ($phone->format() && $success);
                 $phones[] = $phone->toFormArray();
@@ -435,7 +435,6 @@ require_once dirname(__FILE__) . '/addresses.inc.php';
 require_once dirname(__FILE__) . '/groups.inc.php';
 require_once dirname(__FILE__) . '/decos.inc.php';
 require_once dirname(__FILE__) . '/jobs.inc.php';
-require_once dirname(__FILE__) . '/skills.inc.php';
 require_once dirname(__FILE__) . '/mentor.inc.php';
 require_once dirname(__FILE__) . '/deltaten.inc.php';
 
diff --git a/modules/profile/skills.inc.php b/modules/profile/skills.inc.php
deleted file mode 100644 (file)
index 3145811..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-/***************************************************************************
- *  Copyright (C) 2003-2011 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 ProfileSettingSkill implements ProfileSetting
-{
-    private $table;
-    private $id;
-    private $skill_field;
-    private $text_field;
-
-    public function __construct($table, $id, $skill, $text)
-    {
-        $this->table = $table;
-        $this->id = $id;
-        $this->skill_field = $skill;
-        $this->text_field = $text;
-    }
-
-    public function value(ProfilePage $page, $field, $value, &$success)
-    {
-        if (is_null($value)) {
-            $value = array();
-            $res = XDB::iterRow("SELECT  s.{$this->id}, s.{$this->text_field}, i.level
-                                   FROM  profile_{$this->table}_enum AS s
-                             INNER JOIN  profile_{$this->table}s     AS i ON (s.{$this->id} = i.{$this->skill_field})
-                                  WHERE  i.pid = {?}",
-                                $page->pid());
-            while (list($sid, $text, $level) = $res->next()) {
-                $value[$sid] = array('text' => $text, 'level' => $level);
-            }
-        }
-        if (!is_array($value)) {
-            $value = array();
-        } else {
-            foreach ($value as $id=>&$skill) {
-                if (!isset($skill['text']) || empty($skill['text'])) {
-                    $res = XDB::query("SELECT  {$this->text_field}
-                                         FROM  profile_{$this->table}_enum
-                                        WHERE  {$this->id} = {?}", $id);
-                    $skill['text'] = $res->fetchOneCell();
-                }
-            }
-        }
-        ksort($value);
-        $success = true;
-        return $value;
-    }
-
-    public function save(ProfilePage $page, $field, $value)
-    {
-        XDB::execute("DELETE FROM  profile_{$this->table}s
-                            WHERE  pid = {?}",
-                     $page->pid());
-        if (!count($value)) {
-            return;
-        }
-        foreach ($value as $id=>&$skill) {
-            XDB::execute("INSERT INTO  profile_{$this->table}s (pid, {$this->skill_field}, level)
-                               VALUES  ({?}, {?}, {?})",
-                         $page->pid(), $id, $skill['level']);
-        }
-    }
-
-    public function getText($value) {
-        $skills = array();
-
-        if ($this->table == 'langskill') {
-            static $levels = array(
-                1 => 'connaissance basique',
-                2 => 'maîtrise des bases',
-                3 => 'maîtrise limitée',
-                4 => 'maîtrise générale',
-                5 => 'bonne maîtrise',
-                6 => 'maîtrise complète'
-            );
-            foreach ($value as $skill) {
-                $skills[] = $skill['text'] . ' (' . $levels[$skill['level']] . ')';
-            }
-        } else {
-            foreach ($value as $skill) {
-                $skills[] = $skill['text'] . ' (' . $skill['level'] . ')';
-            }
-        }
-
-        return implode(', ' , $skills);
-    }
-}
-
-class ProfilePageSkills extends ProfilePage
-{
-    protected $pg_template = 'profile/skill.tpl';
-
-    public function __construct(PlWizard $wiz)
-    {
-        parent::__construct($wiz);
-        $this->settings['competences'] = new ProfileSettingSkill('skill', 'id', 'cid', 'text_fr');
-        $this->settings['langues'] = new ProfileSettingSkill('langskill', 'iso_639_2b', 'lid', 'language');
-    }
-
-    public function _prepare(PlPage $page, $id)
-    {
-        $page->assign('comp_list', XDB::iterator("SELECT  id, text_fr, FIND_IN_SET('titre',flags) AS title
-                                                    FROM  profile_skill_enum"));
-        $page->assign('comp_level', array('initié' => 'initié',
-                                          'bonne connaissance' => 'bonne connaissance',
-                                          'expert' => 'expert'));
-        $page->assign('lang_list', XDB::iterator('SELECT  iso_639_2b, language
-                                                    FROM  profile_langskill_enum
-                                                ORDER BY  language'));
-        $page->assign('lang_level', array(1 => 'connaissance basique',
-                                          2 => 'maîtrise des bases',
-                                          3 => 'maîtrise limitée',
-                                          4 => 'maîtrise générale',
-                                          5 => 'bonne maîtrise',
-                                          6 => 'maîtrise complète'));
-    }
-}
-
-// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
-?>
index 83169e8..fd9bdd3 100644 (file)
@@ -157,9 +157,10 @@ class RegisterModule extends PLModule
                     // Validate the email address format and domain.
                     require_once 'emails.inc.php';
 
+                    $user = User::get($subState->s('uid'));
                     if (!isvalid_email(Post::v('email'))) {
                         $error[] = "Le champ 'Email' n'est pas valide.";
-                    } elseif (!isvalid_email_redirection(Post::v('email'))) {
+                    } elseif (!isvalid_email_redirection(Post::v('email'), $user)) {
                         $error[] = $subState->s('forlife') . ' doit renvoyer vers un email existant '
                                  . 'valide, en particulier, il ne peut pas être renvoyé vers lui-même.';
                     }
@@ -180,7 +181,12 @@ class RegisterModule extends PLModule
                         if (abs($ref_year - $year) > 2) {
                             $error[] = "La 'Date de naissance' n'est pas correcte.";
                             $alert[] = "Date de naissance incorrecte à l'inscription";
-                            $alert_details .= "\n   * Date de naissance renseignée : " . Post::t('birthdate') . ' (date connue : ' . $subState->v('birthdateRef') . ')';
+                            $alert_details .= "\n   * Date de naissance renseignée : " . Post::t('birthdate');
+                            if ($subState->v('birthdateRef') == '0000-00-00') {
+                                $alert_details .= ' (date inconnue)';
+                            } else {
+                                $alert_details .= ' (date connue : ' . $subState->v('birthdateRef') . ')';
+                            }
                             $subState->set('wrong_birthdate', $birth);
                         }
                     }
@@ -236,7 +242,12 @@ class RegisterModule extends PLModule
                         if ($subState->s('birthdateRef') != '0000-00-00'
                             && $subState->s('birthdateRef') != $subState->s('birthdate')) {
                             $alert[] = "Date de naissance incorrecte à l'inscription";
-                            $alert_details .= "\n   * Date de naissance renseignée : " . $subState->s('birthdate') . ' (date connue : ' . $subState->s('birthdateRef') . ')';
+                            $alert_details .= "\n   * Date de naissance renseignée : " . Post::t('birthdate');
+                            if ($subState->v('birthdateRef') == '0000-00-00') {
+                                $alert_details .= ' (date inconnue)';
+                            } else {
+                                $alert_details .= ' (date connue : ' . $subState->v('birthdateRef') . ')';
+                            }
                         }
                         if ($bannedIp) {
                             $alert[] = "Tentative d'inscription depuis une IP surveillée";
@@ -265,7 +276,9 @@ class RegisterModule extends PLModule
 
         $_SESSION['subState'] = $subState->dict();
         if (count($alert)) {
-            $alert_details = "Détails des alertes :" . $alert_details . "\n\n\n";
+            $alert_details = "Détails des alertes :" . $alert_details . "\n\n";
+            $alert_details .= 'Compte concerné : ' . $subState->s('forlife') . ' (redirection vers : '
+                           . ($subState->s('email') == '' ? Post::t('email') : $subState->s('email')). ")\n\n\n";
             send_warning_mail(implode(' - ', $alert), $alert_details);
         }
 
@@ -294,7 +307,7 @@ class RegisterModule extends PLModule
         $res = XDB::query("SELECT  r.uid, p.pid, r.forlife, r.bestalias, r.mailorg2,
                                    r.password, r.email, r.services, r.naissance,
                                    ppn.lastname_initial, ppn.firstname_initial, pe.promo_year,
-                                   pd.promo, p.sex, p.birthdate_ref, a.type
+                                   pd.promo, p.sex, p.birthdate_ref, a.type, a.email AS old_account_email
                              FROM  register_pending AS r
                        INNER JOIN  accounts         AS a   ON (r.uid = a.uid)
                        INNER JOIN  account_profiles AS ap  ON (a.uid = ap.uid AND FIND_IN_SET('owner', ap.perms))
@@ -320,7 +333,7 @@ class RegisterModule extends PLModule
         }
 
         list($uid, $pid, $forlife, $bestalias, $emailXorg2, $password, $email, $services,
-             $birthdate, $lastname, $firstname, $yearpromo, $promo, $sex, $birthdate_ref, $type) = $res->fetchOneRow();
+             $birthdate, $lastname, $firstname, $yearpromo, $promo, $sex, $birthdate_ref, $type, $old_account_email) = $res->fetchOneRow();
         $isX = ($type == 'x');
         $mail_domain = User::$sub_mail_domains[$type] . $globals->mail->domain;
 
@@ -379,9 +392,17 @@ class RegisterModule extends PLModule
         $redirect->add_email($email);
         fix_bestalias($user);
 
+        // If the user was registered to some aliases and MLs, we must change
+        // the subscription to her forlife email.
+        if ($old_account_email) {
+            $listClient = new MMList($user);
+            $listClient->change_user_email($old_account_email, $user->forlifeEmail());
+            update_alias_user($old_account_email, $user->forlifeEmail());
+        }
+
         // 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);
+        Platal::session()->start(AUTH_PASSWD);
 
         // Subscribe the user to the services she did request at registration time.
         require_once 'newsletter.inc.php';
index 0504a77..fc2b811 100644 (file)
@@ -149,6 +149,7 @@ class SearchModule extends PLModule
     function handler_advanced($page, $model = null, $byletter = null)
     {
         global $globals;
+        $page->addJsLink('jquery.ui.xorg.js');
         $page->addJsLink('search.js');
         $page->assign('advanced',1);
 
@@ -212,7 +213,12 @@ class SearchModule extends PLModule
         $page->assign('public_directory',0);
     }
 
-    function handler_autocomplete($page, $type = null)
+    static public function format_autocomplete(array $item)
+    {
+        return $item['field'] . ' (' . $item['nb'] . ' camarade' . ($item['nb'] > 1 ? 's' : '') . ')';
+    }
+
+    function handler_autocomplete($page, $type = null, $sub_id = null)
     {
         // Autocompletion : according to type required, return
         // a list of results matching with the number of matches.
@@ -227,66 +233,93 @@ class SearchModule extends PLModule
                            array('',
                                  '\\\\\1',
                                  '.*'),
-                           Env::s('q'));
-        if (!$q) exit();
-
-        // try to look in cached results
-        $cache = XDB::query('SELECT  result
-                               FROM  search_autocomplete
-                              WHERE  name = {?} AND
-                                     query = {?} AND
-                                     generated > NOW() - INTERVAL 1 DAY',
-                             $type, $q);
-        if ($res = $cache->fetchOneCell()) {
-            echo $res;
-            die();
-        }
-
-        $enums = array(
-            'binet_text'           => DirEnum::BINETS,
-            'groupex_text'         => DirEnum::GROUPESX,
-            'section_text'         => DirEnum::SECTIONS,
-            'networking_type_text' => DirEnum::NETWORKS,
-            'locality_text'        => DirEnum::LOCALITIES,
-            'country_text'         => DirEnum::COUNTRIES,
-            'entreprise'           => DirEnum::COMPANIES,
-            'jobterm_text'         => DirEnum::JOBTERMS,
-            'description'          => DirEnum::JOBDESCRIPTION,
-            'nationalite_text'     => DirEnum::NATIONALITIES,
-            'school_text'          => DirEnum::EDUSCHOOLS,
-        );
-        if (!array_key_exists($type, $enums)) {
+                           Get::t('term'));
+        if (!$q) {
             exit();
         }
+        if (!is_null($sub_id)) {
+            $query = $q . "\t" . $sub_id;
+        } else {
+            $query = $q;
+        }
 
-        $enum = $enums[$type];
+        // Try to look in cached results.
+        $cached = false;
+        $cache = XDB::query('SELECT  result
+                               FROM  search_autocomplete
+                              WHERE  name = {?} AND query = {?} AND generated > NOW() - INTERVAL 1 DAY',
+                             $type, $query);
+
+        if ($cache->numRows() > 0) {
+            $cached = true;
+            $data = explode("\n", $cache->fetchOneCell());
+            $list = array();
+            foreach ($data as $line) {
+                if ($line != '') {
+                    $aux = explode("\t", $line);
+                    $item = array(
+                        'field' => $aux[0],
+                        'nb'    => $aux[1],
+                        'id'    => $aux[2]
+                    );
+                    $item['value'] = self::format_autocomplete($item);
+                    array_push($list, $item);
+                }
+            }
+        } else {
+            $enums = array(
+                'binet_text'           => DirEnum::BINETS,
+                'groupex_text'         => DirEnum::GROUPESX,
+                'section_text'         => DirEnum::SECTIONS,
+                'networking_type_text' => DirEnum::NETWORKS,
+                'locality_text'        => DirEnum::LOCALITIES,
+                'country_text'         => DirEnum::COUNTRIES,
+                'entreprise'           => DirEnum::COMPANIES,
+                'jobterm_text'         => DirEnum::JOBTERMS,
+                'description'          => DirEnum::JOBDESCRIPTION,
+                'nationalite_text'     => DirEnum::NATIONALITIES,
+                'school_text'          => DirEnum::EDUSCHOOLS,
+            );
+            if (!array_key_exists($type, $enums)) {
+                exit();
+            }
 
-        $list = DirEnum::getAutoComplete($enum, $q);
-        $nbResults = 0;
-        $res = "";
-        while ($result = $list->next()) {
-            $nbResults++;
-            if ($nbResults == 11) {
-                $res .= $q."|-1\n";
+            if (is_null($sub_id)) {
+                $list = DirEnum::getAutoComplete($enums[$type], $q);
             } else {
-                $res .= $result['field'].'|';
-                if (isset($result['nb'])) {
-                    $res .= $result['nb'];
-                }
-                if (isset($result['id'])) {
-                    $res  .= '|'.$result['id'];
-                }
-                $res .= "\n";
+                $list = DirEnum::getAutoComplete($enums[$type], $q, $sub_id);
+            }
+            $to_cache = '';
+            foreach ($list as &$item) {
+                $to_cache .= $item['field'] . "\t" . $item['nb'] . "\t" . $item['id'] . "\n";
+                $item['value'] = self::format_autocomplete($item);
             }
         }
-        if ($nbResults == 0) {
-            $res = $q."|-2\n";
+
+        $count = count($list);
+        if ($count == DirEnumeration::AUTOCOMPLETE_LIMIT) {
+            $list[] = array(
+                'value' => '…',
+                'field' => '',
+                'nb'    => 0,
+                'id'    => -1
+            );
+        } elseif ($count == 0) {
+            $list[] = array(
+                'value' => 'Aucun camarade trouvé pour ' . $q . '.',
+                'field' => '',
+                'nb'    => 0,
+                'id'    => -1
+            );
+        }
+
+        if (!$cached) {
+            XDB::query('INSERT INTO  search_autocomplete (name, query, result, generated)
+                             VALUES  ({?}, {?}, {?}, NOW())
+            ON DUPLICATE KEY UPDATE  result = VALUES(result), generated = VALUES(generated)',
+                       $type, $query, $to_cache);
         }
-        XDB::query('INSERT INTO  search_autocomplete (name, query, result, generated)
-                         VALUES  ({?}, {?}, {?}, NOW())
-        ON DUPLICATE KEY UPDATE  result = VALUES(result), generated = VALUES(generated)',
-                   $type, $q, $res);
-        echo $res;
+        echo json_encode($list);
         exit();
     }
 
@@ -381,6 +414,7 @@ class SearchModule extends PLModule
         $wp->buildCache();
 
         $page->setTitle('Emploi et Carrières');
+        $page->addJsLink('jquery.ui.xorg.js');
 
         // Count mentors
         $res = XDB::query("SELECT count(distinct pid) FROM profile_mentor_term");
index eaef664..26af2d4 100644 (file)
@@ -30,10 +30,10 @@ class SurveyModule extends PLModule
             'survey/result'      => $this->make_hook('result',        AUTH_PUBLIC),
             'survey/edit'        => $this->make_hook('edit',          AUTH_COOKIE, 'user'),
             'survey/ajax'        => $this->make_hook('ajax',          AUTH_COOKIE, 'user'),
-            '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'       => $this->make_hook('admin',         AUTH_PASSWD, 'admin'),
+            'survey/admin/edit'  => $this->make_hook('adminEdit',     AUTH_PASSWD, 'admin'),
+            'survey/admin/valid' => $this->make_hook('adminValidate', AUTH_PASSWD, 'admin'),
+            'survey/admin/del'   => $this->make_hook('adminDelete',   AUTH_PASSWD, 'admin'),
         );
     }
     // }}}
index 33b5153..b9da82e 100644 (file)
@@ -25,7 +25,7 @@ class UrlShortenerModule extends PLModule
     {
         return array(
             'url'       => $this->make_hook('url',       AUTH_PUBLIC),
-            'admin/url' => $this->make_hook('admin_url', AUTH_MDP, 'admin')
+            'admin/url' => $this->make_hook('admin_url', AUTH_PASSWD, 'admin')
         );
     }
 
index 44094d8..9f7e6b3 100644 (file)
@@ -27,15 +27,15 @@ class XnetModule extends PLModule
             'index'        => $this->make_hook('index',        AUTH_PUBLIC),
             'exit'         => $this->make_hook('exit',         AUTH_PUBLIC),
 
-            'admin'        => $this->make_hook('admin',        AUTH_MDP, 'admin'),
+            'admin'        => $this->make_hook('admin',        AUTH_PASSWD, 'admin'),
             'groups'       => $this->make_hook('groups',       AUTH_PUBLIC),
             'groupes.php'  => $this->make_hook('groups2',      AUTH_PUBLIC),
             'plan'         => $this->make_hook('plan',         AUTH_PUBLIC),
             // Should be removed in a future release as links will have expired anyway.
             'register/ext' => $this->make_hook('register_ext', AUTH_PUBLIC),
-            'photo'        => $this->make_hook('photo',        AUTH_MDP, 'groups'),
-            'autologin'    => $this->make_hook('autologin',    AUTH_MDP, 'groups'),
-            'edit'         => $this->make_hook('edit',         AUTH_MDP, 'groups'),
+            'photo'        => $this->make_hook('photo',        AUTH_PASSWD, 'groups'),
+            'autologin'    => $this->make_hook('autologin',    AUTH_PASSWD, 'groups'),
+            'edit'         => $this->make_hook('edit',         AUTH_PASSWD, 'groups'),
             'Xnet'         => $this->make_wiki_hook(),
         );
     }
@@ -255,22 +255,27 @@ class XnetModule extends PLModule
             $directory_name = mb_strtoupper(Post::t('lastname')) . ' ' . Post::t('firstname');
             XDB::query('UPDATE  accounts
                            SET  full_name = {?}, directory_name = {?}, display_name = {?},
-                                firstname = {?}, lastname = {?}, sex = {?}, email = {?}
+                                firstname = {?}, lastname = {?}, sex = {?}
                          WHERE  uid = {?}',
                        $full_name, $directory_name, Post::t('display_name'),
                        Post::t('firstname'), Post::t('lastname'),
-                       (Post::t('sex') == 'male') ? 'male' : 'female', Post::t('email'), $user->id());
-            if (XDB::affectedRows()) {
-                require_once 'emails.inc.php';
-                if (require_email_update($user, Post::t('email'))) {
+                       (Post::t('sex') == 'male') ? 'male' : 'female', $user->id());
+
+            // Updates email.
+            require_once 'emails.inc.php';
+            $new_email = strtolower(Post::t('email'));
+            if (require_email_update($user, $new_email)) {
+                    XDB::query('UPDATE  accounts
+                                   SET  email = {?}
+                                 WHERE  uid = {?}',
+                               $new_email, $user->id());
                     $listClient = new MMList(S::user());
-                    $listClient->change_user_email($user->forlifeEmail(), Post::t('email'));
-                    update_alias_user($user->forlifeEmail(), Post::t('email'));
-                }
-                $user = User::getWithUID($user->id());
-                S::set('user', $user);
-                $page->trigSuccess('Données mises à jour.');
+                    $listClient->change_user_email($user->forlifeEmail(), $new_email);
+                    update_alias_user($user->forlifeEmail(), $new_email);
             }
+            $user = User::getWithUID($user->id());
+            S::set('user', $user);
+            $page->trigSuccess('Données mises à jour.');
         }
 
         $page->addJsLink('password.js');
index f345f13..3dbe0c6 100644 (file)
@@ -26,12 +26,12 @@ class XnetEventsModule extends PLModule
     function handlers()
     {
         return array(
-            '%grp/events'       => $this->make_hook('events', AUTH_MDP, 'groups'),
-            '%grp/events/sub'   => $this->make_hook('sub',    AUTH_MDP, 'groups'),
-            '%grp/events/csv'   => $this->make_hook('csv',    AUTH_MDP, 'groups', NO_HTTPS),
-            '%grp/events/ical'  => $this->make_hook('ical',   AUTH_MDP, 'groups', NO_HTTPS),
-            '%grp/events/edit'  => $this->make_hook('edit',   AUTH_MDP, 'groupadmin'),
-            '%grp/events/admin' => $this->make_hook('admin',  AUTH_MDP, 'groupmember'),
+            '%grp/events'       => $this->make_hook('events', AUTH_PASSWD, 'groups'),
+            '%grp/events/sub'   => $this->make_hook('sub',    AUTH_PASSWD, 'groups'),
+            '%grp/events/csv'   => $this->make_hook('csv',    AUTH_PASSWD, 'groups', NO_HTTPS),
+            '%grp/events/ical'  => $this->make_hook('ical',   AUTH_PASSWD, 'groups', NO_HTTPS),
+            '%grp/events/edit'  => $this->make_hook('edit',   AUTH_PASSWD, 'groupadmin'),
+            '%grp/events/admin' => $this->make_hook('admin',  AUTH_PASSWD, 'groupmember'),
         );
     }
 
@@ -463,12 +463,14 @@ class XnetEventsModule extends PLModule
                                 Post::v('intitule')." - ".$globals->asso('nom'),
                                 Post::v('site'), $money_defaut,
                                 Post::v('confirmation'), 0, 999,
-                                $globals->asso('id'), $eid, Post::b('donation'));
+                                $globals->asso('id'), $eid, Post::v('payment_public') == 'yes');
                 if ($p->accept()) {
                     $p->submit();
                 } else {
-                    $page->assign('paiement_message', Post::v('confirmation'));
-                    $page->assign('paiement_site', Post::v('site'));
+                    $page->assign('payment_message', Post::v('confirmation'));
+                    $page->assign('payment_site', Post::v('site'));
+                    $page->assign('payment_public', Post::v('payment_public') == 'yes');
+                    $page->assign('error', true);
                     $error = true;
                 }
             }
@@ -485,9 +487,10 @@ class XnetEventsModule extends PLModule
         }
 
         // get a list of all the payment for this asso
-        $res = XDB::iterator("SELECT id, text
-                                FROM payments
-                               WHERE asso_id = {?}", $globals->asso('id'));
+        $res = XDB::iterator("SELECT  id, text
+                                FROM  payments
+                               WHERE  asso_id = {?} AND NOT FIND_IN_SET('old', flags)",
+                             $globals->asso('id'));
         $paiements = array();
         while ($a = $res->next()) $paiements[$a['id']] = $a['text']; {
             $page->assign('paiements', $paiements);
@@ -506,7 +509,7 @@ class XnetEventsModule extends PLModule
             $res = XDB::query("SELECT  stamp
                                  FROM  requests
                                 WHERE  type = 'paiements' AND data LIKE {?}",
-                               PayReq::same_event($eid, $globals->asso('id')));
+                              PayReq::same_event($eid, $globals->asso('id')));
             $stamp = $res->fetchOneCell();
             if ($stamp) {
                 $evt['paiement_id']  = -2;
index 71ac30c..acdfa56 100644 (file)
@@ -272,20 +272,23 @@ function event_change_shortname($page, $eid, $old, $new)
         // if we have a first new short_name create the lists
         $lastid = array();
         $where = array(
-            $globals->xnet->participant_list => 'nb > 0',
-            $globals->xnet->payed_list       => 'paid > 0',
-            $globals->xnet->unpayed_list     => 'nb > 0 AND paid = 0'
+            $globals->xnet->participant_list => 'g.nb > 0',
+            $globals->xnet->payed_list       => '(g.paid > 0 OR p.amount > 0)',
+            $globals->xnet->unpayed_list     => 'g.nb > 0 AND g.paid = 0 AND p.amount IS NULL'
         );
 
         foreach (array($globals->xnet->participant_list, $globals->xnet->payed_list, $globals->xnet->unpayed_list) as $suffix) {
-            $uids = XDB::fetchColumn('SELECT  uid
-                                        FROM  group_event_participants
-                                       WHERE  eid = {?} AND ' . $where[$suffix],
+            $uids = XDB::fetchColumn('SELECT  g.uid
+                                        FROM  group_event_participants AS g
+                                  INNER JOIN  group_events             AS e ON (g.eid = e.eid)
+                                   LEFT JOIN  payment_transactions     AS p ON (e.paiement_id = p.ref AND g.uid = p.uid)
+                                       WHERE  g.eid = {?} AND ' . $where[$suffix],
                                      $eid);
             foreach ($uids as $uid) {
                 add_to_list_alias($uid, $new . $suffix, $globals->xnet->evts_domain, 'event');
             }
         }
+
         $uids = XDB::fetchColumn('SELECT  m.uid
                                     FROM  group_members            AS m
                                LEFT JOIN  group_event_participants AS e ON (e.uid = m.uid AND e.eid = {?})
index 48706ab..8960524 100644 (file)
@@ -29,34 +29,34 @@ class XnetGrpModule extends PLModule
             '%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/former_users'    => $this->make_hook('former_users',          AUTH_MDP, 'admin'),
-            '%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/directory/sync'  => $this->make_hook('directory_sync',        AUTH_MDP, 'groupadmin'),
-            '%grp/directory/unact' => $this->make_hook('non_active',            AUTH_MDP, 'groupadmin'),
-            '%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, 'groups'),
-            '%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, 'groups'),
-            '%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, 'groups', NO_AUTH),
-            '%grp/member/del'      => $this->make_hook('admin_member_del',      AUTH_MDP, 'groupadmin'),
-            '%grp/member/suggest'  => $this->make_hook('admin_member_suggest',  AUTH_MDP, 'groupadmin'),
+            '%grp/edit'            => $this->make_hook('edit',                  AUTH_PASSWD, 'groupadmin'),
+            '%grp/mail'            => $this->make_hook('mail',                  AUTH_PASSWD, 'groupadmin'),
+            '%grp/forum'           => $this->make_hook('forum',                 AUTH_PASSWD, 'groupmember'),
+            '%grp/former_users'    => $this->make_hook('former_users',          AUTH_PASSWD, 'admin'),
+            '%grp/annuaire'        => $this->make_hook('annuaire',              AUTH_PASSWD, 'groupannu'),
+            '%grp/annuaire/vcard'  => $this->make_hook('vcard',                 AUTH_PASSWD, 'groupmember:groupannu'),
+            '%grp/annuaire/csv'    => $this->make_hook('csv',                   AUTH_PASSWD, 'groupmember:groupannu'),
+            '%grp/directory/sync'  => $this->make_hook('directory_sync',        AUTH_PASSWD, 'groupadmin'),
+            '%grp/directory/unact' => $this->make_hook('non_active',            AUTH_PASSWD, 'groupadmin'),
+            '%grp/trombi'          => $this->make_hook('trombi',                AUTH_PASSWD, 'groupannu'),
+            '%grp/geoloc'          => $this->make_hook('geoloc',                AUTH_PASSWD, 'groupannu'),
+            '%grp/subscribe'       => $this->make_hook('subscribe',             AUTH_PASSWD, 'groups'),
+            '%grp/subscribe/valid' => $this->make_hook('subscribe_valid',       AUTH_PASSWD, 'groupadmin'),
+            '%grp/unsubscribe'     => $this->make_hook('unsubscribe',           AUTH_PASSWD, 'groupmember'),
+
+            '%grp/change_rights'   => $this->make_hook('change_rights',         AUTH_PASSWD, 'groups'),
+            '%grp/admin/annuaire'  => $this->make_hook('admin_annuaire',        AUTH_PASSWD, 'groupadmin'),
+            '%grp/member'          => $this->make_hook('admin_member',          AUTH_PASSWD, 'groupadmin'),
+            '%grp/member/new'      => $this->make_hook('admin_member_new',      AUTH_PASSWD, 'groupadmin'),
+            '%grp/member/new/ajax' => $this->make_hook('admin_member_new_ajax', AUTH_PASSWD, 'groups', NO_AUTH),
+            '%grp/member/del'      => $this->make_hook('admin_member_del',      AUTH_PASSWD, 'groupadmin'),
+            '%grp/member/suggest'  => $this->make_hook('admin_member_suggest',  AUTH_PASSWD, 'groupadmin'),
 
             '%grp/rss'             => $this->make_token_hook('rss',             AUTH_PUBLIC),
-            '%grp/announce/new'    => $this->make_hook('edit_announce',         AUTH_MDP, 'groupadmin'),
-            '%grp/announce/edit'   => $this->make_hook('edit_announce',         AUTH_MDP, 'groupadmin'),
+            '%grp/announce/new'    => $this->make_hook('edit_announce',         AUTH_PASSWD, 'groupadmin'),
+            '%grp/announce/edit'   => $this->make_hook('edit_announce',         AUTH_PASSWD, 'groupadmin'),
             '%grp/announce/photo'  => $this->make_hook('photo_announce',        AUTH_PUBLIC),
-            '%grp/admin/announces' => $this->make_hook('admin_announce',        AUTH_MDP, 'groupadmin'),
+            '%grp/admin/announces' => $this->make_hook('admin_announce',        AUTH_PASSWD, 'groupadmin'),
         );
     }
 
@@ -120,6 +120,12 @@ class XnetGrpModule extends PLModule
                                     WHERE  asso_id = {?} AND expiration >= CURRENT_DATE()
                                            AND FIND_IN_SET('public', flags)",
                                   $globals->asso('id'));
+            $payments = XDB::fetchAllAssoc("SELECT  id, text
+                                              FROM  payments
+                                             WHERE  asso_id = {?} AND NOT FIND_IN_SET('old', flags) AND FIND_IN_SET('public', flags)
+                                          ORDER BY  id DESC",
+                                           $globals->asso('id'));
+            $page->assign('payments', $payments);
         }
         if (may_update()) {
             $subs_valid = XDB::query("SELECT  uid
@@ -162,6 +168,15 @@ class XnetGrpModule extends PLModule
     {
         global $globals;
         $page->changeTpl('xnetgrp/edit.tpl');
+        $error = false;
+
+        if (S::admin()) {
+            $domains = XDB::iterator('SELECT  *
+                                        FROM  group_dom
+                                    ORDER BY  nom');
+            $page->assign('domains', $domains);
+            $page->assign('super', true);
+        }
 
         if (Post::has('submit')) {
             S::assert_xsrf_token();
@@ -182,12 +197,38 @@ class XnetGrpModule extends PLModule
 
                 if (Post::v('mail_domain') && (strstr(Post::v('mail_domain'), '.') === false)) {
                     $page->trigError('Le domaine doit être un FQDN (aucune modification effectuée)&nbsp;!!!');
-                    return;
+                    $error = true;
                 }
                 if (Post::t('nom') == '' || Post::t('diminutif') == '') {
                     $page->trigError('Ni le nom ni le diminutif du groupe ne peuvent être vide.');
+                    $error = true;
+                }
+                if ($error) {
+                    $page->assign('nom', Post::t('nom'));
+                    $page->assign('diminutif', Post::t('diminutif'));
+                    $page->assign('mail_domain', Post::t('mail_domain'));
+                    $page->assign('cat', Post::v('cat'));
+                    $page->assign('dom', Post::v('dom'));
+                    $page->assign('ax', Post::v('ax'));
+                    $page->assign('axDate', Post::t('axDate'));
+                    $page->assign('site', $site);
+                    $page->assign('resp', Post::t('resp'));
+                    $page->assign('mail', Post::t('mail'));
+                    $page->assign('phone', Post::t('phone'));
+                    $page->assign('fax', Post::t('fax'));
+                    $page->assign('address', Post::t('address'));
+                    $page->assign('forum', Post::t('forum'));
+                    $page->assign('inscriptible', Post::v('inscriptible'));
+                    $page->assign('sub_url', Post::t('sub_url'));
+                    $page->assign('unsub_url', Post::t('unsub_url'));
+                    $page->assign('welcome_msg', Post::t('welcome_msg'));
+                    $page->assign('pub', Post::v('pub'));
+                    $page->assign('notif_unsub', Post::i('notif_unsub'));
+                    $page->assign('descr', Post::t('descr'));
+                    $page->assign('error', $error);
                     return;
                 }
+
                 $axDate = make_datetime(Post::v('axDate'));
                 if (Post::t('axDate') != '') {
                     $axDate = make_datetime(Post::v('axDate'))->format('Y-m-d');
@@ -261,14 +302,13 @@ class XnetGrpModule extends PLModule
 
             pl_redirect('../' . Post::v('diminutif', $globals->asso('diminutif')) . '/edit');
         }
-
-        if (S::admin()) {
-            $dom = XDB::iterator('SELECT  *
-                                    FROM  group_dom
-                                ORDER BY  nom');
-            $page->assign('dom', $dom);
-            $page->assign('super', true);
-        }
+        $page->assign('error', $error);
+        $page->assign('cat', $globals->asso('cat'));
+        $page->assign('dom', $globals->asso('dom'));
+        $page->assign('ax', $globals->asso('ax'));
+        $page->assign('inscriptible', $globals->asso('inscriptible'));
+        $page->assign('pub', $globals->asso('pub'));
+        $page->assign('notif_unsub', $globals->asso('notif_unsub'));
     }
 
     function handler_mail($page)
@@ -334,6 +374,7 @@ class XnetGrpModule extends PLModule
         $view = new UserSet(new UFC_Group($globals->asso('id'), $admins));
         $view->addMod('groupmember', 'Annuaire');
         $view->addMod('trombi', 'Trombinoscope');
+        $view->addMod('map', 'Planisphère');
         $view->apply('annuaire', $page, $action);
         $page->assign('only_admin', $admins);
         $page->changeTpl('xnetgrp/annuaire.tpl');
@@ -810,20 +851,10 @@ class XnetGrpModule extends PLModule
         // + (the data) => %2B (in the url) => + (first decoding) => ' ' (second decoding)
         // Since there can be no spaces in emails, we can fix this with :
         $email = str_replace(' ', '+', $email);
+        $is_valid_email = isvalid_email($email);
 
-        // Finds or creates account: first cases are for users with an account.
-        if (!User::isForeignEmailAddress($email)) {
-            // Standard account
-            $user = User::getSilent($email);
-        } else if (!isvalid_email($email)) {
-            // email might not be a regular email but an alias or a hruid
-            $user = User::getSilent($email);
-            if (!$user) {
-                // need a valid email address
-                $page->trigError('«&nbsp;<strong>' . $email . '</strong>&nbsp;» n\'est pas une adresse email valide.');
-                return;
-            }
-        } else if (Env::v('x') && Env::i('userid')) {
+        // X not registered to main site.
+        if (Env::v('x') && Env::i('userid') && $is_valid_email) {
             $user = User::getSilentWithUID(Env::i('userid'));
             if (!$user) {
                 $page->trigError('Utilisateur invalide.');
@@ -848,40 +879,51 @@ class XnetGrpModule extends PLModule
                 }
             }
         } else {
-            // User is of type xnet. There are 3 possible cases:
-            //  * the email is not known yet: we create a new account and
-            //      propose to send an email to the user so he can activate
-            //      his account,
-            //  * the email is known but the user was not contacted in order to
-            //      activate yet: we propose to send an email to the user so he
-            //      can activate his account,
-            //  * the email is known and the user was already contacted or has
-            //      an active account: nothing to be done.
-            list($mbox, $domain) = explode('@', strtolower($email));
-            $hruid = User::makeHrid($mbox, $domain, 'ext');
-            // User might already have an account (in another group for example).
-            $user = User::getSilent($hruid);
-
-            // If the user has no account yet, creates new account: build names from email address.
-            if (empty($user)) {
-                $parts = explode('.', $mbox);
-                if (count($parts) == 1) {
-                    $lastname = $display_name = $full_name = $directory_name = ucfirst($mbox);
-                    $firstname = '';
-                } else {
-                    $firstname = ucfirst($parts[0]);
-                    $lastname = ucwords(implode(' ', array_slice($parts, 1)));
-                    $display_name = $firstname;
-                    $full_name = "$firstname $lastname";
-                    $directory_name = strtoupper($lastname) . " " . $firstname;
-                }
-                XDB::execute('INSERT INTO  accounts (hruid, display_name, full_name, directory_name, firstname, lastname, email, type, state)
-                                   VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, \'xnet\', \'disabled\')',
-                             $hruid, $display_name, $full_name, $directory_name, $firstname, $lastname, $email);
-                $user = User::getSilent($hruid);
+            $user = User::getSilent($email);
+
+            // Wrong email and no user: failure.
+            if (is_null($user) && !$is_valid_email) {
+                $page->trigError('«&nbsp;<strong>' . $email . '</strong>&nbsp;» n\'est pas une adresse email valide.');
+                return;
             }
 
-            $suggest_account_activation = $this->suggest($user);
+            // Deals with xnet accounts.
+            if (is_null($user) || $user->type == 'xnet') {
+                // User is of type xnet. There are 3 possible cases:
+                //  * the email is not known yet: we create a new account and
+                //      propose to send an email to the user so he can activate
+                //      his account,
+                //  * the email is known but the user was not contacted in order to
+                //      activate yet: we propose to send an email to the user so he
+                //      can activate his account,
+                //  * the email is known and the user was already contacted or has
+                //      an active account: nothing to be done.
+                list($mbox, $domain) = explode('@', strtolower($email));
+                $hruid = User::makeHrid($mbox, $domain, 'ext');
+                // User might already have an account (in another group for example).
+                $user = User::getSilent($hruid);
+
+                // If the user has no account yet, creates new account: build names from email address.
+                if (empty($user)) {
+                    $parts = explode('.', $mbox);
+                    if (count($parts) == 1) {
+                        $lastname = $display_name = $full_name = $directory_name = ucfirst($mbox);
+                        $firstname = '';
+                    } else {
+                        $firstname = ucfirst($parts[0]);
+                        $lastname = ucwords(implode(' ', array_slice($parts, 1)));
+                        $display_name = $firstname;
+                        $full_name = "$firstname $lastname";
+                        $directory_name = strtoupper($lastname) . " " . $firstname;
+                    }
+                    XDB::execute('INSERT INTO  accounts (hruid, display_name, full_name, directory_name, firstname, lastname, email, type, state)
+                                       VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, \'xnet\', \'disabled\')',
+                                 $hruid, $display_name, $full_name, $directory_name, $firstname, $lastname, $email);
+                    $user = User::getSilent($hruid);
+                }
+
+                $suggest_account_activation = $this->suggest($user);
+            }
         }
 
         if ($user) {
@@ -1176,28 +1218,51 @@ class XnetGrpModule extends PLModule
                 }
                 XDB::query('UPDATE  accounts
                                SET  full_name = {?}, directory_name = {?}, display_name = {?},
-                                    firstname = {?}, lastname = {?}, sex = {?}, email = {?}, type = {?}
+                                    firstname = {?}, lastname = {?}, sex = {?}, type = {?}
                              WHERE  uid = {?}',
                            $full_name, $directory_name, Post::t('display_name'), $firstname, $lastname,
-                           (Post::t('sex') == 'male') ? 'male' : 'female', Post::t('email'),
+                           (Post::t('sex') == 'male') ? 'male' : 'female',
                            (Post::t('type') == 'xnet') ? 'xnet' : 'virtual', $user->id());
-            } else if (!$user->perms && Post::has('email') && require_email_update($user, Post::t('email'))) {
+            }
+
+            // Updates email.
+            $new_email = strtolower(Post::t('email'));
+            if (!$user->perms && require_email_update($user, $new_email)) {
                 XDB::query('UPDATE  accounts
                                SET  email = {?}
                              WHERE  uid = {?}',
-                           Post::t('email'), $user->id());
+                           $new_email, $user->id());
                 $listClient = new MMList(S::user());
-                $listClient->change_user_email($user->forlifeEmail(), Post::t('email'));
-                update_alias_user($user->forlifeEmail(), Post::t('email'));
+                $listClient->change_user_email($user->forlifeEmail(), $new_email);
+                update_alias_user($user->forlifeEmail(), $new_email);
             }
             if (XDB::affectedRows()) {
                 $page->trigSuccess('Données de l\'utilisateur mises à jour.');
             }
 
-            if (($user->type == 'xnet' && !$user->perms) && Post::b('suggest')) {
-                $request = new AccountReq(S::user(), $user->hruid, Post::t('email'), $globals->asso('nom'));
-                $request->submit();
-                $page->trigSuccess('Le compte va bientôt être activé.');
+            if (($user->type == 'xnet' && !$user->perms)) {
+                if (Post::b('suggest')) {
+                    $request = new AccountReq(S::user(), $user->hruid, Post::t('email'), $globals->asso('nom'));
+                    $request->submit();
+                    $page->trigSuccess('Le compte va bientôt être activé.');
+                }
+                if (Post::b('again')) {
+                    $data = XDB::fetchOneAssoc('SELECT  hash, group_name, sender_name, email
+                                                  FROM  register_pending_xnet
+                                                 WHERE  uid = {?}',
+                                               $user->id());
+
+                    $mailer = new PlMailer('xnet/account.mail.tpl');
+                    $mailer->addCc('validation+xnet_account@polytechnique.org');
+                    $mailer->setTo($data['email']);
+                    $mailer->assign('hash', $data['hash']);
+                    $mailer->assign('email', $data['email']);
+                    $mailer->assign('group', $data['group_name']);
+                    $mailer->assign('sender_name', $data['sender_name']);
+                    $mailer->assign('again', true);
+                    $mailer->send();
+                    $page->trigSuccess('Relance effectuée avec succès.');
+                }
             }
 
             // Update group params for user
@@ -1268,7 +1333,7 @@ class XnetGrpModule extends PLModule
                 if (Post::i('newsletter') == 1) {
                     $nl->subscribe($user);
                 } else {
-                    $nl->unsubscribe(null, $user->id);
+                    $nl->unsubscribe(null, $user->id());
                 }
             }
         }
@@ -1288,6 +1353,10 @@ class XnetGrpModule extends PLModule
         $page->assign('alias', $user->emailGroupAliases($globals->asso('mail_domain')));
         $page->assign('positions', explode(',', $positions));
         $page->assign('nl_registered', $nl_registered);
+        $page->assign('pending_xnet_account', XDB::fetchOneCell('SELECT  1
+                                                                   FROM  register_pending_xnet
+                                                                  WHERE  uid = {?}',
+                                                                $user->id()));
     }
 
     function handler_rss(PlPage $page, PlUser $user)
index c0eaa38..8fb6fe0 100644 (file)
@@ -28,8 +28,8 @@ 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_PASSWD, 'groupmember'),
+            '%grp/lists/create'       => $this->make_hook('create',   AUTH_PASSWD, 'groupmember'),
 
             '%grp/lists/members'      => $this->make_hook('members',  AUTH_COOKIE, 'groups'),
             '%grp/lists/csv'          => $this->make_hook('csv',      AUTH_COOKIE, 'groups'),
@@ -37,17 +37,17 @@ class XnetListsModule extends ListsModule
             '%grp/lists/archives'     => $this->make_hook('archives', AUTH_COOKIE, 'groups'),
             '%grp/lists/archives/rss' => $this->make_hook('rss',      AUTH_PUBLIC),
 
-            '%grp/lists/moderate'     => $this->make_hook('moderate', AUTH_MDP,    'groups'),
-            '%grp/lists/admin'        => $this->make_hook('admin',    AUTH_MDP,    'groups'),
-            '%grp/lists/options'      => $this->make_hook('options',  AUTH_MDP,    'groups'),
-            '%grp/lists/delete'       => $this->make_hook('delete',   AUTH_MDP,    'groups'),
+            '%grp/lists/moderate'     => $this->make_hook('moderate', AUTH_PASSWD, 'groups'),
+            '%grp/lists/admin'        => $this->make_hook('admin',    AUTH_PASSWD, 'groups'),
+            '%grp/lists/options'      => $this->make_hook('options',  AUTH_PASSWD, 'groups'),
+            '%grp/lists/delete'       => $this->make_hook('delete',   AUTH_PASSWD, 'groups'),
 
-            '%grp/lists/soptions'     => $this->make_hook('soptions', AUTH_MDP,    'groups'),
-            '%grp/lists/check'        => $this->make_hook('check',    AUTH_MDP,    'groups'),
-            '%grp/lists/sync'         => $this->make_hook('sync',     AUTH_MDP,    'groups'),
+            '%grp/lists/soptions'     => $this->make_hook('soptions', AUTH_PASSWD, 'groups'),
+            '%grp/lists/check'        => $this->make_hook('check',    AUTH_PASSWD, 'groups'),
+            '%grp/lists/sync'         => $this->make_hook('sync',     AUTH_PASSWD, 'groups'),
 
-            '%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_PASSWD, 'groupadmin'),
+            '%grp/alias/create'       => $this->make_hook('acreate',  AUTH_PASSWD, 'groupadmin'),
 
             /* hack: lists uses that */
             'profile'                 => $this->make_hook('profile',  AUTH_PUBLIC),
@@ -259,7 +259,7 @@ class XnetListsModule extends ListsModule
             S::assert_xsrf_token();
 
             if (add_to_list_alias(Env::t('add_member'), $local_part, $domain)) {
-                $page->trigSuccess('Ajout réussit.');
+                $page->trigSuccess('Ajout réussi.');
             } else {
                 $page->trigError('Ajout infructueux.');
             }
index 7451a07..f8e9150 100644 (file)
@@ -26,16 +26,16 @@ class XnetNlModule extends NewsletterModule
     function handlers()
     {
         return array(
-            '%grp/nl'                   => $this->make_hook('nl',              AUTH_MDP, 'groups'),
-            '%grp/nl/show'              => $this->make_hook('nl_show',         AUTH_MDP, 'groups'),
-            '%grp/nl/search'            => $this->make_hook('nl_search',       AUTH_MDP, 'groups'),
-            '%grp/admin/nl'             => $this->make_hook('admin_nl',        AUTH_MDP, 'groupadmin'),
-            '%grp/admin/nl/sync'        => $this->make_hook('admin_nl_sync',   AUTH_MDP, 'groupadmin'),
-            '%grp/admin/nl/enable'      => $this->make_hook('admin_nl_enable', AUTH_MDP, 'groupadmin'),
-            '%grp/admin/nl/edit'        => $this->make_hook('admin_nl_edit',   AUTH_MDP, 'groupadmin'),
-            '%grp/admin/nl/edit/cancel' => $this->make_hook('admin_nl_cancel', AUTH_MDP, 'groupadmin'),
-            '%grp/admin/nl/edit/valid'  => $this->make_hook('admin_nl_valid',  AUTH_MDP, 'groupadmin'),
-            '%grp/admin/nl/categories'  => $this->make_hook('admin_nl_cat',    AUTH_MDP, 'groupadmin'),
+            '%grp/nl'                   => $this->make_hook('nl',              AUTH_PASSWD, 'groups'),
+            '%grp/nl/show'              => $this->make_hook('nl_show',         AUTH_PASSWD, 'groups'),
+            '%grp/nl/search'            => $this->make_hook('nl_search',       AUTH_PASSWD, 'groups'),
+            '%grp/admin/nl'             => $this->make_hook('admin_nl',        AUTH_PASSWD, 'groupadmin'),
+            '%grp/admin/nl/sync'        => $this->make_hook('admin_nl_sync',   AUTH_PASSWD, 'groupadmin'),
+            '%grp/admin/nl/enable'      => $this->make_hook('admin_nl_enable', AUTH_PASSWD, 'groupadmin'),
+            '%grp/admin/nl/edit'        => $this->make_hook('admin_nl_edit',   AUTH_PASSWD, 'groupadmin'),
+            '%grp/admin/nl/edit/cancel' => $this->make_hook('admin_nl_cancel', AUTH_PASSWD, 'groupadmin'),
+            '%grp/admin/nl/edit/valid'  => $this->make_hook('admin_nl_valid',  AUTH_PASSWD, 'groupadmin'),
+            '%grp/admin/nl/categories'  => $this->make_hook('admin_nl_cat',    AUTH_PASSWD, 'groupadmin'),
         );
     }
 
index fe40261..abfb165 100644 (file)
@@ -27,7 +27,7 @@ function smarty_function_profile($params, $smarty)
     $with_link  = $params->b('link', true);
     $with_dir   = $params->b('directory', true);
     $with_groupperms = $params->b('groupperms', true);
-    $raw = $params->b('raw', true);
+    $raw = $params->b('raw', false);
     $user = $params->v('user');
     if (is_int($user) || ctype_digit($user)) {
         $user = User::getWithUID($user);
index 67c3b81..ba1443d 100644 (file)
@@ -94,7 +94,7 @@
   <div class="center"><input type="submit" name="action" value="Enregistrer" /></div>
 </form>
 {/if}
-{if !$it_is_xnet}
+{if !t($it_is_xnet)}
 <p class="smaller">
   {icon name="lightbulb" title="Astuce"}Astuce&nbsp;:
   tu peux également consulter les forums en utilisant un client NNTP tel que
diff --git a/templates/carnet/batch.tpl b/templates/carnet/batch.tpl
new file mode 100644 (file)
index 0000000..220441e
--- /dev/null
@@ -0,0 +1,48 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2011 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.org/                                  *}
+{*                                                                        *}
+{*  This program is free software; you can redistribute it and/or modify  *}
+{*  it under the terms of the GNU General Public License as published by  *}
+{*  the Free Software Foundation; either version 2 of the License, or     *}
+{*  (at your option) any later version.                                   *}
+{*                                                                        *}
+{*  This program is distributed in the hope that it will be useful,       *}
+{*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *}
+{*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *}
+{*  GNU General Public License for more details.                          *}
+{*                                                                        *}
+{*  You should have received a copy of the GNU General Public License     *}
+{*  along with this program; if not, write to the Free Software           *}
+{*  Foundation, Inc.,                                                     *}
+{*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<h1>Marketing</h1>
+
+<p>
+  La liste des camarades à ajouter doit comporter un camarade par ligne, sous la forme&nbsp;:
+  <em>Prénom Nom Promo Email</em>, où tous les champs, sauf l'email, sont facultatifs. La promotion éventuelle doit être
+  indiquée sous la forme <em>X2004</em>.
+</p>
+{if $errors}
+<p class="erreur">
+  Les lignes incomplètes ou erronées ont été remises dans le cadre ci-dessous pour que tu puisses les corriger et/ou les complèter.
+</p>
+{/if}
+
+<form method="post" action="{$platal->ns}carnet/batch" enctype="multipart/form-data">
+  {xsrf_token_field}
+  <div>
+  <textarea name="list" cols="60" rows="30">{if $errors}{foreach from=$incomplete item=line}{$line}
+{/foreach}{/if}</textarea><br />
+  Marketer les camarades non inscrits à Polytechnique.org&nbsp;:<br />
+  <label>en ton nom<input type="radio" name="origin" value="user" checked="checked" /></label>&nbsp;-&nbsp;
+  <label><input type="radio" name="origin" value="staff" />au nom de l'équipe Polytechnique.org </label><br />
+  <input type="submit" name="add" value="Ajouter" />
+  </div>
+</form>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index bccf4bd..d26b025 100644 (file)
       </div>
     </td>
   </tr>
+  <tr class="impair">
+    <td colspan="2">
+      <h3><a href="carnet/batch">Ajouter plusieurs camarades à ses contacts</a></h3>
+      <div class="explication">
+        De cette façon, tu peux aussi suggérer d'un seul coup plusieurs camarades dont tu connais les adresses email de s'inscrire à Polytechnique.org.
+        Ceux déjà isncrits seront directement ajoutés à tes contacts.
+      </div>
+    </td>
+  </tr>
 </table>
 
 <br />
index df21a2d..22f0675 100644 (file)
@@ -38,7 +38,9 @@ Tu trouveras les mêmes informations sur [[https://www.polytechnique.org/carnet/
 
 {foreach from=$cat.users item=user}
 {assign var=profile value=$user->profile()}
+{if !$profile->isDead()}
 * Le {$cat.operation->getDate($user)|date_format:"%d %B %Y"}, [[https://www.polytechnique.org/profile/private/{$profile->hrid()}|{$profile->fullname(true)}]]
+{/if}
 {/foreach}
 
 {/foreach}
index 9d13880..86e19b9 100644 (file)
@@ -116,6 +116,36 @@ Attention&nbsp;: pour les promos, tu n'es pas notifié des événements trop fr
   </fieldset>
 </form>
 
+<h2>Surveiller des groupes X</h2>
+
+<p>
+Attention&nbsp;: comme pour les promos, pour les groupes X, tu n'es pas notifié des événements trop fréquents (par exemple les changements de fiche).
+</p>
+
+<form action="carnet/notifs/" method="post">
+  {xsrf_token_field}
+  <fieldset>
+    <legend>{icon name="group"} Ajouter un groupe X</legend>
+    Tu peux surveiller des groupes X (mettre le nom ou le diminutif du groupe).<br />
+    <input type='text' name='group' />
+    <input type='submit' name='add_group' value='ajouter'
+      onclick="this.form.action += 'add_group/' + this.form.group.value;" />
+    <input type='submit' name='del_group' value='retirer'
+      onclick="this.form.action += 'del_group/' + this.form.group.value;" />
+    <br />
+    {if $groups_count eq 0}
+    <p>Tu ne surveilles actuellement aucun groupe X.</p>
+    {else}
+    <p>Tu surveilles {if $groups_count eq 1}le groupe suivant&nbsp;:{else}les groupes suivants&nbsp;:{/if}</p>
+    <ul>
+    {foreach from=$groups item=group}
+      <li>{$group}</li>
+    {/foreach}
+    </ul>
+    {/if}
+  </fieldset>
+</form>
+
 <h2>Surveiller des non inscrits</h2>
 
 <p>
index 8eb7b75..9ebb6bf 100644 (file)
@@ -41,7 +41,7 @@
     <tr>
       <td class="orange">
         <input type="checkbox" {if $mail_public}checked="checked"{/if}
-            onclick="$.xget('{$globals->baseurl}/emails/alias/set/'+(this.checked?'public':'private')+'?token={xsrf_token}');
+            onclick="$.xget('{$globals->baseurl}/emails/alias/set/'+(this.checked?'private':'hidden')+'?token={xsrf_token}');
                 $('#mail_public').html((this.checked?'public et apparaît donc sur ta fiche':'privé et n\'apparaît nulle part sur le site') + '.');
             " />
       </td>
index 1434bc5..1524824 100644 (file)
     }
   }
 
+  function toggleWiki()
+  {
+    if ($('[name="wiki"]').val() == 'text') {
+      $('[name="wiki"]').val('wiki');
+    } else {
+      $('[name="wiki"]').val('text');
+    }
+  }
+
   $(window).unload(
     function() {
       if (sent) {
       <td class="titre">de&nbsp;:</td>
       <td>
         <input type='hidden' name='signature' value='1' />
-        <input type='text' name='from' size='60' value='{if $smarty.request.from}
-{$smarty.request.from}
-{else}
-"{$user->fullName()}" &lt;{$user->bestEmail()}&gt;
-{/if}' />
+        <input type='text' name='from' size='60'
+          value="{if $smarty.request.from}{$smarty.request.from}{else}{$preferences.from_email}{/if}" />
       </td>
     </tr>
     <tr>
     <legend>Sujet&nbsp;:&nbsp;<input type='text' name='sujet' size='60' value="{$smarty.request.sujet}" /></legend>
     <div class="center">
       Tu peux utiliser des <a href="wiki_help" class="popup3">{icon name=information title="Syntaxe wiki"} marqueurs wiki</a> pour formatter ton texte.<br />
-      <small><label><input type="checkbox" name="nowiki" value="1" {if $smarty.request.nowiki}checked="checked"{/if} onchange="updateWikiView(this);" />
-      coche cette case pour envoyer l'email en texte brut, sans formattage</label></small>
+      <small><label>
+        <input type="hidden"  name="wiki" value="{$smarty.request.wiki|default:$preferences.from_format}" />
+        <input type="checkbox" {if $smarty.request.wiki eq "text" || (!$smarty.request.wiki && $preferences.from_format eq "text")}checked="checked"{/if}
+        onchange="updateWikiView(this); toggleWiki();" />
+        coche cette case pour envoyer l'email en texte brut, sans formattage
+      </label></small>
     </div>
     <div id="preview">
       <div id="preview_pv" style="display: none">
index 4d91d37..bd9da07 100644 (file)
 <strong>Montant&nbsp;:</strong> <input type="text" name="pay_montant" size="5" value="{$valid->montant}" />
 (min <input type="text" name="pay_montant_min" size="5" value="{$valid->montant_min}" />
 &nbsp;->&nbsp; max <input type="text" name="pay_montant_max" size="5" value="{$valid->montant_max}" />)
+<br />
+<strong>Public&nbsp;:</strong>
+<label><input type="radio" name="pay_public" value="no" {if !t($valid->public)}checked="checked"{/if} />Non</label>
+&nbsp;-&nbsp;
+<label>Oui<input type="radio" name="pay_public" value="yes" {if t($valid->public)}checked="checked"{/if} /></label><br />
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 58f5663..50080d3 100644 (file)
@@ -59,4 +59,9 @@
 </tr>
 {/if}
 {/if}
+<tr class="pair">
+  <td class="titre">Public&nbsp;:</td>
+  <td>{if $valid->public}Oui{else}Non{/if}</td>
+</tr>
+
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 6bfc6e9..02c8f06 100644 (file)
@@ -140,7 +140,7 @@ emails de marketing. Une fois inscrits à Polytechnique.org, l'inscription à la
     <tr class="pair">
       <td class="titre">ou fichier(*)</td>
       <td colspan="2">
-        <input type="file" name="add_member_file" />*
+        <input type="file" size="40" name="add_member_file" />*
       </td>
     </tr>
     <tr class="pair">
index 431b43e..f0117ee 100644 (file)
@@ -91,7 +91,7 @@
     </td>
   </tr>
   {/if}
-  {if $it_is_xnet && ($details.own || $is_admin)}
+  {if t($it_is_xnet) && ($details.own || $is_admin)}
   <tr>
     <td><strong>Synchroniser&nbsp;:</strong></td>
     {if $on neq 'sync'}
index 07af4c0..0e95f00 100644 (file)
 
 <table class="bicol" cellpadding="3" cellspacing="0" summary="Liste des Newsletter actives">
   <tr>
-    <th>Id</th>
-    <th>Groupe</th>
-    <th>Titre</th>
-    <th>CSS spécifique</th>
-    <th>Critères actifs</th>
+    {foreach from=$titles item=title key=key}
+    <th>
+      {if $sort eq $key}
+      <a href="admin/nls/{$key}/{$next_order}">
+      {if $order eq "DESC"}
+      <img src="images/dn.png" alt="tri descendant" />
+      {else if $order eq "ASC"}
+      <img src="images/up.png" alt="tri ascendant" />
+      {/if}
+      {else}
+      <a href="admin/nls/{$key}">
+      {/if}
+      {$title}
+      </a>
+    </th>
+    {/foreach}
   </tr>
   {foreach from=$nls item=nl}
   <tr class="{cycle values="pair,impair"}">
-    <td class="titre">{$nl->id}</td>
-    <td>{$nl->group}</td>
-    <td><a href="http://www.polytechnique.net/{$nl->group}/admin/nl">{$nl->name}</a></td>
-    <td>{if $nl->hasCustomCss()}Oui{else}Non{/if}</td>
-    <td>{$nl->criteria->flags()}</td>
+    <td class="titre">{$nl.id}</td>
+    <td>{$nl.group_name}</td>
+    <td><a href="http://www.polytechnique.net/{$nl.group_link}/admin/nl">{$nl.name}</a></td>
+    <td>{if $nl.custom_css}Oui{else}Non{/if}</td>
+    <td>{$nl.criteria}</td>
   </tr>
   {/foreach}
 </table>
index c6a3a1a..5ef9561 100644 (file)
         <input type='text' size='60' name='signature' value="{$issue->signature}" />
       </td>
     </tr>
+    <tr>
+      <td class='titre'>
+        Adresse de réponse (optionnelle)
+      </td>
+      <td>
+        <input type='text' size='60' name='reply_to' value="{$issue->reply_to}" />
+      </td>
+    </tr>
     {if $nl->automaticMailingEnabled() && ($issue->isEditable() || $issue->isPending())}
     <tr>
       <td class='titre'>
       </td>
     </tr>
     {/if}
-    {if $issue->isEditable()}
-      {if $nl->criteria->hasFlag('promo')}
+    {if $nl->criteria->hasFlag('promo')}
       <tr>
         <td class="titre">Promotions</td>
         <td>
-          {include file="include/select_promo.tpl" promo_data=$smarty.request egal1="egal1" egal2="egal2" promo1="promo1" promo2="promo2" edu_type="edu_type"}
+          {if $issue->isEditable()}
+            {include file="include/select_promo.tpl" promo_data=$smarty.request egal1="egal1" egal2="egal2" promo1="promo1" promo2="promo2" edu_type="edu_type"}
+          {else}
+            {if t($smarty.request.promo1)}
+              {if $smarty.request.egal1 eq "="}
+                {$smarty.request.promo1}
+              {elseif t($smarty.request.promo2)}
+                {if $smarty.request.egal1 eq "&gt;="}
+                  {$smarty.request.promo1} à {$smarty.request.promo2}
+                {else}
+                  {$smarty.request.promo2} à {$smarty.request.promo1}
+                {/if}
+              {else}
+                {if $smarty.request.egal1 eq "&gt;="}
+                  après {$smarty.request.promo1}
+                {else}
+                  avant {$smarty.request.promo1}
+                {/if}
+              {/if}
+            {else}
+              Toutes les promotions
+            {/if}
+            {if $smarty.request.edu_type eq #UserFilter::GRADE_ING#}(X){/if}
+            {if $smarty.request.edu_type eq #UserFilter::GRADE_MST#}(Master){/if}
+            {if $smarty.request.edu_type eq #UserFilter::GRADE_PHD#}(Docteur){/if}
+          {/if}
         </td>
       </tr>
-      {/if}
-      {if $nl->criteria->hasFlag('axid')}
+    {/if}
+    {if $nl->criteria->hasFlag('axid')}
       <tr>
         <td class="titre">Matricule AX</td>
         <td>
-          <textarea name="axid" rows="10" cols="12">{$smarty.request.axid}</textarea>
-          <br />
-          <i>Entrer une liste de matricules AX (un par ligne)</i><br />
-          <input type="checkbox" name="axid_reversed" id="axid_reversed" {if $smarty.request.axid_reversed}checked="checked"{/if} value="1" />
-          Inverser la sélection <i>(sélectionner dans l'intervalle de promotions, à l'exception des matricules indiqués)</i>
+          {if $issue->isEditable()}
+            <textarea name="axid" rows="10" cols="12">{$smarty.request.axid}</textarea>
+            <br />
+            <i>Entrer une liste de matricules AX (un par ligne)</i><br />
+            <input type="checkbox" name="axid_reversed" id="axid_reversed" {if $smarty.request.axid_reversed}checked="checked"{/if} value="1" />
+            Inverser la sélection <i>(sélectionner dans l'intervalle de promotions, à l'exception des matricules indiqués)</i>
+          {else}
+            {$smarty.request.axid}
+          {/if}
         </td>
       </tr>
-      {/if}
     {/if}
     <tr class='center'>
       <td colspan='2'>
index 6bcb7d5..79da294 100644 (file)
@@ -74,7 +74,7 @@ Tu n'es actuellement pas inscrit à la {$nl->name}.
 </table>
 
 {if $nl->mayEdit()}
-<p>Il y a actuellement {$nl->subscriberCount()} inscrits aux envois.</p>
+<p>Il y a actuellement {$nl->subscriberCount()} inscrits aux envois, parmi lesquels {$nl->lostSubscriberCount()} n'ont aucune redirection active.</p>
 {/if}
 
 
similarity index 81%
rename from templates/payment/index.tpl
rename to templates/payment/payment.tpl
index 69b0bc7..d926a91 100644 (file)
 {*                                                                        *}
 {**************************************************************************}
 
+{if $smarty.request.op eq "submit" and !$pl_errors}
 
 <h1>Télépaiements</h1>
 
-{if $smarty.request.op eq "submit" and !$pl_errors}
-
 <table class="bicol">
   <tr>
     <th colspan="2">Paiement via {$meth->text}</th>
   </tr>
+{if t($public)}
+  <tr>
+    <td><b>Nom</b></td>
+    <td>{$full_name}</td>
+  </tr>
+{/if}
   <tr>
     <td><b>Transaction</b></td>
     <td>{$pay->text}</td>
   </tr>
   <tr>
     <td><b>Montant</b></td>
-    <td>{$montant} &euro;</td>
+    <td>{$amount} &euro;</td>
   </tr>
 {if $comment}
   <tr>
@@ -73,7 +78,7 @@
 </table>
 <p>
 En cliquant sur "Valider", tu seras redirigé{if $sex}e{/if} vers le site de {$pay->api->nomsite}, où il te
-sera demandé de saisir ton numéro de carte bancaire.  Lorsque le paiement aura été effectué, tu
+sera demandé de saisir ton numéro de carte bancaire. Lorsque le paiement aura été effectué, tu
 recevras une confirmation par email.
 </p>
 {if $pay->api->text}
@@ -89,17 +94,9 @@ Si tu n'es pas encore inscrit à cet événement, n'oublie pas d'aller t'<a href
 
 {else}
 
-<script type='text/javascript'>
-{literal}
-function payment_submit(form)
-{
-    form.op.value = 'select';
-    form.montant.value = 0;
-    form.action = 'payment/' + form.ref.value;
-    form.submit();
-}
-{/literal}
-</script>
+{if t($donation)}
+{include wiki=Docs.Dons}
+{/if}
 
 <form method="post" action="{$platal->pl_self()}">
   <table class="bicol">
@@ -109,15 +106,7 @@ function payment_submit(form)
     <tr>
       <td>Transaction</td>
       <td>
-        {if t($asso)}
         <strong>{$pay->text}</strong><input type="hidden" name="ref" value="{$pay->id}" />
-        {else}
-        <select name="ref" onchange="payment_submit(this.form)">
-          {select_db_table table="payments" valeur=$pay->id
-                           where="WHERE FIND_IN_SET('old', t.flags) = 0"
-                           join="LEFT JOIN groups AS g ON (t.asso_id = g.id)" group="g.nom"}
-        </select>
-        {/if}
         {if $pay->url}
         <br />
         <a href="{$pay->url}">plus d'informations</a>
@@ -134,15 +123,21 @@ function payment_submit(form)
     </tr>
     <tr>
       <td>Montant</td>
-      <td><input type="text" name="montant" size="13" class='right' value="{$montant}" /> &euro;</td>
+      <td><input type="text" name="amount" size="13" class="right" value="{$pay->amount_def}" /> &euro;</td>
     </tr>
+    {if t($public)}
+    <tr>
+      <td>Identifiant <small>(prenom.nom.promo)</small></td>
+      <td><input type="text" name="login" size="30" /></td>
+    </tr>
+    {/if}
     <tr>
       <td>Commentaire</td>
       <td><textarea name="comment" rows="5" cols="30"></textarea></td>
     </tr>
     {if t($donation)}
     <tr>
-      <td>Afficher ton nom dans la liste des donateurs sur {#globals.core.sitename#}</td>
+      <td>Afficher ton nom dans la liste des donateurs</td>
       <td>
         <label>Oui<input type="radio" name="display" value="1" checked="checked" /></label>
         &nbsp;-&nbsp;
@@ -153,7 +148,6 @@ function payment_submit(form)
     <tr>
       <td>&nbsp;</td>
       <td>
-        {if !t($donation)}<input type="hidden" name="display" value="0" />{/if}
         <input type="hidden" name="op" value="submit" />
         <input type="submit" value="Continuer" />
       </td>
@@ -175,26 +169,37 @@ function payment_submit(form)
 {/if}
 
 {if t($donation)}
-{if !t($donations)}
-<p class="descr">Aucun don n'a encore été recueilli.</p>
-{else}
-<p class="descr">Les dons suivants ont déjà été recueillis (pour un total de {$sum} &euro;)&nbsp;:</p>
+<p class="descr">Les 10 plus gros dons sont les suivants&nbsp;:</p>
 <table class="bicol">
   <tr>
     <th>Nom</th>
     <th>Montant</th>
+    <th>Date</th>
   </tr>
-  {foreach from=$donations item=d}
+  {foreach from=$biggest_donations item=d}
   <tr class="{cycle values="pair,impair"}">
     <td>{$d.name}</td>
     <td class="center">{$d.amount|replace:'.':','} &euro;</td>
+    <td>{$d.ts_confirmed|date_format}</td>
   </tr>
   {/foreach}
 </table>
-{/if}
-{/if}
 
+<p class="descr">Les dons par période&nbsp;:</p>
+<table class="tinybicol">
+  <tr>
+    <th>Période</th>
+    <th>Montant</th>
+  </tr>
+  {foreach from=$donations item=d}
+  <tr class="{cycle values="pair,impair"}">
+    <td>{if $d.month neq 0}{$d.ts_confirmed|date_format:"%B %Y"}{else}{$d.ts_confirmed|date_format:"%Y"}{/if}</td>
+    <td style="text-align: right">{$d.amount|replace:'.':','} &euro;</td>
+  </tr>
+  {/foreach}
+</table>
 {/if}
 
+{/if}
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/platal/email_preferences.tpl b/templates/platal/email_preferences.tpl
new file mode 100644 (file)
index 0000000..6749669
--- /dev/null
@@ -0,0 +1,49 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2011 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.org/                                  *}
+{*                                                                        *}
+{*  This program is free software; you can redistribute it and/or modify  *}
+{*  it under the terms of the GNU General Public License as published by  *}
+{*  the Free Software Foundation; either version 2 of the License, or     *}
+{*  (at your option) any later version.                                   *}
+{*                                                                        *}
+{*  This program is distributed in the hope that it will be useful,       *}
+{*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *}
+{*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *}
+{*  GNU General Public License for more details.                          *}
+{*                                                                        *}
+{*  You should have received a copy of the GNU General Public License     *}
+{*  along with this program; if not, write to the Free Software           *}
+{*  Foundation, Inc.,                                                     *}
+{*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<h1>Préférences pour tes envois d'email depuis Polytechnique.org</h1>
+
+<form action="{$smarty.server.REQUEST_URI}" method="post">
+  {xsrf_token_field}
+  <table class="bicol" summary="email pref">
+    <tr>
+      <td class="titre">Ton adresse d'émission</td>
+      <td>
+        <input type="text" name="from_email" size="60" value="{$from_email}" {if $error}class="error"{/if} />
+      </td>
+    </tr>
+    <tr>
+      <td class="titre">Formattage des emails</td>
+      <td>
+        <label>HTML<input type="radio" name="from_format" value="html" {if $from_format eq "html"}checked="checked"{/if} /></label>
+        <label><input type="radio" name="from_format" value="text" {if $from_format neq "html"}checked="checked"{/if} />texte brut</label>
+      </td>
+    </tr>
+    <tr>
+      <td colspan="2" class="center">
+        <input type="submit" value="Valider" name="submit" />
+      </td>
+    </tr>
+  </table>
+</form>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 0628af4..a50bfca 100644 (file)
@@ -100,6 +100,11 @@ $(function() {
       http://www.carva.org/{$smarty.session.user->hruid} vers la page de ton choix.<br />
       <a href="prefs/webredirect">Gérer ta redirection Web</a>
     </dd>
+    <dt>Paramètres d'envois d'emails depuis le site</dt>
+    <dd>
+      Tu peux faire retenir au site les paramètres d'envoi par défaut des emails depuis <a href="emails/send">le site</a>.<br />
+      <a href="prefs/email">Gérer tes envois d'emails depuis le site</a>
+    </dd>
   </dl>
 </fieldset>
 {/if}
index cd11e40..0aaa0c3 100644 (file)
 {*                                                                        *}
 {**************************************************************************}
 
-{assign var=isMe value=$smarty.session.user->isMyProfile($profile)}
-{if hasPerm('directory_private')}
-{assign var=viewPrivate value=true}
-{/if}
-
 <form action="{$wiz_baseurl}/{$lookup[$current]}" method="post" id="prof_annu">
   {xsrf_token_field}
   <div>
     {icon name=information title="Voir ma fiche"} Tu peux consulter
-    {if $smarty.session.user->isMyProfile($profile)}ta{else}cette{/if} fiche telle que la
+    {if $isMe}ta{else}cette{/if} fiche telle que la
     voient <a class="popup2" href="profile/{$profile->hrpid}?view=public">n'importe quel internaute</a>,
-    <a class="popup2" href="profile/{$profile->hrpid}?view=ax">l'AX</a>{if hasPerm('directory_private')}ou
+    <a class="popup2" href="profile/{$profile->hrpid}?view=ax">l'AX</a>{if $viewPrivate}ou
     <a class="popup2" href="profile/{$profile->hrpid}">les X</a>{/if}.
   </div>
   <div class="flags">
index 0c99ea0..b206319 100644 (file)
       <input type="hidden" name="medals_{$id}_grade" value="{$medal.grade}" />
       <input type="hidden" name="medals[{$id}][id]" value="{$medal.id}" />
       <input type="hidden" name="medals[{$id}][valid]" value="{$medal.valid}" />
+      <input type="hidden" name="medals[{$id}][has_levels]" value="{$medal.has_levels}" />
+    </div>
+    <div>
+    {if $medal.has_levels}
+    Niveau / Échelon :
+    <select name="medals[{$id}][level]">
+      <option value="Or" {if $medal.level eq "Or"}selected="selected"{/if}>Or</option>
+      <option value="Argent" {if $medal.level eq "Argent"}selected="selected"{/if}>Argent</option>
+      <option value="Bronze" {if $medal.level eq "Bronze"}selected="selected"{/if}>Bronze</option>
+    </select>
+    {else}
+    <input type="hidden" name="medals[{$id}][level]" value="" />
+    {/if}
     </div>
   </div>
   <a class="removeMedal" href="javascript:removeMedal({$id})" style="vertical-align: middle">
index 4c27f5f..334ca32 100644 (file)
@@ -50,7 +50,7 @@
       {foreach from=$medals item=medal key=id}
       {include file="profile/deco.medal.tpl" medal=$medal id=$id}
       {/foreach}
-      <p class="center">
+      <p class="center" style="clear: both">
         <small>
           Si {if $isMe}ta{else}la{/if} décoration
           ou {if $isMe}ta{else}la{/if} médaille ne figure pas dans la liste,
index 0fe683d..fa72041 100644 (file)
@@ -26,6 +26,8 @@
 
 {assign var=terms value=$profile->getMentoringTerms()}
 {assign var=countries value=$profile->getMentoringCountries()}
+{assign var=skills value=$profile->getSkills()}
+{assign var=languages value=$profile->getLanguages()}
 <div id="fiche">
 <div id="fiche_referent">
   <div id="fiche_identite">
   </div>
   <div class="spacer"></div>
 
+  {if $skills|count || $languages|count}
+  <div class="part">
+    <h2>Compétences&nbsp;:</h2>
+    {if $skills|count}
+    <div style="float: left">
+      <em>Professionnelles&nbsp;:</em><br />
+      <ul>
+        {foreach from=$skills item="skill"}
+        <li>{$skill.text_fr} ({$skill.level})</li>
+        {/foreach}
+      </ul>
+    </div>
+    {/if}
+    {if $languages|count}
+    <div {if $skills|count}style="float: right"{/if}>
+      <em>Linguistiques&nbsp;:</em><br />
+      <ul>
+        {foreach from=$languages item="language"}
+        <li>{$language.language} ({$language.level})</li>
+        {/foreach}
+      </ul>
+    </div>
+    {/if}
+    <div class="spacer">&nbsp;</div>
+  </div>
+  {/if}
+
   {if $profile->mentor_expertise != '' || $terms|count || $countries|count }
-  <div id="part">
+  <div class="part">
     <h2>Informations de référent&nbsp;:</h2>
     {if $profile->mentor_expertise}
     <div class="rubrique_referent">
diff --git a/templates/profile/general.hobby.tpl b/templates/profile/general.hobby.tpl
new file mode 100644 (file)
index 0000000..6767329
--- /dev/null
@@ -0,0 +1,56 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2011 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 !hasPerm('directory_private') && ($hobby.pub eq 'private') && !empty($hobby.text|smarty:nodefaults)}
+{assign var=hiddenhobby value=true}
+{else}
+{assign var=hiddenhobby value=false}
+{/if}
+
+<tr id="hobby_{$i}">
+  <td colspan="2">
+    <div style="float: left; width: 200px;">
+      <span class="flags">
+        <label>
+          <input type="checkbox" {if $hobby.pub neq 'private'}checked="checked"{/if}
+                 {if $hiddenhobby} disabled="disabled"{/if} name="hobbies[{$i}][pub]" />
+        {icon name="flag_green" title="site public"}
+      </label>
+      </span>&nbsp;
+      <input type="hidden" name="hobbies[{$i}][type]" value="{$hobby.type}" />
+      <span>{$hobby.type}</span>
+    </div>
+    <div style="float: left">
+      {if $hiddenhobby}
+      <input type="hidden" name="hobbies[{$i}][text]" value="{$hobby.text}" />
+      (masqué)
+      {else}
+      <input type="text" name="hobbies[{$i}][text]" value="{$hobby.text}" size="30" />
+      {/if}
+      <a href="javascript:removeHobby({$i})">
+        {icon name=cross title="Supprimer cet élément"}
+      </a>
+    </div>
+  </td>
+</tr>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 15dbeda..1f4b491 100644 (file)
@@ -21,7 +21,7 @@
 {**************************************************************************}
 
 {assign var=type value=$name.type}
-<tr class="names_advanced" id="search_name_{$id}" {if !$errors.search_names && !t($new_name)}style="display: none"{/if}>
+<tr class="names_advanced_private" id="search_name_{$id}" {if !$errors.search_names && !t($new_name)}style="display: none"{/if}>
   <td>
     <span class="flags">{icon name="flag_red" title="site privé"}</span>{if !t($new_name)}&nbsp;{$other_names.$type}{else}
     <select name="search_names[private_names][{$id}][type]">
index adbdb12..3c21fd8 100644 (file)
@@ -24,7 +24,7 @@
 {assign var=type value="lastname_"|cat:$suffix}
 {assign var=error value=$type|cat:"_error"}
 {assign var=particle value="particle_"|cat:$suffix}
-<tr class="names_advanced" {if !$errors.search_names}style="display: none"{/if}>
+<tr class="names_advanced_public" {if !$errors.search_names}style="display: none"{/if}>
   <td>
     <span class="flags">{icon name="flag_green" title="site public"}</span>&nbsp;{$description}
   </td>
@@ -42,7 +42,7 @@
 
 {foreach from=$firstnames key=type item=description}
 {assign var=error value=$type|cat:"_error"}
-<tr class="names_advanced" {if !$errors.search_names}style="display: none"{/if}>
+<tr class="names_advanced_public" {if !$errors.search_names}style="display: none"{/if}>
   <td>
     <span class="flags">{icon name="flag_green" title="site public"}</span>&nbsp;{$description}
   </td>
index edcc321..254617c 100644 (file)
@@ -32,7 +32,7 @@
       {$public_name}
     </td>
     <td>
-      <a href="javascript:toggleNamesAdvanced();">
+      <a href="javascript:toggleNamesAdvanced({$viewPrivate});">
         {icon name="page_edit" title="Plus de détail"}
       </a>
     </td>
@@ -74,7 +74,7 @@
   {foreach from=$search_names.private_names key=id item=name}
     {include file="profile/general.private_name.tpl"}
   {/foreach}
-  <tr class="names_advanced" id="searchname" {if !$errors.search_names}style="display: none"{/if}>
+  <tr class="names_advanced_private" id="searchname" {if !$errors.search_names}style="display: none"{/if}>
     <td colspan="3">
       <div id="sn_add" class="center">
         <a href="javascript:addSearchName({$isFemale});">
       <span class="titre">Date de naissance de référence</span>
     </td>
     <td>
-    {if $birthdate_ref eq 0}
+    {if hasPerm('admin') && !$is_registered}
       <input type="text" {if $errors.birthdate_ref}class="error"{/if} name="birthdate_ref" value="{$birthdate_ref}" />
     {else}
       {$birthdate_ref}
       <a href="javascript:delNationality('3');">{icon name=cross title="Supprimer cette nationalité"}</a>
     </td>
   </tr>
+  <tr>
+    <td><span class="titre">Civilité</span></td>
+    <td>
+      <select name="profile_title">
+        <option value="M" {if $profile_title eq "M"}selected="selected"{/if}>M</option>
+        <option value="MLLE" {if $profile_title eq "MLLE"}selected="selected"{/if}>MLLE</option>
+        <option value="MME" {if $profile_title eq "MME"}selected="selected"{/if}>MME</option>
+      </select>
+    </td>
+  </tr>
 </table>
 
 <table class="bicol" style="margin-bottom: 1em" summary="Profil&nbsp;: Formations à l'X">
   </tr>
   <tr class="{$class}">
     <td><span class="titre">Promotion&nbsp;:</span></td>
-    <td>{$main_edu.promo_year}</td>
+    <td>{if t($main_edu.promo_year)}{$main_edu.promo_year}{/if}</td>
   </tr>
   <tr class="{$class}">
     <td><span class="titre">Domaine de formation&nbsp;:</span></td>
       </div>
     </td>
   </tr>
+  <tr>
+    <td colspan="2">
+      <span class="titre">Sports, loisirs, hobbies&hellip;</span>
+    </td>
+  </tr>
+  {foreach from=$hobbies item=hobby key=id}
+    {include file="profile/general.hobby.tpl" hobby=$hobby i=$id}
+  {/foreach}
+  <tr id="hobby">
+    <td colspan="2">
+      <div id="hobby_add" class="center">
+        <a href="javascript:addHobby();">
+          {icon name=add title="Ajouter un hobby"} Ajouter un hobby
+        </a>
+      </div>
+    </td>
+  </tr>
   {if $viewPrivate || $isMe}
   <tr class="pair">
     <td>
index 68958f0..dde72e9 100644 (file)
@@ -73,7 +73,7 @@
         {/if}
         {else}
         {if t($job.tmp_name)}{$job.tmp_name} <small>(en cours de validation)</small>{else}
-        <input type="text" class="enterpriseName{if t($job.name_error)} error{/if}" size="35" maxlength="100"
+        <input type="text" class="enterprise_name{if t($job.name_error)} error{/if}" size="35" maxlength="100"
                name="{$jobpref}[name]" value="{$job.name}" />
         {/if}
         {/if}
           {foreach from=$job.terms item=term}
           addJobTerm("{$i}", "{$term.jtid}", "{$term.full_name|replace:'"':'\\"'}");
           {/foreach}
-          $('#jobs_{$i} .term_search').autocomplete($.plURL('profile/jobterms'),
+          $('#jobs_{$i} .term_search').autocomplete(
             {ldelim}
-              "formatItem" : displayJobTerm,
-              "extraParams" : {ldelim} "jobid" : "{$i}" {rdelim},
-              "width" : $('#jobs_{$i} .term_search').width()*2,
-              "onItemSelect" : selectJobTerm,
-              "matchSubset" : false
+              source: $.plURL('profile/jobterms'),
+              select: function(event, ui) {ldelim}
+                selectJobTerm(ui.item.id, ui.item.value, {$i});
+              {rdelim},
+              change: function(event, ui) {ldelim}
+                $(this).val('');
+              {rdelim}
             {rdelim});
         {rdelim});
         /* ]]> */
index 02ffefd..7430ddd 100644 (file)
   <li>ou bien, plus âgés, qui souhaitent réorienter leur carrière.</li>
 </ul>
 
+<table class="bicol" id="competences_table" style="margin-bottom: 1em">
+  <tr>
+    <th>
+      <div class="flags" style="float: left">
+        <input type="checkbox" name="accesX" checked="checked" disabled="disabled" />
+        {icon name="flag_red" title="privé"}
+      </div>
+      Compétences professionnelles
+    </th>
+  </tr>
+  <tr>
+    <td>
+      <span class="titre">Domaine&nbsp;:</span>
+      <select name="competences_sel" onchange="updateElement('competences')">
+        <option value="">&nbsp;</option>
+        {assign var=ingroup value=false}
+        {iterate from=$comp_list item=comp}
+        {if $comp.title}
+        {if $ingroup}</optgroup>{/if}
+        <optgroup label="{$comp.text_fr}">
+        {assign var=ingroup value=true}
+        {/if}
+        <option value="{$comp.id}">{$comp.text_fr}</option>
+        {/iterate}
+        {if $ingroup}</optgroup>{/if}
+      </select>
+      <span id="competences_add" style="display: none">
+        <a href="javascript:addSkill('competences')">{icon name=add title="Ajouter cette compétence"}</a>
+      </span>
+    </td>
+  </tr>
+  <tr class="pair">
+    <td id="competences">
+      {foreach from=$competences item=competence key=id}
+      {include file="profile/skill.skill.tpl" cat='competences' skill=$competence id=$id levels=$comp_level}
+      {/foreach}
+    </td>
+  </tr>
+</table>
+
+<table class="bicol" id="langues_table" style="margin-bottom: 1em">
+  <tr>
+    <th>
+      <div class="flags" style="float: left">
+        <input type="checkbox" name="accesX" checked="checked" disabled="disabled" />
+        {icon name="flag_red" title="privé"}
+      </div>
+      Compétences linguistiques
+    </th>
+  </tr>
+  <tr>
+    <td>
+      <span class="titre">Domaine&nbsp;:</span>
+      <select name="langues_sel" onchange="updateElement('langues')">
+        <option value="">&nbsp;</option>
+        {iterate from=$lang_list item=lang}
+        <option value="{$lang.iso_639_2b}">{$lang.language}</option>
+        {/iterate}
+      </select>
+      <span id="langues_add" style="display: none">
+        <a href="javascript:addSkill('langues')">{icon name=add title="Ajouter cette langue"}</a>
+      </span>
+    </td>
+  </tr>
+  <tr class="pair">
+    <td id="langues">
+      {foreach from=$langues item=langue key=id}
+      {include file="profile/skill.skill.tpl" cat='langues' skill=$langue id=$id levels=$lang_level}
+      {/foreach}
+    </td>
+  </tr>
+ </table>
+
 <table class="bicol" id="countries_table" style="margin-bottom: 1em" summary="Profil&nbsp;: Mentoring">
   <tr>
     <th>
         {foreach from=$terms item=term}
         addJobTerm(-1, "{$term.jtid}", "{$term.full_name|replace:'"':'\\"'}");
         {/foreach}
-        $('.term_search').autocomplete($.plURL('profile/jobterms'),
-          {ldelim}
-            "formatItem" : displayJobTerm,
-            "extraParams" : {ldelim} "jobid" : "-1" {rdelim},
-            "width" : $('.term_search').width()*2,
-            "onItemSelect" : selectJobTerm,
-            "matchSubset" : false
-          {rdelim});
+        $('.term_search').autocomplete({ldelim}
+            source: $.plURL('profile/jobterms'),
+            select: function(event, ui) {ldelim}
+              selectJobTerm(ui.item.id, ui.item.value, -1);
+            {rdelim},
+            change: function(event, ui) {ldelim}
+              $(this).val('');
+            {rdelim}
+        {rdelim});
       {rdelim});
       /* ]]> */
       </script>
index ea76a36..f005f45 100644 (file)
@@ -257,7 +257,7 @@ $($.closeOnEsc);
       <div class="medal_frame">
         <img src="profile/medal/thumb/{$m.mid}" height="50px" alt="{$m.text}" title="{$m.text}" style='float: left;' />
         <div class="medal_text">
-          {$m.text}<br />{$m.grade}
+          {$m.text}{if $m.level} ({$m.level}){/if}<br />{$m.grade}
         </div>
       </div>
       {/foreach}
diff --git a/templates/profile/skill.tpl b/templates/profile/skill.tpl
deleted file mode 100644 (file)
index 7b423a8..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-{**************************************************************************}
-{*                                                                        *}
-{*  Copyright (C) 2003-2011 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               *}
-{*                                                                        *}
-{**************************************************************************}
-
-<table class="bicol" id="competences_table" style="margin-bottom: 1em">
-  <tr>
-    <th>
-      <div class="flags" style="float: left">
-        <input type="checkbox" name="accesX" checked="checked" disabled="disabled" />
-        {icon name="flag_red" title="privé"}
-      </div>
-      Compétences professionnelles
-    </th>
-  </tr>
-  <tr>
-    <td>
-      <span class="titre">Domaine&nbsp;:</span>
-      <select name="competences_sel" onchange="updateElement('competences')">
-        <option value="">&nbsp;</option>
-        {assign var=ingroup value=false}
-        {iterate from=$comp_list item=comp}
-        {if $comp.title}
-        {if $ingroup}</optgroup>{/if}
-        <optgroup label="{$comp.text_fr}">
-        {assign var=ingroup value=true}
-        {/if}
-        <option value="{$comp.id}">{$comp.text_fr}</option>
-        {/iterate}
-        {if $ingroup}</optgroup>{/if}
-      </select>
-      <span id="competences_add" style="display: none">
-        <a href="javascript:addSkill('competences')">{icon name=add title="Ajouter cette compétence"}</a>
-      </span>
-    </td>
-  </tr>
-  <tr class="pair">
-    <td id="competences">
-      {foreach from=$competences item=competence key=id}
-      {include file="profile/skill.skill.tpl" cat='competences' skill=$competence id=$id levels=$comp_level}
-      {/foreach}
-    </td>
-  </tr>
-</table>
-
-<table class="bicol" id="langues_table">
-  <tr>
-    <th>
-      <div class="flags" style="float: left">
-        <input type="checkbox" name="accesX" checked="checked" disabled="disabled" />
-        {icon name="flag_red" title="privé"}
-      </div>
-      Compétences linguistiques
-    </th>
-  </tr>
-  <tr>
-    <td>
-      <span class="titre">Domaine&nbsp;:</span>
-      <select name="langues_sel" onchange="updateElement('langues')">
-        <option value="">&nbsp;</option>
-        {iterate from=$lang_list item=lang}
-        <option value="{$lang.iso_639_2b}">{$lang.language}</option>
-        {/iterate}
-      </select>
-      <span id="langues_add" style="display: none">
-        <a href="javascript:addSkill('langues')">{icon name=add title="Ajouter cette langue"}</a>
-      </span>
-    </td>
-  </tr>
-  <tr class="pair">
-    <td id="langues">
-      {foreach from=$langues item=langue key=id}
-      {include file="profile/skill.skill.tpl" cat='langues' skill=$langue id=$id levels=$lang_level}
-      {/foreach}
-    </td>
-  </tr>
- </table>
-
-{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 6f38815..0a425a1 100644 (file)
         </table>
       </td>
     </tr>
-        {if hasPerm('admin,edit_directory')}
+    {if hasPerm('admin,edit_directory')}
     <tr>
       <td>Matricule AX</td>
       <td>
         <br />
         <i>Entrer une liste de matricules AX (un par ligne)</i>
       </td>
-        {/if}
-        {if $smarty.session.auth ge AUTH_COOKIE}
     </tr>
+    {/if}
+    {if $smarty.session.auth ge AUTH_COOKIE}
     <tr>
       <td colspan="2">
           <input type='checkbox' name='order' value='date_mod' {if $smarty.request.order eq "date_mod"}checked='checked'{/if} id="order"/>
            <label for="exact">Faire une recherche exacte.</label>
       </td>
     </tr>
-        {/if}
+    {/if}
+    {if hasPerm('admin,edit_directory')}
+    <tr>
+      <td colspan="2">
+           <label><input type="checkbox" id="addresses_dump" onclick="addressesDump();" />Tableau des adresses postales.</label>
+      </td>
+    </tr>
+    {/if}
     <tr><td colspan="2"></td></tr>
     <tr>
       <td colspan="2" style="text-align: center">
index f11a265..0b1f12e 100644 (file)
@@ -48,12 +48,12 @@ function toggleJobTermsTree()
 }
 
 /** Function called by autocomplete when a term is selected */
-function selectJobTerm(li)
+function selectJobTerm(id, value)
 {
-    if (li.extra[1] < 0) {
+    if (value < 0) {
         return;
     }
-    chooseJobTermInTree(null,li.extra[1],li.selectValue);
+    chooseJobTermInTree(null, id, value);
 }
 
 /** Prepares display for a jobterm in select's dropdown
@@ -146,13 +146,16 @@ function validateSearchForm(f)
 {literal}
 $(function() {
   createJobTermsTree('#mentoring_terms', 'profile/ajax/tree/jobterms/mentors', 'mentor', 'chooseJobTermInTree');
-  $("#jobtermText").autocomplete(baseurl + "autocomplete",
-  {
-    "selectOnly":1,
-    "width":$("#jobtermText").width()*2,
-    "onItemSelect" : selectJobTerm,
-    "formatItem" : displayJobTerm,
-    "matchSubset" : false
+  $('#jobtermText').autocomplete({
+      source: $.plURL(baseurl + 'autocomplete'),
+      select: function(event, ui) {
+          selectJobTerm(ui.item.id, ui.item.value);
+      },
+      change: function(event, ui) {
+          if (ui.item != null && ui.item.field != null) {
+              $(this).val(ui.item.field);
+          }
+      }
   });
   $('#jobTermsTreeToggle').click(toggleJobTermsTree);
 {/literal}
index 8b7eeba..88d920b 100644 (file)
   <a href="Reference/Convention-AX">Lien avec l'AX</a>
   &nbsp;-&nbsp;
   <a href="Equipe/APropos">À propos de ce site et ses équipes</a>
+  {if hasPerm('payment')}
+  &nbsp;-&nbsp;
+  <a href="payment">Faire un don</a>
+  {/if}
 <br />
   <a href="Docs/Ethique">Services et éthique</a>
   | <a href="Reference/Charte">Charte</a>
index a07bb56..a50c9f4 100644 (file)
@@ -38,7 +38,7 @@
 
 {else}
 
-{if $smarty.session.auth == AUTH_MDP}
+{if $smarty.session.auth == AUTH_PASSWD}
 <div class="menu_item"><a href="exit">Déconnexion</a></div>
 {elseif $smarty.cookies.ORGaccess}
 <div class="menu_item"><a href="exit/forget">Déconnexion totale</a></div>
@@ -71,9 +71,6 @@
 {if hasPerm('user')}
 <div class="menu_item"><a href="lists">Listes de diffusion</a></div>
 {/if}
-{if hasPerm('payment')}
-<div class="menu_item"><a href="payment">Télépaiements</a></div>
-{/if}
 {if hasPerm('mail')}
 <div class="menu_item"><a href="emails/antispam/submit">Soumettre un spam</a></div>
 {/if}
index 6c57b33..d219f32 100644 (file)
@@ -28,7 +28,7 @@
 {elseif $mail_part eq 'text'}
 Bonjour,
 
-{$sender_name} nous a demandé de vous créer un compte pour que vous puissiez disposer pleinement de toutes les fonctionnalités liées au groupe {$group}.
+{$sender_name} nous a demandé de vous {if $again}relancer{else}créer un compte{/if} pour que vous puissiez disposer pleinement de toutes les fonctionnalités liées au groupe {$group}.
 
 Après activation, vos paramètres de connexion seront :
 
index c27462d..551fa14 100644 (file)
@@ -32,7 +32,7 @@
   qui aura lieu {$evt.date}.
 </p>
 
-{if $participants|@count && $is_admin}
+{if $evt.short_name && $participants|@count && $is_admin}
 <p class="center">
   [<a href="mailto:?bcc={$evt.short_name}-participants@{#globals.xnet.evts_domain#}">envoyer un email à ceux qui viennent</a>]
   <br />
index 09053af..132ffbe 100644 (file)
@@ -167,11 +167,12 @@ function deadlineChange(box)
           <option value='-2'>Paiement en attente de validation</option>
           {/if}
           <option value=''>Pas de paiement</option>
-          <option value='-1' {if $paiement_message}selected="selected"{/if}>- Nouveau paiement -</option>
+          <option value='-1' {if $error}selected="selected"{/if}>- Nouveau paiement -</option>
           {html_options options=$paiements selected=$evt.paiement_id}
         </select>
       </th>
     </tr>
+    {if $evt.paiement_id neq -2}
     <tr id="new_pay" style="display:none">
       <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;:
@@ -186,7 +187,7 @@ function deadlineChange(box)
           <div id="preview"></div>
           <hr />
         </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;,
+        <textarea name="confirmation" id="payment_text" rows="12" cols="65">{if $payment_message}{$payment_message}{else}&lt;salutation&gt; &lt;prenom&gt; &lt;nom&gt;,
 
 Ton inscription à [METS LE NOM DE L'ÉVÉNEMENT ICI] a bien été enregistrée et ton paiement de &lt;montant&gt; a bien
 été reçu avec le commentaire suivant&nbsp;:
@@ -200,8 +201,12 @@ Ton inscription à [METS LE NOM DE L'ÉVÉNEMENT ICI] a bien été enregistrée
 {assign var="profile" value=$smarty.session.user->profile()}
 {$profile->fullName("promo")}{/if}</textarea><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 />
-        <label><input type="checkbox" name="donation" {if t($donation)}check="checked"{/if} />Afficher la liste des payeurs ne s'y opposant pas sur {#globals.core.sitename#}</label><br />
+        Page internet de l'événement&nbsp;: <input size="40" name="site" value="{$payment_site|default:$asso->site|default:$asso_url}" /><br />
+        Rendre public le télépaiement&nbsp;:
+        <label><input type="radio" name="payment_public" value="no" {if !t($payment_public)}checked="checked"{/if} />Non</label>
+        &nbsp;-&nbsp;
+        <label>Oui<input type="radio" name="payment_public" value="yes" {if t($payment_public)}checked="checked"{/if} /></label><br />
+        Attention&nbsp;: cela aura pour effet de rendre accessible ce télépaiement à tout le monde, même aux personnes non connectées.<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[
@@ -211,6 +216,7 @@ Ton inscription à [METS LE NOM DE L'ÉVÉNEMENT ICI] a bien été enregistrée
         <input type="submit" name="preview" value="Aperçu" onclick="previewWiki('payment_text', 'preview', true, 'pay_preview'); return false;" />
       </td>
     </tr>
+    {/if}
   </table>
 
   <hr />
index a63a3c3..9c5c4fe 100644 (file)
@@ -23,7 +23,7 @@
 <h1>{$asso->nom}&nbsp;: Annuaire du groupe </h1>
 
 <p class="descr">
-Le groupe {$asso->nom} compte {$plset_count} membres&nbsp;:
+Le groupe {$asso->nom} compte {$plset_total_count} membres&nbsp;:
 </p>
 
 <ul class="descr">
index 5043faf..d6aea31 100644 (file)
@@ -203,4 +203,13 @@ interprétée comme polémique par un lecteur.
 </div>
 {/if}
 
+{if t($payments)}
+<p>Télépaiements publics pour le groupe {$asso->nom}&nbsp;:</p>
+<ul>
+{foreach from=$payments item=payment}
+<li><a href="{$platal->ns}payment/{$payment.id}">{icon name=money title="Télépaiement"}{$payment.text}</a></li>
+{/foreach}
+</ul>
+{/if}
+
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 5af8cda..b63c1bd 100644 (file)
@@ -31,7 +31,7 @@
         Nom&nbsp;:
       </td>
       <td>
-        <input type="text" size="40" value="{$asso->nom}" name="nom" />
+        <input type="text" size="40" value="{if $error}{$nom}{else}{$asso->nom}{/if}" name="nom" />
       </td>
     </tr>
     <tr>
@@ -39,7 +39,7 @@
         Diminutif&nbsp;:
       </td>
       <td>
-        <input type="text" size="40" value="{$asso->diminutif}" name="diminutif" />
+        <input type="text" size="40" value="{if $error}{$diminutif}{else}{$asso->diminutif}{/if}" name="diminutif" />
       </td>
     </tr>
     <tr>
@@ -47,7 +47,7 @@
         Domaine DNS&nbsp;:
       </td>
       <td>
-        <input type="text" size="40" value="{$asso->mail_domain}" name="mail_domain" />
+        <input type="text" size="40" value="{if $error}{$mail_domain}{else}{$asso->mail_domain}{/if}" name="mail_domain" />
       </td>
     </tr>
     <tr>
       </td>
       <td>
         <select name="cat">
-          <option value="groupesx" {if $asso->cat eq 'GroupesX'}selected="selected"{/if}>Groupes X</option>
-          <option value="binets" {if $asso->cat eq 'Binets'}selected="selected"{/if}>Binets</option>
-          <option value="promotions" {if $asso->cat eq 'Promotions'}selected="selected"{/if}>Promotions</option>
-          <option value="institutions" {if $asso->cat eq 'Institutions'}selected="selected"{/if}>Institutions</option>
+          <option value="groupesx" {if $cat eq 'GroupesX'}selected="selected"{/if}>Groupes X</option>
+          <option value="binets" {if $cat eq 'Binets'}selected="selected"{/if}>Binets</option>
+          <option value="promotions" {if $cat eq 'Promotions'}selected="selected"{/if}>Promotions</option>
+          <option value="institutions" {if $cat eq 'Institutions'}selected="selected"{/if}>Institutions</option>
         </select>
       </td>
     </tr>
       <td>
         <select name="dom">
           <option value="">&nbsp;</option>
-          {iterate from=$dom item=d}
-          <option value="{$d.id}" {if $d.id eq $asso->dom}selected="selected"{/if}>{$d.nom} [{$d.cat}]</option>
+          {iterate from=$domains item=d}
+          <option value="{$d.id}" {if $d.id eq $dom}selected="selected"{/if}>{$d.nom} [{$d.cat}]</option>
           {/iterate}
         </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> le <input type="text" size="10" maxlength="10" value="{$asso->axDate}" name="axDate" />
+        <label><input type="checkbox" value="1" name="ax" {if $ax}checked="checked"{/if} />
+        groupe agréé par l'AX</label> le <input type="text" size="10" maxlength="10" value="{if $error}{$axDate}{$asso->axDate}{/if}" name="axDate" />
         <small>(ex: 01/01/1970)</small>
       </td>
     </tr>
         Site web&nbsp;:
       </td>
       <td>
-        <input type="text" size="40" value="{$asso->site|default:"http://"}" name="site" />
+        <input type="text" size="40" value="{if $error}{$site}{else}{$asso->site|default:"http://"}{/if}" name="site" />
       </td>
     </tr>
 
         Contact&nbsp;:
       </td>
       <td>
-        <input type="text" size="40" name="resp" value="{$asso->resp}" />
+        <input type="text" size="40" name="resp" value="{if $error}{$resp}{else}{$asso->resp}{/if}" />
       </td>
     </tr>
 
         Adresse email&nbsp;:
       </td>
       <td>
-        <input type="text" size="40" name="mail" value="{$asso->mail}" />
+        <input type="text" size="40" name="mail" value="{if $error}{$mail}{else}{$asso->mail}{/if}" />
       </td>
     </tr>
 
     <tr>
       <td class="titre">Téléphone</td>
       <td>
-        <input type="text" maxlength="28" name="phone" value="{$asso->phone}" />
+        <input type="text" maxlength="28" name="phone" value="{if $error}{$phone}{else}{$asso->phone}{/if}" />
       </td>
     </tr>
     <tr>
       <td class="titre">Fax</td>
       <td>
-        <input type="text" maxlength="28" name="fax" value="{$asso->fax}" />
+        <input type="text" maxlength="28" name="fax" value="{if $error}{$fax}{else}{$asso->fax}{/if}" />
       </td>
     </tr>
     <tr>
       <td class="titre">Adresse</td>
       <td>
-        <textarea name="address" cols="30" rows="4">{$asso->address}</textarea>
+        <textarea name="address" cols="30" rows="4">{if $error}{$address}{else}{$asso->address}{/if}</textarea>
       </td>
     </tr>
 
         Forum&nbsp;:
       </td>
       <td>
-        <input type="text" size="40" name="forum" value="{$asso->forum}" />
+        <input type="text" size="40" name="forum" value="{if $error}{$forum}{else}{$asso->forum}{/if}" />
       </td>
     </tr>
 
         Inscription possible&nbsp;:
       </td>
       <td>
-        <input type="radio" value="1" id="inscr_yes"
-          {if $asso->inscriptible eq 1}checked="checked"{/if}
-          name="inscriptible" />
-        <label for="inscr_yes">oui</label>
-        <input type="radio" value="0" id="inscr_no"
-          {if $asso->inscriptible neq 1}checked="checked"{/if}
-          name="inscriptible" />
-        <label for="inscr_no">non</label>
+        <label><input type="radio" value="1" {if $inscriptible eq 1}checked="checked"{/if} name="inscriptible" />oui</label>
+        <label><input type="radio" value="0" {if $inscriptible neq 1}checked="checked"{/if} name="inscriptible" />non</label>
       </td>
     </tr>
 
         <em>laisser vide par défaut</em>
       </td>
       <td>
-        <input type="text" size="40" name="sub_url" value="{$asso->sub_url}" />
+        <input type="text" size="40" name="sub_url" value="{if $error}{$sub_url}{else}{$asso->sub_url}{/if}" />
       </td>
     </tr>
 
         <em>laisser vide par défaut</em>
       </td>
       <td>
-        <input type="text" size="40" name="unsub_url" value="{$asso->unsub_url}" />
+        <input type="text" size="40" name="unsub_url" value="{if $error}{$unsub_url}{else}{$asso->unsub_url}{/if}" />
       </td>
     </tr>
 
         <em>envoyé à l'inscription</em>
       </td>
       <td>
-        <textarea cols='40' rows='8' name='welcome_msg'>{$asso->welcome_msg}</textarea>
+        <textarea cols='40' rows='8' name='welcome_msg'>{if $error}{$welcome_msg}{else}{$asso->welcome_msg}{/if}</textarea>
       </td>
     </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>
-          <option value="membre" {if $asso->pub eq 'membre'}selected="selected"{/if}>Aux membres du groupe</option>
-          <option value="private" {if $asso->pub eq 'private'}selected="selected"{/if}>Aux animateurs du groupe</option>
+          <option value="public" {if $pub eq 'public'}selected="selected"{/if}>Publique</option>
+          <option value="membre" {if $pub eq 'membre'}selected="selected"{/if}>Aux membres du groupe</option>
+          <option value="private" {if $pub eq 'private'}selected="selected"{/if}>Aux animateurs du groupe</option>
         </select>
       </td>
     </tr>
     <tr>
       <td class="titre center" colspan="2">
-        <label><input type="checkbox" value="1" name="notif_unsub" {if $asso->notif_unsub}checked="checked"{/if} />
+        <label><input type="checkbox" value="1" name="notif_unsub" {if $notif_unsub}checked="checked"{/if} />
         prévenir les animateurs lors de la désinscription d'un membre</label>
       </td>
     </tr>
     <a href="wiki_help" class="popup3">
       {icon name=information title="Syntaxe wiki"} Voir la syntaxe wiki autorisée pour la description.
     </a>
-    <textarea name="descr" cols="70" rows="15" id="descr">{$asso->descr}</textarea>
+    <textarea name="descr" cols="70" rows="15" id="descr">{if $error}{$descr}{else}{$asso->descr}{/if}</textarea>
     <input type="submit" name="preview" value="Aperçu de la description"
            onclick="previewWiki('descr', 'preview_descr', true, 'preview_descr'); return false;" /><br />
     <input type="submit" name="submit" value="Enregistrer" />
index 24edb37..acad698 100644 (file)
       <td colspan="2">
         <label>
           <input type="checkbox" name="suggest" />
-          coche cette case si tu souhaites qu'un compte « Extérieur » soit créé
+          coche cette case si tu souhaites qu'un compte «&nbsp;Extérieur&nbsp;» soit créé
           pour cette personne et que nous lui envoyions un email afin qu'il ait
           accès aux nombreuses fonctionnalités de Polytechnique.net (inscription
           aux évènements, télépaiement, modération des listes de diffusion&hellip;)
       </td>
     </tr>
     {/if}
+    {if $user->type eq 'xnet' && $pending_xnet_account}
+    <tr>
+      <td colspan="2">
+        <label>
+          <input type="checkbox" name="again" />
+          Cette personne a un compte «&nbsp;Extérieur&nbsp;» en attente d'activation de sa part. Pour la relancer, il suffit
+          de cocher la case ci-contre.
+        </label>
+      </td>
+    </tr>
+    {/if}
   </table>
 
   <h2>Abonnement aux listes</h2>
index 19f82a7..e41905f 100755 (executable)
@@ -184,6 +184,11 @@ XDB::rawExecute("UPDATE  profile_corps           AS c
 XDB::rawExecute("DELETE FROM  profile_corps_rank_enum
                        WHERE  name LIKE 'DEL%'");
 
+// Updates title.
+XDB::rawExecute("UPDATE  profiles         AS p
+             INNER JOIN  fusionax_anciens AS f ON (p.pid = f.pid)
+                    SET  p.title = f.Civilite");
+
 // Updates email_directory.
 XDB::rawExecute("UPDATE  profiles         AS p
              INNER JOIN  fusionax_anciens AS f ON (p.pid = f.pid)
diff --git a/upgrade/1.1.4/01_payments.sql b/upgrade/1.1.4/01_payments.sql
new file mode 100644 (file)
index 0000000..49e0c91
--- /dev/null
@@ -0,0 +1,4 @@
+ALTER TABLE payments MODIFY COLUMN flags SET('unique', 'old') NOT NULL DEFAULT '';
+ALTER TABLE payments MODIFY COLUMN flags SET('unique', 'old', 'public') NOT NULL DEFAULT '';
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/02_newsletter_issues.sql b/upgrade/1.1.4/02_newsletter_issues.sql
new file mode 100644 (file)
index 0000000..a12b70a
--- /dev/null
@@ -0,0 +1,3 @@
+ALTER TABLE newsletter_issues ADD COLUMN reply_to varchar(255) NOT NULL DEFAULT '';
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/03_watch_group.sql b/upgrade/1.1.4/03_watch_group.sql
new file mode 100644 (file)
index 0000000..a873863
--- /dev/null
@@ -0,0 +1,9 @@
+CREATE TABLE watch_group (
+  uid int(11) unsigned NOT NULL DEFAULT '0',
+  groupid smallint(5) unsigned NOT NULL DEFAULT '0',
+  PRIMARY KEY (uid, groupid),
+  CONSTRAINT FOREIGN KEY (uid) REFERENCES accounts (uid) ON DELETE CASCADE ON UPDATE CASCADE,
+  CONSTRAINT FOREIGN KEY (groupid) REFERENCES groups (id) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/04_accounts.sql b/upgrade/1.1.4/04_accounts.sql
new file mode 100644 (file)
index 0000000..bda29e8
--- /dev/null
@@ -0,0 +1,4 @@
+ALTER TABLE accounts ADD COLUMN from_email VARCHAR(255) NOT NULL DEFAULT '';
+ALTER TABLE accounts ADD COLUMN from_format ENUM('text','html') NOT NULL DEFAULT 'html';
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/05_medals.sql b/upgrade/1.1.4/05_medals.sql
new file mode 100644 (file)
index 0000000..00d7298
--- /dev/null
@@ -0,0 +1,7 @@
+ALTER TABLE profile_medals ADD COLUMN level ENUM('', 'Or', 'Argent', 'Bronze') NOT NULL DEFAULT '';
+ALTER TABLE profile_medal_enum MODIFY COLUMN flags SET('validation', 'has_levels') NOT NULL DEFAULT '';
+UPDATE profile_medal_enum SET flags = 'has_levels' WHERE id = 20; -- Médaille de la Défense Nationale
+UPDATE profile_medal_enum SET flags = 'validation,has_levels' WHERE id IN (61, 62, 63); -- sports
+DELETE FROM profile_medal_grade_enum WHERE mid IN (61, 62, 63); -- Not used in prod yet, thus no need to update.
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/06_hobby.sql b/upgrade/1.1.4/06_hobby.sql
new file mode 100644 (file)
index 0000000..0370f7b
--- /dev/null
@@ -0,0 +1,12 @@
+CREATE TABLE profile_hobby (
+  pid INT(11) UNSIGNED NOT NULL DEFAULT 0,
+  id TINYINT(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'number of the hobby for the user',
+  type ENUM('Sport', 'Loisir', 'Hobby') NOT NULL DEFAULT 'Hobby',
+  text VARCHAR(255) NOT NULL DEFAULT '',
+  pub ENUM('hidden','private','ax','public') NOT NULL DEFAULT 'private',
+  PRIMARY KEY (pid, id),
+  KEY pid (pid),
+  CONSTRAINT FOREIGN KEY (pid) REFERENCES profiles (pid) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/07_autocomplete.sql b/upgrade/1.1.4/07_autocomplete.sql
new file mode 100644 (file)
index 0000000..f760b19
--- /dev/null
@@ -0,0 +1,3 @@
+DELETE FROM search_autocomplete;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/08_ax_id.sql b/upgrade/1.1.4/08_ax_id.sql
new file mode 100644 (file)
index 0000000..457cb77
--- /dev/null
@@ -0,0 +1,6 @@
+UPDATE profiles SET ax_id = '2008D046' WHERE pid = 45818;
+UPDATE profiles SET ax_id = '2009D059' WHERE pid = 45855;
+UPDATE profiles SET ax_id = '2009D369' WHERE pid = 46232;
+UPDATE profiles SET ax_id = '2009D221' WHERE pid = 46016;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/09_title.sql b/upgrade/1.1.4/09_title.sql
new file mode 100644 (file)
index 0000000..699b422
--- /dev/null
@@ -0,0 +1,3 @@
+ALTER TABLE profiles ADD COLUMN title ENUM('M', 'MLLE', 'MME') NOT NULL DEFAULT 'M';
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/10_virtual_alias_pub.sql b/upgrade/1.1.4/10_virtual_alias_pub.sql
new file mode 100644 (file)
index 0000000..4151e8a
--- /dev/null
@@ -0,0 +1,4 @@
+UPDATE profiles SET alias_pub = 'hidden' WHERE alias_pub = 'private';
+UPDATE profiles SET alias_pub = 'private' WHERE alias_pub = 'public';
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.4/README b/upgrade/1.1.4/README
new file mode 100644 (file)
index 0000000..ecbf37f
--- /dev/null
@@ -0,0 +1,5 @@
+platal.conf:
+[Money]
+mpay_def_id = 386 # donation id
+
+https://www.polytechnique.org/Docs/Dons must be adapted after the release (cf https://dev.m4x.org/~x2004jacob/Docs/Dons).