Merge branch 'xorg/maint' into xorg/master
authorStéphane Jacob <sj@m4x.org>
Mon, 12 Dec 2011 11:45:49 +0000 (12:45 +0100)
committerStéphane Jacob <sj@m4x.org>
Mon, 12 Dec 2011 11:45:49 +0000 (12:45 +0100)
52 files changed:
ChangeLog
bin/promo_update_help.php [new file with mode: 0755]
classes/profile.php
classes/xorg.php
configs/mails.conf
core
htdocs/css/nl.FX.css [new file with mode: 0644]
htdocs/images/icons/email_open.gif [new file with mode: 0644]
htdocs/javascript/search.js
htdocs/javascript/xnet_members.js [new file with mode: 0644]
include/name.func.inc.php
include/newsletter.inc.php
include/profilefields.inc.php
include/userset.inc.php
include/validations.inc.php
include/validations/account.inc.php
include/validations/bulkaccounts.inc.php
modules/admin.php
modules/fusionax.php
modules/fxletter.php [new file with mode: 0644]
modules/profile/general.inc.php
modules/search.php
modules/xnet.php
modules/xnetevents.php
modules/xnetevents/xnetevents.inc.php
modules/xnetgrp.php
plugins/function.display_address.php
templates/admin/admin_name.tpl [new file with mode: 0644]
templates/admin/index.tpl
templates/fusionax/names.tpl
templates/include/form.valid.account.tpl
templates/include/form.valid.bulk_accounts.tpl
templates/newsletter/nl.FX.mail.tpl [new file with mode: 0644]
templates/profile/general.public_names.tpl
templates/profile/general.tpl
templates/skin/common.menu.tpl
templates/xnetgrp/members_new_form.tpl [new file with mode: 0644]
templates/xnetgrp/membres-add.tpl
templates/xnetgrp/membres-edit.tpl
templates/xnetgrp/membres-new-search.tpl
upgrade/1.0.1/merge.php
upgrade/1.0.1/merge_accent_names.php [new file with mode: 0755]
upgrade/1.0.1/merge_issues.php
upgrade/1.0.1/merge_issues_geocoding.php [deleted file]
upgrade/1.0.1/merge_names.php [new file with mode: 0755]
upgrade/1.1.5/01_names.sql [new file with mode: 0644]
upgrade/1.1.5/02_validate.sql [new file with mode: 0644]
upgrade/1.1.5/03_ax_id.sql [new file with mode: 0644]
upgrade/1.1.5/connect.db.inc.php [new symlink]
upgrade/1.1.5/name.php [new file with mode: 0755]
upgrade/1.1.5/update.sh [new file with mode: 0755]
ut/nametest.php [new file with mode: 0644]

index 34eef48..12158fa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,27 @@
 ================================================================================
+VERSION 1.1.5                                                         XX XX XXXX
+
+Bug/Wish:
+
+    * Search:
+        - #1572: Removes remaining results count from queries              -JAC
+        - #1574: Correctly displays State corps                            -GLN
+
+    * Validations:
+        - #1571: Fixes the opening of the comments panel                   -GLN
+
+    * XnetEvent:
+        - #1577: Fixes alternative payements given by admins               -GLN
+        - #1578: Fixes deletion of people inscriptions                     -GLN
+        - #1348: Keeps the amount paid when updating participation         -GLN
+
+From 1.1.4 branch:
+
+    * XnetEvent:
+        - #1566: Corrects the total number in events                       -GLN
+        - #1567: Payment takes into account the amount when it is given    -GLN
+
+================================================================================
 VERSION 1.1.4                                                         14 11 2011
 
 New:
diff --git a/bin/promo_update_help.php b/bin/promo_update_help.php
new file mode 100755 (executable)
index 0000000..aaf5c27
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/php5 -q
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2011 Polytechnique.org                              *
+ *  http://opensource.polytechnique.org/                                   *
+ *                                                                         *
+ *  This program is free software; you can redistribute it and/or modify   *
+ *  it under the terms of the GNU General Public License as published by   *
+ *  the Free Software Foundation; either version 2 of the License, or      *
+ *  (at your option) any later version.                                    *
+ *                                                                         *
+ *  This program is distributed in the hope that it will be useful,        *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *  GNU General Public License for more details.                           *
+ *                                                                         *
+ *  You should have received a copy of the GNU General Public License      *
+ *  along with this program; if not, write to the Free Software            *
+ *  Foundation, Inc.,                                                      *
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
+ ***************************************************************************/
+
+require './connect.db.inc.php';
+require '../include/name.func.inc.php';
+
+$globals->debug = 0; // Do not store backtraces
+
+$opts = getopt('f:p:');
+
+if (empty($opts['f']) || empty($opts['p'])) {
+    print "File name missing (-f=file_name) or promotion missing (-p=file_name).\n";
+    exit;
+}
+
+$file = $opts['f'];
+$handle = fopen($file, 'r');
+$promo_year = $opts['p'];
+
+$already = array();
+$new = array();
+$ambiguous = array();
+
+while ($line = trim(fgets($handle))) {
+    $data = explode(';', $line);
+    $cond = new PFC_And(new UFC_NameTokens(split_name_for_search($data[0]), array(), false, false, Profile::LASTNAME));
+    $cond->addChild(new UFC_NameTokens(split_name_for_search($data[1]), array(), false, false, Profile::FIRSTNAME));
+    $uf = new UserFilter($cond);
+    $profiles = $uf->getProfiles();
+    switch (count($profiles)) {
+      case 0:
+        $new[] = $line;
+        break;
+      case 1:
+        foreach ($profiles as $profile) {
+            $already[] = $profile->hrid();
+        }
+        break;
+      default:
+        $hrids = array();
+        foreach ($profiles as $profile) {
+            $hrids[] = $profile->hrid();
+        }
+        $ambiguous[] = $line . ': ' . implode(', ', $hrids);
+        break;
+    }
+}
+
+$cond = new UFC_Promo('=', UserFilter::GRADE_MST, $promo_year);
+$uf = new UserFilter($cond);
+$profiles = $uf->getProfiles();
+$promo = array();
+foreach ($profiles as $profile) {
+    $promo[] = $profile->hrid();
+}
+
+$intersect = array_intersect($promo, $already);
+if (count($intersect) != count($already)) {
+    print "There seems to be a problem: intersection of this promo and already found users differ.\n";
+}
+$to_remove = array_diff($promo, $intersect);
+
+sort($new);
+sort($ambiguous);
+sort($to_remove);
+
+print "New users:\n" . implode("\n", $new) . "\n\n";
+print "Ambiguous users:\n" . implode("\n", $ambiguous) . "\n\n";
+print "Users to remove (louk out for ambiguous users before!):\n" . implode("\n", $to_remove) . "\n";
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
index 104702b..b11e31d 100644 (file)
@@ -1227,18 +1227,19 @@ class Profile implements PlExportable
      */
     public static function getAccountEquivalentName($name)
     {
-        switch ($name)
-        {
-        case self::DN_DIRECTORY:
-        case self::DN_SORT:
+        switch ($name) {
+          case self::DN_DIRECTORY:
             return 'directory_name';
-        case self::DN_FULL:
-        case self::DN_PUBLIC:
+          case self::DN_SORT:
+            return 'sort_name';
+          case self::DN_FULL:
+          case self::DN_PUBLIC:
+          case self::DN_PRIVATE:
+          case self::DN_SHORT:
             return 'full_name';
-        case self::DN_PRIVATE:
-        case self::DN_SHORT:
-        case self::DN_YOURSELF:
-        default:
+          case self::DN_YOURSELF:
+            return 'display_name';
+          default:
             return 'display_name';
         }
     }
index c53f31a..17a350a 100644 (file)
@@ -37,6 +37,7 @@ class Xorg extends Platal
             'events',
             'forums',
             'fusionax',
+            'fxletter',
             'gadgets',
             'geoloc',
             'googleapps',
index fc294d4..29d632e 100644 (file)
@@ -44,6 +44,10 @@ to=non-geoloc@staff.polytechnique.org
 from="Amicale des Anciens de l'X" <reponses@amicale.polytechnique.org>
 replyto=reponses@amicale.polytechnique.org
 
+[mails_fx]
+from="Fondation de l'Ecole polytechnique" <reponses@fondationx.fr>
+replyto=reponses@fondationx.fr
+
 [marketing]
 from="Marketing Polytechnique.org" <register@polytechnique.org>
 
diff --git a/core b/core
index 7a6b4d9..6317421 160000 (submodule)
--- a/core
+++ b/core
@@ -1 +1 @@
-Subproject commit 7a6b4d999856fd697015f719dda5909127f899a1
+Subproject commit 6317421644b2c574711b3b12f221e04206f53d3a
diff --git a/htdocs/css/nl.FX.css b/htdocs/css/nl.FX.css
new file mode 100644 (file)
index 0000000..dcbab87
--- /dev/null
@@ -0,0 +1,83 @@
+/***************************************************************************
+ *  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                *
+ ***************************************************************************/
+
+
+div.fx_mail {
+    margin : auto;
+    width : 72ex;
+    font-family : "Georgia", "Times New Roman", serif;
+    font-size : 10pt;
+    text-align : justify;
+    background-color : #fff;
+    color : #000;
+}
+
+/* Links */
+div.fx_mail a[href] {
+    background-color: transparent;
+    color : #444;
+    text-decoration : none;
+    background-image: none;
+}
+
+div.fx_mail a[href]:hover {
+    background-color: transparent;
+    color : #D44;
+    text-decoration : none;
+    background-image: none;
+}
+
+/* Title */
+div.fx_mail .title {
+    background-color: #FA2;
+    margin : 0 0 3ex;
+    padding : 4.5ex 1ex 1ex 15ex;
+    font-size : 130%;
+    font-weight : bold;
+    text-align : left;
+}
+
+/* Intro */
+div.fx_mail div.intro {
+    margin : 4ex 2ex 2ex 2ex;
+}
+
+div.fx_mail div.signature {
+    margin : 3ex 2ex 0 0;
+    font-size : 90%;
+    font-style: italic;
+    text-align : right;
+}
+
+/* Give */
+div.fx_mail div.give {
+    font-weight: bold;
+    text-align: center;
+    padding: 0.5ex 0 0.5ex 0;
+    border-top: solid 2ex #FA2;
+}
+
+/* Footer */
+div.fx_mail div.foot1, div.fx_mail div.foot2 {
+    background-color: #FA2;
+    text-align: center;
+    font-size: 90%;
+    padding: 0.5ex 0;
+}
diff --git a/htdocs/images/icons/email_open.gif b/htdocs/images/icons/email_open.gif
new file mode 100644 (file)
index 0000000..2b72ce7
Binary files /dev/null and b/htdocs/images/icons/email_open.gif differ
index 52870ad..989aee7 100644 (file)
@@ -124,7 +124,10 @@ function display_list(field_name)
 // }}}
 // {{{ Regexps to wipe out from search queries
 
-var default_form_values = [ /&woman=0(&|$)/, /&subscriber=0(&|$)/, /&alive=0(&|$)/, /&egal[12]=[^&]*&promo[12]=(&|$)/g, /&networking_type=0(&|$)/, /&[^&=]+=(&|$)/g ];
+var default_form_values = [ /&woman=0(&|$)/, /&subscriber=0(&|$)/, /&alive=0(&|$)/, /&egal2=[^&]*&promo2=(&|$)/,
+                            /&egal1=[^&]*&promo1=&edu_type=(?:Ing[^n]+nieur|Master|Doctorat)(&|$)/, /&networking_type=0(&|$)/,
+                            /&origin_corps=0(&|$)/, /&current_corps=0(&|$)/,
+                            /corps_rank=0(&|$)/, /&has_email_redirect=0(&|$)/, /&[^&=]+=(&|$)/g ];
 
 /** Uses javascript to clean form from all empty fields */
 function cleanForm(f, targeturl)
@@ -140,7 +143,11 @@ function cleanForm(f, targeturl)
             } while (old_query != query);
         }
     }
-    query = query.replace(/^&*(.*)&*$/, '$1');
+    query = query.replace(/^(.*)&+$/, '$1');
+    query = query.replace(/^&+(.*)$/, '$1');
+
+    // Removes "(n camarades)" if any of them are remaining.
+    query = query.replace(/\+\(\d+\+camarade(?:s)?\)/, '');
     if (query == 'rechercher=Chercher') {
         alert("Aucun critère n'a été spécifié.");
         return false;
diff --git a/htdocs/javascript/xnet_members.js b/htdocs/javascript/xnet_members.js
new file mode 100644 (file)
index 0000000..3f8999b
--- /dev/null
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *  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                *
+ ***************************************************************************/
+
+function xStateChange(box, baseurl)
+{
+    $('.details').toggle();
+    $('#search_result').updateHtml(baseurl + 'member/new/ajax?login=' + $('#email').val());
+}
+
+var nom;
+var prenom;
+var promo;
+function searchX(baseurl)
+{
+    if ($('#nom').val() == nom && $('#prenom').val() == prenom && $('#promo').val() == promo) {
+       return;
+    }
+    nom = $('#nom').val();
+    prenom = $('#prenom').val();
+    promo = $('#promo').val();
+    $('#search_result').updateHtml(baseurl + 'member/new/ajax?prenom=' + prenom + '&nom=' + nom + '&promo=' + promo,
+        function (data) {
+            updateSuggestions(baseurl, $('select:[name=userid]').val());
+    });
+}
+
+function updateSuggestions(baseurl, uid)
+{
+    $('#broken').hide();
+    $('#marketing').hide();
+    if (uid && uid != 0) {
+        $.xget(baseurl + 'member/reg/' + uid, function(data) {
+            if (data) {
+                $('#broken').show();
+                $('#broken').find('[name=broken]').attr('checked', 'checked');
+            } else {
+                $('#marketing').show();
+                $('#marketing').find('[name=marketing]').attr('checked', 'checked');
+            }
+        });
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 6483449..1df275b 100644 (file)
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
  ***************************************************************************/
 
+class Particles
+{
+    // Some particles should not be capitalized (cf "ORTHOTYPO", by Jean-Pierre
+    // Lacroux).
+    // Note that some of them are allowed to use capital letters in some cases,
+    // for instance "De" in American English.
+    public static $particles = array('d', 'de', 'an', 'auf', 'von', 'von dem',
+                                     'von der', 'zu', 'of', 'del', 'de las',
+                                     'de les', 'de los', 'las', 'los', 'y', 'a',
+                                     'da', 'das', 'do', 'dos', 'af', 'av');
+}
+
+
 function build_javascript_names($data, $isFemale)
 {
     $names = array();
@@ -57,11 +70,11 @@ function build_display_names(array $public_names, array $private_names, $isFemal
     $firstname = build_first_name($public_names);
 
     $display_names = array();
-    $display_names['public_name']    = $firstname . ' ' . $full_last_name;
+    $display_names['public_name']    = build_full_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;
+    $display_names['directory_name'] = build_directory_name($firstname, $full_last_name);
+    $display_names['short_name']     = build_full_name($firstname, $short_last_name);
+    $display_names['sort_name']      = build_sort_name($firstname, $short_last_name);
 
     return $display_names;
 }
@@ -117,6 +130,38 @@ function build_private_name(array $private_names)
     return ' (' . implode(', ', $names_array) . ')';
 }
 
+function build_directory_name($firstname, $lastname)
+{
+    if ($firstname == '') {
+        return mb_strtoupper($lastname);
+    }
+    return mb_strtoupper($lastname) . ' ' . $firstname;
+}
+
+function build_full_name($firstname, $lastname)
+{
+    if ($firstname == '') {
+        return $lastname;
+    }
+    return $firstname . ' ' . $lastname;
+}
+
+// Returns the name on which the sort is performed, according to French
+// typographic rules.
+function build_sort_name($firstname, $lastname)
+{
+    // Remove uncapitalized particles.
+    $particles = "/^(d'|(" . implode(Particles::$particles, '|') . ') )/';
+    $name = preg_replace($particles, '', $lastname);
+    // Mac must also be uniformized.
+    $lastname = preg_replace("/^(Mac|Mc)( |)/", 'Mac', $name);
+
+    if ($firstname == '') {
+        return $lastname;
+    }
+    return $lastname . ' ' . $firstname;
+}
+
 /** Splits a name into tokens, as used in search_name.
  * Used for search_name rebuilding and for queries.
  */
@@ -152,7 +197,7 @@ function update_account_from_profile($uid)
               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
+                          a.full_name = pd.short_name, a.directory_name = pd.directory_name, a.sort_name = pd.sort_name
                    WHERE  a.uid = {?}",
                  $uid);
 }
@@ -185,21 +230,59 @@ function update_display_names(Profile $profile, array $public_names, array $priv
 
 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);
-        }
-    }
-
     XDB::execute('UPDATE  profile_public_names
-                     SET  particles = {?}, lastname_main = {?}, lastname_marital = {?}, lastname_ordinary = {?},
+                     SET  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['lastname_main'], $public_names['lastname_marital'], $public_names['lastname_ordinary'],
                  $public_names['firstname_main'], $public_names['firstname_ordinary'], $public_names['pseudonym'], $pid);
 }
 
