Merge remote branch 'origin/xorg/f/geocoding' into xorg/master
authorStéphane Jacob <sj@m4x.org>
Wed, 1 Jun 2011 16:12:40 +0000 (18:12 +0200)
committerStéphane Jacob <sj@m4x.org>
Wed, 1 Jun 2011 16:12:40 +0000 (18:12 +0200)
38 files changed:
ChangeLog
bin/cron/registrations.php
bin/export_sql.bash
classes/direnum.php
classes/profile.php
classes/userfilter.php
classes/userfilter/conditions.inc.php
classes/userfilter/orders.inc.php
htdocs/javascript/profile.js
include/education.func.inc.php
include/name.func.inc.php
include/userset.inc.php
include/validations/names.inc.php
include/webservices/manageurs.server.inc.php
modules/admin.php
modules/payment.php
modules/profile.php
modules/profile/general.inc.php
modules/register.php
modules/xnetevents.php
modules/xnetevents/xnetevents.inc.php
modules/xnetgrp.php
templates/admin/add_secondary_edu.tpl [new file with mode: 0644]
templates/admin/index.tpl
templates/include/form.valid.names.tpl
templates/payment/index.tpl
templates/payment/xnet.tpl
templates/profile/general.private_name.tpl [new file with mode: 0644]
templates/profile/general.public_names.tpl [new file with mode: 0644]
templates/profile/general.searchname.tpl [deleted file]
templates/profile/general.tpl
templates/xnetevents/admin.tpl
upgrade/1.0.1/13_payments.sql
upgrade/1.1.2/02_payments.sql
upgrade/1.1.2/03_names.sql [new file with mode: 0644]
upgrade/1.1.2/04_education.sql [new file with mode: 0644]
upgrade/1.1.2/README
upgrade/1.1.2/names.php [new file with mode: 0755]

index fb1a927..cbc48a9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,14 @@ Bug/Wish:
 
     * Paiement:
         - #192: Displays users donations                                   -JAC
+        - #1499: Fixes session user's payment display in xnet admin page   -JAC
+
+    * Profile:
+        - #1489: Enables automatic procecessing for secondary education    -JAC
+        - #1497: Fixes issues with ordinary names                          -JAC
+
+    * Register:
+        - #1501: Displays redirections in succesful registration summary   -JAC
 
     * Search:
         - #1285: Autocompletes on internal words in university search      -JAC
@@ -15,6 +23,7 @@ Bug/Wish:
 
     * XnetEvent:
         - #1487: Removes link to event attending users to group outsiders  -JAC
+        - #1491: Fixes participants multi-page display                     -JAC
 
 ================================================================================
 VERSION 1.1.1                                                         09 05 2011
index 91cb1ac..a2c22dc 100755 (executable)
@@ -5,19 +5,20 @@ require 'connect.db.inc.php';
 
 $message = '';
 
-$res = XDB::iterRow("SELECT  a.registration_date, a.hruid, s.email
-                       FROM  accounts             AS a
-                 INNER JOIN  account_profiles     AS ap ON (ap.uid = a.uid AND FIND_IN_SET('owner', ap.perms))
-                 INNER JOIN  profile_display      AS pd ON (ap.pid = pd.pid)
-                  LEFT JOIN  email_source_account AS s  ON (a.uid = s.uid)
+$res = XDB::iterRow("SELECT  a.registration_date, a.hruid, s.email, GROUP_CONCAT(r.redirect SEPARATOR ', ')
+                       FROM  accounts               AS a
+                 INNER JOIN  account_profiles       AS ap ON (ap.uid = a.uid AND FIND_IN_SET('owner', ap.perms))
+                 INNER JOIN  profile_display        AS pd ON (ap.pid = pd.pid)
+                  LEFT JOIN  email_source_account   AS s  ON (a.uid = s.uid)
+                  LEFT JOIN  email_redirect_account AS r  ON (a.uid = r.uid)
                       WHERE  a.registration_date > {?}
                    GROUP BY  a.hruid
                    ORDER BY  pd.promo",
        date("Ymd000000", strtotime('last Monday')));
 if ($count = $res->total()) {
     $message .= "$count INSCRIPTIONS CONFIRMÉES CETTE SEMAINE :\n";
-    while (list($date, $hruid, $email) = $res->next()) {
-             $message .= "$date, $hruid, $email\n";
+    while (list($date, $hruid, $email, $redirect) = $res->next()) {
+             $message .= "$date, $hruid, $email, $redirect\n";
     }
 }
 
index 9b85b2a..51417c8 100755 (executable)
@@ -25,7 +25,6 @@ profile_job_term_relation \
 profile_langskill_enum \
 profile_medal_enum \
 profile_medal_grade_enum \
-profile_name_enum \
 profile_networking_enum \
 profile_section_enum \
 profile_skill_enum \
index 0b51cb6..a94c69b 100644 (file)
@@ -29,9 +29,6 @@ class DirEnum
      * Each of these consts contains the basename of the class (its full name
      * being DE_$basename).
      */
-    const NAMETYPES      = 'nametypes';
-    const NAMES          = 'names';
-
     const BINETS         = 'binets';
     const GROUPESX       = 'groupesx';
     const SECTIONS       = 'sections';
@@ -435,29 +432,6 @@ abstract class DE_WithSuboption extends DirEnumeration
 }
 // }}}
 
-// {{{ class DE_NameTypes
-// returns 'system' names ('lastname', 'lastname_marital', ...)
-class DE_NameTypes extends DirEnumeration
-{
-    public $capabilities = 0x005; // self::HAS_OPTIONS | self::SAVE_IN_SESSION;
-
-    protected $from     = 'profile_name_enum';
-    protected $valfield = 'type';
-}
-// }}}
-
-// {{{ class DE_Names
-// returns 'system' names ('lastname', 'lastname_marital', ...)
-class DE_Names extends DirEnumeration
-{
-    public $capabilities = 0x005; // self::HAS_OPTIONS | self::SAVE_IN_SESSION;
-
-    protected $from     = 'profile_name_enum';
-    protected $idfield  = 'type';
-    protected $valfield = 'name';
-}
-// }}}
-
 /** GROUPS
  */
 // {{{ class DE_Binets
index 9c7cc3e..b7a190c 100644 (file)
@@ -273,6 +273,20 @@ class Profile implements PlExportable
         }
     }
 
+    public static function educationDuration($education)
+    {
+        switch ($education) {
+          case self::DEGREE_X:
+            return 3;
+          case self::DEGREE_M:
+            return 2;
+          case self::DEGREE_D:
+            return 3;
+          default:
+            return 0;
+        }
+    }
+
     /** Number of years between the promotion year until the
      * graduation year. In standard schools it's 0, but for
      * Polytechnique the promo year is the entry year.
@@ -446,7 +460,7 @@ class Profile implements PlExportable
      *      profile_job, profile_langskills, profile_mentor, profile_networking,
      *      profile_phones, profile_skills, watch_profile
      *  *always keeps in: profile_corps, profile_display, profile_education,
-     *      profile_medals, profile_name, profile_photos, search_name
+     *      profile_medals, profile_*_names, profile_photos, search_name
      *  *modifies: profiles
      */
     public function clear()
@@ -966,10 +980,9 @@ class Profile implements PlExportable
                                      IF (p.freetext_pub IN {?}, p.freetext, NULL) AS freetext,
                                      pe.entry_year, pe.grad_year, pe.promo_year, pe.program, pe.fieldid,
                                      IF ({?}, pse.text, NULL) AS section,
-                                     pn_f.name AS firstname, pn_l.name AS lastname,
-                                     IF ({?}, pn_n.name, NULL) AS nickname,
-                                     IF (pn_uf.name IS NULL, pn_f.name, pn_uf.name) AS firstname_ordinary,
-                                     IF (pn_ul.name IS NULL, pn_l.name, pn_ul.name) AS lastname_ordinary,
+                                     ppn.firstname_main AS firstname, ppn.lastname_main AS lastname, IF ({?}, pn.name, NULL) AS nickname,
+                                     IF (ppn.firstname_ordinary = \'\', ppn.firstname_main, ppn.firstname_ordinary) AS firstname_ordinary,
+                                     IF (ppn.lastname_ordinary = \'\', ppn.firstname_main, ppn.lastname_ordinary) AS lastname_ordinary,
                                      pd.yourself, pd.promo, pd.short_name, pd.public_name AS full_name,
                                      pd.directory_name, pd.public_name, pd.private_name,
                                      IF (pp.pub IN {?}, pp.display_tel, NULL) AS mobile,
@@ -983,16 +996,8 @@ class Profile implements PlExportable
                          INNER JOIN  profile_display AS pd ON (pd.pid = p.pid)
                          INNER JOIN  profile_education AS pe ON (pe.pid = p.pid AND FIND_IN_SET(\'primary\', pe.flags))
                           LEFT JOIN  profile_section_enum AS pse ON (pse.id = p.section)
-                         INNER JOIN  profile_name AS pn_f ON (pn_f.pid = p.pid
-                                                              AND pn_f.typeid = ' . self::getNameTypeId('firstname', true) . ')
-                         INNER JOIN  profile_name AS pn_l ON (pn_l.pid = p.pid
-                                                              AND pn_l.typeid = ' . self::getNameTypeId('lastname', true) . ')
-                          LEFT JOIN  profile_name AS pn_uf ON (pn_uf.pid = p.pid
-                                                               AND pn_uf.typeid = ' . self::getNameTypeId('firstname_ordinary', true) . ')
-                          LEFT JOIN  profile_name AS pn_ul ON (pn_ul.pid = p.pid
-                                                               AND pn_ul.typeid = ' . self::getNameTypeId('lastname_ordinary', true) . ')
-                          LEFT JOIN  profile_name AS pn_n ON (pn_n.pid = p.pid
-                                                              AND pn_n.typeid = ' . self::getNameTypeId('nickname', true) . ')
+                         INNER JOIN  profile_public_names AS ppn ON (ppn.pid = p.pid)
+                          LEFT JOIN  profile_private_names AS pn ON (pn.pid = p.pid AND type = \'nickname\')
                           LEFT JOIN  profile_phones AS pp ON (pp.pid = p.pid AND pp.link_type = \'user\' AND tel_type = \'mobile\')
                           LEFT JOIN  profile_photos AS ph ON (ph.pid = p.pid)
                           LEFT JOIN  profile_mentor AS pm ON (pm.pid = p.pid)
@@ -1134,47 +1139,46 @@ class Profile implements PlExportable
         }
     }
 
-    public static function getNameTypeId($type, $for_sql = false)
-    {
-        if (!S::has('name_types')) {
-            $table = XDB::fetchAllAssoc('type', 'SELECT  id, type
-                                                   FROM  profile_name_enum');
-            S::set('name_types', $table);
-        } else {
-            $table = S::v('name_types');
-        }
-        if ($for_sql) {
-            return XDB::escape($table[$type]);
-        } else {
-            return $table[$type];
-        }
-    }
-
     public static function rebuildSearchTokens($pids, $transaction = true)
     {
+        require_once 'name.func.inc.php';
         if (!is_array($pids)) {
             $pids = array($pids);
         }
-        $keys = XDB::iterator("(SELECT  n.pid AS pid, n.name AS name, e.score AS score, e.general_type,
-                                        IF(FIND_IN_SET('public', e.flags), 'public', '') AS public
-                                  FROM  profile_name      AS n
-                            INNER JOIN  profile_name_enum AS e ON (n.typeid = e.id)
-                                 WHERE  n.pid IN {?} AND NOT FIND_IN_SET('not_displayed', e.flags))
-                                 UNION
-                                (SELECT  n.pid AS pid, n.particle AS name, 0 AS score, e.general_type,
-                                         IF(FIND_IN_SET('public', e.flags), 'public', '') AS public
-                                   FROM  profile_name      AS n
-                             INNER JOIN  profile_name_enum AS e ON (n.typeid = e.id)
-                                  WHERE  n.pid IN {?} AND NOT FIND_IN_SET('not_displayed', e.flags))
-                               ",
-                              $pids, $pids);
+        $keys = XDB::iterator("(SELECT  pid, name, type, IF(type = 'nickname', 2, 1) AS score, '' AS public
+                                  FROM  profile_private_names
+                                 WHERE  pid IN {?})
+                                UNION
+                               (SELECT  pid, lastname_main, 'lastname' AS type, 10 AS score, 'public' AS public
+                                  FROM  profile_public_names
+                                 WHERE  lastname_main != '' AND pid IN {?})
+                                UNION
+                               (SELECT  pid, lastname_marital, 'lastname' AS type, 10 AS score, 'public' AS public
+                                  FROM  profile_public_names
+                                 WHERE  lastname_marital != '' AND pid IN {?})
+                                UNION
+                               (SELECT  pid, lastname_ordinary, 'lastname' AS type, 10 AS score, 'public' AS public
+                                  FROM  profile_public_names
+                                 WHERE  lastname_ordinary != '' AND pid IN {?})
+                                UNION
+                               (SELECT  pid, firstname_main, 'firstname' AS type, 10 AS score, 'public' AS public
+                                  FROM  profile_public_names
+                                 WHERE  firstname_main != '' AND pid IN {?})
+                                UNION
+                               (SELECT  pid, firstname_ordinary, 'firstname' AS type, 10 AS score, 'public' AS public
+                                  FROM  profile_public_names
+                                 WHERE  firstname_ordinary != '' AND pid IN {?})
+                                UNION
+                               (SELECT  pid, pseudonym, 'nickname' AS type, 10 AS score, 'public' AS public
+                                  FROM  profile_public_names
+                                 WHERE  pseudonym != '' AND pid IN {?})",
+                              $pids, $pids, $pids, $pids, $pids, $pids, $pids);
         $names = array();
         while ($key = $keys->next()) {
             if ($key['name'] == '') {
                 continue;
             }
-            $pid   = $key['pid'];
-            require_once 'name.func.inc.php';
+            $pid  = $key['pid'];
             $toks = split_name_for_search($key['name']);
             $toks = array_reverse($toks);
 
@@ -1189,7 +1193,7 @@ class Profile implements PlExportable
                 $token = $tok . $token;
                 $names["$pid-$token"] = XDB::format('({?}, {?}, {?}, {?}, {?}, {?})',
                                                     $token, $pid, soundex_fr($token),
-                                                    $eltScore, $key['public'], $key['general_type']);
+                                                    $eltScore, $key['public'], $key['type']);
             }
         }
         if ($transaction) {
index be9e13b..21fc1bf 100644 (file)
@@ -543,12 +543,12 @@ class UserFilter extends PlFilter
 
     static public function sortByName()
     {
-        return array(new UFO_Name(Profile::LASTNAME), new UFO_Name(Profile::FIRSTNAME));
+        return array(new UFO_Name());
     }
 
     static public function sortByPromo()
     {
-        return array(new UFO_Promo(), new UFO_Name(Profile::LASTNAME), new UFO_Name(Profile::FIRSTNAME));
+        return array(new UFO_Promo(), new UFO_Name());
     }
 
     static private function getDBSuffix($string)
@@ -676,44 +676,6 @@ class UserFilter extends PlFilter
         return $joins;
     }
 
-    /** NAMES
-     */
-
-    static public function assertName($name)
-    {
-        if (!DirEnum::getID(DirEnum::NAMETYPES, $name)) {
-            Platal::page()->kill('Invalid name type: ' . $name);
-        }
-    }
-
-    private $pn  = array();
-    public function addNameFilter($type, $variant = null)
-    {
-        $this->requireProfiles();
-        if (!is_null($variant)) {
-            $ft  = $type . '_' . $variant;
-        } else {
-            $ft = $type;
-        }
-        $sub = '_' . $ft;
-        self::assertName($ft);
-
-        if (!is_null($variant) && $variant == 'other') {
-            $sub .= $this->option++;
-        }
-        $this->pn[$sub] = DirEnum::getID(DirEnum::NAMETYPES, $ft);
-        return $sub;
-    }
-
-    protected function nameJoins()
-    {
-        $joins = array();
-        foreach ($this->pn as $sub => $type) {
-            $joins['pn' . $sub] = PlSqlJoin::left('profile_name', '$ME.pid = $PID AND $ME.typeid = {?}', $type);
-        }
-        return $joins;
-    }
-
     /** NAMETOKENS
      */
     private $name_tokens = array();
index 61bfb09..e931395 100644 (file)
@@ -583,67 +583,28 @@ class UFC_EducationField extends UserFilterCondition
     }
 }
 // }}}
-// {{{ class UFC_Name
-/** Filters users based on name
- * @param $type Type of name field on which filtering is done (firstname, lastname...)
- * @param $text Text on which to filter
- * @param $mode Flag indicating search type (prefix, suffix, with particule...)
+// {{{ class UFC_NameInitial
+/** Filters users based on sort_name
+ * @param $initial Initial on which to filter
  */
-class UFC_Name extends UserFilterCondition
+class UFC_NameInitial extends UserFilterCondition
 {
-    const EXACT    = XDB::WILDCARD_EXACT;    // 0x000
-    const PREFIX   = XDB::WILDCARD_PREFIX;   // 0x001
-    const SUFFIX   = XDB::WILDCARD_SUFFIX;   // 0x002
-    const CONTAINS = XDB::WILDCARD_CONTAINS; // 0x003
-    const PARTICLE = 0x004;
-    const VARIANTS = 0x008;
+    private $initial;
 
-    private $type;
-    private $text;
-    private $mode;
-
-    public function __construct($type, $text, $mode)
-    {
-        $this->type = $type;
-        $this->text = $text;
-        $this->mode = $mode;
-    }
-
-    private function buildNameQuery($type, $variant, $where, UserFilter $uf)
+    public function __construct($initial)
     {
-        $sub = $uf->addNameFilter($type, $variant);
-        return str_replace('$ME', 'pn' . $sub, $where);
+        $this->initial = $initial;
     }
 
     public function buildCondition(PlFilter $uf)
     {
-        $left = '$ME.name';
-        if (($this->mode & self::PARTICLE) == self::PARTICLE) {
-            $left = 'CONCAT($ME.particle, \' \', $ME.name)';
-        }
-        $right = XDB::formatWildcards($this->mode & self::CONTAINS, $this->text);
-
-        $cond = $left . $right;
-        $conds = array($this->buildNameQuery($this->type, null, $cond, $uf));
-        if (($this->mode & self::VARIANTS) != 0 && isset(Profile::$name_variants[$this->type])) {
-            foreach (Profile::$name_variants[$this->type] as $var) {
-                $conds[] = $this->buildNameQuery($this->type, $var, $cond, $uf);
-            }
-        }
-        return implode(' OR ', $conds);
+        $sub = $uf->addDisplayFilter();
+        return 'SUBSTRING(pd.sort_name, 1, 1) ' . XDB::formatWildcards(XDB::WILDCARD_PREFIX, $this->initial);
     }
 
     public function export()
     {
-        $export = $this->buildExport($this->type);
-        if ($this->mode & self::VARIANTS) {
-            $export['search_in_variants'] = true;
-        }
-        if ($this->mode & self::PARTICLE) {
-            $export['search_in_particle'] = true;
-        }
-        $export['comparison'] = self::comparisonFromXDBWildcard($this->mode & 0x3);
-        $export['text'] = $this->text;
+        $export = $this->buildExport($this->initial);
         return $export;
     }
 }
index ad41bb3..b64a8e8 100644 (file)
@@ -36,13 +36,8 @@ abstract class UserFilterOrders
           case 'promo':
             return new UFO_Promo($export->v('grade'), $desc);
 
-          case 'lastname':
           case 'name':
-          case 'firstname':
-          case 'nickname':
-          case 'pseudonym':
-            return new UFO_Name($type, $export->v('variant'),
-                                $export->b('particle'), $desc);
+            return new UFO_Name($desc);
 
           case 'score':
           case 'registration':
@@ -106,43 +101,19 @@ class UFO_Promo extends PlFilterGroupableOrder
 // }}}
 // {{{ class UFO_Name
 /** Sorts users by name
- * @param $type Type of name on which to sort (firstname...)
- * @param $variant Variant of that name to use (marital, ordinary...)
- * @param $particle Set to true if particles should be included in the sorting order
  * @param $desc If sort order should be descending
  */
 class UFO_Name extends PlFilterGroupableOrder
 {
-    private $type;
-    private $variant;
-    private $particle;
-
-    public function __construct($type, $variant = null, $particle = false, $desc = false)
-    {
-        parent::__construct($desc);
-        $this->type = $type;
-        $this->variant = $variant;
-        $this->particle = $particle;
-    }
-
     protected function getSortTokens(PlFilter $uf)
     {
-        if (Profile::isDisplayName($this->type)) {
-            $sub = $uf->addDisplayFilter();
-            $token = 'pd' . $sub . '.' . $this->type;
-            if ($uf->accountsRequired()) {
-                $account_token = Profile::getAccountEquivalentName($this->type);
-                return 'IFNULL(' . $token . ', a.' . $account_token . ')';
-            } else {
-                return $token;
-            }
+        $sub = $uf->addDisplayFilter();
+        $token = 'pd.sort_name';
+        if ($uf->accountsRequired()) {
+            $account_token = Profile::getAccountEquivalentName('sort_name');
+            return 'IFNULL(' . $token . ', a.' . $account_token . ')';
         } else {
-            $sub = $uf->addNameFilter($this->type, $this->variant);
-            if ($this->particle) {
-                return 'CONCAT(pn' . $sub . '.particle, \' \', pn' . $sub . '.name)';
-            } else {
-                return 'pn' . $sub . '.name';
-            }
+            return $token;
         }
     }
 
@@ -153,30 +124,12 @@ class UFO_Name extends PlFilterGroupableOrder
 
     public function getCondition($initial)
     {
-        if (Profile::isDisplayName($this->type)) {
-            switch ($this->type) {
-            case Profile::DN_PRIVATE:
-            case Profile::DN_SHORT:
-            case Profile::DN_YOURSELF:
-                $type = Profile::FIRSTNAME;
-            default:
-                $type = Profile::LASTNAME;
-            }
-        } else {
-            $type = $this->type;
-        }
-        return new UFC_Name($type, $initial, UFC_Name::PREFIX);
+        return new UFC_NameInitial($initial);
     }
 
     public function export()
     {
-        $export = $this->buildExport($this->type);
-        if (!is_null($this->variant)) {
-            $export['variant'] = $this->variant;
-        }
-        if ($this->particle) {
-            $export['particle'] = true;
-        }
+        $export = $this->buildExport();
         return $export;
     }
 }
index f117885..765c43d 100644 (file)
@@ -77,12 +77,10 @@ function addSearchName(isFemale)
     while ($('#search_name_' + i).length != 0) {
         i++;
     }
-    $('#search_name_' + i)
-        .updateHtml('profile/ajax/searchname/' + i + '/' + isFemale,
-                    function(data) {
-                        $('#searchname').before(data);
-                        changeNameFlag(i);
-                    });
+    $('#search_name_' + i).updateHtml('profile/ajax/searchname/' + i + '/' + isFemale,
+        function(data) {
+            $('#searchname').before(data);
+    });
 }
 
 function removeSearchName(i, isFemale)
@@ -91,34 +89,29 @@ function removeSearchName(i, isFemale)
     updateNameDisplay(isFemale);
 }
 