+// Returns the @p name with all letters in lower case, but the first one.
+function mb_ucfirst($name)
+{
+    return mb_strtoupper(mb_substr($name, 0, 1)) . mb_substr($name, 1);
+}
+
+// Capitalizes the @p name using French typographic rules. Returns
+// false when capitalization rule is not known for the name format.
+function capitalize_name($name)
+{
+    // Some suffixes should not be captitalized either, eg 's' in Bennett's.
+    static $suffixes = array('h', 's', 't');
+
+    // Extracts the first token of the name.
+    if (!preg_match('/^(\pL+)(([\' -])(.*))?$/ui', $name, $m)) {
+        return false;
+    }
+
+    $token = mb_strtolower($m[1]);
+    $separator = (isset($m[3]) ? $m[3] : false);
+    $tail = (isset($m[4]) ? $m[4] : false);
+
+    // Special case for "Malloc'h".
+    if ($separator == "'" && in_array(strtolower($tail[0]), $suffixes) &&
+        (strlen($tail) == 1 || $tail[1] == ' ')) {
+        $token .= "'" . strtolower($tail[0]);
+        $separator = (strlen($tail) == 1 ? false : $tail[1]);
+        $tail = (strlen($tail) > 2 ? substr($tail, 2) : false);
+    }
+
+    // Capitalizes the first token.
+    if (!in_array($token, Particles::$particles)) {
+        $token = mb_ucfirst($token);
+    }
+
+    // Capitalizes the tail of the name.
+    if ($tail) {
+        if (($tail = capitalize_name($tail))) {
+            return $token . $separator . $tail;
+        }
+        return false;
+    }
+
+    return $token . $separator;
+}
+
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
 ?>
index 5dbe438..a51aeae 100644 (file)
@@ -46,6 +46,7 @@ class NewsLetter
     const GROUP_XORG = 'Polytechnique.org';
     const GROUP_AX = 'AX';
     const GROUP_EP = 'Ecole';
+    const GROUP_FX = 'FX';
 
     // Searches on mutiple fields
     const SEARCH_ALL = 'all';
@@ -551,6 +552,8 @@ class NewsLetter
             return 'ax';
         case self::GROUP_EP:
             return 'epletter';
+        case self::GROUP_FX:
+            return 'fxletter';
         default:
             // Don't display groups NLs on X.org
             assert(!$enforce_xnet);
@@ -575,6 +578,8 @@ class NewsLetter
             return 'ax/admin';
         case self::GROUP_EP:
             return 'epletter/admin';
+        case self::GROUP_FX:
+            return 'fxletter/admin';
         default:
             // Don't display groups NLs on X.org
             assert(!$enforce_xnet);
@@ -599,6 +604,8 @@ class NewsLetter
             return 'ax/stat';
         case self::GROUP_EP:
             return 'epletter/stat';
+        case self::GROUP_FX:
+            return 'fxletter/stat';
         default:
             // Don't display groups NLs on X.org
             assert(!$enforce_xnet);
@@ -642,6 +649,7 @@ class NewsLetter
           case self::GROUP_XORG:
           case self::GROUP_AX:
           case self::GROUP_EP:
+          case self::GROUP_FX:
             return false;
           default:
             return true;