-function changeNameFlag(i)
-{
-    $('#flag_' + i).remove();
-    var typeid = $('#search_name_' + i).find('select').val();
-    var type   = $('#search_name_' + i).find('select :selected').text();
-    if ($('[name=sn_type_' + typeid + '_' + i + ']').val() > 0) {
-        $('#flag_cb_' + i).after('<span id="flag_' + i + '">&nbsp;' +
-            '<img src="images/icons/flag_green.gif" alt="site public" title="site public" />' +
-            '<input type="hidden" name="search_names[' + i + '][pub]" value="1"/>' +
-            '<input type="hidden" name="search_names[' + i + '][typeid]" value="' + typeid + '"/>' +
-            '<input type="hidden" name="search_names[' + i + '][type]" value="' + type + '"/></span>');
-    } else {
-        $('#flag_cb_' + i).after('<span id="flag_' + i + '">&nbsp;' +
-            '<img src="images/icons/flag_red.gif" alt="site privé" title="site privé" />' +
-            '<input type="hidden" name="search_names[' + i + '][typeid]" value="' + typeid + '"/>' +
-            '<input type="hidden" name="search_names[' + i + '][type]" value="' + type + '"/></span>');
-    }
-}
-
 function updateNameDisplay(isFemale)
 {
+    var lastnames = new Array('lastname_main', 'lastname_ordinary', 'lastname_marital', 'pseudonym');
+    var firstnames = new Array('firstname_main', 'firstname_ordinary');
     var searchnames = '';
-    for (var i = 0; i < 10; i++) {
+
+    for (var i = 0; i < 4; ++i) {
+        searchnames += $('.names_advanced').find('[name*=' + lastnames[i] + ']').val() + ';';
+    }
+    searchnames += '-;'
+    for (var i = 0; i < 2; ++i) {
+        searchnames += $('.names_advanced').find('[name*=' + firstnames[i] + ']').val() + ';';
+    }
+    searchnames += '-';
+
+    var has_private = false;
+    for (var i = 0; i < 10; ++i) {
         if ($('#search_name_' + i).find(':text').val()) {
-            searchnames += $('#search_name_' + i).find('[name*=typeid]').val() + ';';
-            searchnames += $('#search_name_' + i).find(':text').val() + ';;';
+            searchnames += ';' + $('#search_name_' + i).find('[name*=type]').val() + ';' + $('#search_name_' + i).find(':text').val();
+            has_private = true;
         }
     }
+    searchnames += (has_private ? '' : ';');
     $.xget('profile/ajax/buildnames/' + searchnames + '/' + isFemale,
            function(data){
                var name = data.split(';');
@@ -127,15 +120,6 @@ function updateNameDisplay(isFemale)
            });
 }
 
-function toggleParticle(id)
-{
-    if ($('#search_name_' + id).find("[name*='[particle]']").val() == '') {
-        $('#search_name_' + id).find("[name*='[particle]']").val(1);
-    } else {
-        $('#search_name_' + id).find("[name*='[particle]']").val('');
-    }
-}
-
 // Promotions {{{1
 
 function togglePromotionEdition()
index 9c7ab44..cb25855 100644 (file)
@@ -28,8 +28,9 @@ function education_options($current = 0)
                         LEFT JOIN  geoloc_countries       AS gc ON (e.country = gc.iso_3166_1_a2)
                      WHERE EXISTS  (SELECT  *
                                       FROM  profile_education_degree AS d
-                                     WHERE  e.id = d.eduid)
-                         ORDER BY  gc.country, e.name");
+                                     WHERE  e.id = d.eduid) AND e.name != {?}
+                         ORDER BY  gc.country, e.name",
+                          Profile::EDU_X);
     $country = "";
     while ($arr_edu = $res->next()) {
         if ($arr_edu["country"] != $country) {
index 1f78daf..6483449 100644 (file)
 
 function build_javascript_names($data, $isFemale)
 {
-    $data_array = explode(';;', $data);
-    $n = count($data_array);
-    $n--;
-    for ($i = 0; $i < $n; $i++) {
-        $searchname = explode(';', $data_array[$i]);
-        if (isset($search_names[$searchname[0]])) {
-            $search_names[$searchname[0]][] = $searchname[1];
-        } else {
-            $search_names[$searchname[0]] = array('fullname' => $searchname[1]);
-        }
-    }
+    $names = array();
+    foreach (explode(';-;', $data) as $key => $item) {
+        $names[$key] = explode(';', $item);
+    }
+    $lastnames = array(
+        'lastname_main'     => $names[0][0],
+        'lastname_ordinary' => $names[0][1],
+        'lastname_marital'  => $names[0][2],
+        'pseudonym'         => $names[0][3]
+    );
+    $firstnames = array(
+        'firstname_main'     => $names[1][0],
+        'firstname_ordinary' => $names[1][1]
+    );
+    $private_names_count = intval(count($names[2]) / 2);
+    $private_names = array();
+    for ($i = 0; $i < $private_names_count; ++$i) {
+        $private_names[] = array('type' => $names[2][2 * $i], 'name' => $names[2][2 * $i + 1]);
+    }
+
+    return build_first_name($firstnames) . ' ' . build_full_last_name($lastnames, $isFemale) . ';' . build_private_name($private_names);
+}
 
-    $sn_types_public  = build_types('public');
-    $sn_types_private = build_types('private');
-    $full_name        = build_full_name($search_names, $sn_types_public, $isFemale);
-    return build_public_name($search_names, $sn_types_public, $full_name) . ';' .
-           build_private_name($search_names, $sn_types_private);
+function build_email_alias(array $public_names)
+{ 
+    return PlUser::makeUserName(build_first_name($public_names), build_short_last_name($public_names));
 }
 
-function build_display_names(&$display_names, $search_names, $isFemale, $private_name_end = null, &$alias = null)
+function build_display_names(array $public_names, array $private_names, $isFemale)
 {
-    $sn_types_public  = build_types('public');
-    $full_name        = build_full_name($search_names, $sn_types_public, $isFemale);
-    $display_names['public_name']    = build_public_name($search_names, $sn_types_public, $full_name);
-    $display_names['private_name']   = $display_names['public_name'] . $private_name_end;
-    $display_names['directory_name'] = build_directory_name($search_names, $sn_types_public, $full_name);
-    $display_names['short_name']     = build_short_name($search_names, $sn_types_public, $alias);
-    $display_names['sort_name']      = build_sort_name($search_names, $sn_types_public);
+    $short_last_name = build_short_last_name($public_names);
+    $full_last_name = build_full_last_name($public_names, $isFemale);
+    $private_last_name_end = build_private_name($private_names);
+    $firstname = build_first_name($public_names);
+
+    $display_names = array();
+    $display_names['public_name']    = $firstname . ' ' . $full_last_name;
+    $display_names['private_name']   = $display_names['public_name'] . $private_last_name_end;
+    $display_names['directory_name'] = $full_last_name . ' ' . $firstname;
+    $display_names['short_name']     = $firstname . ' ' . $short_last_name;
+    $display_names['sort_name']      = $short_last_name . ' ' . $firstname;
+
+    return $display_names;
 }
 
-function build_types($pub = null)
+function build_short_last_name(array $lastnames)
 {
-    if ($pub == 'public') {
-        $sql_pub = "AND FIND_IN_SET('public', flags)";
-    } elseif ($pub == 'private') {
-        $sql_pub = "AND NOT FIND_IN_SET('public', flags)";
-    } else {
-        $sql_pub = "";
-    }
-    $sql = "SELECT  id, type, name
-              FROM  profile_name_enum
-             WHERE  NOT FIND_IN_SET('not_displayed', flags)" . $sql_pub;
-    $sn_types = XDB::iterator($sql);
-    $types    = array();
-    while ($sn_type = $sn_types->next()) {
-        if ($pub) {
-            $types[$sn_type['type']] = $sn_type['id'];
-        } else {
-            $types[$sn_type['id']]   = $sn_type['name'];
-        }
-    }
-    return $types;
+    return ($lastnames['lastname_ordinary'] == '') ? $lastnames['lastname_main'] : $lastnames['lastname_ordinary'];
 }
 
-function build_full_name(&$search_names, &$sn_types, $isFemale)
+function build_full_last_name(array $lastnames, $isFemale)
 {
-    $name = "";
-    if (isset($search_names[$sn_types['lastname_ordinary']])) {
-        $name .= $search_names[$sn_types['lastname_ordinary']]['fullname'] . " ("
-              . $search_names[$sn_types['lastname']]['fullname'] . ")";
+    if ($lastnames['lastname_ordinary'] != '') {
+        $name = $lastnames['lastname_ordinary'] . ' (' . $lastnames['lastname_main'] . ')';
     } else {
-        $name .= $search_names[$sn_types['lastname']]['fullname'];
+        $name = $lastnames['lastname_main'];
     }
-    if (isset($search_names[$sn_types['lastname_marital']])
-        || isset($search_names[$sn_types['pseudonym']])) {
-        $name .= " (";
-        if (isset($search_names[$sn_types['lastname_marital']])) {
-            if ($isFemale) {
-                $name .= "Mme ";
-            } else {
-                $name .= "M ";
-            }
-            $name .= $search_names[$sn_types['lastname_marital']]['fullname'];
-            if (isset($search_names[$sn_types['pseudonym']])) {
-                $name .= ", ";
-            }
-        }
-        if (isset($search_names[$sn_types['pseudonym']])) {
-            $name .= $search_names[$sn_types['pseudonym']]['fullname'];
+    if ($lastnames['lastname_marital'] != '' || $lastnames['pseudonym'] != '') {
+        $name .= ' (';
+        if ($lastnames['lastname_marital'] != '') {
+            $name .= ($isFemale ? 'Mme ' : 'M ') . $lastnames['lastname_marital'];
+            $name .= (($lastnames['pseudonym'] == '') ? '' : ', ');
         }
-        $name .= ")";
+        $name .= (($lastnames['pseudonym'] == '')? '' : $lastnames['pseudonym']) . ')';
     }
     return $name;
 }
 
-function build_public_name(&$search_names, &$sn_types, $full_name)
+function build_first_name(array $firstnames)
 {
-    return $search_names[$sn_types['firstname']]['fullname'] . " " . $full_name;
+    return ($firstnames['firstname_ordinary'] ? $firstnames['firstname_ordinary'] : $firstnames['firstname_main']);
 }
 
-function build_private_name(&$search_names, &$sn_types)
+function build_private_name(array $private_names)
 {
-    $name = "";
-    if (isset($search_names[$sn_types['nickname']])
-        || (isset($search_names[$sn_types['name_other']])
-        || isset($search_names[$sn_types['name_other']]))) {
-        $name .= " (";
-        if (isset($search_names[$sn_types['nickname']])) {
-            $name .= "alias " . $search_names[$sn_types['nickname']]['fullname'];
-            $i = 0;
-            while (isset($search_names[$sn_types['nickname']][$i])) {
-                $name .= ", " . $search_names[$sn_types['nickname']][$i];
-                $i++;
-            }
-            if (isset($search_names[$sn_types['name_other']])
-                || isset($search_names[$sn_types['firstname_other']])) {
-                $name .= ", ";
-            }
-        }
-        if (isset($search_names[$sn_types['firstname_other']])) {
-            $name .= "autres prénoms : " . $search_names[$sn_types['firstname_other']]['fullname'];
-            $i = 0;
-            while (isset($search_names[$sn_types['firstname_other']][$i])) {
-                $name .= ", " . $search_names[$sn_types['firstname_other']][$i];
-                $i++;
-            }
-            if (isset($search_names[$sn_types['name_other']])) {
-                $name .= ", ";
-            }
-        }
-        if (isset($search_names[$sn_types['name_other']])) {
-            $name .= "autres noms : " . $search_names[$sn_types['name_other']]['fullname'];
-            $i = 0;
-            while (isset($search_names[$sn_types['name_other']][$i])) {
-                $name .= ", " . $search_names[$sn_types['name_other']][$i];
-                $i++;
-            }
-        }
-        $name .= ")";
+    if (is_null($private_names) || count($private_names) == 0) {
+        return '';
     }
-    return $name;
-}
 
-function build_directory_name(&$search_names, &$sn_types, $full_name)
-{
-    return $full_name . " " . $search_names[$sn_types['firstname']]['fullname'];
-}
+    static $types = array('nickname' => 'alias ', 'firstname' => 'autres prénoms : ', 'lastname' => 'autres noms : ');
+    $names_sorted = array('nickname' => array(), 'firstname' => array(), 'lastname' => array());
 
-function build_short_name(&$search_names, &$sn_types, &$alias = null)
-{
-    if (isset($search_names[$sn_types['lastname_ordinary']])) {
-        $lastname = $search_names[$sn_types['lastname_ordinary']]['fullname'];
-    } else {
-        $lastname = $search_names[$sn_types['lastname']]['fullname'];
-    }
-    if (isset($search_names[$sn_types['firstname_ordinary']])) {
-        $firstname = $search_names[$sn_types['firstname_ordinary']]['fullname'];
-    } else {
-        $firstname = $search_names[$sn_types['firstname']]['fullname'];
-    }
-    if ($alias) {
-        $alias = PlUser::makeUserName($firstname, $lastname);
-    }
-    return $firstname . " " . $lastname;
-}
-
-function build_sort_name(&$search_names, &$sn_types)
-{
-    $name = "";
-    if (isset($search_names[$sn_types['lastname_ordinary']])) {
-        $name .= $search_names[$sn_types['lastname_ordinary']]['name'];
-    } else {
-        $name .= $search_names[$sn_types['lastname']]['name'];
+    foreach ($private_names as $private_name) {
+        $names_sorted[$private_name['type']][] = $private_name['name'];
     }
-    $name .= " " . $search_names[$sn_types['firstname']]['fullname'];
-    return $name;
-}
-
-function set_profile_display(&$display_names, Profile $profile)
-{
-    XDB::execute("UPDATE  profile_display
-                     SET  public_name = {?}, private_name = {?},
-                          directory_name = {?}, short_name = {?}, sort_name = {?}
-                   WHERE  pid = {?}",
-                 $display_names['public_name'], $display_names['private_name'],
-                 $display_names['directory_name'], $display_names['short_name'],
-                 $display_names['sort_name'], $profile->id());
 
-    $owner = $profile->owner();
-    if ($owner) {
-        XDB::execute('UPDATE  accounts
-                         SET  full_name = {?}, directory_name = {?}
-                       WHERE  uid = {?}',
-                     $display_names['public_name'], $display_names['directory_name'], $owner->id());
+    $names_array = array();
+    foreach ($names_sorted as $type => $names) {
+        if (count($names)) {
+            $names_array[] = $types[$type] . implode(', ', $names);
+        }
     }
-}
 
-function build_sn_pub($pid)
-{
-    $res = XDB::iterator("SELECT  CONCAT(sn.particle, sn.name) AS fullname, sn.typeid,
-                                  sn.particle, sn.name, sn.id
-                            FROM  profile_name      AS sn
-                      INNER JOIN  profile_name_enum AS e  ON (e.id = sn.typeid)
-                           WHERE  sn.pid = {?} AND NOT FIND_IN_SET('not_displayed', e.flags)
-                                  AND FIND_IN_SET('public', e.flags)
-                        ORDER BY  NOT FIND_IN_SET('always_displayed', e.flags), e.id, sn.name",
-                         $pid);
-    $sn_old = array();
-    while ($old = $res->next()) {
-        $sn_old[$old['typeid']] = array('fullname' => $old['fullname'],
-                                        'name'     => $old['name'],
-                                        'particle' => $old['particle'],
-                                        'id'       => $old['id']);
-    }
-    return $sn_old;
+    return ' (' . implode(', ', $names_array) . ')';
 }
 
 /** Splits a name into tokens, as used in search_name.
@@ -255,94 +144,61 @@ function compare_basename($a, $b) {
     return name_to_basename($a) == name_to_basename($b);
 }
 
-function set_alias_names(&$sn_new, $sn_old, $pid, PlUser $user, $update_new = false, $new_alias = null)
+function update_account_from_profile($uid)
 {
-    $has_new = false;
-    foreach ($sn_new as $typeid => $sn) {
-        if (isset($sn['pub']) && !is_null($sn['fullname'])) {
-            if (isset($sn_old[$typeid]) && $update_new) {
-                XDB::execute("UPDATE  profile_name
-                                 SET  particle = {?}, name = {?}, typeid = {?}
-                               WHERE  id = {?} AND pid = {?}",
-                             $sn['particle'], $sn['name'], $typeid, $sn_old[$typeid]['id'], $pid);
-                unset($sn_old[$typeid]);
-            } elseif ($sn['fullname'] == $sn_old[$typeid]['fullname'] && $sn['name'] == $sn_old[$typeid]['name']) {
-                XDB::execute('INSERT INTO  profile_name (particle, name, typeid, pid)
-                                   VALUES  ({?}, {?}, {?}, {?})',
-                             $sn_old[$typeid]['particle'], $sn_old[$typeid]['name'], $typeid, $pid);
-                unset($sn_old[$typeid]);
-            } else {
-                $has_new = true;
-            }
-        } else {
-            if ($sn['fullname'] != '') {
-                XDB::execute("INSERT INTO  profile_name (particle, name, typeid, pid)
-                                   VALUES  ('', {?}, {?}, {?})",
-                             $sn['fullname'], $typeid, $pid);
-            }
-            $i = 0;
-            while (isset($sn[$i])) {
-                XDB::execute("INSERT INTO  profile_name (particle, name, typeid, pid)
-                                   VALUES  ('', {?}, {?}, {?})",
-                             $sn[$i], $typeid, $pid);
-                $i++;
-            }
-        }
-    }
-    if (count($sn_old) > 0) {
-        if (!$update_new) {
-            $has_new = true;
-            foreach ($sn_old as $typeid => $sn) {
-                XDB::execute("INSERT INTO  profile_name (particle, name, typeid, pid)
-                                   VALUES  ({?}, {?}, {?}, {?})",
-                             $sn['particle'], $sn['name'], $typeid, $pid);
-            }
-        } else {
-            foreach ($sn_old as $typeid => $sn) {
-                XDB::execute("DELETE FROM  profile_name
-                                    WHERE  pid = {?} AND id = {?}",
-                             $pid, $sn['id']);
-            }
-        }
-    }
-    if ($update_new) {
-        XDB::execute('DELETE FROM  email_source_account
-                            WHERE  FIND_IN_SET(\'usage\', flags) AND uid = {?} AND type = \'alias\'',
-                     $user->id());
-    }
-    if ($new_alias) {
-        XDB::execute('INSERT INTO  email_source_account (email, uid, type, flags, domain)
-                           SELECT  {?}, {?}, \'alias\', \'usage\', id
-                             FROM  email_virtual_domains
-                            WHERE  name = {?}',
-                     $new_alias, $user->id(), $user->mainEmailDomain());
+    XDB::execute("UPDATE  accounts             AS a
+              INNER JOIN  account_profiles     AS ap  ON (ap.uid = a.uid AND FIND_IN_SET('owner', ap.perms))
+              INNER JOIN  profile_public_names AS ppn ON (ppn.pid = ap.pid)
+              INNER JOIN  profile_display      AS pd  ON (pd.pid = ap.pid)
+                     SET  a.lastname = IF(ppn.lastname_ordinary = '', ppn.lastname_main, ppn.lastname_ordinary),
+                          a.firstname = IF(ppn.firstname_ordinary = '', ppn.firstname_main, ppn.firstname_ordinary),
+                          a.full_name = pd.short_name, a.directory_name = pd.directory_name
+                   WHERE  a.uid = {?}",
+                 $uid);
+}
+
+function update_display_names(Profile $profile, array $public_names, array $private_names = null)
+{
+    if (is_null($private_names)) {
+        $private_names = XDB::fetchAllAssoc('SELECT  type, name
+                                               FROM  profile_private_names
+                                              WHERE  pid = {?}
+                                           ORDER BY  type, id',
+                                            $profile->id());
     }
+    $display_names = build_display_names($public_names, $private_names, $profile->isFemale());
+
+    XDB::execute('UPDATE  profile_display
+                     SET  public_name = {?}, private_name = {?},
+                          directory_name = {?}, short_name = {?}, sort_name = {?}
+                   WHERE  pid = {?}',
+                 $display_names['public_name'], $display_names['private_name'],
+                 $display_names['directory_name'], $display_names['short_name'],
+                 $display_names['sort_name'], $profile->id());
+
+    Profile::rebuildSearchTokens($profile->id(), false);
 
-    // XXX: Improve this when we optimize names handling.
-    // Updates accounts firt and last names.
-    XDB::execute('UPDATE  accounts          AS a
-              INNER JOIN  account_profiles  AS ap ON (ap.uid = a.uid AND FIND_IN_SET(\'owner\', ap.perms))
-              INNER JOIN  profile_name_enum AS le ON (le.type = \'lastname\')
-              INNER JOIN  profile_name_enum AS ce ON (ce.type = \'lastname_ordinary\')
-              INNER JOIN  profile_name      AS l  ON (ap.pid = l.pid AND le.id = l.typeid)
-               LEFT JOIN  profile_name      AS c  ON (ap.pid = c.pid AND ce.id = c.typeid)
-                     SET  a.lastname = IF(c.pid IS NULL, IF(l.particle != \'\', l.name, CONCAT(l.particle, \' \', l.name)),
-                                                         IF(c.particle != \'\', c.name, CONCAT(c.particle, \' \', c.name)))
-                   WHERE  a.uid = {?}',
-                 $user->id());
+    if ($profile->owner()) {
+        update_account_from_profile($profile->owner()->id());
+    }
+}
 
-    XDB::execute('UPDATE  accounts          AS a
-              INNER JOIN  account_profiles  AS ap ON (ap.uid = a.uid AND FIND_IN_SET(\'owner\', ap.perms))
-              INNER JOIN  profile_name_enum AS fe ON (fe.type = \'firstname\')
-              INNER JOIN  profile_name_enum AS ce ON (ce.type = \'firstname_ordinary\')
-              INNER JOIN  profile_name      AS f  ON (ap.pid = f.pid AND fe.id = f.typeid)
-               LEFT JOIN  profile_name      AS c  ON (ap.pid = c.pid AND ce.id = c.typeid)
-                     SET  a.firstname = IF(c.pid IS NULL, f.name, c.name)
-                   WHERE  a.uid = {?}',
-                 $user->id());
+function update_public_names($pid, array $public_names)
+{
+    $public_names['particles'] = new PlFlagSet();
+    static $suffixes = array('main', 'marital', 'ordinary');
+    foreach ($suffixes as $suffix) {
+        if (isset($public_names['particle_' . $suffix]) && ($public_names['particle_' . $suffix] == 1 || $public_names['particle_' . $suffix] == 'on')) {
+            $public_names['particles']->addFlag($suffix, 1);
+        }
+    }
 
-    Profile::rebuildSearchTokens($pid, false);
-    return $has_new;
+    XDB::execute('UPDATE  profile_public_names
+                     SET  particles = {?}, lastname_main = {?}, lastname_marital = {?}, lastname_ordinary = {?},
+                          firstname_main = {?}, firstname_ordinary = {?}, pseudonym = {?}
+                   WHERE  pid = {?}',
+                 $public_names['particles'], $public_names['lastname_main'], $public_names['lastname_marital'], $public_names['lastname_ordinary'],
+                 $public_names['firstname_main'], $public_names['firstname_ordinary'], $public_names['pseudonym'], $pid);
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 55521c7..6153836 100644 (file)
@@ -245,8 +245,7 @@ class MinificheView extends MixedView
             && $this->params['starts_with'] != null) {
 
             $this->set->addCond(
-                new UFC_Name(Profile::LASTNAME,
-                    $this->params['starts_with'], UFC_Name::PREFIX)
+                new UFC_NameInitial($this->params['starts_with'])
             );
         }
         return parent::apply($page);
index 4d6eb66..8590eb7 100644 (file)
@@ -26,46 +26,35 @@ class NamesReq extends ProfileValidate
     // {{{ properties
 
     public $unique = true;
-
-    public $sn_old;
-    public $sn_new;
-    public $display_names;
-    public $mail_domain;
-    public $old_alias;
-    public $new_alias;
-    public $sn_types;
-
+    public $public_names;
+    public $old_public_names;
+    public $old_alias = null;
+    public $new_alias = null;
+    public $descriptions = array('lastname_main' => 'Nom patronymique', 'lastname_marital' => 'Nom marital', 'lastname_ordinary' => 'Nom usuel', 'firstname_main' => 'Prénom', 'firstname_ordinary' => 'Prénom usuel', 'pseudonym' => 'Pseudonyme (nom de plume)');
     public $rules = "Refuser tout ce qui n'est visiblement pas un nom de famille (ce qui est extremement rare car à peu près n'importe quoi peut être un nom de famille).";
 
     // }}}
     // {{{ constructor
 
-    public function __construct(User $_user, Profile $_profile, $_search_names, $_private_name_end)
+    public function __construct(User $_user, Profile $_profile, array $_public_names, array $_old_public_names)
     {
         parent::__construct($_user, $_profile, true, 'usage');
-        require_once 'name.func.inc.php';
 
-        $this->sn_types  = build_types();
-        $this->sn_old    = build_sn_pub($this->profile->id());
-        $this->sn_new    = $_search_names;
-        $this->new_alias = true;
-        $this->display_names = array();
-        $this->mail_domain = $this->profileOwner->mainEmailDomain();
-
-        build_display_names($this->display_names, $_search_names,
-                            $this->profile->isFemale(), $_private_name_end, $this->new_alias);
-        foreach ($this->sn_new AS $key => &$sn) {
-            if (!isset($sn['pub'])) {
-                unset($this->sn_new[$key]);
-            }
-        }
+        $this->public_names = $_public_names;
+        $this->old_public_names = $_old_public_names;
 
         if (!is_null($this->profileOwner)) {
+            require_once 'name.func.inc.php';
+
+            $this->new_alias = build_email_alias($this->public_names);
             $this->old_alias = XDB::fetchOneCell('SELECT  email
                                                     FROM  email_source_account
                                                    WHERE  uid = {?} AND type = \'alias\' AND FIND_IN_SET(\'usage\', flags)',
                                                  $this->profileOwner->id());
-            if ($this->old_alias != $this->new_alias) {
+
+            if ($this->old_alias == $this->new_alias) {
+                $this->old_alias = $this->new_alias = null;
+            } else {
                 $used = XDB::fetchOneCell('SELECT  COUNT(uid)
                                              FROM  email_source_account
                                             WHERE  email = {?} AND type != \'alias_aux\'',
@@ -130,11 +119,24 @@ class NamesReq extends ProfileValidate
     {
         require_once 'name.func.inc.php';
 
-        set_profile_display($this->display_names, $this->profile);
+        update_public_names($this->profile->id(), $this->public_names);
+        update_display_names($this->profile, $this->public_names);
 
         if (!is_null($this->profileOwner)) {
-            set_alias_names($this->sn_new, $this->sn_old, $this->profile->id(),
-                            $this->profileOwner, true, $this->new_alias);
+            if (!is_null($this->old_alias)) {
+                XDB::execute('DELETE FROM  email_source_account
+                                    WHERE  FIND_IN_SET(\'usage\', flags) AND uid = {?} AND type = \'alias\'',
+                             $this->profileOwner->id());
+            }
+            if (!is_null($this->new_alias)) {
+                XDB::execute('INSERT INTO  email_source_account (email, uid, type, flags, domain)
+                                   SELECT  {?}, {?}, \'alias\', \'usage\', id
+                                     FROM  email_virtual_domains
+                                    WHERE  name = {?}',
+                             $this->new_alias, $this->profileOwner->id(), $this->profileOwner->mainEmailDomain());
+            }
+            require_once 'emails.inc.php';
+            fix_bestalias($this->profileOwner);
 
             // Update the local User object, to pick up the new bestalias.
             $this->profileOwner = User::getSilentWithUID($this->profileOwner->id());
@@ -144,6 +146,18 @@ class NamesReq extends ProfileValidate
     }
 
     // }}}
+    // {{{ function getPublicNames()
+
+    static public function getPublicNames($pid)
+    {
+        if ($request = parent::get_typed_request($pid, 'usage')) {
+            return $request->public_names;
+        }
+        return false;
+    }
+
+    // }}}
+
 }
 // }}}
 
index 5a4b18c..8eb6d9b 100644 (file)
@@ -179,10 +179,7 @@ function get_nouveau_infos($method, $params) {
     }
     // We check we actually have an identification number.
     if(!empty($params[1])) {
-        $nameTypes = DirEnum::getOptions(DirEnum::NAMETYPES);
-        $nameTypes = array_flip($nameTypes);
-
-        $res = XDB::query("SELECT  pnl.name AS nom, pnu.name AS nom_usage, pnf.name AS prenom,
+        $res = XDB::query("SELECT  ppn.lastname_initial AS nom, ppn.lastname_ordinary AS nom_usage, ppn.firstname_initial AS prenom,
                                    p.sex = 'female' AS femme, p.deathdate IS NOT NULL AS decede,
                                    p.birthdate, pd.promo, CONCAT(e.email, '@', d.name) AS mail
                              FROM  profiles         AS p
@@ -190,12 +187,9 @@ function get_nouveau_infos($method, $params) {
                        INNER JOIN  email_source_account AS s ON (s.uid = ap.uid AND FIND_IN_SET('bestalias', s.flags))
                        INNER JOIN  email_virtual_domains AS d ON (s.domain = s.id)
                        INNER JOIN  profile_display  AS pd PN (p.pid = pd.pid)
-                       INNER JOIN  profile_name AS pnl ON (p.pid = pnl.pid AND pnl.typeid = {?})
-                       INNER JOIN  profile_name AS pnf ON (p.pid = pnf.pid AND pnf.typeid = {?})
-                       INNER JOIN  profile_name AS pnu ON (p.pid = pnu.pid AND pnu.typeid = {?})
+                       INNER JOIN  profile_public_names AS ppn ON (ppn.pid = p.pid)
                             WHERE  a.flags = 'bestalias' AND p.xorg_id = {?}",
-                          $nameTypes['name_ini'], $nameTypes['lastname_ordinary'],
-                          $nameTypes['firstname_ini'], $params[1]);
+                          $params[1]);
         // $data['mail'] .= '@polytechnique.org';
 
 
index 0ce61e7..9778979 100644 (file)
@@ -54,7 +54,8 @@ class AdminModule extends PLModule
             '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/phd'                    => $this->make_hook('phd',                    AUTH_MDP,    'admin'),
+            'admin/add_secondary_edu'      => $this->make_hook('add_secondary_edu',      AUTH_MDP,    'admin')
         );
     }
 
@@ -816,8 +817,6 @@ class AdminModule extends PLModule
             $lines = explode("\n", Env::t('people'));
             $separator = Env::t('separator');
             $promotion = Env::i('promotion');
-            $nameTypes = DirEnum::getOptions(DirEnum::NAMETYPES);
-            $nameTypes = array_flip($nameTypes);
 
             if (Env::t('add_type') == 'promo') {
                 $eduSchools = DirEnum::getOptions(DirEnum::EDUSCHOOLS);
@@ -877,15 +876,9 @@ class AdminModule extends PLModule
                                                VALUES  ({?}, {?}, {?}, {?}, {?})',
                                          $infos['hrid'], $xorgId, (isset($infos[5]) ? $infos[5] : null), $birthDate, $sex);
                             $pid = XDB::insertId();
-                            XDB::execute('INSERT INTO  profile_name (pid, name, typeid)
-                                               VALUES  ({?}, {?}, {?}),
-                                                       ({?}, {?}, {?}),
-                                                       ({?}, {?}, {?}),
-                                                       ({?}, {?}, {?})',
-                                         $pid, $infos[0], $nameTypes['name_ini'],
-                                         $pid, $infos[0], $nameTypes['lastname'],
-                                         $pid, $infos[1], $nameTypes['firstname_ini'],
-                                         $pid, $infos[1], $nameTypes['firstname']);
+                            XDB::execute('INSERT INTO  profile_public_names (pid, lastname_initial, lastname_main, firstname_initial, firstname_main)
+                                               VALUES  ({?}, {?}, {?}, {?}, {?})',
+                                         $pid, $infos[0], $infos[0], $infos[1], $infos[1]);
                             XDB::execute('INSERT INTO  profile_display (pid, yourself, public_name, private_name,
                                                                         directory_name, short_name, sort_name, promo)
                                                VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
@@ -1893,6 +1886,115 @@ class AdminModule extends PLModule
         $page->assign('list', $list);
         $page->assign('promo', $promo);
     }
+
+    function handler_add_secondary_edu($page)
+    {
+        $page->changeTpl('admin/add_secondary_edu.tpl');
+
+        if (!(Post::has('verify') || Post::has('add'))) {
+            return;
+        } elseif (!Post::has('people')) {
+            $page->trigWarning("Aucune information n'a été fournie.");
+            return;
+        }
+
+        require_once 'name.func.inc.php';
+        $lines = explode("\n", Post::t('people'));
+        $separator = Post::t('separator');
+        $degree = Post::v('degree');
+        $promotion = Post::i('promotion');
+        $schoolsList = array_flip(DirEnum::getOptions(DirEnum::EDUSCHOOLS));
+        $degreesList = array_flip(DirEnum::getOptions(DirEnum::EDUDEGREES));
+        $edu_id = $schoolsList[Profile::EDU_X];
+        $degree_id = $degreesList[$degree];
+
+        $res = array(
+            'incomplete' => array(),
+            'empty'      => array(),
+            'multiple'   => array(),
+            'already'    => array(),
+            'new'        => array()
+        );
+        $old_pids = array();
+        $new_pids = array();
+        foreach ($lines as $line) {
+            $line = trim($line);
+            $line_array = explode($separator, $line);
+            array_walk($line_array, 'trim');
+            if (count($line_array) != 3) {
+                $page->trigError("La ligne « $line » est incomplète.");
+                $res['incomplete'][] = $line;
+                continue;
+            }
+            $cond = new PFC_And(new UFC_NameTokens(split_name_for_search($line_array[0]), array(), false, false, Profile::LASTNAME));
+            $cond->addChild(new UFC_NameTokens(split_name_for_search($line_array[1]), array(), false, false, Profile::FIRSTNAME));
+            $cond->addChild(new UFC_Promo('=', UserFilter::DISPLAY, $line_array[2]));
+            $uf = new UserFilter($cond);
+            $pid = $uf->getPIDs();
+            $count = count($pid);
+            if ($count == 0) {
+                $page->trigError("La ligne « $line » ne correspond à aucun profil existant.");
+                $res['empty'][] = $line;
+                continue;
+            } elseif ($count > 1) {
+                $page->trigError("La ligne « $line » correspond à plusieurs profils existant.");
+                $res['multiple'][] = $line;
+                continue;
+            } else {
+                $count = XDB::fetchOneCell('SELECT  COUNT(*) AS count
+                                              FROM  profile_education
+                                             WHERE  pid = {?} AND eduid = {?} AND degreeid = {?}',
+                                      $pid, $edu_id, $degree_id);
+                if ($count == 1) {
+                    $res['already'][] = $line;
+                    $old_pids[] = $pid[0];
+                } else {
+                    $res['new'][] = $line;
+                    $new_pids[] = $pid[0];
+                }
+            }
+        }
+
+        $display = array();
+        foreach ($res as $type => $res_type) {
+            if (count($res_type) > 0) {
+                $display = array_merge($display, array('--------------------' . $type . ':'), $res_type);
+            }
+        }
+        $page->assign('people', implode("\n", $display));
+        $page->assign('promotion', $promotion);
+        $page->assign('degree', $degree);
+
+        if (Post::has('add')) {
+            $entry_year = $promotion - Profile::educationDuration($degree);
+
+            if (Post::b('force_addition')) {
+                $pids = array_unique(array_merge($old_pids, $new_pids));
+            } else {
+                $pids = array_unique($new_pids);
+
+                // Updates years.
+                XDB::execute('UPDATE  profile_education
+                                 SET  entry_year = {?}, grad_year = {?}, promo_year = {?}
+                               WHERE  pid IN {?} AND eduid = {?} AND degreeid = {?}',
+                             $entry_year, $promotion, $promotion, $old_pids, $edu_id, $degree_id);
+            }
+
+            // Precomputes values common to all users.
+            $select = XDB::format('MAX(id) + 1, pid, {?}, {?}, {?}, {?}, {?}, \'secondary\'',
+                                  $edu_id, $degree_id, $entry_year, $promotion, $promotion );
+            XDB::startTransaction();
+            foreach ($pids as $pid) {
+                XDB::execute('INSERT INTO  profile_education (id, pid, eduid, degreeid, entry_year, grad_year, promo_year, flags)
+                                   SELECT  ' . $select . '
+                                     FROM  profile_education
+                                    WHERE  pid = {?}',
+                             $pid);
+            }
+            XDB::commit();
+        }
+
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 40d5d12..bd6139b 100644 (file)
@@ -163,10 +163,10 @@ class PaymentModule extends PLModule
             $pay->init($val, $meth);
             $pay->prepareform($pay);
         } else {
-            $res = XDB::iterator('SELECT  timestamp, amount
+            $res = XDB::iterator('SELECT  ts_confirmed, amount
                                     FROM  payment_transactions
                                    WHERE  uid = {?} AND ref = {?}
-                                ORDER BY  timestamp DESC',
+                                ORDER BY  ts_confirmed DESC',
                                  S::v('uid', -1), $ref);
 
             if ($res->total()) {
@@ -186,8 +186,7 @@ class PaymentModule extends PLModule
                                                 $ref);
                 $sum = 0;
                 foreach ($donations as $d) {
-                    $amount = $d['amount'];
-                    $sum += trim(strtr(substr($amount, 0, strpos($amount, 'EUR')), ',', '.'));
+                    $sum += $d['amount'];
                 }
 
                 $page->assign('donations', $donations);
@@ -195,7 +194,7 @@ class PaymentModule extends PLModule
             }
         }
 
-        $val = floor($val) . '.' . substr(floor(($val - floor($val)) * 100 + 100), 1);
+        $val = floor($val*100)/100;
         $page->assign('montant', $val);
         $page->assign('comment', Env::v('comment'));
 
@@ -246,8 +245,7 @@ class PaymentModule extends PLModule
         if (Env::v('vads_currency') != '978') {
             cb_erreur("monnaie autre que l'euro");
         }
-        $amount = ((float)Env::i('vads_amount')) / 100;
-        $montant = sprintf("%.02f EUR", $amount);
+        $montant = ((float)Env::i('vads_amount')) / 100;
 
         /* on extrait le code de retour */
         if (Env::v('vads_result') != '00') {
@@ -255,10 +253,10 @@ class PaymentModule extends PLModule
         }
 
         /* on fait l'insertion en base de donnees */
-        XDB::execute('INSERT INTO  payment_transactions (id, uid, ref, fullref, amount, pkey, comment, display)
-                           VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
+        XDB::execute('INSERT INTO  payment_transactions (id, method_id, uid, ref, fullref, ts_confirmed, amount, pkey, comment, status, display)
+                           VALUES  ({?}, 2, {?}, {?}, {?}, NOW(), {?}, {?}, {?}, "confirmed", {?})',
                      Env::v('vads_trans_date'), $user->id(), $ref, Env::v('vads_order_id'), $montant, '', Env::v('vads_order_info'), Env::i('vads_order_info2'));
-        echo "Paiement stored.\n";
+        echo "Payment stored.\n";
 
         // We check if it is an Xnet payment and then update the related ML.
         $res = XDB::query('SELECT  eid, asso_id
@@ -319,10 +317,11 @@ class PaymentModule extends PLModule
         /* reference complete de la commande */
         $fullref = Env::s('cm');
         /* montant de la transaction */
-        $montant_nb = Env::s('amt');
+        $montant = Env::s('amt');
         /* devise */
-        $montant_dev = Env::s('cc');
-        $montant = "$montant_nb $montant_dev";
+        if (Env::s('cc') != 'EUR') {
+            cb_erreur("monnaie autre que l'euro");
+        }
 
         /* on extrait le code de retour */
         if ($status != "Completed") {
@@ -353,8 +352,8 @@ class PaymentModule extends PLModule
         }
 
         /* on fait l'insertion en base de donnees */
-        XDB::execute("INSERT INTO  payment_transactions (id, uid, ref, fullref, amount, pkey, comment, display)
-                           VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, '?})",
+        XDB::execute("INSERT INTO  payment_transactions (id, method_id, uid, ref, fullref, ts_confirmed, amount, pkey, comment, status, display)
+                           VALUES  ({?}, 1, {?}, {?}, {?}, NOW(), {?}, {?}, {?}, 'confirmed', {?})",
                     $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.
@@ -462,7 +461,7 @@ class PaymentModule extends PLModule
         foreach($tit as $foo) {
             $pid = $foo['id'];
             if (may_update()) {
-                $res = XDB::query('SELECT  p.uid, IF(p.timestamp = \'0000-00-00\', 0, p.timestamp) AS date, p.comment, p.amount
+                $res = XDB::query('SELECT  p.uid, IF(p.ts_confirmed = \'0000-00-00\', 0, p.ts_confirmed) AS date, p.comment, p.amount
                                      FROM  payment_transactions AS p
                                INNER JOIN  accounts             AS a  ON (a.uid = p.uid)
                                 LEFT JOIN  account_profiles     AS ap ON (ap.uid = p.uid AND FIND_IN_SET(\'owner\', ap.perms))
@@ -472,11 +471,11 @@ class PaymentModule extends PLModule
                 $trans[$pid] = User::getBulkUsersWithUIDs($res->fetchAllAssoc(), 'uid', 'user');
                 $sum = 0;
                 foreach ($trans[$pid] as $i => $t) {
-                    $sum += strtr(substr($t['amount'], 0, strpos($t['amount'], 'EUR')), ',', '.');
-                    $trans[$pid][$i]['amount'] = str_replace('EUR', '€', $t['amount']);
+                    $sum += $t['amount'];
+                    $trans[$pid][$i]['amount'] = $t['amount'];
                 }
                 $trans[$pid][] = array('limit'  =>  true,
-                                       'amount' => strtr($sum, '.', ',') . ' €');
+                                       'amount' => $sum);
             }
             $res = XDB::iterRow("SELECT  e.eid, e.short_name, e.intitule, ep.nb, ei.montant, ep.paid
                                    FROM  group_events             AS e
@@ -497,15 +496,10 @@ class PaymentModule extends PLModule
                     $event[$pid]['paid']      = $paid;
                 }
             }
-            $res = XDB::query('SELECT  amount
+            $res = XDB::query('SELECT  SUM(amount) AS sum_amount
                                  FROM  payment_transactions
-                                WHERE  id = {?} AND uid = {?}', $pid, S::v('uid'));
-            $montants = $res->fetchColumn();
-
-            foreach ($montants as $m) {
-                $p = strtr(substr($m, 0, strpos($m, 'EUR')), ',', '.');
-                $event[$pid]['paid'] += trim($p);
-            }
+                                WHERE  ref = {?} AND uid = {?}', $pid, S::v('uid'));
+            $event[$pid]['paid'] = $res->fetchOneCell();
         }
         $page->register_modifier('decode_comment', 'decode_comment');
         $page->assign('trans', $trans);
@@ -521,10 +515,10 @@ class PaymentModule extends PLModule
             $pid = substr($pid, 0, strlen($pid) - 4);
         }
 
-        $res = XDB::fetchAllAssoc('SELECT  uid, IF(timestamp = \'0000-00-00\', 0, timestamp) AS date, comment, amount
+        $res = XDB::fetchAllAssoc('SELECT  uid, IF(ts_confirmed = \'0000-00-00\', 0, ts_confirmed) AS date, comment, amount
                                      FROM  payment_transactions
                                     WHERE  ref = {?}
-                                 ORDER BY  timestamp',
+                                 ORDER BY  ts_confirmed',
                                   $pid);
         if (is_null($res)) {
             pl_redirect('payment');
@@ -538,12 +532,12 @@ class PaymentModule extends PLModule
         fputcsv($csv, array('Date', 'Nom', 'Prénom', 'Sexe', 'Promotion', 'Email', 'Commentaire', 'Montant'), ';');
         foreach ($users as $item) {
             $user = $item['user'];
-            $sum += strtr(substr($item['amount'], 0, strpos($item['amount'], 'EUR')), ',', '.');
+            $sum += $item['amount'];
             fputcsv($csv, array(format_datetime($item['date'], '%d/%m/%y'), $user->lastName(), $user->firstName(),
                                 ($user->isFemale()) ? 'F' : 'M', $user->promo(), $user->ForlifeEmail(),
-                                $item['comment'], str_replace('EUR', '€', $item['amount'])), ';');
+                                $item['comment'], strtr($item['amount'],'.',',').' €' ), ';');
         }
-        fputcsv($csv, array(date('d/m/y'), 'Total', '', '', '' , '', '', strtr($sum, '.', ',') . ' €'), ';');
+        fputcsv($csv, array(date('d/m/y'), 'Total', '', '', '' , '', '', strtr($sum,'.',',').' €'), ';');
 
         fclose($csv);
         exit;
@@ -928,7 +922,11 @@ class PaymentLogsImporter extends CSVImporter {
         $this->result = array();
         foreach ($this->data as $line) {
             $a = $this->makeAssoc($line, $insert_relation);
+            // 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']);
             $this->result[] = $a;
index c464e94..2327016 100644 (file)
@@ -48,7 +48,6 @@ class ProfileModule extends PLModule
             'javascript/education.js'    => $this->make_hook('education_js',               AUTH_COOKIE),
             'javascript/grades.js'       => $this->make_hook('grades_js',                  AUTH_COOKIE),
             'profile/medal'              => $this->make_hook('medal',                      AUTH_PUBLIC),
-            'profile/name_info'          => $this->make_hook('name_info',                  AUTH_PUBLIC),
 
             'referent'                   => $this->make_hook('referent',                   AUTH_COOKIE),
             'referent/country'           => $this->make_hook('ref_country',                AUTH_COOKIE, 'user', NO_AUTH),
@@ -69,7 +68,6 @@ class ProfileModule extends PLModule
             '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/names'                => $this->make_hook('admin_names',                AUTH_MDP,    'admin'),
         );
     }
 
@@ -116,19 +114,6 @@ class ProfileModule extends PLModule
         exit;
     }
 
-    function handler_name_info($page)
-    {
-        pl_content_headers("text/html");
-        $page->changeTpl('profile/name_info.tpl', SIMPLE);
-        $res = XDB::iterator("SELECT  name, explanations,
-                                      FIND_IN_SET('public', flags) AS public,
-                                      FIND_IN_SET('has_particle', flags) AS has_particle
-                                FROM  profile_name_enum
-                               WHERE  NOT FIND_IN_SET('not_displayed', flags)
-                            ORDER BY  NOT FIND_IN_SET('public', flags)");
-        $page->assign('types', $res);
-    }
-
     function handler_networking($page, $mid)
     {
         $res = XDB::query("SELECT  icon
@@ -495,14 +480,11 @@ class ProfileModule extends PLModule
     function handler_ajax_searchname($page, $id, $isFemale)
     {
         pl_content_headers("text/html");
-        $page->changeTpl('profile/general.searchname.tpl', NO_SKIN);
-        $res = XDB::query("SELECT  id, name, FIND_IN_SET('public', flags) AS pub
-                             FROM  profile_name_enum
-                            WHERE  NOT FIND_IN_SET('not_displayed', flags)
-                                   AND NOT FIND_IN_SET('always_displayed', flags)");
-        $page->assign('sn_type_list', $res->fetchAllAssoc());
+        $page->changeTpl('profile/general.private_name.tpl', NO_SKIN);
+        $page->assign('other_names', array('nickname' => 'Surnom', 'firstname' => 'Autre prénom', 'lastname' => 'Autre nom'));
+        $page->assign('new_name', true);
         $page->assign('isFemale', $isFemale);
-        $page->assign('i', $id);
+        $page->assign('id', $id);
     }
 
     function handler_ajax_buildnames($page, $data, $isFemale)
@@ -715,17 +697,6 @@ class ProfileModule extends PLModule
                 break;
         }
     }
-    function handler_admin_names($page, $action = 'list', $id = null) {
-        $page->setTitle('Administration - Types de noms');
-        $page->assign('title', 'Gestion des types de noms');
-        $table_editor = new PLTableEditor('admin/names', 'profile_name_enum', 'id', true);
-        $table_editor->describe('name', 'Nom', true);
-        $table_editor->describe('explanations', 'Explications', true);
-        $table_editor->describe('type', 'Type', true);
-        $table_editor->describe('flags', 'Flags', true);
-        $table_editor->describe('score', 'Score', true);
-        $table_editor->apply($page, $action, $id);
-    }
     function handler_admin_binets($page, $action = 'list', $id = null) {
         $page->setTitle('Administration - Binets');
         $page->assign('title', 'Gestion des binets');
index 6c29940..6eef643 100644 (file)
 
 class ProfileSettingSearchNames implements ProfileSetting
 {
-    private $private_name_end;
-    private $search_names;
-    private $name_types;
+    private function diff($pid, array $old, array $new)
+    {
+        $diff = false;
+        foreach ($old as $field => $name) {
+            $diff = $diff || ($name != $new[$field]);
+        }
 
-    public function __construct() {
-            $this->name_types = DirEnum::getOptions(DirEnum::NAMES);
+        return $diff;
     }
 
     private function matchWord($old, $new, $newLen)
@@ -36,174 +38,84 @@ class ProfileSettingSearchNames implements ProfileSetting
             && ($i + $newLen == strlen($old) || $old{$i + $newLen} == ' ');
     }
 
-    private function prepareField($value)
+    private function prepare(ProfilePage $page, array &$new_value)
     {
-        return name_to_basename($value);
-    }
+        $initial_value = XDB::fetchOneAssoc('SELECT  lastname_main, firstname_main
+                                               FROM  profile_public_names
+                                              WHERE  pid = {?}',
+                                            $page->pid());
 
-    private function prepare(ProfilePage $page, $field, $value, $init, &$success)
-    {
         $success = true;
-        $ini     = $this->prepareField($init);
-        $new     = $this->prepareField($value);
-        $newLen  = strlen($new);
-        $success = $this->matchWord($ini, $new, $newLen)
-                   || ($field == 'lastname' && $new == 'DE ' . $ini);
-        if (!$success) {
-            $field = strtolower($field);
-            Platal::page()->trigError("Le " . $this->name_types[$field] . " que tu as choisi (" . $value .
-                                      ") est trop loin de ton " . $this->name_types[$field] . " initial (" . $init . ").");
-        }
-        return $success ? $value : $init;
-    }
+        foreach ($initial_value as $field => $name) {
+            $initial = name_to_basename($name);
+            $new = name_to_basename($new_value[$field]);
 
-    /* Removes duplicated entries for the fields that do not allow them. */
-    private function clean($value)
-    {
-        $single_types = XDB::fetchAllAssoc('id',
-                                           'SELECT  id, 0
-                                              FROM  profile_name_enum
-                                             WHERE  NOT FIND_IN_SET(\'allow_duplicates\', flags)');
-
-        foreach ($value as $key => $item) {
-            if (isset($single_types[$item['typeid']])) {
-                if ($single_types[$item['typeid']] === true) {
-                    unset($value[$key]);
-                } else {
-                    $single_types[$item['typeid']] = true;
-                }
+            if (!($this->matchWord($initial, $new, strlen($new))
+                || ($field == 'lastname_main' && $new == 'DE ' . $initial))) {
+                $new_value[$field . '_error'] = true;
+                $success = false;
+                Platal::page()->trigError('Le nom choisi (' . $new . ') est trop loin de sa valeur initiale (' . $initial . ').');
             }
         }
 
-        return $value;
+        return $success;
     }
 
     public function value(ProfilePage $page, $field, $value, &$success)
     {
-        $success     = true;
-        $success_tmp = true;
+        $success = true;
 
         if (is_null($value)) {
-            $sn_all = XDB::iterator("SELECT  CONCAT(sn.particle, sn.name) AS name,
-                                             sn.particle, sn.typeid, e.type, e.name AS type_name,
-                                             FIND_IN_SET('has_particle', e.flags) AS has_particle,
-                                             FIND_IN_SET('always_displayed', e.flags) AS always_displayed,
-                                             FIND_IN_SET('public', e.flags) AS pub
-                                       FROM  profile_name      AS sn
-                                 INNER JOIN  profile_name_enum AS e  ON (e.id = sn.typeid)
-                                      WHERE  sn.pid = {?} AND NOT FIND_IN_SET('not_displayed', e.flags)
-                                   ORDER BY  NOT FIND_IN_SET('always_displayed', e.flags), e.id, sn.name",
-                                     $page->pid());
-
-            $sn_types = XDB::iterator("SELECT  id, type, name,
-                                               FIND_IN_SET('has_particle', flags) AS has_particle
-                                         FROM  profile_name_enum
-                                        WHERE  NOT FIND_IN_SET('not_displayed', flags)
-                                               AND FIND_IN_SET('always_displayed', flags)
-                                     ORDER BY  id");
+            $request = NamesReq::getPublicNames($page->pid());
 
-            $value = array();
-            $sn = $sn_all->next();
-            while ($sn_type = $sn_types->next()) {
-                if ($sn_type['id'] == $sn['typeid']) {
-                    $value[] = $sn;
-                    if ($sn) {
-                        $sn = $sn_all->next();
-                    }
-                } else {
-                    $value[] = array('name'             => '',
-                                     'particle'         => '',
-                                     'typeid'           => $sn_type['id'],
-                                     'type'             => $sn_type['type'],
-                                     'type_name'        => $sn_type['name'],
-                                     'has_particle'     => $sn_type['has_particle'],
-                                     'always_displayed' => 1,
-                                     'pub'              => 1);
+            if (!$request) {
+                $value['public_names'] = XDB::fetchOneAssoc('SELECT  particles, lastname_main, lastname_marital, lastname_ordinary,
+                                                                     firstname_main, firstname_ordinary, pseudonym
+                                                               FROM  profile_public_names
+                                                              WHERE  pid = {?}',
+                                                            $page->pid());
+
+                $flags = new PlFlagSet($value['public_names']['particles']);
+                unset($value['public_names']['particles']);
+                static $suffixes = array('main', 'marital', 'ordinary');
+
+                foreach ($suffixes as $suffix) {
+                    $value['public_names']['particle_' . $suffix] = $flags->hasFlag($suffix);
                 }
-            }
-            if ($sn) {
-                do {
-                    $value[] = $sn;
-                } while ($sn = $sn_all->next());
-            }
-            $namesRequest = ProfileValidate::get_typed_requests($page->pid(), 'usage');
-            if (count($namesRequest) > 0) {
+            } else {
+                $value['public_names'] = $request;
                 Platal::page()->assign('validation', true);
             }
-            $value = $this->clean($value);
+
+            $value['private_names'] = XDB::fetchAllAssoc('SELECT  type, name
+                                                            FROM  profile_private_names
+                                                           WHERE  pid = {?}
+                                                        ORDER BY  type, id',
+                                                         $page->pid());
         } else {
-            require_once 'name.func.inc.php';
-
-            $value = $this->clean($value);
-            $res = XDB::query("SELECT  s.particle, s.name
-                                 FROM  profile_name      AS s
-                           INNER JOIN  profile_name_enum AS e ON (e.id = s.typeid)
-                                WHERE  s.pid = {?} AND (e.type = 'lastname' OR e.type = 'firstname')
-                             ORDER BY  e.type = 'firstname'",
-                             $page->pid());
-            $res = $res->fetchAllAssoc();
-            $initial = array();
-            $initial['lastname'] = $res[0]['particle'] . $res[0]['name'];
-            $initial['firstname'] = $res[1]['name'];
-            $sn_types = build_types();
-            $this->search_names = array();
-            foreach ($value as &$sn) {
-                $sn['name'] = trim($sn['name']);
-                if (S::user()->isMe($page->owner) && ($sn['type'] == 'firstname' || $sn['type'] == 'lastname')) {
-                    $sn['name'] = $this->prepare($page, $sn['type'], $sn['name'],
-                                                 $initial[$sn['type']], $success_tmp);
-                    $success = $success && $success_tmp;
-                }
-                if ($sn['pub']) {
-                    if (isset($sn['particle']) && ($sn['particle'] != '')) {
-                        // particle is before first blank
-                        list($particle, $name) = explode(' ', $sn['name'], 2);
-                        $particle = trim($particle) . ' ';
-                        if (!$name) {
-                            // particle is before first quote
-                            list($particle, $name) = explode('\'', $sn['name'], 2);
-                            $particle = trim($particle);
-                            if (!$name) {
-                                // actually there is no particle
-                                $particle = '';
-                                $name = $sn['name'];
-                            }
-                        }
-                    } else {
-                        $particle = '';
-                        $name     = $sn['name'];
-                    }
-                }
-                if ($sn['name'] != '') {
-                    if ($sn['pub']) {
-                        $this->search_names[$sn['typeid']] = array('fullname' => $sn['name'],
-                                                                   'name'     => $name,
-                                                                   'particle' => $particle,
-                                                                   'pub'      => $sn['pub']);
-                    } else {
-                        if (isset($this->search_names[$sn['typeid']])) {
-                            $this->search_names[$sn['typeid']][] = $sn['name'];
-                        } else {
-                            $this->search_names[$sn['typeid']] = array('fullname' => $sn['name']);
-                        }
-                        $sn['type_name'] = $sn_types[$sn['typeid']];
-                    }
+            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]);
                 }
             }
-            $res = XDB::query("SELECT  public_name, private_name
-                                 FROM  profile_display
-                                WHERE  pid = {?}",
-                              $page->pid());
-            list($public_name, $private_name) = $res->fetchOneRow();
-            if ($success) {
-                $sn_types_private       = build_types('private');
-                $this->private_name_end = build_private_name($this->search_names, $sn_types_private);
-                $private_name           = $public_name . $this->private_name_end;
+
+            if (S::user()->isMe($page->owner)) {
+                $success = $this->prepare($page, $value['public_names']);
             }
-            Platal::page()->assign('public_name', $public_name);
-            Platal::page()->assign('private_name', $private_name);
         }
 
+        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;
+
+        Platal::page()->assign('public_name', $public_name);
+        Platal::page()->assign('private_name', $private_name);
+
         return $value;
     }
 
@@ -211,36 +123,57 @@ class ProfileSettingSearchNames implements ProfileSetting
     {
         require_once 'name.func.inc.php';
 
-        $sn_old = build_sn_pub($page->pid());
-        XDB::execute("DELETE FROM  s
-                            USING  profile_name      AS s
-                       INNER JOIN  profile_name_enum AS e ON (s.typeid = e.id)
-                            WHERE  s.pid = {?} AND NOT FIND_IN_SET('not_displayed', e.flags)",
-                     $page->pid());
-        $has_new = set_alias_names($this->search_names, $sn_old, $page->pid(), $page->owner);
+        $old = XDB::fetchOneAssoc('SELECT  lastname_main, lastname_marital, lastname_ordinary,
+                                           firstname_main, firstname_ordinary, pseudonym
+                                     FROM  profile_public_names
+                                    WHERE  pid = {?}',
+                                  $page->pid());
 
-        // Only requires validation if modification in public names
-        if ($has_new) {
-            $new_names = new NamesReq(S::user(), $page->profile, $this->search_names, $this->private_name_end);
+        if ($has_diff = $this->diff($page->pid(), $old, $value['public_names'])) {
+            $new_names = new NamesReq(S::user(), $page->profile, $value['public_names'], $old);
             $new_names->submit();
-            Platal::page()->trigWarning('La demande de modification de tes noms a bien été prise en compte.' .
-                                        ' Tu recevras un email dès que ces changements auront été effectués.');
+            Platal::page()->assign('validation', true);
+            Platal::page()->trigWarning('La demande de modification des noms a bien été prise en compte.' .
+                                        ' Un email sera envoyé dès que ces changements auront été effectués.');
+        }
+
+        XDB::execute('DELETE FROM  profile_private_names
+                            WHERE  pid = {?}',
+                     $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 (count($values)) {
+            XDB::rawExecute('INSERT INTO  profile_private_names (pid, type, id, name)
+                                  VALUES  ' . implode(',', $values));
+        }
+
+        if ($has_diff) {
+            update_display_names($page->profile, $old, $value['private_names']);
         } else {
-            $display_names = array();
-            build_display_names($display_names, $this->search_names,
-                                $page->profile->isFemale(), $this->private_name_end);
-            set_profile_display($display_names, $page->profile);
+            update_display_names($page->profile, $value['public_names'], $value['private_names']);
         }
     }
 
     public function getText($value) {
-        $names = array();
-        foreach ($value as $name) {
-            if ($name['name'] != '') {
-                $names[] = mb_strtolower($name['type_name']) . ' : ' . $name['name'];
+        $public_names = array();
+        foreach ($value['public_names'] as $name) {
+            if ($name != '') {
+                $public_names[] = $name;
             }
         }
-        return implode(', ' , $names);
+
+        if (count($value['private_names'])) {
+            $private_names = array();
+            foreach ($value['private_names'] as $name) {
+                $private_names[] = $name['name'];
+            }
+            return 'noms publics : ' . implode(', ' , $public_names) . ', noms privés : ' . implode(', ' , $private_names);;
+        }
+
+        return 'noms publics : ' . implode(', ' , $public_names);
     }
 }
 
@@ -265,7 +198,7 @@ class ProfileSettingEdu implements ProfileSetting
             $value = array();
             $value = XDB::fetchAllAssoc("SELECT  eduid, degreeid, fieldid, grad_year, program
                                            FROM  profile_education
-                                          WHERE  pid = {?} AND !FIND_IN_SET('primary', flags)
+                                          WHERE  pid = {?} AND !(FIND_IN_SET('primary', flags) OR FIND_IN_SET('secondary', flags))
                                        ORDER BY  id",
                                         $page->pid());
         } else if (!is_array($value)) {
@@ -296,10 +229,11 @@ class ProfileSettingEdu implements ProfileSetting
     public function save(ProfilePage $page, $field, $value)
     {
         XDB::execute("DELETE FROM  profile_education
-                            WHERE  pid = {?} AND !FIND_IN_SET('primary', flags)",
+                            WHERE  pid = {?} AND !(FIND_IN_SET('primary', flags) OR FIND_IN_SET('secondary', flags))",
                      $page->pid());
+        $schoolsList = DirEnum::getOptions(DirEnum::EDUSCHOOLS);
         foreach ($value as $eduid=>&$edu) {
-            if ($edu['eduid'] != '') {
+            if ($edu['eduid'] != '' && $schoolsList[$edu['eduid']] != Profile::EDU_X) {
                 $fieldId = ($edu['fieldid'] == 0) ? null : $edu['fieldid'];
                 XDB::execute("INSERT INTO  profile_education
                                       SET  id = {?}, pid = {?}, eduid = {?}, degreeid = {?},
@@ -368,8 +302,8 @@ class ProfileSettingMainEdu implements ProfileSetting
             $value = array();
             $value = XDB::fetchAllAssoc("SELECT  degreeid, fieldid, promo_year, program
                                            FROM  profile_education
-                                          WHERE  pid = {?} AND FIND_IN_SET('primary', flags)
-                                       ORDER BY  degreeid",
+                                          WHERE  pid = {?} AND (FIND_IN_SET('primary', flags) OR FIND_IN_SET('secondary', flags))
+                                       ORDER BY  NOT FIND_IN_SET('primary', flags), degreeid",
                                         $page->pid());
 
             foreach ($value as &$item) {
@@ -394,7 +328,7 @@ class ProfileSettingMainEdu implements ProfileSetting
             $fieldId = ($item['fieldid'] == 0) ? null : $item['fieldid'];
             XDB::execute("UPDATE  profile_education
                              SET  fieldid = {?}, program = {?}
-                           WHERE  pid = {?} AND FIND_IN_SET('primary', flags) AND degreeid = {?}",
+                           WHERE  pid = {?} AND (FIND_IN_SET('primary', flags) OR FIND_IN_SET('secondary', flags)) AND degreeid = {?}",
                          $fieldId, $item['program'], $page->pid(), $item['degreeid']);
         }
     }
@@ -795,13 +729,9 @@ class ProfilePageGeneral extends ProfilePage
                          ORDER BY  name");
         $page->assign('network_list', $res->fetchAllAssoc());
 
-        $res = XDB::query("SELECT  public_name, private_name
-                             FROM  profile_display
-                            WHERE  pid = {?}",
-                          $this->pid());
-        $res = $res->fetchOneRow();
-        $page->assign('public_name', $res[0]);
-        $page->assign('private_name', $res[1]);
+        $page->assign('lastnames', array('main' => 'Nom patronymique', 'marital' => 'Nom marital', 'ordinary' => 'Nom usuel'));
+        $page->assign('firstnames', array('firstname_main' => 'Prénom', 'firstname_ordinary' => 'Prénom usuel', 'pseudonym' => 'Pseudonyme (nom de plume)'));
+        $page->assign('other_names', array('nickname' => 'Surnom', 'firstname' => 'Autre prénom', 'lastname' => 'Autre nom'));
         $page->assign('isFemale', $this->profile->isFemale() ? 1 : 0);
     }
 }
index 3a4279a..16d02a7 100644 (file)
@@ -49,9 +49,7 @@ class RegisterModule extends PLModule
         }
 
         if ($hash) {
-            $nameTypes = DirEnum::getOptions(DirEnum::NAMETYPES);
-            $nameTypes = array_flip($nameTypes);
-            $res = XDB::query("SELECT  a.uid, a.hruid, pnl.name AS lastname, pnf.name AS firstname, p.xorg_id AS xorgid,
+            $res = XDB::query("SELECT  a.uid, a.hruid, ppn.lastname_initial AS lastname, ppn.firstname_initial AS firstname, p.xorg_id AS xorgid,
                                        pd.promo, pe.promo_year AS yearpromo, pde.degree AS edu_type,
                                        p.birthdate_ref AS birthdateRef, FIND_IN_SET('watch', a.flags) AS watch, m.hash, a.type
                                  FROM  register_marketing AS m
@@ -61,10 +59,9 @@ class RegisterModule extends PLModule
                            INNER JOIN  profile_display    AS pd  ON (p.pid = pd.pid)
                            INNER JOIN  profile_education  AS pe  ON (pe.pid = p.pid AND FIND_IN_SET('primary', pe.flags))
                            INNER JOIN  profile_education_degree_enum AS pde ON (pde.id = pe.degreeid)
-                           INNER JOIN  profile_name       AS pnl ON (p.pid = pnl.pid AND pnl.typeid = {?})
-                           INNER JOIN  profile_name       AS pnf ON (p.pid = pnf.pid AND pnf.typeid = {?})
+                           INNER JOIN  profile_public_names AS ppn ON (ppn.pid = p.pid)
                                 WHERE  m.hash = {?} AND a.state = 'pending'",
-                              $nameTypes['name_ini'], $nameTypes['firstname_ini'], $hash);
+                              $hash);
 
             if ($res->numRows() == 1) {
                 $subState->merge($res->fetchOneRow());
@@ -281,25 +278,21 @@ class RegisterModule extends PLModule
             return PL_FORBIDDEN;
         }
 
-        $nameTypes = DirEnum::getOptions(DirEnum::NAMETYPES);
-        $nameTypes = array_flip($nameTypes);
-
         // Retrieve the pre-registration information using the url-provided
         // authentication token.
         $res = XDB::query("SELECT  r.uid, p.pid, r.forlife, r.bestalias, r.mailorg2,
                                    r.password, r.email, r.services, r.naissance,
-                                   pnl.name AS lastname, pnf.name AS firstname, pe.promo_year,
+                                   ppn.lastname_initial, ppn.firstname_initial, pe.promo_year,
                                    pd.promo, p.sex, p.birthdate_ref, a.type
                              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))
                        INNER JOIN  profiles         AS p   ON (p.pid = ap.pid)
-                       INNER JOIN  profile_name     AS pnl ON (p.pid = pnl.pid AND pnl.typeid = {?})
-                       INNER JOIN  profile_name     AS pnf ON (p.pid = pnf.pid AND pnf.typeid = {?})
+                       INNER JOIN  profile_public_names AS ppn ON (ppn.pid = p.pid)
                        INNER JOIN  profile_display  AS pd  ON (p.pid = pd.pid)
                        INNER JOIN  profile_education AS pe ON (pe.pid = p.pid AND FIND_IN_SET('primary', pe.flags))
                             WHERE  hash = {?} AND hash != 'INSCRIT' AND a.state = 'pending'",
-                          $nameTypes['name_ini'], $nameTypes['firstname_ini'], $hash);
+                          $hash);
         if (!$hash || $res->numRows() == 0) {
             $page->kill("<p>Cette adresse n'existe pas, ou plus, sur le serveur.</p>
                          <p>Causes probables&nbsp;:</p>
index 45767f5..edee012 100644 (file)
@@ -151,16 +151,11 @@ class XnetEventsModule extends PLModule
                 $e['topay'] += $m['nb'] * $m['montant'];
             }
 
-            $query = XDB::query(
-                "SELECT amount
+            $montant = XDB::fetchOneCell(
+                "SELECT SUM(amount) as sum_amount
                    FROM payment_transactions AS t
                  WHERE ref = {?} AND uid = {?}", $e['paiement_id'], S::v('uid'));
-            $montants = $query->fetchColumn();
-
-            foreach ($montants as $m) {
-                $p = strtr(substr($m, 0, strpos($m, 'EUR')), ',', '.');
-                $e['paid'] += trim($p);
-            }
+            $e['paid'] += $montant;
 
             make_event_date($e);
 
@@ -635,8 +630,7 @@ class XnetEventsModule extends PLModule
                                            GROUP BY  p.uid', $evt['eid']);
 
         $ofs = Env::i('offset');
-        $tot = (is_null($evt['nb_tot']) ? $evt['nb'] : $evt['nb_tot']);
-        $nbp = ceil($tot / NB_PER_PAGE);
+        $nbp = ceil($evt['user_count'] / NB_PER_PAGE);
         if ($nbp > 1) {
             $links = array();
             if ($ofs) {
index cc95c4d..c60b938 100644 (file)
@@ -27,7 +27,7 @@ function get_event_detail($eid, $item_id = false, $asso_id = null)
     if (is_null($asso_id)) {
         $asso_id = $globals->asso('id');
     }
-    $evt = XDB::fetchOneAssoc('SELECT  SUM(nb) AS nb_tot, COUNT(DISTINCT ep.uid) AS nb, e.*,
+    $evt = XDB::fetchOneAssoc('SELECT  SUM(nb) AS nb_tot, COUNT(DISTINCT ep.uid) AS nb, e.*, SUM(IF(nb > 0, 1, 0)) AS user_count,
                                        IF(e.deadline_inscription,
                                           e.deadline_inscription >= LEFT(NOW(), 10),
                                           1) AS inscr_open,
@@ -80,16 +80,12 @@ function get_event_detail($eid, $item_id = false, $asso_id = null)
         $evt['notify_payment'] = $evt['notify_payment'] || $m['notify_payment'];
     }
 
-    $montants = XDB::fetchColumn('SELECT  amount
+    $montant = XDB::fetchOneCell('SELECT  SUM(amount) AS sum_amount
                                     FROM  payment_transactions AS t
                                    WHERE  ref = {?} AND uid = {?}',
                                    $evt['paiement_id'], S::v('uid'));
-    $evt['telepaid'] = 0;
-    foreach ($montants as $m) {
-        $p = strtr(substr($m, 0, strpos($m, 'EUR')), ',', '.');
-        $evt['paid'] += trim($p);
-        $evt['telepaid'] += trim($p);
-    }
+    $evt['telepaid'] = $montant;
+    $evt['paid'] += $montant;
     $evt['organizer'] = User::getSilent($evt['uid']);
 
     make_event_date($evt);
@@ -102,7 +98,7 @@ function get_event_detail($eid, $item_id = false, $asso_id = null)
 // }}}
 
 // {{{ function get_event_participants()
-function get_event_participants(&$evt, $item_id, array $tri = array(), $limit = null)
+function get_event_participants(&$evt, $item_id, array $tri = array(), $limit = null, $offset = 0)
 {
     global $globals;
 
@@ -117,7 +113,7 @@ function get_event_participants(&$evt, $item_id, array $tri = array(), $limit =
                                          WHERE  ep.eid = {?} AND nb > 0 ' . $append . '
                                       GROUP BY  ep.uid', $eid);
     $uf = new UserFilter(new PFC_True(), $tri);
-    $users = User::getBulkUsersWithUIDs($uf->filter(array_keys($query), new PlLimit($count, $offset)));
+    $users = User::getBulkUsersWithUIDs($uf->filter(array_keys($query), new PlLimit($limit, $offset)));
     $tab = array();
     foreach ($users as $user) {
         $uid = $user->id();
@@ -137,14 +133,11 @@ function get_event_participants(&$evt, $item_id, array $tri = array(), $limit =
         $u['adminpaid'] = $u['paid'];
         $u['montant'] = 0;
         if ($money && $pay_id) {
-            $montants = XDB::fetchColumn('SELECT  amount
+            $montant = XDB::fetchOneCell('SELECT  SUM(amount)
                                             FROM  payment_transactions AS t
                                            WHERE  ref = {?} AND uid = {?}',
                                          $pay_id, $uid);
-            foreach ($montants as $m) {
-                $p = strtr(substr($m, 0, strpos($m, "EUR")), ",", ".");
-                $u['paid'] += trim($p);
-            }
+            $u['paid'] += $montant;
         }
         $u['telepayment'] = $u['paid'] - $u['adminpaid'];
         $res_ = XDB::iterator('SELECT  ep.nb, ep.item_id, ei.montant
index 4b5e9f6..41fe737 100644 (file)
@@ -970,10 +970,10 @@ class XnetGrpModule extends PLModule
             list($lastname, $firstname) = str_replace(array('-', ' ', "'"), '%', array(Env::t('nom'), Env::t('prenom')));
             $cond = new PFC_And(new PFC_Not(new UFC_Registered()));
             if (!empty($lastname)) {
-                $cond->addChild(new UFC_Name(Profile::LASTNAME, $lastname, UFC_Name::CONTAINS));
+                $cond->addChild(new UFC_NameTokens($lastname, array(), false, false, Profile::LASTNAME));
             }
             if (!empty($firstname)) {
-                $cond->addChild(new UFC_Name(Profile::FIRSTNAME, $firstname, UFC_Name::CONTAINS));
+                $cond->addChild(new UFC_NameTokens($firstname, array(), false, false, Profile::FIRSTNAME));
             }
             if (Env::t('promo')) {
                 $cond->addChild(new UFC_Promo('=', UserFilter::DISPLAY, Env::t('promo')));
diff --git a/templates/admin/add_secondary_edu.tpl b/templates/admin/add_secondary_edu.tpl
new file mode 100644 (file)
index 0000000..7616d46
--- /dev/null
@@ -0,0 +1,72 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  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>Ajout de formations secondaires</h1>
+
+<form action="{$platal->pl_self()}" method="post">
+<table class="tinybicol" style="margin-bottom: 1em">
+  <tr>
+    <td>
+      <strong>Promotion&nbsp;:</strong>
+    </td>
+    <td>
+      <input type="text" name="promotion" size="4" maxlength="4" {if t($promotion)}value="{$promotion}"{/if} />
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <strong>Formation&nbsp;:</strong>
+    </td>
+    <td>
+      <label><input type="radio" name="degree" value="Master" {if !t($degree) || $degree eq "Master"}checked="checked"{/if} /> master</label> -
+      <label><input type="radio" name="degree" value="Doctorat" {if t($degree) && $degree eq "Doctorat"}checked="checked"{/if} /> doctorat</label>
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <strong>Forcer l'ajout&nbsp;:</strong><br /><small>(en cas de formation du même niveau préexistante)</small>
+    </td>
+    <td>
+      <input type="checkbox" name="force_addition" />
+    </td>
+  </tr>
+</table>
+
+<table class="bicol">
+  <tr>
+    <td>Nom</td>
+    <td>Prénom</td>
+    <td>Promotion principale</td>
+  </tr>
+  <tr>
+    <td colspan="3"><textarea name="people" rows="20" cols="80">{if t($people)}{$people}{/if}</textarea></td>
+  </tr>
+</table>
+
+<p class="center">
+  <strong>Séparateur&nbsp;:</strong>
+  <input type="text" name="separator" value=";" size="1" maxlength="1" /><br /><br />
+  <input type="submit" name="verify" value="Vérifier" />&nbsp;&nbsp;&nbsp;&nbsp;<input type="submit" name="add" value="Ajouter" />
+</p>
+</form>
+
+{* vim:set et sws=2 sts=2 sw=2 enc=utf-8: *}
index fbb6ad3..7132a26 100644 (file)
     </td>
   </tr>
   <tr class="impair">
-    <td class="titre">Promotions</td>
+    <td class="titre">Formations</td>
     <td>
       <a href="admin/phd">Doctorants</a>
+      &nbsp;&nbsp;|&nbsp;&nbsp;
+      <a href="admin/add_secondary_edu">Ajout de formation</a>
     </td>
   </tr>
 
       &nbsp;&nbsp;|&nbsp;&nbsp;
       <a href="admin/sections">Sections</a>
       &nbsp;&nbsp;|&nbsp;&nbsp;
-      <a href="admin/names">Noms</a>
-      &nbsp;&nbsp;|&nbsp;&nbsp;
       <a href="admin/networking">Networking</a>
       &nbsp;&nbsp;|&nbsp;&nbsp;
       <a href="admin/profile">Modifications récentes</a>
index 57383a7..2e33212 100644 (file)
   <td class="titre">Nouvel alias&nbsp;:</td>
   <td>{$valid->new_alias}</td>
 </tr>
-{foreach from=$valid->sn_new item=sn key=typeid}
+{foreach from=$valid->public_names item=name key=type}
 <tr class="impair">
-  <td class="titre">*{$valid->sn_types.$typeid}&nbsp;:</td>
-  <td>{$sn.name}</td>
+  <td class="titre">*{$valid->descriptions.$type}&nbsp;:</td>
+  <td>{$name}</td>
 </tr>
 {/foreach}
-{foreach from=$valid->sn_old item=sn key=typeid}
+{foreach from=$valid->old_public_names item=name key=type}
 <tr class="impair">
-  <td class="titre">&#8224;{$valid->sn_types.$typeid}&nbsp;:</td>
-  <td>{$sn.name}</td>
+  <td class="titre">&#8224;{$valid->descriptions.$type}&nbsp;:</td>
+  <td>{$name}</td>
 </tr>
 {/foreach}
 <tr class="impair">
index 1b40c17..69b0bc7 100644 (file)
@@ -167,8 +167,8 @@ function payment_submit(form)
 <tr><th>Date</th><th>Montant</th></tr>
 {iterate from=$transactions item=t}
   <tr class="{cycle values="pair,impair"}">
-    <td>{$t.timestamp|date_format}</td>
-    <td>{$t.amount|replace:'EUR':'&euro;'}</td>
+    <td>{$t.ts_confirmed|date_format}</td>
+    <td>{$t.amount|replace:'.':','} &euro;</td>
   </tr>
 {/iterate}
 </table>
@@ -187,7 +187,7 @@ function payment_submit(form)
   {foreach from=$donations item=d}
   <tr class="{cycle values="pair,impair"}">
     <td>{$d.name}</td>
-    <td class="center">{$d.amount|replace:'EUR':'&euro;'}</td>
+    <td class="center">{$d.amount|replace:'.':','} &euro;</td>
   </tr>
   {/foreach}
 </table>
index 89dddb1..1ab4219 100644 (file)
@@ -139,7 +139,7 @@ il suffit de cliquer sur le titre de la colonne concernée.
     </td>
     <td class="center">{$p.user->promo()}</td>
     <td>{$p.comment|comment_decode}</td>
-    <td class="right">{$p.amount}</td>
+    <td class="right">{$p.amount|replace:'.':','} &euro;</td>
   </tr>
   {elseif $smarty.foreach.people.first}
   <tr>
@@ -148,7 +148,7 @@ il suffit de cliquer sur le titre de la colonne concernée.
   {else}
   <tr class="pair">
     <td class="right" colspan="5"><strong>Total </strong></td>
-    <th class="right">{$p.amount}</th>
+    <th class="right">{$p.amount|replace:'.':','} &euro;</th>
   </tr>
   {/if}
   {/foreach}
diff --git a/templates/profile/general.private_name.tpl b/templates/profile/general.private_name.tpl
new file mode 100644 (file)
index 0000000..15dbeda
--- /dev/null
@@ -0,0 +1,44 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+{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}>
+  <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]">
+    {foreach from=$other_names item=description key=type}
+      <option value="{$type}">{$description}</option>
+    {/foreach}
+    </select>
+    {/if}
+  </td>
+  <td>
+    {if !t($new_name)}<input type="hidden" name="search_names[private_names][{$id}][type]" value="{$type}" />{/if}
+    <input type="text" name="search_names[private_names][{$id}][name]" value="{$name.name}"
+      size="25" onkeyup="updateNameDisplay({$isFemale});"/>
+  </td>
+  <td>
+    <a href="javascript:removeSearchName({$id}, {$isFemale})">{icon name=cross title="Supprimer ce nom"}</a>
+  </td>
+</tr>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/profile/general.public_names.tpl b/templates/profile/general.public_names.tpl
new file mode 100644 (file)
index 0000000..adbdb12
--- /dev/null
@@ -0,0 +1,57 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+{foreach from=$lastnames key=suffix item=description}
+{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}>
+  <td>
+    <span class="flags">{icon name="flag_green" title="site public"}</span>&nbsp;{$description}
+  </td>
+  <td>
+    <input type="text" name="search_names[public_names][{$type}]" value="{$names.$type}"
+      title="Coche la case en bout de ligne si ton nom commence par une particule."
+      {if t($names.$error)} class="error"{/if} size="25" onkeyup="updateNameDisplay({$isFemale});"/>
+  </td>
+  <td>
+    <input type="checkbox"{if t($names.$particle) neq ''} checked="checked"{/if}
+      title="Coche cette case si ton nom commence par une particule." />
+  </td>
+</tr>
+{/foreach}
+
+{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}>
+  <td>
+    <span class="flags">{icon name="flag_green" title="site public"}</span>&nbsp;{$description}
+  </td>
+  <td>
+    <input type="text" name="search_names[public_names][{$type}]" value="{$names.$type}"
+      {if t($names.$error)} class="error"{/if} size="25" onkeyup="updateNameDisplay({$isFemale});" />
+  </td>
+  <td></td>
+</tr>
+{/foreach}
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/profile/general.searchname.tpl b/templates/profile/general.searchname.tpl
deleted file mode 100644 (file)
index 8ede1d9..0000000
+++ /dev/null
@@ -1,65 +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               *}
-{*                                                                        *}
-{**************************************************************************}
-
-<tr id="search_name_{$i}"{if t($class)} class="{$class}" {if !t($error_name)}style="{$style}"{/if}{/if}>
-  <td>
-    <input type="hidden" name="search_names[{$i}][always_displayed]" value="{$sn.always_displayed}"/>
-    <input type="hidden" name="search_names[{$i}][has_particle]" value="{$sn.has_particle}"/>
-    <span class="flags">
-      <span id="flag_{$i}">{if $sn.pub}{icon name="flag_green" title="site public"}
-      {else}{icon name="flag_red" title="site privé"}{/if}</span>
-    </span>&nbsp;
-    {if t($sn_type_list)}
-    <select id="search_name_select_{$i}" name="search_names[{$i}][typeid]"
-      onchange="changeNameFlag({$i});updateNameDisplay({$isFemale});">
-        {foreach from=$sn_type_list item=sn_type}
-          <option value="{$sn_type.id}">{$sn_type.name}</option>
-        {/foreach}
-    </select>
-    {foreach from=$sn_type_list item=sn_type}
-    <input type="hidden" name="sn_type_{$sn_type.id}_{$i}" value="{$sn_type.pub}"/>
-    {/foreach}
-    {else}
-    {$sn.type_name}
-    <input type="hidden" name="search_names[{$i}][pub]" value="{$sn.pub}"/>
-    <input type="hidden" name="search_names[{$i}][type]" value="{$sn.type}"/>
-    <input type="hidden" name="search_names[{$i}][type_name]" value="{$sn.type_name}"/>
-    <input type="hidden" name="search_names[{$i}][typeid]" value="{$sn.typeid}"/>
-    {/if}
-  </td>
-  <td>
-    <input type="text" name="search_names[{$i}][name]" value="{$sn.name}"
-      {if $sn.has_particle}title="Coche la case en bout de ligne si ton nom commence par une particule."{/if}
-      {if t($sn.error)} class="error"{/if} size="25" onkeyup="updateNameDisplay({$isFemale});"/>
-  </td>
-  <td>
-    {if $sn.has_particle}<input type="checkbox"{if $sn.particle neq ''} checked="checked"{/if}
-      title="Coche cette case si ton nom commence par une particule." onchange="toggleParticle({$i});"/>
-    {/if}
-    <input type="hidden"  name="search_names[{$i}][particle]" value="{$sn.particle}"/>
-    {if !$sn.always_displayed}<a href="javascript:removeSearchName({$i},{$isFemale})">
-      {icon name=cross title="Supprimer ce nom"}
-    </a>{/if}
-  </td>
-</tr>
-
-{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index e23aec5..f0ddda7 100644 (file)
       <span class="titre">Gestion des noms, prénoms, surnoms...</span>
       <span class="smaller">Ils déterminent la façon dont
       {if $isMe}ton{else}son{/if} nom apparaît sur les annuaires
-      en ligne et papier et ta fiche apparaitra quand on cherche un de ces noms. Pour plus
-      d'explications sur l'icône suivante
-      <a href="profile/name_info" class="popup3">{icon name="information" title="Plus d'infos"}</a>.</span><br/>
+      en ligne et papier et ta fiche apparaitra quand on cherche un de ces noms.</span><br/>
       <div class="small center">Si un de tes noms commence par une particule,
       coche la case en bout de ligne.</div>
     </td>
   </tr>
-  {foreach from=$search_names item=sn key=id}
-    {include file="profile/general.searchname.tpl" i=$id sn=$sn
-    class="names_advanced" style="display: none" error_name=$errors.search_names}
+  {include file="profile/general.public_names.tpl" names=$search_names.public_names}
+  {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}>
     <td colspan="3">
index 4ed095d..c27462d 100644 (file)
@@ -97,7 +97,7 @@ Ils ont payé mais ont oublié de s'inscrire&nbsp;:
       <a href="https://www.polytechnique.org/vcard/{$m.user->login()}.vcf">{icon name=vcard title="vcard"}</a>
       <a href="mailto:{$m.user->bestEmail()}">{icon name=email title="email"}</a>
     </td>
-    <td>{$m.amount}</td>
+    <td>{$m.amount|replace:'.':','} &euro;</td>
   </tr>
   {/foreach}
 </table>
index 6252fbd..0196b9a 100644 (file)
@@ -55,26 +55,6 @@ CREATE TABLE payment_reconcilations (
   comments text NOT NULL
 ) ENGINE=InnoDB, CHARSET=utf8;
 
-ALTER TABLE payment_transactions ADD method_id INTEGER DEFAULT NULL AFTER id; # NULL if not initiated from the site
-ALTER TABLE payment_transactions CHANGE timestamp ts_confirmed DATETIME DEFAULT NULL; # NULL = not confirmed
-ALTER TABLE payment_transactions ADD ts_initiated DATETIME DEFAULT NULL AFTER ts_confirmed; # NULL = not initiated
-ALTER TABLE payment_transactions CHANGE amount amount_tmp VARCHAR(15);
-ALTER TABLE payment_transactions ADD amount DECIMAL(9,2) NOT NULL AFTER amount_tmp; # only local currency allowed (EUR)
-ALTER TABLE payment_transactions ADD commission DECIMAL(9,2) DEFAULT NULL AFTER amount;
-ALTER TABLE payment_transactions ADD status ENUM('confirmed','pending','canceled') NOT NULL DEFAULT 'pending';
-ALTER TABLE payment_transactions ADD recon_id INTEGER DEFAULT NULL; # NULL = not reconciliated
-UPDATE payment_transactions SET method_id = 0 WHERE length(id)=7;
-UPDATE payment_transactions SET method_id = 1 WHERE length(id)=15 OR length(id)=17;
-UPDATE payment_transactions SET method_id = 2 WHERE length(id)=14;
-UPDATE payment_transactions SET status = 'confirmed';
-UPDATE payment_transactions SET amount=CONVERT(REPLACE(REPLACE(amount_tmp," EUR",""),",","."),DECIMAL(9,2));
-ALTER TABLE payment_transactions ADD KEY method_id (method_id);
-ALTER TABLE payment_transactions ADD KEY ref (ref);
-# ALTER TABLE payment_transactions ADD UNIQUE KEY fullref (fullref);
-#fullref dupliqués :
-#select t1.* from payment_transactions as t1 join payment_transactions as t2 using(fullref) group by(t1.id) having count(*)!=1 order by fullref;
-ALTER TABLE payment_transactions DROP amount_tmp;
-
 DROP TABLE IF EXISTS payment_transfers;
 CREATE TABLE payment_transfers (
   id INTEGER PRIMARY KEY auto_increment,
index 64359f7..99332d3 100644 (file)
@@ -1,4 +1,25 @@
-ALTER TABLE payments MODIFY COLUMN flags SET('unique', 'old', 'donation') NOT NULL DEFAULT '';
+ALTER TABLE payment_transactions ADD method_id INTEGER DEFAULT NULL AFTER id; # NULL if not initiated from the site
+ALTER TABLE payment_transactions CHANGE timestamp ts_confirmed DATETIME DEFAULT NULL; # NULL = not confirmed
+ALTER TABLE payment_transactions ADD ts_initiated DATETIME DEFAULT NULL AFTER ts_confirmed; # NULL = not initiated
+ALTER TABLE payment_transactions CHANGE amount amount_tmp VARCHAR(15);
+ALTER TABLE payment_transactions ADD amount DECIMAL(9,2) NOT NULL AFTER amount_tmp; # only local currency allowed (EUR)
+ALTER TABLE payment_transactions ADD commission DECIMAL(9,2) DEFAULT NULL AFTER amount;
+ALTER TABLE payment_transactions ADD status ENUM('confirmed','pending','canceled') NOT NULL DEFAULT 'pending';
+ALTER TABLE payment_transactions ADD recon_id INTEGER DEFAULT NULL; # NULL = not reconciliated
+UPDATE payment_transactions SET method_id = 0 WHERE length(id)=7;
+UPDATE payment_transactions SET method_id = 1 WHERE length(id)=15 OR length(id)=17;
+UPDATE payment_transactions SET method_id = 2 WHERE length(id)=14;
+UPDATE payment_transactions SET status = 'confirmed';
+UPDATE payment_transactions SET amount=CONVERT(REPLACE(REPLACE(amount_tmp," EUR",""),",","."),DECIMAL(9,2));
+ALTER TABLE payment_transactions ADD KEY method_id (method_id);
+ALTER TABLE payment_transactions ADD KEY ref (ref);
+# ALTER TABLE payment_transactions ADD UNIQUE KEY fullref (fullref);
+#fullref dupliqués :
+#select t1.* from payment_transactions as t1 join payment_transactions as t2 using(fullref) group by(t1.id) having count(*)!=1 order by fullref;
+ALTER TABLE payment_transactions DROP amount_tmp;
+
 ALTER TABLE payment_transactions ADD COLUMN display BOOL NOT NULL DEFAULT FALSE;
+ALTER TABLE payments MODIFY COLUMN flags SET('unique', 'old', 'donation') NOT NULL DEFAULT '';
 
 -- vim:set syntax=mysql:
+
diff --git a/upgrade/1.1.2/03_names.sql b/upgrade/1.1.2/03_names.sql
new file mode 100644 (file)
index 0000000..1f4ac25
--- /dev/null
@@ -0,0 +1,106 @@
+DROP TABLE IF EXISTS profile_public_names;
+CREATE TABLE IF NOT EXISTS profile_public_names (
+  pid INT(11) UNSIGNED NOT NULL DEFAULT 0,
+  particles SET('initial', 'main', 'marital', 'ordinary') NOT NULL DEFAULT '',
+  lastname_initial VARCHAR(255) NOT NULL DEFAULT '',
+  lastname_main VARCHAR(255) NOT NULL DEFAULT '',
+  lastname_marital VARCHAR(255) NOT NULL DEFAULT '',
+  lastname_ordinary VARCHAR(255) NOT NULL DEFAULT '',
+  firstname_initial VARCHAR(255) NOT NULL DEFAULT '',
+  firstname_main VARCHAR(255) NOT NULL DEFAULT '',
+  firstname_ordinary VARCHAR(255) NOT NULL DEFAULT '',
+  pseudonym VARCHAR(255) NOT NULL DEFAULT '',
+  PRIMARY KEY (pid),
+  FOREIGN KEY (pid) REFERENCES profiles (pid) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS profile_private_names;
+CREATE TABLE IF NOT EXISTS profile_private_names (
+  pid INT(11) UNSIGNED NOT NULL DEFAULT 0,
+  type ENUM('lastname', 'firstname', 'nickname') NOT NULL DEFAULT 'nickname',
+  id TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'id of the name among those sharing the same pid / general_type',
+  name VARCHAR(255) NOT NULL DEFAULT '',
+  PRIMARY KEY (pid, type, id),
+  FOREIGN KEY (pid) REFERENCES profiles (pid) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Initiates profile_public_names.
+INSERT INTO  profile_public_names (pid)
+     SELECT  pid
+       FROM  profiles;
+
+-- Insert lastnames.
+    UPDATE  profile_public_names AS ppn
+INNER JOIN  profile_name         AS pn  ON (pn.pid = ppn.pid)
+INNER JOIN  profile_name_enum    AS pne ON (pn.typeid = pne.id)
+       SET  ppn.lastname_initial = IF(pn.particle = '', pn.name, CONCAT(pn.particle, ' ', pn.name)),
+            ppn.particles = IF(pn.particle = '', '', 'initial')
+     WHERE  pne.type = 'name_ini';
+    UPDATE  profile_public_names AS ppn
+INNER JOIN  profile_name         AS pn  ON (pn.pid = ppn.pid)
+INNER JOIN  profile_name_enum    AS pne ON (pn.typeid = pne.id)
+       SET  ppn.lastname_main = IF(pn.particle = '', pn.name, CONCAT(pn.particle, ' ', pn.name)),
+            ppn.particles = IF(pn.particle = '', ppn.particles, CONCAT_WS(',', ppn.particles, 'main'))
+     WHERE  pne.type = 'lastname';
+UPDATE  profile_public_names
+   SET  particles = TRIM(BOTH ',' FROM particles);
+    UPDATE  profile_public_names AS ppn
+INNER JOIN  profile_name         AS pn  ON (pn.pid = ppn.pid)
+INNER JOIN  profile_name_enum    AS pne ON (pn.typeid = pne.id)
+       SET  ppn.lastname_marital = IF(pn.particle = '', pn.name, CONCAT(pn.particle, ' ', pn.name)),
+            ppn.particles = IF(pn.particle = '', ppn.particles, CONCAT_WS(',', ppn.particles, 'marital'))
+     WHERE  pne.type = 'lastname_marital';
+UPDATE  profile_public_names
+   SET  particles = TRIM(BOTH ',' FROM particles);
+    UPDATE  profile_public_names AS ppn
+INNER JOIN  profile_name         AS pn  ON (pn.pid = ppn.pid)
+INNER JOIN  profile_name_enum    AS pne ON (pn.typeid = pne.id)
+       SET  ppn.lastname_ordinary = IF(pn.particle = '', pn.name, CONCAT(pn.particle, ' ', pn.name)),
+            ppn.particles = IF(pn.particle = '', ppn.particles, CONCAT_WS(',', ppn.particles, 'ordinary'))
+     WHERE  pne.type = 'lastname_ordinary';
+UPDATE  profile_public_names
+   SET  particles = TRIM(BOTH ',' FROM particles);
+
+-- Insert other names.
+    UPDATE  profile_public_names AS ppn
+INNER JOIN  profile_name         AS pn  ON (pn.pid = ppn.pid)
+INNER JOIN  profile_name_enum    AS pne ON (pn.typeid = pne.id)
+       SET  ppn.firstname_initial = pn.name
+     WHERE  pne.type = 'firstname_ini';
+    UPDATE  profile_public_names AS ppn
+INNER JOIN  profile_name         AS pn  ON (pn.pid = ppn.pid)
+INNER JOIN  profile_name_enum    AS pne ON (pn.typeid = pne.id)
+       SET  ppn.firstname_main = pn.name
+     WHERE  pne.type = 'firstname';
+    UPDATE  profile_public_names AS ppn
+INNER JOIN  profile_name         AS pn  ON (pn.pid = ppn.pid)
+INNER JOIN  profile_name_enum    AS pne ON (pn.typeid = pne.id)
+       SET  ppn.firstname_ordinary = pn.name
+     WHERE  pne.type = 'firstname_other';
+    UPDATE  profile_public_names AS ppn
+INNER JOIN  profile_name         AS pn  ON (pn.pid = ppn.pid)
+INNER JOIN  profile_name_enum    AS pne ON (pn.typeid = pne.id)
+       SET  ppn.pseudonym = pn.name
+     WHERE  pne.type = 'pseudonym';
+
+-- Insert privates names.
+INSERT INTO  profile_private_names (pid, type, id, name)
+     SELECT  pn.pid, 'nickname', 0, pn.name
+       FROM  profile_name      AS pn
+ INNER JOIN  profile_name_enum AS pne ON (pn.typeid = pne.id)
+      WHERE  pne.type = 'nickname';
+INSERT INTO  profile_private_names (pid, type, id, name)
+     SELECT  pn.pid, 'lastname', 0, pn.name
+       FROM  profile_name      AS pn
+ INNER JOIN  profile_name_enum AS pne ON (pn.typeid = pne.id)
+      WHERE  pne.type = 'name_other';
+INSERT INTO  profile_private_names (pid, type, id, name)
+     SELECT  pn.pid, 'firstname', 0, pn.name
+       FROM  profile_name      AS pn
+ INNER JOIN  profile_name_enum AS pne ON (pn.typeid = pne.id)
+      WHERE  pne.type = 'firstname_other';
+
+DROP TABLE IF EXISTS profile_name;
+DROP TABLE IF EXISTS profile_name_enum;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.2/04_education.sql b/upgrade/1.1.2/04_education.sql
new file mode 100644 (file)
index 0000000..9249af7
--- /dev/null
@@ -0,0 +1,57 @@
+-- Adds secondary education.
+
+ALTER TABLE profile_education MODIFY COLUMN flags SET('primary', 'secondary', 'completed') NOT NULL DEFAULT '';
+
+    UPDATE  profile_education      AS pe
+INNER JOIN  profile_education_enum AS pen ON (pe.eduid = pen.id)
+       SET  pe.flags = IF(pe.flags = '', 'secondary', 'secondary,completed')
+     WHERE  pen.abbreviation = 'X' AND NOT FIND_IN_SET('primary', flags);
+
+-- Updates secondary education details.
+
+UPDATE  profile_education
+   SET  degreeid = 33
+ WHERE  FIND_IN_SET('secondary', flags) AND (degreeid = 4 OR degreeid = 6);
+
+UPDATE  profile_education
+   SET  degreeid = 5
+ WHERE  FIND_IN_SET('secondary', flags) AND degreeid IS NULL;
+
+UPDATE  profile_education
+   SET  promo_year = grad_year
+ WHERE  FIND_IN_SET('secondary', flags);
+
+-- Removes duplicates.
+    DELETE  e1
+      FROM  profile_education AS e1
+INNER JOIN  profile_education AS e2 ON (e1.pid = e2.pid AND e1.degreeid = e2.degreeid AND e1.id < e2.id
+                                        AND FIND_IN_SET('secondary', e1.flags) AND FIND_IN_SET('secondary', e2.flags))
+     WHERE  e1.fieldid IS NULL AND e1.program IS NULL;
+    DELETE  e1
+      FROM  profile_education AS e1
+INNER JOIN  profile_education AS e2 ON (e1.pid = e2.pid AND e1.degreeid = e2.degreeid AND e1.id > e2.id
+                                        AND FIND_IN_SET('secondary', e1.flags) AND FIND_IN_SET('secondary', e2.flags))
+     WHERE  e1.fieldid IS NULL AND e1.program IS NULL;
+
+-- Updates secondary education ids.
+   UPDATE  profile_education AS e1
+LEFT JOIN  profile_education AS e2 ON (e1.pid = e2.pid AND e1.degreeid = e2.degreeid AND e1.id != e2.id AND FIND_IN_SET('secondary', e2.flags))
+      SET  e1.id = 101
+    WHERE  FIND_IN_SET('secondary', e1.flags) AND e1.degreeid = 33 AND e2.pid IS NULL;
+
+    UPDATE  profile_education AS e1
+INNER JOIN  profile_education AS e2 ON (e1.pid = e2.pid AND e1.degreeid = e2.degreeid AND e1.id > e2.id)
+       SET  e1.id = 101, e2.id = 102
+     WHERE  FIND_IN_SET('secondary', e1.flags) AND FIND_IN_SET('secondary', e2.flags) AND e1.degreeid = 33;
+
+   UPDATE  profile_education AS e1
+LEFT JOIN  profile_education AS e2 ON (e1.pid = e2.pid AND e2.degreeid = 33 AND FIND_IN_SET('secondary', e2.flags))
+      SET  e1.id = 101
+    WHERE  FIND_IN_SET('secondary', e1.flags) AND e1.degreeid = 5 AND e2.pid IS NULL;
+
+    UPDATE  profile_education AS e1
+INNER JOIN  profile_education AS e2 ON (e1.pid = e2.pid AND e2.degreeid = 33)
+       SET  e1.id = 102
+     WHERE  FIND_IN_SET('secondary', e1.flags) AND FIND_IN_SET('secondary', e2.flags) AND e1.degreeid = 5;
+
+-- vim:set syntax=mysql:
index 5cbee98..03f5fe5 100644 (file)
@@ -1,3 +1,8 @@
+Check that the following queries return the same results before updating:
+SELECT COUNT(*), COUNT(DISTINCT(pid)) FROM profile_name AS pn INNER JOIN profile_name_enum AS pne ON (pn.typeid = pne.id) WHERE pne.type = 'nickname';
+SELECT COUNT(*), COUNT(DISTINCT(pid)) FROM profile_name AS pn INNER JOIN profile_name_enum AS pne ON (pn.typeid = pne.id) WHERE pne.type = 'name_other';
+SELECT COUNT(*), COUNT(DISTINCT(pid)) FROM profile_name AS pn INNER JOIN profile_name_enum AS pne ON (pn.typeid = pne.id) WHERE pne.type = 'firstname_other';
+
 Once all sql/php scripts have be run, run retrieve_address_tables.sh and finally xx_retrieve_geocoding.sql.
 Then "./formatAddresses.php -g -t g -r e" will format the last ungeocoded addresses.
 
diff --git a/upgrade/1.1.2/names.php b/upgrade/1.1.2/names.php
new file mode 100755 (executable)
index 0000000..b6d74d3
--- /dev/null
@@ -0,0 +1,162 @@
+#!/usr/bin/php5
+<?php
+
+require_once 'connect.db.inc.php';
+require_once 'name.func.inc.php';
+
+$globals->debug = 0; // Do not store backtraces.
+
+$options = getopt('', array('perform-updates::'));
+if (isset($options['perform-updates']) && $options['perform-updates'] == 'YES') {
+    $perform_updates = true;
+} else {
+    $perform_updates = false;
+}
+
+$other_data = XDB::rawFetchOneCell("SELECT  COUNT(*)
+                                      FROM  profile_name      AS pn
+                                INNER JOIN  profile_name_enum AS pne ON (pn.typeid = pne.id)
+                                     WHERE  pne.type = 'name_other' OR pne.type = 'firstname_other'");
+if ($other_data) {
+    print "Update this script to take 'name_other' and 'firstname_other' into account.";
+    exit();
+} else {
+    $aliases = XDB::fetchAllAssoc('pid', "SELECT  pid, name
+                                            FROM  profile_private_names
+                                           WHERE  type = 'nickname'");
+}
+
+// This contains a firstname and a lastname, both can be either main or ordinary.
+function update_main($data, $string, &$update)
+{
+    $matches = explode(' ', $string);
+    $count = count($matches);
+    $i = 0;
+
+    for (; $i < $count + 1; ++$i) {
+        $firstname = implode(' ', array_slice($matches, 0, $i + 1));
+        $lastname = implode(' ', array_slice($matches, $i + 1));
+        if ($firstname == $data['firstname_main'] || $firstname == $data['firstname_ordinary']) {
+            if ($lastname == $data['lastname_ordinary']) {
+                return true;
+            }
+            if ($lastname != $data['lastname_main'] && $lastname != $data['lastname_ordinary']) {
+                $update[] = XDB::format('lastname_ordinary = {?}', $lastname);
+                return true;
+            }
+            return false;
+        }
+        if ($lastname == $data['lastname_main'] || $lastname == $data['lastname_ordinary']) {
+            if ($firstname != $data['firstname_main'] && $firstname != $data['firstname_ordinary']) {
+                $update[] = XDB::format('firstname_ordinary = {?}', $firstname);
+            }
+            if ($lastname == $data['lastname_ordinary']) {
+                return true;
+            }
+            return false;
+        }
+    }
+    return false;
+}
+
+// This is detected by a starting 'M/Mme'. But it can also include a pseudonym.
+function update_marital($data, $string, &$update)
+{
+    preg_match('/^([^,]+)(?:, (.*))?$/', $string, $matches);
+    if ($matches[1] != $data['lastname_marital']) {
+        $update[] = XDB::format('lastname_marital = {?}', $matches[1]);
+    }
+    if (count($matches) == 3 && $matches[2] != $data['pseudonym']) {
+        $update[] = XDB::format('pseudonym = {?}', $matches[2]);
+    }
+}
+
+function update_private($data, $string, $pid, &$aliases, $perform_updates)
+{
+    // We here assume there are no other last/firstnames as there do not seem to be any in the db.
+    $string = substr($string, 1, strlen($string) - 2);
+    $string = substr($string, 6, strlen($string) - 6);
+
+    if (!isset($aliases[$pid])) {
+        if ($perform_updates) {
+            XDB::execute("INSERT INTO  profile_private_names (pid, type, id, name)
+                               VALUES  ({?}, 'nickname', 0, {?})",
+                         $pid, $string);
+        } else {
+            print $string . ' (alias for pid ' . $pid . ")\n";
+        }
+    } elseif ($aliases[$pid] != $string) {
+        if ($perform_updates) {
+            XDB::execute('UPDATE  profile_private_names
+                             SET  name = {?}
+                           WHERE  pid = {?} AND name = {?}',
+                         $string, $pid, $aliases[$pid]);
+        } else {
+            print $string . ' (new alias for pid ' . $pid . ' replacing ' . $aliases[$pid] . ")\n";
+        }
+
+    }
+}
+
+// This can either be a main name or a pseudonym.
+function update_plain($data, $string, &$update, $has_ordinary)
+{
+    $string = substr($string, 1, strlen($string) - 2);
+    if ($string == $data['lastname_main']) {
+        return true;
+    }
+
+    if ($string != $data['pseudonym']) {
+        if ($has_ordinary) {
+            $update[] = XDB::format('pseudonym = {?}', $string);
+        } else {
+            $update[] = XDB::format('lastname_main = {?}', $string);
+        }
+        return true;
+    }
+    return false;
+}
+
+$res = XDB::rawIterator('SELECT  pd.pid, pd.private_name, pn.lastname_main, pn.lastname_marital, pn.lastname_ordinary,
+                                 pn.firstname_main, pn.firstname_ordinary, pn.pseudonym
+                           FROM  profile_display      AS pd
+                     INNER JOIN  profile_public_names AS pn ON (pd.pid = pn.pid)');
+
+$pattern = '/^([^\(\)]+)(?: (\([^\(\)]+\)))?(?: (\([^\(\)]+\)))?(?: (\([^\(\)]+\)))?$/';
+while ($data = $res->next()) {
+    preg_match($pattern, $data['private_name'], $matches);
+    $has_ordinary = false;
+
+    $count = count($matches);
+    $update = array();
+    $has_ordinary = update_main($data, $matches[1], $update);
+    for ($i = 2; $i < $count; ++$i) {
+        if (preg_match('/^\((?:M|Mme) (.+)\)$/', $matches[$i], $pieces)) {
+            update_marital($data, $pieces[1], $update);
+        } elseif (preg_match('/^\((?:alias|autres prénoms :|autres noms :) .+\)$/', $matches[$i], $pieces)) {
+            update_private($data, $matches[$i], $data['pid'], $aliases, $perform_updates);
+        } else {
+            $has_ordinary = update_plain($data, $matches[$i], $update, $has_ordinary);
+        }
+    }
+
+    if (count($update)) {
+        $set = implode(', ', $update);
+        if ($perform_updates) {
+            XDB::rawExecute('UPDATE  profile_public_names
+                                SET  ' . $set . '
+                              WHERE  pid = ' . $data['pid']);
+        } else {
+            print $set . ' (for pid ' . $data['pid'] . ")\n";
+        }
+    }
+}
+
+if ($perform_updates) {
+    print "\nUpdates done.\n";
+} else {
+    print "\nIf this seems correct, relaunch this script with option --perform-updates=YES.\n";
+}
+
+/* vim:set et sw=4 sts=4 ts=4: */
+?>