index ef574c0..263fcb5 100644 (file)
@@ -875,7 +875,7 @@ class CompanyList
 
     static public function get($id)
     {
-        if (!array_key_exists($id, self::$companies)) {
+        if (!is_null($id) && !array_key_exists($id, self::$companies)) {
             self::preload();
         }
         if (isset(self::$companies[$id])) {
index 243c1fe..3b18a44 100644 (file)
@@ -433,23 +433,26 @@ class AddressesView implements PlView
             $res = XDB::query("SELECT  pd.promo, p.title,
                                        IF (pn.firstname_ordinary = '', UPPER(pn.firstname_main), UPPER(pn.firstname_ordinary)) AS firstname,
                                        IF (pn.lastname_ordinary = '', UPPER(pn.lastname_main), UPPER(pn.lastname_ordinary)) AS lastname,
-                                       UPPER(pje.name), pa.postalText, pa.postal_code, p.email_directory
-                                 FROM  (SELECT  pa.pid, pa.postalText, pace.long_name AS postal_code
+                                       UPPER(pje.name), pa.postalText, GROUP_CONCAT(pace.long_name) AS postal_code, p.email_directory
+                                 FROM  (SELECT  pa.pid, pa.postalText, pa.jobid, pa.groupid, pa.type, pa.id
                                           FROM  profile_addresses                 AS pa
-                                     LEFT JOIN  profile_addresses_components      AS pac  ON (pa.pid = pac.pid
-                                                                                              AND pa.jobid = pac.jobid
-                                                                                              AND pa.groupid = pac.groupid
-                                                                                              AND pa.type = pac.type)
-                                     LEFT JOIN  profile_addresses_components_enum AS pace ON (pac.component_id = pace.id
-                                                                                              AND FIND_IN_SET('postal_code', pace.types))
                                          WHERE  pa.pub IN ('public', 'ax') AND FIND_IN_SET('mail', pa.flags) AND pa.pid IN {?}
                                       ORDER BY  pa.pid, NOT FIND_IN_SET('current', pa.flags),
-                                                FIND_IN_SET('secondary', pa.flags), pa.type = 'job', pace.long_name IS NULL) AS pa
-                           INNER JOIN  profiles             AS p   ON (pa.pid = p.pid)
-                           INNER JOIN  profile_display      AS pd  ON (pd.pid = pa.pid)
-                           INNER JOIN  profile_public_names AS pn  ON (pn.pid = pa.pid)
-                            LEFT JOIN  profile_job          AS pj  ON (pj.pid = pa.pid)
-                            LEFT JOIN  profile_job_enum     AS pje ON (pj.jobid = pje.id)
+                                                FIND_IN_SET('secondary', pa.flags), pa.type = 'job') AS pa
+                           INNER JOIN  profiles                          AS p    ON (pa.pid = p.pid)
+                           INNER JOIN  profile_display                   AS pd   ON (pd.pid = pa.pid)
+                           INNER JOIN  profile_public_names              AS pn   ON (pn.pid = pa.pid)
+                            LEFT JOIN  profile_addresses_components      AS pac  ON (pa.pid = pac.pid
+                                                                                     AND pa.jobid = pac.jobid
+                                                                                     AND pa.groupid = pac.groupid
+                                                                                     AND pa.type = pac.type
+                                                                                     AND pa.id = pac.id)
+                            LEFT JOIN  profile_addresses_components_enum AS pace ON (pac.component_id = pace.id
+                                                                                     AND FIND_IN_SET('postal_code', pace.types))
+
+                            LEFT JOIN  profile_job                       AS pj   ON (pj.pid = pa.pid
+                                                                                     AND pj.id = IF(pa.type = 'job', pa.id, NULL))
+                            LEFT JOIN  profile_job_enum                  AS pje  ON (pj.jobid = pje.id)
                              GROUP BY  pa.pid", $pids);
             foreach ($res->fetchAllAssoc() as $item) {
                 fputcsv($csv, array_map('utf8_decode', $item), ';');
index 35746bd..8f5df65 100644 (file)
@@ -390,7 +390,7 @@ abstract class Validate
 
     public function id()
     {
-        return $this->user->id() . '_' . $this->type . '_' . $this->stamp;
+        return str_replace(" ", "_", $this->user->id() . '_' . $this->type . '_' . $this->stamp);
     }
 
     // }}}
index f2154dd..7b41877 100644 (file)
@@ -28,6 +28,7 @@ class AccountReq extends Validate
     public $hruid;
     public $email;
     public $group;
+    public $dim;
     public $groups;
 
     public $rules = "Accepter si l'adresse email parait correcte, et pas absurde
@@ -37,22 +38,23 @@ class AccountReq extends Validate
     // }}}
     // {{{ constructor
 
-    public function __construct(User $user, $hruid, $email, $group)
+    public function __construct(User $user, $hruid, $email, $group, $dim)
     {
         parent::__construct($user, false, 'account');
         $this->hruid = $hruid;
         $this->email = $email;
         $this->group = $group;
+        $this->dim   = $dim;
         $this->uid = XDB::fetchOneCell('SELECT  uid
                                           FROM  accounts
                                          WHERE  hruid = {?}',
                                        $hruid);
-        $this->groups = implode(',', XDB::fetchColumn('SELECT  g.nom
-                                                         FROM  groups AS g
-                                                   INNER JOIN  group_members AS m ON (g.id = m.asso_id)
-                                                        WHERE  m.uid = {?}
-                                                     ORDER BY  g.nom',
-                                                      $this->uid));
+        $this->groups = XDB::fetchAllAssoc('SELECT  g.nom, g.diminutif
+                                              FROM  groups AS g
+                                        INNER JOIN  group_members AS m ON (g.id = m.asso_id)
+                                             WHERE  m.uid = {?}
+                                          ORDER BY  g.nom',
+                                           $this->uid);
     }
 
     // }}}
index b3fbcf2..c49ae12 100644 (file)
@@ -27,16 +27,18 @@ class BulkAccountsReq extends Validate
     private $limit = 50;
     public $users;
     public $group;
+    public $dim;
 
     public $rules = "Accepter si les adresses email paraissent correctes, et pas
         absurdes et si le demandeur est de confiance.";
     // }}}
     // {{{ constructor
 
-    public function __construct(User $user, array $uids, $group)
+    public function __construct(User $user, array $uids, $group, $dim)
     {
         parent::__construct($user, false, 'bulkaccounts');
         $this->group = $group;
+        $this->dim   = $dim;
         $this->users = XDB::fetchAllAssoc('SELECT  uid, hruid, email
                                              FROM  accounts
                                             WHERE  uid IN {?}',
index a2d5d59..7bdd213 100644 (file)
@@ -55,6 +55,7 @@ class AdminModule extends PLModule
             'admin/jobs'                   => $this->make_hook('jobs',                   AUTH_PASSWD, 'admin,edit_directory'),
             'admin/profile'                => $this->make_hook('profile',                AUTH_PASSWD, 'admin,edit_directory'),
             'admin/phd'                    => $this->make_hook('phd',                    AUTH_PASSWD, 'admin'),
+            'admin/name'                   => $this->make_hook('admin_name',             AUTH_PASSWD, 'admin'),
             'admin/add_secondary_edu'      => $this->make_hook('add_secondary_edu',      AUTH_PASSWD, 'admin')
         );
     }
@@ -451,23 +452,25 @@ class AdminModule extends PLModule
             $to_update['weak_password'] = null;
         } else if (Post::has('update_account')) {
             if (!$user->hasProfile()) {
+                require_once 'name.func.inc.php';
                 $name_update = false;
-                if (Post::s('lastname') != $user->lastname) {
-                    $to_update['lastname'] = Post::s('lastname');
+                $lastname = capitalize_name(Post::t('lastname'));
+                $firstname = capitalize_name(Post::t('firstname'));
+                if ($lastname != $user->lastname) {
+                    $to_update['lastname'] = $lastname;
                     $name_update = true;
                 }
-                if (Post::s('type') != 'virtual' && Post::s('firstname') != $user->firstname) {
-                    $to_update['firstname'] = Post::s('firstname');
+                if (Post::s('type') != 'virtual' && $firstname != $user->firstname) {
+                    $to_update['firstname'] = $firstname;
                     $name_update = true;
                 }
                 if ($name_update) {
-                    if (Post::s('type') != 'virtual') {
-                        $to_update['full_name'] = Post::s('firstname') . ' ' . Post::s('lastname');
-                        $to_update['directory_name'] = mb_strtoupper(Post::s('lastname')) . ' ' . Post::s('firstname');
-                    } else {
-                        $to_update['full_name'] = Post::s('lastname');
-                        $to_update['directory_name'] = mb_strtoupper(Post::s('lastname'));
+                    if (Post::s('type') == 'virtual') {
+                        $firstname = '';
                     }
+                    $to_update['full_name'] = build_full_name($firstname, $lastname);
+                    $to_update['directory_name'] = build_directory_name($firstname, $lastname);
+                    $to_update['sort_name'] = build_sort_name($firstname, $lastname);
                 }
                 if (Post::s('display_name') != $user->displayName()) {
                     $to_update['display_name'] = Post::s('display_name');
@@ -812,6 +815,7 @@ class AdminModule extends PLModule
 
     function handler_add_accounts($page, $action = null, $promo = null)
     {
+        require_once 'name.func.inc.php';
         $page->changeTpl('admin/add_accounts.tpl');
 
         if (Env::has('add_type') && Env::has('people')) {
@@ -853,14 +857,21 @@ class AdminModule extends PLModule
                   default:
                     $page->killError("La formation n'est pas reconnue : " . Env::t('edu_type') . '.');
                 }
+                $best_domain = XDB::fetchOneCell('SELECT  id
+                                                    FROM  email_virtual_domains
+                                                   WHERE  name = {?}',
+                                                 User::$sub_mail_domains[$type] . Platal::globals()->mail->domain);
 
                 XDB::startTransaction();
                 foreach ($lines as $line) {
                     if ($infos = self::formatNewUser($page, $line, $separator, $hrpromo, 6)) {
                         $sex = self::formatSex($page, $infos[3], $line);
+                        $lastname = capitalize_name($infos[0]);
+                        $firstname = capitalize_name($infos[1]);
                         if (!is_null($sex)) {
-                            $fullName = $infos[1] . ' ' . $infos[0];
-                            $directoryName = $infos[0] . ' ' . $infos[1];
+                            $fullName = build_full_name($firstname, $lastname);
+                            $directoryName = build_directory_name($firstname, $lastname);
+                            $sortName = build_sort_name($firstname, $lastname);
                             $birthDate = self::formatBirthDate($infos[2]);
                             if ($type == 'x') {
                                 $xorgId = Profile::getXorgId($infos[4]);
@@ -881,19 +892,19 @@ class AdminModule extends PLModule
                             $pid = XDB::insertId();
                             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]);
+                                         $pid, $lastname, $lastname, $firstname, $firstname);
                             XDB::execute('INSERT INTO  profile_display (pid, yourself, public_name, private_name,
                                                                         directory_name, short_name, sort_name, promo)
                                                VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
-                                         $pid, $infos[1], $fullName, $fullName, $directoryName, $fullName, $directoryName, $promo);
+                                         $pid, $firstname, $fullName, $fullName, $directoryName, $fullName, $sortName, $promo);
                             XDB::execute('INSERT INTO  profile_education (id, pid, eduid, degreeid, entry_year, grad_year, promo_year, flags)
                                                VALUES  (100, {?}, {?}, {?}, {?}, {?}, {?}, \'primary\')',
                                          $pid, $eduSchools[Profile::EDU_X], $degreeid, $entry_year, $grad_year, $promotion);
                             XDB::execute('INSERT INTO  accounts (hruid, type, is_admin, state, full_name, directory_name,
-                                                                 display_name, lastname, firstname, sex)
-                                               VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
-                                         $infos['hrid'], $type, 0, 'pending', $fullName, $directoryName,
-                                         $infos[1], $infos[0], $infos[1], $sex);
+                                                                 display_name, sort_name, lastname, firstname, sex, best_domain)
+                                               VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
+                                         $infos['hrid'], $type, 0, 'pending', $fullName, $directoryName, $sortName,
+                                         $firstname, $lastname, $firstname, $sex, $best_domain);
                             $uid = XDB::insertId();
                             XDB::execute('INSERT INTO  account_profiles (uid, pid, perms)
                                                VALUES  ({?}, {?}, {?})',
@@ -910,14 +921,17 @@ class AdminModule extends PLModule
                     if ($infos = self::formatNewUser($page, $line, $separator, $type, 4)) {
                         $sex = self::formatSex($page, $infos[3], $line);
                         if (!is_null($sex)) {
-                            $fullName = $infos[1] . ' ' . $infos[0];
-                            $directoryName = $infos[0] . ' ' . $infos[1];
+                            $lastname = capitalize_name($infos[0]);
+                            $firstname = capitalize_name($infos[1]);
+                            $fullName = build_full_name($firstname, $lastname);
+                            $directoryName = build_directory_name($firstname, $lastname);
+                            $sortName = build_sort_name($firstname, $lastname);
                             XDB::execute('INSERT INTO  accounts (hruid, type, is_admin, state, email, full_name, directory_name,
-                                                                 display_name, lastname, firstname, sex)
-                                               VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
+                                                                 sort_name, display_name, lastname, firstname, sex)
+                                               VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
                                          $infos['hrid'], $type, 0, 'pending', $infos[2], $fullName, $directoryName,
-                                         $infos[1], $infos[0], $infos[1], $sex);
-                            $newAccounts[$infos['hrid']] = $infos[1] . ' ' . $infos[0];
+                                         $sortName ,$firstname, $lastname, $firstname, $sex);
+                            $newAccounts[$infos['hrid']] = $fullName;
                         }
                     }
                 }
@@ -1999,6 +2013,107 @@ class AdminModule extends PLModule
         }
 
     }
+
+    function handler_admin_name($page, $hruid = null)
+    {
+        $page->changeTpl('admin/admin_name.tpl');
+
+        if (Post::has('id')) {
+            $user = User::get(Post::t('id'));
+            if (is_null($user)) {
+                $page->trigError("L'identifiant donné ne correspond à personne ou est ambigu.");
+                exit();
+            }
+            pl_redirect('admin/name/' . $user->hruid);
+        }
+
+        $user = User::getSilent($hruid);
+        if (!is_null($user)) {
+            require_once 'name.func.inc.php';
+
+            if ($user->hasProfile()) {
+                $name_types = array(
+                    'lastname_main'      => 'Nom patronymique',
+                    'lastname_marital'   => 'Nom marital',
+                    'lastname_ordinary'  => 'Nom usuel',
+                    'firstname_main'     => 'Prénom',
+                    'firstname_ordinary' => 'Prénom usuel',
+                    'pseudonym'          => 'Pseudonyme'
+                );
+                $names = XDB::fetchOneAssoc('SELECT  lastname_main, lastname_marital, lastname_ordinary,
+                                                     firstname_main, firstname_ordinary, pseudonym
+                                               FROM  profile_public_names
+                                              WHERE  pid = {?}',
+                                            $user->profile()->id());
+            } else {
+                $name_types = array(
+                    'lastname'  => 'Nom',
+                    'firstname' => 'Prénom'
+                );
+                $names = XDB::fetchOneAssoc('SELECT  lastname, firstname
+                                               FROM  accounts
+                                              WHERE  uid = {?}',
+                                            $user->id());
+            }
+
+            if (Post::has('correct')) {
+                $new_names = array();
+                $update = true;
+                foreach ($name_types as $key => $fullname) {
+                    $new_names[$key] = Post::t($key);
+                    if (mb_strtolower($new_names[$key]) != mb_strtolower($names[$key])) {
+                        $update = false;
+                    }
+                }
+
+                if ($update) {
+                    if ($user->hasProfile()) {
+                        update_public_names($user->profile()->id(), $new_names);
+                        update_display_names($user->profile(), $new_names);
+                    } else {
+                        $new_names['full_name'] = build_full_name($new_names['firstname'], $new_names['lastname']);
+                        $new_names['directory_name'] = build_directory_name($new_names['firstname'], $new_names['lastname']);
+                        $new_names['sort_name'] = build_sort_name($new_names['firstname'], $new_names['lastname']);
+                        XDB::execute('UPDATE  accounts
+                                         SET  lastname = {?}, firstname = {?}, full_name = {?},
+                                              directory_name = {?}, sort_name = {?}
+                                       WHERE  uid = {?}',
+                                     $new_names['lastname'], $new_names['firstname'], $new_names['full_name'],
+                                     $new_names['directory_name'], $new_names['sort_name'], $user->id());
+                    }
+                    $page->trigSuccess('Mise à jour réussie.');
+                } else {
+                    $page->trigError('Seuls des changements de casse sont autorisés ici.');
+                }
+            }
+
+            if ($user->hasProfile()) {
+                $names = XDB::fetchOneAssoc('SELECT  lastname_main, lastname_marital, lastname_ordinary,
+                                                     firstname_main, firstname_ordinary, pseudonym
+                                               FROM  profile_public_names
+                                              WHERE  pid = {?}',
+                                            $user->profile()->id());
+            } else {
+                $names = XDB::fetchOneAssoc('SELECT  lastname, firstname
+                                               FROM  accounts
+                                              WHERE  uid = {?}',
+                                            $user->id());
+            }
+
+            foreach ($names as $key => $name) {
+                $names[$key] = array(
+                    'value'    => $name,
+                    'standard' => capitalize_name($name)
+                );
+                $names[$key]['different'] = ($names[$key]['value'] != $names[$key]['standard']);
+            }
+
+            $page->assign('uid', $user->id());
+            $page->assign('hruid', $user->hruid);
+            $page->assign('names', $names);
+            $page->assign('name_types', $name_types);
+        }
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 6fdb360..16aa488 100644 (file)
@@ -629,30 +629,125 @@ class FusionAxModule extends PLModule
         $page->assign('nbMissmatchingPromosTotal', $nbMissmatchingPromos);
     }
 
-    function handler_names($page, $action = '')
+    private function format($string)
+    {
+        return preg_replace('/(\s+|\-)/', '', $string);
+    }
+
+    private function retrieve_firstnames()
+    {
+        $res = XDB::rawFetchAllAssoc('SELECT  p.pid, p.ax_id, p.hrpid,
+                                              f.prenom, ppn.firstname_initial, ppn.firstname_main, ppn.firstname_ordinary
+                                        FROM  fusionax_anciens     AS f
+                                  INNER JOIN  profiles             AS p   ON (f.ax_id = p.ax_id)
+                                  INNER JOIN  profile_public_names AS ppn ON (p.pid = ppn.pid)
+                                       WHERE  f.prenom NOT IN (ppn.firstname_initial, ppn.firstname_main, ppn.firstname_ordinary)');
+
+        $issues = array();
+        foreach ($res as $item) {
+            if (!($item['firstname_ordinary'] != '' || $item['firstname_main'] != $item['firstname_initial'])) {
+                $ax = $this->format(mb_strtolower(replace_accent($item['prenom'])));
+                $xorg = $this->format(mb_strtolower(replace_accent($item['firstname_main'])));
+                if ($ax != $xorg) {
+                    $issues[] = $item;
+                }
+            }
+        }
+
+        return $issues;
+    }
+
+    function handler_names($page, $action = '', $csv = false)
     {
         $page->changeTpl('fusionax/names.tpl');
 
         if ($action == 'first') {
+            $res = $this->retrieve_firstnames();
+            if ($csv) {
+                pl_cached_content_headers('text/x-csv', 'utf-8', 1, 'firstnames.csv');
+
+                $csv = fopen('php://output', 'w');
+                fputcsv($csv,  array('pid', 'ax_id', 'hrpid', 'AX', 'initial', 'principal', 'ordinaire'), ';');
+                foreach ($res as $item) {
+                    fputcsv($csv, $item, ';');
+                }
+                fclose($csv);
+                exit();
+            } else {
+                $page->assign('firstnameIssues', $res);
+            }
+        } elseif ($action == 'last' || $action == 'last3' || $action == 'last2' || $action == 'last1') {
+            $ax_patro = "(IF(f.partic_patro, CONCAT(f.partic_patro, CONCAT(' ', f.Nom_patronymique)), f.Nom_patronymique) NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary))";
+            $ax_ordinary = "(IF(f.partic_nom, CONCAT(f.partic_nom, CONCAT(' ', f.Nom_usuel)), f.Nom_usuel) NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary))";
+            $ax_full = "(f.Nom_complet NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary))";
+
+            switch ($action) {
+              case 'last':
+                $where = $ax_patro . ' OR ' . $ax_ordinary . ' OR ' . $ax_full;
+                break;
+              case 'last3':
+                $where = $ax_patro . ' AND ' . $ax_ordinary . ' AND ' . $ax_full;
+                break;
+              case 'last2':
+                $where = '(' . $ax_patro . ' AND ' . $ax_ordinary . ' AND NOT ' . $ax_full . ') OR ('
+                       . $ax_patro . ' AND NOT ' . $ax_ordinary . ' AND ' . $ax_full . ') OR ('
+                       . 'NOT ' . $ax_patro . ' AND ' . $ax_ordinary . ' AND ' . $ax_full . ')';
+                break;
+              case 'last1':
+                $where = '(' . $ax_patro . ' AND NOT ' . $ax_ordinary . ' AND NOT ' . $ax_full . ') OR ('
+                       . 'NOT ' . $ax_patro . ' AND NOT ' . $ax_ordinary . ' AND ' . $ax_full . ') OR ('
+                       . 'NOT ' . $ax_patro . ' AND ' . $ax_ordinary . ' AND NOT ' . $ax_full . ')';
+                break;
+            }
+
             $res = XDB::rawFetchAllAssoc('SELECT  p.pid, p.ax_id, p.hrpid,
-                                                  f.prenom, ppn.firstname_initial, ppn.firstname_main, ppn.firstname_ordinary
-                                            FROM  fusionax_anciens     AS f
-                                      INNER JOIN  profiles             AS p   ON (f.ax_id = p.ax_id)
-                                      INNER JOIN  profile_public_names AS ppn ON (p.pid = ppn.pid)
-                                           WHERE  f.prenom NOT IN (ppn.firstname_initial, ppn.firstname_main, ppn.firstname_ordinary)');
-            $page->assign('firstnameIssues', $res);
-        } elseif ($action == 'last') {
-            $res = XDB::rawFetchAllAssoc("SELECT  p.pid, p.ax_id, p.hrpid,
                                                   f.Nom_patronymique, f.Nom_usuel, f.Nom_complet,
                                                   ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary
                                             FROM  fusionax_anciens     AS f
                                       INNER JOIN  profiles             AS p   ON (f.ax_id = p.ax_id)
                                       INNER JOIN  profile_public_names AS ppn ON (p.pid = ppn.pid)
-                                           WHERE  IF(f.partic_patro, CONCAT(f.partic_patro, CONCAT(' ', f.Nom_patronymique)), f.Nom_patronymique) NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)
-                                                  AND IF(f.partic_nom, CONCAT(f.partic_nom, CONCAT(' ', f.Nom_usuel)), f.Nom_usuel) NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)
-                                                  AND f.Nom_complet NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)");
-            $page->assign('lastnameIssues', $res);
+                                           WHERE  ' . $where);
 
+            if ($csv) {
+                function format($string)
+                {
+                    $string = preg_replace('/\-/', ' ', $string);
+                    return preg_replace('/\s+/', ' ', $string);
+                }
+
+
+                pl_cached_content_headers('text/x-csv', 'utf-8', 1, 'lastnames.csv');
+
+                $csv = fopen('php://output', 'w');
+                fputcsv($csv,  array('pid', 'ax_id', 'hrpid', 'AX patro', 'AX usuel', 'AX complet', 'initial', 'principal', 'marital', 'ordinaire'), ';');
+                foreach ($res as $item) {
+                    $ax = array(
+                        'Nom_patronymique' => format(mb_strtolower(replace_accent($item['Nom_patronymique']))),
+                        'Nom_usuel'        => format(mb_strtolower(replace_accent($item['Nom_usuel']))),
+                        'Nom_complet'      => format(mb_strtolower(replace_accent($item['Nom_complet'])))
+                    );
+                    $xorg = array(
+                        'lastname_initial'  => format(mb_strtolower(replace_accent($item['lastname_initial']))),
+                        'lastname_main'     => format(mb_strtolower(replace_accent($item['lastname_main']))),
+                        'lastname_ordinary' => format(mb_strtolower(replace_accent($item['lastname_ordinary'])))
+                    );
+
+                    if (!in_array($ax['Nom_patronymique'], $xorg) || !in_array($ax['Nom_usuel'], $xorg) || !in_array($ax['Nom_complet'], $xorg)) {
+                        fputcsv($csv, $item, ';');
+                    }
+                }
+                fclose($csv);
+                exit();
+            } else {
+                $page->assign('lastnameIssues', $res);
+                $page->assign('total', count($res));
+                $page->assign('issuesTypes', array(
+                        'last'  => "1, 2 ou 3 noms de l'AX manquant",
+                        'last1' => "1 nom de l'AX manquant",
+                        'last2' => "2 noms de l'AX manquant",
+                        'last3' => "3 noms de l'AX manquant"
+                ));
+            }
         } else {
             $res = XDB::query('SELECT  COUNT(*)
                                  FROM  fusionax_anciens AS f
@@ -664,8 +759,8 @@ class FusionAxModule extends PLModule
                                      INNER JOIN  profiles             AS p   ON (f.ax_id = p.ax_id)
                                      INNER JOIN  profile_public_names AS ppn ON (p.pid = ppn.pid)
                                           WHERE  IF(f.partic_patro, CONCAT(f.partic_patro, CONCAT(' ', f.Nom_patronymique)), f.Nom_patronymique) NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)
-                                                 AND IF(f.partic_nom, CONCAT(f.partic_nom, CONCAT(' ', f.Nom_usuel)), f.Nom_usuel) NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)
-                                                 AND f.Nom_complet NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)");
+                                                 OR IF(f.partic_nom, CONCAT(f.partic_nom, CONCAT(' ', f.Nom_usuel)), f.Nom_usuel) NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)
+                                                 OR f.Nom_complet NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)");
             $page->assign('lastnameIssues', $res);
 
             $res = XDB::rawFetchOneCell('SELECT  COUNT(*)
@@ -673,7 +768,7 @@ class FusionAxModule extends PLModule
                                      INNER JOIN  profiles             AS p   ON (f.ax_id = p.ax_id)
                                      INNER JOIN  profile_public_names AS ppn ON (p.pid = ppn.pid)
                                           WHERE  f.prenom NOT IN (ppn.firstname_initial, ppn.firstname_main, ppn.firstname_ordinary)');
-            $page->assign('firstnameIssues', $res);
+            $page->assign('firstnameIssues', count($this->retrieve_firstnames()));
         }
         $page->assign('action', $action);
     }
diff --git a/modules/fxletter.php b/modules/fxletter.php
new file mode 100644 (file)
index 0000000..defcd0a
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2011 Polytechnique.org                              *
+ *  http://opensource.polytechnique.org/                                   *
+ *                                                                         *
+ *  This program is free software; you can redistribute it and/or modify   *
+ *  it under the terms of the GNU General Public License as published by   *
+ *  the Free Software Foundation; either version 2 of the License, or      *
+ *  (at your option) any later version.                                    *
+ *                                                                         *
+ *  This program is distributed in the hope that it will be useful,        *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *  GNU General Public License for more details.                           *
+ *                                                                         *
+ *  You should have received a copy of the GNU General Public License      *
+ *  along with this program; if not, write to the Free Software            *
+ *  Foundation, Inc.,                                                      *
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
+ ***************************************************************************/
+
+Platal::load('newsletter');
+
+class FXLetterModule extends NewsletterModule
+{
+    function handlers()
+    {
+        return array(
+            'fxletter'                   => $this->make_hook('nl',              AUTH_COOKIE, 'user'),
+            'fxletter/out'               => $this->make_hook('out',             AUTH_PUBLIC),
+            'fxletter/show'              => $this->make_hook('nl_show',         AUTH_COOKIE, 'user'),
+            'fxletter/search'            => $this->make_hook('nl_search',       AUTH_COOKIE, 'user'),
+            'fxletter/admin'             => $this->make_hook('admin_nl',        AUTH_PASSWD, 'user'),
+            'fxletter/admin/edit'        => $this->make_hook('admin_nl_edit',   AUTH_PASSWD, 'user'),
+            'fxletter/admin/edit/valid'  => $this->make_hook('admin_nl_valid',  AUTH_PASSWD, 'user'),
+            'fxletter/admin/edit/cancel' => $this->make_hook('admin_nl_cancel', AUTH_PASSWD, 'user'),
+            'fxletter/admin/edit/delete' => $this->make_hook('admin_nl_delete', AUTH_PASSWD, 'user'),
+            'fxletter/admin/categories'  => $this->make_hook('admin_nl_cat',    AUTH_PASSWD, 'user'),
+            'fxletter/stat'              => $this->make_hook('stat_nl',         AUTH_PASSWD, 'user')
+        );
+    }
+
+    protected function getNl()
+    {
+        require_once 'newsletter.inc.php';
+        return NewsLetter::forGroup(NewsLetter::GROUP_FX);
+    }
+
+    function handler_out($page, $hash = null, $issue_id = null)
+    {
+        if (!$hash) {
+            if (!S::logged()) {
+                return PL_DO_AUTH;
+            }
+        }
+        return $this->handler_nl($page, 'out', $hash, $issue_id);
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
index f382e7b..d95416b 100644 (file)
@@ -63,25 +63,18 @@ class ProfileSettingSearchNames implements ProfileSetting
 
     public function value(ProfilePage $page, $field, $value, &$success)
     {
+        require_once 'name.func.inc.php';
         $success = true;
 
         if (is_null($value)) {
             $request = NamesReq::getPublicNames($page->pid());
 
             if (!$request) {
-                $value['public_names'] = XDB::fetchOneAssoc('SELECT  particles, lastname_main, lastname_marital, lastname_ordinary,
+                $value['public_names'] = XDB::fetchOneAssoc('SELECT  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);
-                }
             } else {
                 $value['public_names'] = $request;
                 Platal::page()->assign('validation', true);
@@ -94,7 +87,7 @@ class ProfileSettingSearchNames implements ProfileSetting
                                                          $page->pid());
         } else {
             foreach ($value['public_names'] as $key => $name) {
-                $value['public_names'][$key] = trim($name);
+                $value['public_names'][$key] = capitalize_name(trim($name));
             }
             if (isset($value['private_names'])) {
                 foreach ($value['private_names'] as $key => $name) {
@@ -110,7 +103,6 @@ class ProfileSettingSearchNames implements ProfileSetting
             }
         }
 
-        require_once 'name.func.inc.php';
         $public_name = build_first_name($value['public_names']) . ' ' . build_full_last_name($value['public_names'], $page->profile->isFemale());
         if (isset($value['private_names'])) {
             $private_name_end = build_private_name($value['private_names']);
index fc2b811..e9c3724 100644 (file)
@@ -158,8 +158,8 @@ class SearchModule extends PLModule
         $networks[0] = '-';
         ksort($networks);
         $page->assign('networking_types', $networks);
-        $origin_corps_list = DirEnum::getOptions(DirEnum::CURRENTCORPS);
-        $current_corps_list = DirEnum::getOptions(DirEnum::ORIGINCORPS);
+        $origin_corps_list = DirEnum::getOptions(DirEnum::ORIGINCORPS);
+        $current_corps_list = DirEnum::getOptions(DirEnum::CURRENTCORPS);
         $corps_rank_list = DirEnum::getOptions(DirEnum::CORPSRANKS);
         $origin_corps_list[0] = '-';
         $current_corps_list[0] = '-';
index 9f7e6b3..6964996 100644 (file)
@@ -250,19 +250,24 @@ class XnetModule extends PLModule
                 }
             }
 
+            require_once 'emails.inc.php';
+            require_once 'name.func.inc.php';
+
             // Update user info
-            $full_name = Post::t('firstname') . ' ' . Post::t('lastname');
-            $directory_name = mb_strtoupper(Post::t('lastname')) . ' ' . Post::t('firstname');
+            $lastname = capitalize_name(Post::t('lastname'));
+            $firstname = capitalize_name(Post::t('firstname'));
+            $full_name = build_full_name($firstname, $lastname);
+            $directory_name = build_directory_name($firstname, $lastname);
+            $sort_name = build_sort_name($firstname, $lastname);
             XDB::query('UPDATE  accounts
-                           SET  full_name = {?}, directory_name = {?}, display_name = {?},
+                           SET  full_name = {?}, directory_name = {?}, sort_name = {?}, display_name = {?},
                                 firstname = {?}, lastname = {?}, sex = {?}
                          WHERE  uid = {?}',
-                       $full_name, $directory_name, Post::t('display_name'),
+                       $full_name, $directory_name, $sort_name, Post::t('display_name'),
                        Post::t('firstname'), Post::t('lastname'),
                        (Post::t('sex') == 'male') ? 'male' : 'female', $user->id());
 
             // Updates email.
-            require_once 'emails.inc.php';
             $new_email = strtolower(Post::t('email'));
             if (require_email_update($user, $new_email)) {
                     XDB::query('UPDATE  accounts
index 0dc18e3..a12c669 100644 (file)
@@ -237,18 +237,20 @@ class XnetEventsModule extends PLModule
         }
 
         // update actual inscriptions
-        $updated = false;
-        $total   = 0;
-        $paid    = $evt['paid'] ? $evt['paid'] : 0;
-        $telepaid= $evt['telepaid'] ? $evt['telepaid'] : 0;
+        $updated       = false;
+        $total         = 0;
+        $paid          = $evt['paid'] ? $evt['paid'] : 0;
+        $telepaid      = $evt['telepaid'] ? $evt['telepaid'] : 0;
+        $paid_inserted = false;
         foreach ($subs as $j => $nb) {
             if ($nb >= 0) {
                 XDB::execute('INSERT INTO  group_event_participants (eid, uid, item_id, nb, flags, paid)
                                    VALUES  ({?}, {?}, {?}, {?}, {?}, {?})
                   ON DUPLICATE KEY UPDATE  nb = VALUES(nb), flags = VALUES(flags), paid = VALUES(paid)',
                              $eid, S::v('uid'), $j, $nb, (Env::has('notify_payment') ? 'notify_payment' : ''),
-                             ($j == 1 ? $paid - $telepaid : 0));
+                             ((!$paid_inserted) ? $paid - $telepaid : 0));
                 $updated = $eid;
+                $paid_inserted = true;
             } else {
                 XDB::execute(
                     "DELETE FROM  group_event_participants
@@ -594,27 +596,36 @@ class XnetEventsModule extends PLModule
                 $amount = strtr(Env::v('montant'), ',', '.');
                 XDB::execute("UPDATE group_event_participants
                                  SET paid = paid + {?}
-                               WHERE uid = {?} AND eid = {?} AND item_id = 1",
+                               WHERE uid = {?} AND eid = {?} AND nb > 0
+                            ORDER BY item_id ASC
+                               LIMIT 1",
                              $amount, $member->uid, $evt['eid']);
                 subscribe_lists_event($member->uid, $evt['short_name'], 1, $amount);
             }
 
             // change the number of personns coming with a participant
             if (Env::v('adm') == 'nbs' && $member) {
-                $res = XDB::query("SELECT paid
+                $res = XDB::query("SELECT SUM(paid)
                                      FROM group_event_participants
                                     WHERE uid = {?} AND eid = {?}",
                                   $member->uid, $evt['eid']);
 
-                $paid = intval($res->fetchOneCell());
+                $paid = $res->fetchOneCell();
                 $nbs  = Post::v('nb', array());
 
+                $paid_inserted = false;
                 foreach ($nbs as $id => $nb) {
                     $nb = max(intval($nb), 0);
+                    if (!$paid_inserted && $nb > 0) {
+                        $item_paid = $paid;
+                        $paid_inserted = true;
+                    } else {
+                        $item_paid = 0;
+                    }
                     XDB::execute('INSERT INTO  group_event_participants (eid, uid, item_id, nb, flags, paid)
                                        VALUES  ({?}, {?}, {?}, {?}, {?}, {?})
                       ON DUPLICATE KEY UPDATE  nb = VALUES(nb), flags = VALUES(flags), paid = VALUES(paid)',
-                                 $evt['eid'], $member->uid, $id, $nb, '', ($id == 1 ? $paid : 0));
+                                 $evt['eid'], $member->uid, $id, $nb, '', $item_paid);
                 }
 
                 $res = XDB::query('SELECT  COUNT(uid) AS cnt, SUM(nb) AS nb
@@ -623,7 +634,7 @@ class XnetEventsModule extends PLModule
                                  GROUP BY  uid',
                                   $member->uid, $evt['eid']);
                 $u = $res->fetchOneAssoc();
-                if ($u['cnt'] == 1 && $paid == 0 && Post::v('cancel')) {
+                if ($paid == 0 && Post::v('cancel')) {
                     XDB::execute("DELETE FROM group_event_participants
                                         WHERE uid = {?} AND eid = {?}",
                                     $member->uid, $evt['eid']);
index dcc8d26..fe20a8e 100644 (file)
@@ -79,7 +79,7 @@ function get_event_detail($eid, $item_id = false, $asso_id = null)
         if ($m['montant']) {
             $evt['money'] = true;
         }
-        $evt['paid']  = $m['paid'];
+        $evt['paid'] += $m['paid'];
         $evt['notify_payment'] = $evt['notify_payment'] || $m['notify_payment'];
     }
 
index 2c6479b..4fccb1b 100644 (file)
@@ -51,6 +51,7 @@ class XnetGrpModule extends PLModule
             '%grp/member/new/ajax' => $this->make_hook('admin_member_new_ajax', AUTH_PASSWD, 'groups', NO_AUTH),
             '%grp/member/del'      => $this->make_hook('admin_member_del',      AUTH_PASSWD, 'groupadmin'),
             '%grp/member/suggest'  => $this->make_hook('admin_member_suggest',  AUTH_PASSWD, 'groupadmin'),
+            '%grp/member/reg'      => $this->make_hook('admin_member_reg',      AUTH_PASSWD, 'groupadmin'),
 
             '%grp/rss'             => $this->make_token_hook('rss',             AUTH_PUBLIC),
             '%grp/announce/new'    => $this->make_hook('edit_announce',         AUTH_PASSWD, 'groupadmin'),
@@ -514,20 +515,22 @@ class XnetGrpModule extends PLModule
                     continue;
                 }
 
+                require_once 'name.func.inc.php';
                 $parts = explode('.', $local_part);
                 if (count($parts) == 1) {
-                    $lastname = $display_name = $full_name = $directory_name = ucfirst($local_part);
+                    $lastname = $display_name = capitalize_name($mbox);
                     $firstname = '';
                 } else {
-                    $firstname = ucfirst($parts[0]);
-                    $lastname = ucwords(implode(' ', array_slice($parts, 1)));
-                    $display_name = $firstname;
-                    $full_name = $firstname . ' ' . $lastname;
-                    $directory_name = strtoupper($lastname) . ' ' . $firstname;
+                    $display_name = $firstname = capitalize_name($parts[0]);
+                    $lastname = capitalize_name(implode(' ', array_slice($parts, 1)));
                 }
-                XDB::execute('INSERT INTO  accounts (hruid, display_name, full_name, directory_name, firstname, lastname, email, type, state)
-                                   VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, \'xnet\', \'disabled\')',
-                             $hruid, $display_name, $full_name, $directory_name, $firstname, $lastname, $email);
+                $full_name = build_full_name($firstname, $lastname);
+                $directory_name = build_directory_name($firstname, $lastname);
+                $sort_name = build_sort_name($firstname, $lastname);
+                XDB::execute('INSERT INTO  accounts (hruid, display_name, full_name, directory_name, sort_name,
+                                                     firstname, lastname, email, type, state)
+                                   VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, \'xnet\', \'disabled\')',
+                             $hruid, $display_name, $full_name, $directory_name, $sort_name, $firstname, $lastname, $email);
                 $uid = XDB::insertId();
                 XDB::execute('INSERT INTO  group_members (asso_id, uid)
                                    VALUES  ({?}, {?})',
@@ -613,8 +616,7 @@ class XnetGrpModule extends PLModule
             $uids_to_enable = array_intersect(array_keys(Post::v('enable_accounts')), $uids);
 
             $user = S::user();
-            $group = Platal::globals()->asso('nom');
-            $request = new BulkAccountsReq($user, $uids_to_enable, $group);
+            $request = new BulkAccountsReq($user, $uids_to_enable, $globals->asso('nom'), $globals->asso('diminutif'));
             $request->submit();
             $page->trigSuccess('Un email va bientôt être envoyé aux personnes sélectionnées pour l\'activation de leur compte.');
 
@@ -880,6 +882,7 @@ class XnetGrpModule extends PLModule
         global $globals;
 
         $page->changeTpl('xnetgrp/membres-add.tpl');
+        $page->addJsLink('xnet_members.js');
 
         if (is_null($email)) {
             return;
@@ -908,16 +911,20 @@ class XnetGrpModule extends PLModule
                 XDB::query('UPDATE  accounts
                                SET  email = {?}
                              WHERE  uid = {?} AND email IS NULL',
-                           Post::t('email'), $user->id());
+                           $email, $user->id());
                 // Add email for marketing if required.
-                if (Env::v('market')) {
+                if (Env::v('marketing')) {
                     $market = Marketing::get($user->uid, $email);
                     if (!$market) {
                         $market = new Marketing($user->uid, $email, 'group', $globals->asso('nom'),
-                                                Env::v('market_from'), S::v('uid'));
+                                                Env::v('marketing_from'), S::v('uid'));
                         $market->add();
                     }
                 }
+            } elseif (Env::v('broken')) {
+                // Add email for broken if required.
+                $valid = new BrokenReq(S::user(), $user, $email, 'Groupe : ' . $globals->asso('nom'));
+                $valid->submit();
             }
         } else {
             $user = User::getSilent($email);
@@ -946,20 +953,22 @@ class XnetGrpModule extends PLModule
 
                 // If the user has no account yet, creates new account: build names from email address.
                 if (empty($user)) {
+                    require_once 'name.func.inc.php';
                     $parts = explode('.', $mbox);
                     if (count($parts) == 1) {
-                        $lastname = $display_name = $full_name = $directory_name = ucfirst($mbox);
+                        $lastname = $display_name = capitalize_name($mbox);
                         $firstname = '';
                     } else {
-                        $firstname = ucfirst($parts[0]);
-                        $lastname = ucwords(implode(' ', array_slice($parts, 1)));
-                        $display_name = $firstname;
-                        $full_name = "$firstname $lastname";
-                        $directory_name = strtoupper($lastname) . " " . $firstname;
+                        $display_name = $firstname = capitalize_name($parts[0]);
+                        $lastname = capitalize_name(implode(' ', array_slice($parts, 1)));
                     }
-                    XDB::execute('INSERT INTO  accounts (hruid, display_name, full_name, directory_name, firstname, lastname, email, type, state)
-                                       VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, \'xnet\', \'disabled\')',
-                                 $hruid, $display_name, $full_name, $directory_name, $firstname, $lastname, $email);
+                    $full_name = build_full_name($firstname, $lastname);
+                    $directory_name = build_directory_name($firstname, $lastname);
+                    $sort_name = build_sort_name($firstname, $lastname);
+                    XDB::execute('INSERT INTO  accounts (hruid, display_name, full_name, directory_name, sort_name,
+                                                         firstname, lastname, email, type, state)
+                                       VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, \'xnet\', \'disabled\')',
+                                 $hruid, $display_name, $full_name, $directory_name, $sort_name, $firstname, $lastname, $email);
                     $user = User::getSilent($hruid);
                 }
 
@@ -1024,11 +1033,13 @@ class XnetGrpModule extends PLModule
 
         if (Post::has('suggest')) {
             if (Post::t('suggest') == 'yes') {
+                global $globals;
+
                 $user = S::user();
-                $request = new AccountReq($user, $hruid, $email, Platal::globals()->asso('nom'));
+                $request = new AccountReq($user, $hruid, $email, $globals->asso('nom'), $globals->asso('diminutif'));
                 $request->submit();
                 $page->trigSuccessRedirect('Un email va bien être envoyé à ' . $email . ' pour l\'activation de son compte.',
-                                           Platal::globals()->asso('diminutif') . '/member/' . $hruid);
+                                           $globals->asso('diminutif') . '/member/' . $hruid);
             } else {
                 pl_redirect('member/' . $hruid);
             }
@@ -1037,20 +1048,34 @@ class XnetGrpModule extends PLModule
         $page->assign('hruid', $hruid);
     }
 
+    function handler_admin_member_reg($page, $uid)
+    {
+        pl_content_headers('text/plain');
+
+        $user = User::getSilentWithUID($uid);
+        if ($user && $user->state != 'pending' && $user->hasProfile()) {
+            echo true;
+        }
+        echo false;
+        exit();
+    }
+
     function handler_admin_member_new_ajax($page)
     {
         pl_content_headers("text/html");
         $page->changeTpl('xnetgrp/membres-new-search.tpl', NO_SKIN);
         $users = array();
+        $same_email = false;
         if (Env::has('login')) {
             $user = User::getSilent(Env::t('login'));
             if ($user && $user->state != 'pending') {
-                $users = array($user);
+                $users = array($user->id() => $user);
+                $same_email = true;
             }
         }
         if (empty($users)) {
             list($lastname, $firstname) = str_replace(array('-', ' ', "'"), '%', array(Env::t('nom'), Env::t('prenom')));
-            $cond = new PFC_And(new PFC_Not(new UFC_Registered()));
+            $cond = new PFC_And();
             if (!empty($lastname)) {
                 $cond->addChild(new UFC_NameTokens($lastname, array(), false, false, Profile::LASTNAME));
             }
@@ -1067,7 +1092,9 @@ class XnetGrpModule extends PLModule
                 $users = array();
             }
         }
+
         $page->assign('users', $users);
+        $page->assign('same_email', $same_email);
     }
 
     function unsubscribe(PlUser $user, $remember = false)
@@ -1190,7 +1217,7 @@ class XnetGrpModule extends PLModule
         }
     }
 
-    private function changeLogin(PlPage $page, PlUser $user, $login)
+    private function changeLogin(PlPage $page, PlUser $user, $login, $req_broken = false, $req_marketing = false, $marketing_from = 'user')
     {
         // Search the user's uid.
         $xuser = User::getSilent($login);
@@ -1210,6 +1237,19 @@ class XnetGrpModule extends PLModule
             return false;
         }
 
+        // Market or suggest new redirection if required.
+        $email = $user->bestEmail();
+        if ($req_broken) {
+            $valid = new BrokenReq(S::user(), $xuser, $email, 'Groupe : ' . Platal::globals()->asso('nom'));
+            $valid->submit();
+        } elseif ($req_marketing) {
+            $market = Marketing::get($xuser->uid, $email);
+            if (!$market) {
+                $market = new Marketing($xuser->uid, $email, 'group', Platal::globals()->asso('nom'), $marketing_from, S::i('uid'));
+                $market->add();
+            }
+        }
+
         if ($user->mergeIn($xuser)) {
             return $xuser->login();
         }
@@ -1230,16 +1270,18 @@ class XnetGrpModule extends PLModule
         }
 
         $page->changeTpl('xnetgrp/membres-edit.tpl');
+        $page->addJsLink('xnet_members.js');
 
         $mmlist = new MMList(S::user(), $globals->asso('mail_domain'));
 
         if (Post::has('change')) {
-            require_once 'emails.inc.php';
             S::assert_xsrf_token();
+            require_once 'emails.inc.php';
+            require_once 'name.func.inc.php';
 
             // Convert user status to X
-            if (!Post::blank('login_X')) {
-                $forlife = $this->changeLogin($page, $user, Post::t('login_X'));
+            if (!Post::blank('x')) {
+                $forlife = $this->changeLogin($page, $user, Post::i('userid'), Post::b('broken'), Post::b('marketing'), Post::v('marketing_from'));
                 if ($forlife) {
                     pl_redirect('member/' . $forlife);
                 }
@@ -1247,21 +1289,20 @@ class XnetGrpModule extends PLModule
 
             // Update user info
             if ($user->type == 'virtual' || ($user->type == 'xnet' && !$user->perms)) {
-                $lastname = Post::s('lastname');
+                $lastname = capitalize_name(Post::t('lastname'));
                 if (Post::s('type') != 'virtual') {
-                    $firstname = Post::s('firstname');
-                    $full_name = $firstname . ' ' . $lastname;
-                    $directory_name = mb_strtoupper($lastname) . ' ' . $firstname;
+                    $firstname = capitalize_name(Post::t('firstname'));
                 } else {
                     $firstname = '';
-                    $full_name = $lastname;
-                    $directory_name = mb_strtoupper($lastname);
                 }
+                $full_name = build_full_name($firstname, $lastname);
+                $directory_name = build_directory_name($firstname, $lastname);
+                $sort_name = build_sort_name($firstname, $lastname);
                 XDB::query('UPDATE  accounts
-                               SET  full_name = {?}, directory_name = {?}, display_name = {?},
+                               SET  full_name = {?}, directory_name = {?}, sort_name = {?}, display_name = {?},
                                     firstname = {?}, lastname = {?}, sex = {?}, type = {?}
                              WHERE  uid = {?}',
-                           $full_name, $directory_name, Post::t('display_name'), $firstname, $lastname,
+                           $full_name, $directory_name, $sort_name, Post::t('display_name'), $firstname, $lastname,
                            (Post::t('sex') == 'male') ? 'male' : 'female',
                            (Post::t('type') == 'xnet') ? 'xnet' : 'virtual', $user->id());
             }
@@ -1287,7 +1328,7 @@ class XnetGrpModule extends PLModule
 
             if (($user->type == 'xnet' && !$user->perms)) {
                 if (Post::b('suggest')) {
-                    $request = new AccountReq(S::user(), $user->hruid, Post::t('email'), $globals->asso('nom'));
+                    $request = new AccountReq(S::user(), $user->hruid, Post::t('email'), $globals->asso('nom'), $globals->asso('diminutif'));
                     $request->submit();
                     $page->trigSuccess('Le compte va bientôt être activé.');
                 }
index 02e1edc..6728ee1 100644 (file)
@@ -69,6 +69,11 @@ function smarty_function_display_address($param, $smarty)
     $map = "<a href=\"http://maps.google.fr/?q="
         .   urlencode(implode(", ", $lines) . " ($idt)")
         . "\"><img src=\"images/icons/map.gif\" alt=\"Google Maps\" title=\"Carte\"/></a>";
+    if ($adr->flags->hasflag('mail')) {
+        $mail = '&nbsp;<img src="images/icons/email_open.gif" alt="Adresse courier" title="On peut lui envoyer du courier à cette adresse." />';
+    } else {
+        $mail = '';
+    }
     $comment = "";
     if ($adr->comment != "")
     {
@@ -89,9 +94,9 @@ function smarty_function_display_address($param, $smarty)
     if ($param['titre'])
     {
         if ($param['titre_div'])
-            $txthtml .= "<div class='titre'>".pl_entity_decode($param['titre'])."&nbsp;".$map.$comment."</div>\n";
+            $txthtml .= '<div class="titre">' . pl_entity_decode($param['titre']) . '&nbsp;' . $map . $mail . $comment . "</div>\n";
         else
-            $txthtml .= "<em>".pl_entity_decode($param['titre'])."&nbsp;</em>".$map.$comment."<br />\n";
+            $txthtml .= '<em>' . pl_entity_decode($param['titre']) . '&nbsp;</em>' . $map . $mail . $comment . "<br />\n";
     }
     foreach ($lines as $line)
     {
diff --git a/templates/admin/admin_name.tpl b/templates/admin/admin_name.tpl
new file mode 100644 (file)
index 0000000..7317529
--- /dev/null
@@ -0,0 +1,58 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  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>Gestion des noms{if t($hruid)} de {profile user=$uid promo=true directory=false}{/if}</h1>
+
+{if t($hruid)}
+<form method="post" action="{$platal->ns}admin/name/{$hruid}">
+  <table class="bicol">
+    <tr>
+      <th></th>
+      <th>Version actuelle</th>
+      <th>Version suggérée</th>
+    </tr>
+    {foreach from=$names item=name key=type}
+    <tr>
+      <th>{$name_types.$type}</th>
+      <td><input type="text" size="40" name="{$type}" value="{$name.value}" {if $name.different}class="warning"{/if} /></td>
+      <td>{$name.standard}</td>
+    </tr>
+    {/foreach}
+  </table>
+  <p class="center">
+    <input type="submit" name="correct" value="Corriger" />
+  </p>
+</form>
+<p>
+  <a href="admin/name">Retour à la gestion des noms.</a>
+</p>
+{else}
+<form method="post" action="{$platal->ns}admin/name">
+  <p>
+    Il est possible d'entrer ici n'importe quelle adresse email&nbsp;: redirection, melix ou alias.<br />
+    <input type="text" size="60" name="id" />
+    <input type="submit" value="Chercher" />
+  </p>
+</form>
+{/if}
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index a29b211..74d07d1 100644 (file)
       <a href="admin/homonyms">Homonymes</a>
       &nbsp;&nbsp;|&nbsp;&nbsp;
       <a href="admin/deaths">Décès</a>
+      &nbsp;&nbsp;|&nbsp;&nbsp;
+      <a href="admin/name">Noms</a>
     </td>
   </tr>
   <tr class="pair">
index 2b1e15d..41f94fd 100644 (file)
@@ -28,6 +28,7 @@
 {if $firstnameIssues|@count eq 0}
 <p>Aucun problème avec les prénoms.</p>
 {else}
+<p><a href="fusionax/names/first/true">Obtenir le csv des conflits.</a></p>
 <table class="bicol">
   <tr>
     <th>pid</th>
 {/foreach}
 </table>
 {/if}
-{elseif $action eq "last"}
+{elseif $action eq "last" || $action eq "last1" || $action eq "last2" || $action eq "last3"}
+<h3>{$issuesTypes.$action}&nbsp;: {$total}</h3>
+<ul>
+  <li><a href="fusionax/names/last">{$issuesTypes.last}.</a></li>
+  <li><a href="fusionax/names/last1">{$issuesTypes.last1}.</a></li>
+  <li><a href="fusionax/names/last2">{$issuesTypes.last2}.</a></li>
+  <li><a href="fusionax/names/last3">{$issuesTypes.last3}.</a></li>
+</ul>
 {if $lastnameIssues|@count eq 0}
-<p>Aucun problème avec les noms.</p>
+<p>Aucun problème de ce type avec les noms.</p>
 {else}
+<p><a href="fusionax/names/last/true">Obtenir le csv des conflits.</a></p>
 <table class="bicol">
   <tr>
     <th>pid</th>
index 99cebb5..ec95e7f 100644 (file)
 
 <tr class="pair">
   <td class="titre">Groupe demandeur&nbsp;:</td>
-  <td>{$valid->group}</td>
+  <td><a href="http://polytechnique.net/{$valid->dim}">{$valid->group}</a></td>
 </tr>
 <tr class="pair">
   <td class="titre">Tous les groupes&nbsp;:</td>
-  <td>{$valid->groups}</td>
+  <td>
+  {foreach from=$valid->groups item=group}
+    <a href="http://polytechnique.net/{$group.diminutif}">{$group.nom}</a>
+  {/foreach}
+  </td>
 </tr>
 <tr class="pair">
   <td class="titre">Adresse email&nbsp;:</td>
index 59c27a4..2feb883 100644 (file)
@@ -22,7 +22,7 @@
 
 <tr class="pair">
   <td class="titre">Groupe demandeur&nbsp;:</td>
-  <td>{$valid->group}</td>
+  <td><a href="http://polytechnique.net/{$valid->dim}">{$valid->group}</a></td>
 </tr>
 <tr class="pair">
   <td class="titre">Adresses emails&nbsp;:</td>
diff --git a/templates/newsletter/nl.FX.mail.tpl b/templates/newsletter/nl.FX.mail.tpl
new file mode 100644 (file)
index 0000000..8332667
--- /dev/null
@@ -0,0 +1,99 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+{config_load file="mails.conf" section="mails_fx"}
+{if $mail_part eq 'head'}
+{from full=#from#}
+{subject text=$issue->title(true)}
+{if isset(#replyto#)}{add_header name='Reply-To' value=#replyto#}{/if}
+{if isset(#retpath#)}{add_header name='Return-Path' value=#retpath#}{/if}
+{elseif $mail_part eq 'text'}
+{if !$is_mail}
+<pre style="width : 72ex; margin: auto">
+{/if}
+====================================================================
+{$issue->title()}
+====================================================================
+
+{$issue->head($user, 'text')}
+
+{$issue->signature('text')}
+
+--------------------------------------------------------------------
+{if $is_mail}
+Pour faire un don : <http://fondationx.fr/fond/paiement.php>
+{else}
+Pour faire un don : &lt;http://fondationx.fr/fond/paiement.php&gt;
+{/if}
+Cette lettre est envoyée par la FX grâce aux outils de Polytechnique.org.
+
+{if $is_mail}
+archives         : <https://www.polytechnique.org/fxletter>
+ne plus recevoir : <https://www.polytechnique.org/fxletter/out/{if $hash}{$hash}{else}nohash{/if}/{$issue->id}>
+{else}
+archives         : &lt;https://www.polytechnique.org/fxletter&gt;
+ne plus recevoir : &lt;https://www.polytechnique.org/fxletter/out/{if $hash}{$hash}{else}nohash{/if}/{$issue->id}&gt;
+{/if}
+
+{if !$is_mail}
+</pre>
+{/if}
+{elseif $mail_part eq 'html'}
+{if $is_mail}
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Lettre d'information de la Fondation de l'École polytechnique</title>
+    <style type="text/css">
+      {literal}
+      body      { background-color: #ddd; color: #000; }
+      {/literal}
+    <!--
+      {$issue->css()}
+    -->
+    </style>
+  </head>
+  <body>
+    <div class="fx_background">
+{/if}
+    <div class='fx_mail'>
+      <div class="title">{$issue->title()}</div>
+      <div class="intro">{$issue->head($user, 'html')|smarty:nodefaults}</div>
+      <div class="signature">{$issue->signature('html')|smarty:nodefaults}</div>
+      <div class="give"><a href="http://fondationx.fr/fond/paiement.php">Faire un don</a></div>
+      <div class="foot1">
+        Cette lettre est envoyée par la FX grâce aux outils de Polytechnique.org.
+      </div>
+      <div class="foot2">
+        [<a href="https://www.polytechnique.org/fxletter">archives</a>&nbsp;|
+        <a href="https://www.polytechnique.org/fxletter/out/{if $hash}{$hash}{else}nohash{/if}/{$issue->id}">ne plus recevoir</a>]
+      </div>
+    </div>
+{if $is_mail}
+    </div>
+  </body>
+</html>
+{/if}
+{/if}
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 3c21fd8..c97b37f 100644 (file)
   </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>
+  <td></td>
 </tr>
 {/foreach}
 
index 254617c..4ee4407 100644 (file)
@@ -60,7 +60,7 @@
     <td></td>
   </tr>
   {/if}
-  <tr class="names_advanced" {if !$errors.search_names}style="display: none"{/if}>
+  <tr class="names_advanced_public" {if !$errors.search_names}style="display: none"{/if}>
     <td colspan="3">
       <span class="titre">Gestion des noms, prénoms, surnoms...</span>
       <span class="smaller">Ils déterminent la façon dont
       </div>
     </td>
   </tr>
+  <tr class="names_advanced_private" {if !$errors.search_names}style="display: none"{/if}>
+    <td class="center" colspan="2">
+      <small>Si la casse de ton nom est erronée et que tu n'arrives pas à la corriger,
+      <a href="mailto:support@{#globals.mail.domain#}">contacte-nous</a>.</small>
+    </td>
+  </tr>
 </table>
 
 <table class="bicol" style="margin-bottom: 1em"
index a50c9f4..3ef2d78 100644 (file)
 <div class="menu_item"><a href="nl">Lettres mensuelles</a></div>
 <div class="menu_item"><a href="ax">Lettres de l'AX</a></div>
 <div class="menu_item"><a href="epletter">Lettres de l'École</a></div>
+<div class="menu_item"><a href="fxletter">Lettres de la FX</a></div>
 <div class="menu_item"><a href="Xorg/NousContacter">Nous contacter</a></div>
 <div class="menu_item"><a href="send_bug/{ $smarty.server.REQUEST_URI }" class="popup2">Signaler un bug</a></div>
 
diff --git a/templates/xnetgrp/members_new_form.tpl b/templates/xnetgrp/members_new_form.tpl
new file mode 100644 (file)
index 0000000..2776c85
--- /dev/null
@@ -0,0 +1,47 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  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>
+  <td colspan="2">
+    <input type="checkbox" id="x" name="x" onchange="xStateChange(this, '{$platal->ns}');" />
+    <label for="x">Coche cette case s'il s'agit d'un X ou un master ou doctorant de l'X non inscrit à Polytechnique.org.</label>
+  </td>
+</tr>
+<tr class="details" style="display: none">
+  <td class="titre">Nom&nbsp;:</td>
+  <td><input type="text" id="nom" name="nom" size="20" value="" onkeyup="searchX('{$platal->ns}');" /></td>
+</tr>
+<tr class="details" style="display: none">
+  <td class="titre">Prénom&nbsp;:</td>
+  <td><input type="text" id="prenom" name="prenom" size="20" value="" onkeyup="searchX('{$platal->ns}');" /></td>
+</tr>
+<tr class="details" style="display: none">
+  <td class="titre">Promotion&nbsp;:</td>
+  <td><input type="text" id="promo" name="promo" size="4" value="" onkeyup="searchX('{$platal->ns}');" /> <small>(X2004)</small></td>
+</tr>
+<tr class="details pair" style="display: none">
+  <td colspan="2" id="search_result">
+    {include file="xnetgrp/membres-new-search.tpl"}
+  </td>
+</tr>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 43f52a7..1e2ee24 100644 (file)
 {*                                                                        *}
 {**************************************************************************}
 
-<script type="text/javascript">//<![CDATA[
-{literal}
-function xStateChange(box)
-{
-    var state = (box.checked ? '' : 'none');
-    document.getElementById('xnom').style.display = state;
-    document.getElementById('xprenom').style.display = state;
-    document.getElementById('xpromo').style.display = state;
-    document.getElementById('xsearch').style.display = state;
-    $('#search_result').updateHtml('{/literal}{$platal->ns}{literal}member/new/ajax?login='
-                                  + $('#email').val());
-}
-
-var nom;
-var prenom;
-var promo;
-function searchX()
-{
-    if (document.getElementById('nom').value == nom
-       && document.getElementById('prenom').value == prenom
-       && document.getElementById('promo').value == promo) {
-       return;
-    }
-    var nom = document.getElementById('nom').value;
-    var prenom = document.getElementById('prenom').value;
-    var promo = document.getElementById('promo').value;
-    $('#search_result').updateHtml('{/literal}{$platal->ns}{literal}member/new/ajax?prenom=' + prenom + '&nom=' + nom + '&promo=' + promo);
-}
-{/literal}
-//]]></script>
-
 <h1>{$asso->nom}&nbsp;: Ajout d'un membre</h1>
 
 <form method="post" action="{$platal->ns}member/new/">
@@ -77,34 +46,9 @@ function searchX()
           onclick='this.form.action += this.form.email.value' />
       </td>
     </tr>
-    <tr>
-      <td colspan="2">
-        <input type="checkbox" id="x" name="x" onchange="xStateChange(this);" />
-        {* TODO: adapts text for masters and doctorates when required. *}
-        <label for="x">Coche cette case s'il s'agit d'un X ou un master ou doctorant de l'X non inscrit à Polytechnique.org.</label>
-      </td>
-    </tr>
-    <tr id="xnom" style="display: none">
-      <td class="titre">Nom&nbsp;:</td>
-      <td><input type="text" id="nom" name="nom" size="20" value="" onkeyup="searchX();" /></td>
-    </tr>
-    <tr id="xprenom" style="display: none">
-      <td class="titre">Prénom&nbsp;:</td>
-      <td><input type="text" id="prenom" name="prenom" size="20" value="" onkeyup="searchX();" /></td>
-    </tr>
-    <tr id="xpromo" style="display: none">
-      <td class="titre">Promotion&nbsp;:</td>
-      {* TODO: add examples for masters and doctorates when required. *}
-      <td><input type="text" id="promo" name="promo" size="4" value="" onkeyup="searchX();" /> <small>(X2004)</small></td>
-    </tr>
-    <tr id="xsearch" style="display: none" class="pair">
-      <td colspan="2" id="search_result">
-        {include file="xnetgrp/membres-new-search.tpl"}
-      </td>
-    </tr>
+    {include file="xnetgrp/members_new_form.tpl" registered=false}
   </table>
 </form>
-
 {literal}
 <script type="text/javascript">
   $("#email").focus();
index acad698..14aef75 100644 (file)
       var state = (box.value != 'virtual') ? '' : 'none';
       document.getElementById('prenom').style.display = state;
       document.getElementById('sexe').style.display = state;
-      document.getElementById('make_X').style.display = state;
       document.getElementById('password').style.display = state;
   }
-
-  function showXInput(box)
-  {
-     if (box.checked) {
-       document.getElementById('make_X_cb').style.display = 'none';
-       document.getElementById('make_X_login').style.display = '';
-     }
-  }
 {/literal}
 </script>
 
 
 <h2>
   Édition du profil de {profile user=$user groupperms=false sex=false promo=true}
+  {if $user->bestEmail()}
   <a href="mailto:{$user->bestEmail()}">{icon name=email title="mail"}</a>
+  {/if}
 </h2>
 
+{if $user->type eq 'x' || $user->type eq 'master' || $user->type eq 'phd'}
+{if $user->state eq 'pending'}
+<p>
+  {"Ce"|sex:"Cette":$user} camarade n'est pas {"inscrit"|sex:"inscrite":$user}.
+  <a href="{$globals->xnet->xorg_baseurl}marketing/public/{$user->login()}" class='popup'>Si tu connais son adresse email,
+    <strong>n'hésite pas à nous la transmettre !</strong>
+  </a>
+</p>
+{elseif $user->state neq 'disabled' && $user->lost}
+<p>
+  {"Ce"|sex:"Cette":$user} camarade n'a plus d'adresse de redirection valide.
+  <a href="{$globals->xnet->xorg_baseurl}marketing/broken/{$user->login()}">
+    Si tu en connais une, <strong>n'hésite pas à nous la transmettre</strong>.
+  </a>
+</p>
+{/if}
+{/if}
+
 <form method="post" action="{$platal->ns}member/{$platal->argv[1]}">
   {xsrf_token_field}
   <table cellpadding="0" cellspacing="0" class='tinybicol'>
     </tr>
     {/if}
     {if $user->type eq 'xnet'}
-    <tr id="make_X">
-      <td colspan="2">
-        <span id="make_X_cb">
-          <input type="checkbox" name="is_x" id="is_x" onclick="showXInput(this);" onchange="showXInput(this);" />
-          <label for="is_x">coche cette case s'il s'agit d'un X ou un master ou doctorant de l'X</label>
-        </span>
-        <span id="make_X_login" style="display: none">
-          <span class="titre">Identifiant (prenom.nom.promo)&nbsp;:</span>
-          <input type="text" name="login_X" value="" />
-        </span>
-      </td>
-    </tr>
+    {include file="xnetgrp/members_new_form.tpl" registered=true}
     {/if}
     {if $user->type eq 'xnet' && $suggest}
     <tr>
     {/if}
   </table>
 
+  {if $user->bestEmail()}
   <h2>Abonnement aux listes</h2>
 
   <table cellpadding="0" cellspacing="0" class='large'>
     <tr><td colspan='2'>Pas d'alias pour ce groupe</td></tr>
     {/foreach}
   </table>
+  {else}
+  <p>Cette personne n'a pas d'email renseigné sur le site et ne peut donc pas être inscrite aux listes de diffusions et aux alias du groupe.</p>
+  {/if}
 
   <div class="center">
     <br />
index 8b70729..9c3b5b6 100644 (file)
 {*                                                                        *}
 {**************************************************************************}
 
-  {if t($too_many)}
-  Les critères de recherche ne sont pas assez précis.
-  {elseif !t($users) || $users|@count eq 0}
-  Aucun camarade non-inscrit ne correspond aux informations fournies.
-  {else}
-  Camarades correspondants&nbsp;:
-  <select name="userid" onchange="document.getElementById('marketing').style.display = (this.value == 0 ? 'none' : '')">
-    <option value="0">&nbsp;</option>
-    {foreach item=user from=$users}
-    <option value="{$user->id()}" {if $users|@count == 1}selected="selected"{/if}>{profile user=$user link=false promo=true}</option>
-    {/foreach}
+{if t($too_many)}
+Les critères de recherche ne sont pas assez précis.
+{elseif !t($users) || $users|@count eq 0}
+Aucun camarade non-inscrit ne correspond aux informations fournies.
+{else}
+Camarades correspondants&nbsp;:
+<select name="userid" onchange="updateSuggestions('{$platal->ns}', this.value)">
+  <option value="0" {if $users|@count neq 1}selected="selected"{/if}>&nbsp;</option>
+  {foreach item=user from=$users}
+  <option value="{$user->id()}" {if $users|@count == 1}selected="selected"{/if}>{profile user=$user link=false promo=true}</option>
+  {/foreach}
+</select>
+{if !$same_email}
+<span id="marketing" style="display: none"><br />
+  <label>
+    <input type="checkbox" name="marketing" onchange="$('#marketing_from').toggle()" />
+    Lui envoyer un marketing
+  </label>
+  <select name="marketing_from" id="marketing_from">
+    <option value="user" selected="selected">de ta part.</option>
+    <option value="staff">de la part de Polytechnique.org.</option>
   </select>
-  <span id="marketing" {if $users|@count != 1}style="display: none"{/if}><br />
-    <label><input type="checkbox" name="market" checked="checked"
-        onchange="document.getElementById('from').style.display = (this.checked ? '' : 'none')"/>
-    Lui envoyer un marketing</label>
-    <select name="market_from" id="from">
-      <option value="user" selected="selected">de ta part.</option>
-      <option value="staff">de la part de Polytechnique.org.</option>
-    </select>
-  </span>
-  {/if}
+</span>
+<span id="broken" style="display: none"><br />
+  Ce camarade est inscrit, mais l'email fourni ne fait pas partie de ses adresses de redirection.<br />
+  <label>
+    <input type="checkbox" name="broken" />
+    Lui suggérer d'ajouter cette adresse email à ses redirections.
+  </label>
+</span>
+{/if}
+{/if}
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index c451d2d..dc5e678 100755 (executable)
@@ -130,17 +130,17 @@ XDB::rawExecute("INSERT IGNORE INTO  profile_merge_issues (pid, issues, entry_ye
 XDB::rawExecute('ALTER TABLE geoloc_countries ADD INDEX (licensePlate)');
 XDB::rawExecute('UPDATE  profiles         AS p
              INNER JOIN  fusionax_anciens AS f ON (p.pid = f.pid)
-             INNER JOIN  geoloc_countries AS g ON (g.licensePlate = f.Code_nationalite AND g.nationalityFR IS NOT NULL)
+             INNER JOIN  geoloc_countries AS g ON (g.licensePlate = f.Code_nationalite AND g.nationality IS NOT NULL)
                     SET  p.nationality1 = g.iso_3166_1_a2
                   WHERE  p.nationality1 IS NULL');
 XDB::rawExecute('UPDATE  profiles         AS p
              INNER JOIN  fusionax_anciens AS f ON (p.pid = f.pid)
-             INNER JOIN  geoloc_countries AS g ON (g.licensePlate = f.Code_nationalite AND g.nationalityFR IS NOT NULL)
+             INNER JOIN  geoloc_countries AS g ON (g.licensePlate = f.Code_nationalite AND g.nationality IS NOT NULL)
                     SET  p.nationality2 = g.iso_3166_1_a2
                   WHERE  p.nationality1 != g.iso_3166_1_a2 AND p.nationality2 IS NULL');
 XDB::rawExecute('UPDATE  profiles         AS p
              INNER JOIN  fusionax_anciens AS f ON (p.pid = f.pid)
-             INNER JOIN  geoloc_countries AS g ON (g.licensePlate = f.Code_nationalite AND g.nationalityFR IS NOT NULL)
+             INNER JOIN  geoloc_countries AS g ON (g.licensePlate = f.Code_nationalite AND g.nationality IS NOT NULL)
                     SET  p.nationality3 = g.iso_3166_1_a2
                   WHERE  p.nationality1 != g.iso_3166_1_a2 AND p.nationality2 != g.iso_3166_1_a2 AND p.nationality3 IS NULL');
 XDB::rawExecute('ALTER TABLE geoloc_countries DROP INDEX licensePlate');
@@ -196,12 +196,12 @@ XDB::rawExecute("UPDATE  profiles         AS p
                   WHERE  f.Mel_publiable = 1 AND f.Mel_usage != '' AND p.email_directory IS NULL");
 XDB::rawExecute("INSERT IGNORE INTO  register_marketing (uid, email, type)
                              SELECT  ap.uid, f.Mel_usage, 'ax'
-                               FROM  fusionax_anciens AS f
-                         INNER JOIN  account_profiles AS ap ON (ap.pid = f.pid AND FIND_IN_SET('owner', perms))
-                          LEFT JOIN  emails           AS e  ON (e.uid = ap.uid AND e.flags = 'active')
+                               FROM  fusionax_anciens       AS f
+                         INNER JOIN  account_profiles       AS ap ON (ap.pid = f.pid AND FIND_IN_SET('owner', perms))
+                          LEFT JOIN  email_redirect_account AS e  ON (e.uid = ap.uid AND e.flags = 'active')
                               WHERE  f.Mel_usage != '' AND f.Mel_usage NOT LIKE '%@polytechnique.edu'
                                      AND f.Mel_usage NOT LIKE '%@polytechnique.org' AND f.Mel_usage NOT LIKE '%@m4x.org'
-                                     AND f.Mel_usage NOT LIKE '%@melix.%' AND e.email IS NULL");
+                                     AND f.Mel_usage NOT LIKE '%@melix.%' AND e.redirect IS NULL");
 
 // Retrieves different deathdates.
 XDB::rawExecute("UPDATE  profile_merge_issues AS pm
diff --git a/upgrade/1.0.1/merge_accent_names.php b/upgrade/1.0.1/merge_accent_names.php
new file mode 100755 (executable)
index 0000000..b8237a8
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/php5 -q
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2011 Polytechnique.org                              *
+ *  http://opensource.polytechnique.org/                                   *
+ *                                                                         *
+ *  This program is free software; you can redistribute it and/or modify   *
+ *  it under the terms of the GNU General Public License as published by   *
+ *  the Free Software Foundation; either version 2 of the License, or      *
+ *  (at your option) any later version.                                    *
+ *                                                                         *
+ *  This program is distributed in the hope that it will be useful,        *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *  GNU General Public License for more details.                           *
+ *                                                                         *
+ *  You should have received a copy of the GNU General Public License      *
+ *  along with this program; if not, write to the Free Software            *
+ *  Foundation, Inc.,                                                      *
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
+ ***************************************************************************/
+
+require '../../bin/connect.db.inc.php';
+
+$globals->debug = 0; // Do not store backtraces
+
+
+$res = XDB::iterator("SELECT  p.pid, p.ax_id, p.hrpid,
+                              f.Nom_patronymique, f.Nom_usuel, f.Nom_complet,
+                              ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary
+                        FROM  fusionax_anciens     AS f
+                  INNER JOIN  profiles             AS p   ON (f.ax_id = p.ax_id)
+                  INNER JOIN  profile_public_names AS ppn ON (p.pid = ppn.pid)
+                    ORDER BY  pid");
+
+function format($string)
+{
+    $string = preg_replace('/\-/', ' ', $string);
+    return preg_replace('/\s+/', ' ', $string);
+}
+
+$updates_count = 0;
+$count = 0;
+$total = $res->total();
+while ($item = $res->next()) {
+    array_map('trim', $item);
+    $ax_plain = array(
+        'Nom_patronymique' => mb_strtolower(replace_accent($item['Nom_patronymique'])),
+        'Nom_usuel'        => mb_strtolower(replace_accent($item['Nom_usuel'])),
+        'Nom_complet'      => mb_strtolower(replace_accent($item['Nom_complet']))
+    );
+    $ax = array();
+    foreach ($ax_plain as $key => $value) {
+        $ax[$key] = format($value);
+    }
+    $xorg = array(
+        'lastname_initial'  => format(mb_strtolower(replace_accent($item['lastname_initial']))),
+        'lastname_main'     => format(mb_strtolower(replace_accent($item['lastname_main']))),
+        'lastname_ordinary' => format(mb_strtolower(replace_accent($item['lastname_ordinary'])))
+    );
+
+    foreach ($xorg as $key => $name) {
+        $ax_key = array_search($name, $ax);
+        if ($ax_key !== false && mb_strtolower($item[$ax_key]) != mb_strtolower($item[$key]) && $ax_plain[$ax_key] == mb_strtolower($item[$key])) {
+            XDB::execute("UPDATE  profile_public_names
+                             SET  $key = {?}
+                           WHERE  pid = {?}",
+                         $item[$ax_key], $item['pid']);
+
+            ++$updates_count;
+        }
+    }
+
+    printf("\r%u / %u",  $count, $total);
+    ++$count;
+}
+printf("\r%u / %u\n\n",  $count, $total);
+
+echo "Nombre de mises à jour effectuées : " . $updates_count . ".\n";
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
index 1e8fdbb..1c06efc 100755 (executable)
@@ -5,6 +5,7 @@
 require_once 'connect.db.inc.php';
 require_once '../../classes/phone.php';
 require_once '../../classes/address.php';
+require_once '../../classes/visibility.php';
 
 $globals->debug = 0; // Do not store backtraces.
 
@@ -117,7 +118,7 @@ $rawAddresses = array();
 $duplicates = array();
 foreach ($pids as $pid) {
     $count = 0;
-    $it = Address::iterate(array($pid), array(Address::LINK_PROFILE), array(0));
+    $it = Address::iterate(array($pid), array(Address::LINK_PROFILE), array(0), Visibility::get(Visibility::VIEW_PRIVATE));
     while ($item = $it->next()) {
         $addresses[$count] = $item;
         $rawAddress = preg_replace('/[^a-z0-9]/', ' ', mb_strtolower(replace_accent($item->text)));
@@ -131,8 +132,7 @@ foreach ($pids as $pid) {
         for ($j = $i + 1; $j < $count; ++$j) {
             if (check($rawAddresses[$i], $rawAddresses[$j])) {
                 $duplicates[$j] = true;
-                $minPub = new ProfileVisibility($addresses[$j]->pub);
-                if ($minPub->isVisible($addresses[$i]->pub)) {
+                if (Visibility::isLessRestrictive($addresses[$i]->pub, $addresses[$j]->pub)) {
                     $addresses[$i]->pub = $addresses[$j]->pub;
                 }
                 if ($addresses[$j]->hasFlag('mail') && !$addresses[$i]->hasFlag('mail')) {
@@ -141,8 +141,10 @@ foreach ($pids as $pid) {
             }
         }
     }
-    foreach ($duplicates as $key => $bool) {
-        unset($addresses[$key]);
+    if (count($duplicates)) {
+        foreach ($duplicates as $key => $bool) {
+            unset($addresses[$key]);
+        }
     }
     if (count($addresses) != $count) {
         $deleted += ($count - count($addresses));
@@ -210,25 +212,25 @@ $phones = array();
 $duplicates = array();
 foreach ($pids as $pid) {
     $count = 0;
-    $it = Phone::iterate(array($pid), array(Phone::LINK_PROFILE), array(0));
+    $it = Phone::iterate(array($pid), array(Phone::LINK_PROFILE), array(0), Visibility::get(Visibility::VIEW_PRIVATE));
     while ($item = $it->next()) {
         $phones[] = $item;
         ++$count;
     }
     for ($i = 0; $i < $count; ++$i) {
         for ($j = $i + 1; $j < $count; ++$j) {
-            if ($phones[$i]->search() == $phones[$j]->search()) {
+            if ($phones[$i]->search == $phones[$j]->search) {
                 $duplicates[$j] = true;
-                $minPub = new ProfileVisibility($phones[$j]->pub);
-                if ($minPub->isVisible($phones[$i]->pub)) {
+                if (Visibility::isLessRestrictive($phones[$i]->pub, $phones[$j]->pub)) {
                     $phones[$i]->pub = $phones[$j]->pub;
                 }
-
             }
         }
     }
-    foreach ($duplicates as $key => $bool) {
-        unset($phones[$key]);
+    if (count($duplicates)) {
+        foreach ($duplicates as $key => $bool) {
+            unset($phones[$key]);
+        }
     }
     if (count($phones) != $count) {
         $deleted += ($count - count($phones));
diff --git a/upgrade/1.0.1/merge_issues_geocoding.php b/upgrade/1.0.1/merge_issues_geocoding.php
deleted file mode 100755 (executable)
index df98463..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/php5
-<?php
-// WARNING: this script takes a few weeks to be executed completly, thus run it into a screen.
-
-require_once 'connect.db.inc.php';
-require_once '../../classes/address.php';
-
-$globals->debug = 0; // Do not store backtraces.
-
-print "Tries to geocode addresses (due a bug in the previous release, all addresses must run once again).\n";
-$time = XDB::fetchOneCell('SELECT  COUNT(distinct(pid), jobid)
-                             FROM  profile_addresses
-                            WHERE  accuracy IS NOT NULL AND accuracy > 0');
-$time = ceil($time / 60 / 24);
-print "It will approximately take $time days.\n";
-
-$it = XDB::rawIterator('SELECT  *
-                          FROM  profile_addresses
-                         WHERE  accuracy IS NOT NULL AND accuracy > 0
-                      ORDER BY  pid, jobid, type, id');
-$total = $it->total();
-$i = 0;
-printf("\r%u / %u",  $i, $total);
-$pid = 0;
-$jobid = 0;
-while ($item = $it->next()) {
-    $address = new Address($item);
-    $address->format(array('requireGeocoding' => true, 'stripGeocoding' => true));
-    $address->delete();
-    $address->save();
-    if (!($pid == $address->pid && $jobid == $address->jobid)) {
-        $pid = $address->pid;
-        $jobid = $address->jobid;
-        sleep(60);
-    }
-
-    ++$i;
-    printf("\r%u / %u",  $i, $total);
-}
-print "\nGeocoding done.\n\n";
-print "That's all folks!\n";
-
-/* vim:set et sw=4 sts=4 ts=4: */
-?>
diff --git a/upgrade/1.0.1/merge_names.php b/upgrade/1.0.1/merge_names.php
new file mode 100755 (executable)
index 0000000..c1c784b
--- /dev/null
@@ -0,0 +1,186 @@
+#!/usr/bin/php5 -q
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2011 Polytechnique.org                              *
+ *  http://opensource.polytechnique.org/                                   *
+ *                                                                         *
+ *  This program is free software; you can redistribute it and/or modify   *
+ *  it under the terms of the GNU General Public License as published by   *
+ *  the Free Software Foundation; either version 2 of the License, or      *
+ *  (at your option) any later version.                                    *
+ *                                                                         *
+ *  This program is distributed in the hope that it will be useful,        *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *  GNU General Public License for more details.                           *
+ *                                                                         *
+ *  You should have received a copy of the GNU General Public License      *
+ *  along with this program; if not, write to the Free Software            *
+ *  Foundation, Inc.,                                                      *
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
+ ***************************************************************************/
+
+require '../../bin/connect.db.inc.php';
+
+$globals->debug = 0; // Do not store backtraces
+
+$res = XDB::rawFetchAllAssoc("SELECT  p.pid, p.ax_id, p.hrpid,
+                                      f.Nom_patronymique, f.Nom_usuel, f.Nom_complet,
+                                      ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary
+                                FROM  fusionax_anciens     AS f
+                          INNER JOIN  profiles             AS p   ON (f.ax_id = p.ax_id)
+                          INNER JOIN  profile_public_names AS ppn ON (p.pid = ppn.pid)
+                               WHERE  IF(f.partic_patro, CONCAT(f.partic_patro, CONCAT(' ', f.Nom_patronymique)), f.Nom_patronymique) NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)
+                                      OR IF(f.partic_nom, CONCAT(f.partic_nom, CONCAT(' ', f.Nom_usuel)), f.Nom_usuel) NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)
+                                      OR f.Nom_complet NOT IN (ppn.lastname_initial, ppn.lastname_main, ppn.lastname_marital, ppn.lastname_ordinary)");
+
+function fix_ax_particles($ax, $xorg, $item)
+{
+    $count = 0;
+    foreach ($ax as $ax_key => $ax_name) {
+        if (!in_array($ax_name, $xorg)) {
+            $new_name = '';
+            foreach ($xorg as $xorg_key => $xorg_name) {
+                if ($xorg_name && strpos($xorg_name, $ax_name) !== false) {
+                    if ($xorg_name == 'de ' . $ax_name) {
+                        $new_name = 'de ' . $item[$ax_key];
+                    } elseif ($xorg_name == "d'" . $ax_name) {
+                        $new_name = "d'" . $item[$ax_key];
+                    } elseif ($xorg_name == 'du ' . $ax_name) {
+                        $new_name = 'du ' . $item[$ax_key];
+                    }
+
+                    if ($new_name) {
+                        XDB::execute("UPDATE  fusionax_anciens
+                                         SET  $ax_key = {?}
+                                       WHERE  ax_id = {?}",
+                                     $new_name, $item['ax_id']);
+                        ++$count;
+                        break;
+                    }
+                }
+            }
+            if ($new_name) {
+                continue;
+            }
+            foreach ($ax as $ax_key2 => $ax_name2) {
+                if ($ax_name2 && strpos($ax_name2, $ax_name) !== false) {
+                    if ($ax_name2 == 'de ' . $ax_name) {
+                        $new_name = 'de ' . $item[$ax_key];
+                    } elseif ($ax_name2 == "d'" . $ax_name) {
+                        $new_name = "d'" . $item[$ax_key];
+                    } elseif ($ax_name2 == 'du ' . $ax_name) {
+                        $new_name = 'du ' . $item[$ax_key];
+                    }
+
+                    if ($new_name) {
+                        XDB::execute("UPDATE  fusionax_anciens
+                                         SET  $ax_key = {?}
+                                       WHERE  ax_id = {?}",
+                                     $new_name, $item['ax_id']);
+                        ++$count;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    return $count;
+}
+
+function fix_xorg_particles($ax, $xorg, $item)
+{
+    $count = 0;
+    foreach ($ax as $ax_key => $ax_name) {
+        if (!in_array($ax_name, $xorg)) {
+            foreach ($xorg as $xorg_key => $xorg_name) {
+                $new_name = '';
+                if ($xorg_name && strpos($ax_name, $xorg_name) !== false) {
+                    if ($ax_name == 'de ' . $xorg_name) {
+                        $new_name = 'de ' . $item[$xorg_key];
+                    } elseif ($ax_name == "d'" . $xorg_name) {
+                        $new_name = "d'" . $item[$xorg_key];
+                    } elseif ($ax_name == 'du ' . $xorg_name) {
+                        $new_name = 'du ' . $item[$xorg_key];
+                    }
+
+                    if ($new_name) {
+                        XDB::execute("UPDATE  profile_public_names
+                                         SET  $xorg_key = {?}
+                                       WHERE  pid = {?}",
+                                     $new_name, $item['pid']);
+                        ++$count;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    return $count;
+}
+
+function fix_xorg_full_name($ax, $xorg, $item)
+{
+    $new_name = '';
+    if (!in_array($ax['Nom_complet'], $xorg) && strpos($ax['Nom_complet'], $xorg['lastname_main']) !== false && $xorg['lastname_ordinary'] == '') {
+        XDB::execute("UPDATE  profile_public_names
+                         SET  lastname_main = {?}, lastname_ordinary = {?}
+                       WHERE  pid = {?}",
+                     $item['Nom_complet'], $item['lastname_main'], $item['pid']);
+        return 1;
+    }
+
+    return 0;
+}
+
+function fix_xorg_ordinary_name($ax, $xorg, $item)
+{
+    $new_name = '';
+    if (!in_array($ax['Nom_usuel'], $xorg) && $xorg['lastname_ordinary'] == '') {
+        XDB::execute("UPDATE  profile_public_names
+                         SET  lastname_ordinary = {?}
+                       WHERE  pid = {?}",
+                     $item['Nom_usuel'], $item['pid']);
+        return 1;
+    }
+
+    return 0;
+}
+
+function format($string)
+{
+    $string = preg_replace('/\-/', ' ', $string);
+    return preg_replace('/\s+/', ' ', $string);
+}
+
+$updates_count = 0;
+$count = 0;
+$total = count($res);
+foreach($res as $item) {
+    array_map('trim', $item);
+    $ax = array(
+        'Nom_patronymique' => format(mb_strtolower(replace_accent($item['Nom_patronymique']))),
+        'Nom_usuel'        => format(mb_strtolower(replace_accent($item['Nom_usuel']))),
+        'Nom_complet'      => format(mb_strtolower(replace_accent($item['Nom_complet'])))
+    );
+    $xorg = array(
+        'lastname_initial'  => format(mb_strtolower(replace_accent($item['lastname_initial']))),
+        'lastname_main'     => format(mb_strtolower(replace_accent($item['lastname_main']))),
+        'lastname_ordinary' => format(mb_strtolower(replace_accent($item['lastname_ordinary'])))
+    );
+
+    $updates_count += fix_ax_particles($ax, $xorg, $item);
+    $updates_count += fix_xorg_particles($ax, $xorg, $item);
+    $updates_count += fix_xorg_full_name($ax, $xorg, $item);
+    $updates_count += fix_xorg_ordinary_name($ax, $xorg, $item);
+    printf("\r%u / %u",  $count, $total);
+    ++$count;
+}
+printf("\r%u / %u\n\n",  $count, $total);
+
+echo "Nombre de mises à jour effectuées : " . $updates_count . ".\n";
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/upgrade/1.1.5/01_names.sql b/upgrade/1.1.5/01_names.sql
new file mode 100644 (file)
index 0000000..1f82d0c
--- /dev/null
@@ -0,0 +1,4 @@
+ALTER TABLE profile_public_names DROP COLUMN particles;
+ALTER TABLE accounts ADD COLUMN sort_name VARCHAR(255) DEFAULT NULL AFTER directory_name;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.5/02_validate.sql b/upgrade/1.1.5/02_validate.sql
new file mode 100644 (file)
index 0000000..514740e
--- /dev/null
@@ -0,0 +1,3 @@
+ALTER TABLE  requests_answers MODIFY COLUMN  category ENUM('alias','liste','usage','photo','evts','gapps-unsuspend','marketing','orange','homonyme','nl','paiements','medal','broken','surveys', 'entreprise','account','address','bulkaccounts') NOT NULL DEFAULT 'alias';
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.5/03_ax_id.sql b/upgrade/1.1.5/03_ax_id.sql
new file mode 100644 (file)
index 0000000..96e52e5
--- /dev/null
@@ -0,0 +1,3 @@
+UPDATE profiles SET ax_id = '20110202' WHERE pid = 47038;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.1.5/connect.db.inc.php b/upgrade/1.1.5/connect.db.inc.php
new file mode 120000 (symlink)
index 0000000..442fab7
--- /dev/null
@@ -0,0 +1 @@
+../../bin/connect.db.inc.php
\ No newline at end of file
diff --git a/upgrade/1.1.5/name.php b/upgrade/1.1.5/name.php
new file mode 100755 (executable)
index 0000000..c72f3a6
--- /dev/null
@@ -0,0 +1,103 @@
+#!/usr/bin/php5
+<?php
+require_once 'connect.db.inc.php';
+require_once '../../include/name.func.inc.php';
+
+// Returns the lower-cased name; if proper capitalization rule was not known,
+// warns the user, and returns the initial name.
+function capitalize_name_checked($name)
+{
+    if ($name == '') {
+        return '';
+    }
+
+    $capitalized = capitalize_name($name);
+    if (!$capitalized) {
+        echo " - WARNING: Unable to capitalize '$name'.\n";
+        return $name;
+    }
+    if (mb_strtolower($name, 'UTF-8') != mb_strtolower($capitalized, 'UTF-8')) {
+        echo " - WARNING: Capitalization of '$name' is unexpected: '$capitalized'\n";
+        return $name;
+    }
+
+    return $capitalized;
+}
+
+// Returns true iff the @p name looks like it should be properly recapitalized.
+function needs_conversion($name)
+{
+    if (strlen($name) == 0) {
+        return false;
+    }
+    if ($name == mb_strtoupper($name, 'UTF-8')) {
+        return true;
+    }
+
+    $name_length = mb_strlen($name, 'UTF-8');
+    $name_capitals = preg_replace('/\P{Lu}/u', '', $name);
+    return (mb_strlen($name_capitals, 'UTF-8') > 0.4 * $name_length);
+}
+
+// Retrieves all the names to convert.
+$conversions = 0;
+$names = XDB::iterator('SELECT  pid, lastname_initial, lastname_main, lastname_marital, lastname_ordinary,
+                                firstname_initial, firstname_main, firstname_ordinary, pseudonym
+                          FROM  profile_public_names');
+$name_list = array('lastname_initial', 'lastname_main', 'lastname_marital', 'lastname_ordinary',
+                   'firstname_initial', 'firstname_main', 'firstname_ordinary', 'pseudonym');
+$total = $names->total();
+while ($item = $names->next()) {
+    foreach ($name_list as $type) {
+        $item[$type] = capitalize_name_checked($item[$type]);
+    }
+
+    XDB::execute('UPDATE  profile_public_names
+                     SET  lastname_initial = {?}, lastname_main = {?}, lastname_marital = {?}, lastname_ordinary = {?},
+                          firstname_initial = {?}, firstname_main = {?}, firstname_ordinary = {?}, pseudonym = {?}
+                   WHERE  pid = {?}',
+                 $item['lastname_initial'], $item['lastname_main'], $item['lastname_marital'], $item['lastname_ordinary'],
+                 $item['firstname_initial'], $item['firstname_main'], $item['firstname_ordinary'], $item['pseudonym'],
+                 $item['pid']);
+    $profile = Profile::get($item['pid']);
+    update_display_names($profile, $item);
+
+    printf("\r%u / %u",  $conversions, $total);
+    $conversions++;
+    unset($item, $profile);
+}
+
+printf("\r%u / %u",  $conversions, $total);
+echo "\n$conversions names from profiles properly recapitalized.\n";
+
+$conversions = 0;
+$names = XDB::iterator('SELECT  uid, firstname, lastname
+                          FROM  accounts
+                         WHERE  NOT EXISTS (SELECT  1
+                                             FROM  account_profiles
+                                            WHERE  account_profiles.uid = accounts.uid)');
+
+$total = $names->total();
+while ($item = $names->next()) {
+    $lastname = capitalize_name_checked($item['lastname']);
+    $firstname = capitalize_name_checked($item['firstname']);
+
+    $full_name = build_full_name($firstname, $lastname);
+    $directory_name = build_directory_name($firstname, $lastname);
+    $sort_name = build_sort_name($firstname, $lastname);
+
+    XDB::execute('UPDATE  accounts
+                     SET  firstname = {?}, lastname = {?}, full_name = {?}, directory_name = {?}, sort_name = {?}
+                   WHERE  uid = {?}',
+                 $firstname, $lastname, $full_name, $directory_name, $sort_name, $item['uid']);
+
+    printf("\r%u / %u",  $conversions, $total);
+    $conversions++;
+    unset($item);
+}
+printf("\r%u / %u",  $conversions, $total);
+
+echo "\n$conversions names from accounts properly recapitalized.\n";
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
diff --git a/upgrade/1.1.5/update.sh b/upgrade/1.1.5/update.sh
new file mode 100755 (executable)
index 0000000..9230e34
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+. ../inc/pervasive.sh
+
+###########################################################
+[ "$DATABASE" != "x4dat" ] || die "Cannot target x4dat"
+
+confirm "* Running database upgrade scripts"
+mysql_run_directory .
diff --git a/ut/nametest.php b/ut/nametest.php
new file mode 100644 (file)
index 0000000..c85da5c
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2011 Polytechnique.org                              *
+ *  http://opensource.polytechnique.org/                                   *
+ *                                                                         *
+ *  This program is free software; you can redistribute it and/or modify   *
+ *  it under the terms of the GNU General Public License as published by   *
+ *  the Free Software Foundation; either version 2 of the License, or      *
+ *  (at your option) any later version.                                    *
+ *                                                                         *
+ *  This program is distributed in the hope that it will be useful,        *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *  GNU General Public License for more details.                           *
+ *                                                                         *
+ *  You should have received a copy of the GNU General Public License      *
+ *  along with this program; if not, write to the Free Software            *
+ *  Foundation, Inc.,                                                      *
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
+ ***************************************************************************/
+
+require_once dirname(__FILE__) . '/../include/test.inc.php';
+
+class NameTest extends PlTestCase
+{
+    private static function checkPlatal()
+    {
+        global $platal;
+
+        if (is_null($platal)) {
+            $platal = new Xorg();
+        }
+    }
+
+    public static function nameProvider()
+    {
+        return array(
+            array('jacob', 'Jacob', 'Jacob'),
+            array('pierre-alexis', 'Pierre-Alexis', 'Pierre-Alexis'),
+            array('de gaulle', 'de Gaulle', 'Gaulle'),
+            array("d'abcdef", "d'Abcdef", "Abcdef"),
+            array("o'brian", "O'Brian", "O'Brian"),
+            array("malloc'h", "Malloc'h", "Malloc'h"),
+            array("D'IRUMBERRY DE SALABERRY", "d'Irumberry de Salaberry", "Irumberry de Salaberry"),
+            array("LE BOUCHER D'HEROUVILLE", "Le Boucher d'Herouville", "Le Boucher d'Herouville"),
+            array("ÖZTÜRK-N'Dong-Nzue", "Öztürk-N'Dong-Nzue", "Öztürk-N'Dong-Nzue"),
+            array('MAC NAMARA', 'Mac Namara', 'MacNamara'),
+            array('MACNAMARA', 'Macnamara', 'Macnamara'),
+            array('MCNAMARA', 'Mcnamara', 'Macnamara')
+        );
+    }
+
+    /**
+     * @dataProvider nameProvider
+     */
+    public function testName($name, $capitalized_name, $sort_name)
+    {
+        self::checkPlatal();
+        require_once 'name.func.inc.php';
+
+        $test = capitalize_name($name);
+        $this->assertEquals($test, $capitalized_name);
+        $this->assertEquals(build_sort_name('', $test), $sort_name);
+    }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>