Merge branch 'xorg/maint' into xorg/1.0.2/master
authorFlorent Bruneau <florent.bruneau@polytechnique.org>
Sun, 16 Jan 2011 16:45:30 +0000 (17:45 +0100)
committerFlorent Bruneau <florent.bruneau@polytechnique.org>
Sun, 16 Jan 2011 16:45:30 +0000 (17:45 +0100)
104 files changed:
ChangeLog
bin/cron/profile_modification.php
bin/formatAddresses.php [new file with mode: 0755]
classes/address.php
classes/direnum.php
classes/geocoder.php
classes/gmapsgeocoder.php
classes/phone.php
classes/profile.php
classes/userfilter.php
configs/platal.ini
core
htdocs/images/none_md.png [new file with mode: 0644]
htdocs/images/none_x.png [moved from htdocs/images/none.png with 100% similarity]
htdocs/javascript/profile.js
include/education.func.inc.php
include/name.func.inc.php
include/notifs.inc.php
include/profilefields.inc.php
include/ufbuilder.inc.php
include/userset.inc.php
include/validations.inc.php
include/validations/entreprises.inc.php
modules/admin.php
modules/carnet.php
modules/email.php
modules/fusionax.php
modules/fusionax/Activites.sql
modules/fusionax/Adresses.sql
modules/fusionax/Anciens.sql
modules/fusionax/Formations.sql
modules/fusionax/Formations_MD.sql [new file with mode: 0644]
modules/fusionax/formation.pl
modules/gadgets.php
modules/googleapps.php
modules/lists.php
modules/lists/lists.inc.php
modules/payment.php
modules/payment/money/bplccyberplus.inc.php
modules/payment/money/paypal.inc.php
modules/profile.php
modules/profile/addresses.inc.php
modules/profile/general.inc.php
modules/profile/jobs.inc.php
modules/profile/mentor.inc.php
modules/profile/page.inc.php
modules/profile/skills.inc.php
modules/register.php
modules/search.php
modules/xnetevents.php
modules/xnetgrp.php
plugins/function.select_nat.php
templates/admin/index.tpl
templates/admin/profile.tpl [new file with mode: 0644]
templates/admin/validation.tpl
templates/carnet/notif.mail.tpl
templates/emails/broken-web.mail.tpl
templates/emails/broken.mail.tpl
templates/emails/rewrite-in.mail.tpl
templates/emails/test.mail.tpl
templates/fusionax/corps.tpl [new file with mode: 0644]
templates/fusionax/index.tpl
templates/geoloc/form.address.tpl
templates/googleapps/create.mail.tpl
templates/googleapps/unsuspend.mail.tpl
templates/include/emails.combobox.tpl
templates/include/flags.radio.tpl
templates/lists/admin.tpl
templates/lists/display_list.tpl [new file with mode: 0644]
templates/lists/members.tpl
templates/marketing/relance.mail.tpl
templates/payment/index.tpl
templates/profile/adresses.address.tpl
templates/profile/general.tpl
templates/profile/geocoding.mail.tpl
templates/profile/jobs.job.tpl
templates/profile/jobs.tpl
templates/profile/mentor.tpl
templates/profile/notification.mail.tpl
templates/profile/phone.tpl
templates/register/end.mail.tpl
templates/register/lostalias.mail.tpl
templates/register/marketer.mail.tpl
templates/register/step3.tpl
templates/register/success.mail.tpl
templates/search/adv.form.tpl
templates/skin/common.menu.tpl
templates/xnetevents/newpayment.mail.tpl
templates/xnetgrp/unsubscription-notif.mail.tpl
upgrade/1.0.1/merge.php
upgrade/1.0.1/merge_issues.php
upgrade/1.0.1/merge_issues_geocoding.php
upgrade/1.0.2/00_address.sql [new file with mode: 0644]
upgrade/1.0.2/01_photos.sql [new file with mode: 0644]
upgrade/1.0.2/02_modifications.sql [new file with mode: 0644]
upgrade/1.0.2/03_phones.sql [new file with mode: 0644]
upgrade/1.0.2/04_publicity.sql [new file with mode: 0644]
upgrade/1.0.2/05_educations.sql [moved from upgrade/1.0.1/xxx.educations.sql with 100% similarity]
upgrade/1.0.2/06_geocoding.sql [new file with mode: 0644]
upgrade/1.0.2/07_areas.sql [new file with mode: 0644]
upgrade/1.0.2/08_xnet_payments.sql [new file with mode: 0644]
upgrade/1.0.2/connect.db.inc.php [new symlink]
upgrade/1.0.2/geocoding.php [new file with mode: 0755]
ut/checkdb.php

index b8bbc3d..46886f1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,43 @@
 ================================================================================
+VERSION 1.0.2                                                         XX XX XXXX
+
+Bug/Wish:
+
+    * Admin:
+        - #1362: List last profile modifications for secretary             -JAC
+
+    * Core:
+        - #1352: Fixes csv downloading with IE8.                           -JAC
+        - #1355: Mode with propagation of the skinning mode                -FRU
+
+    * Payments:
+        - #1290: Fixes display of payments on xnet                         -JAC
+        - #1318: Fixes PHP errors in PayPal payments                       -JAC
+
+    * Profile:
+        - #1270: Adapts default picture to main education                  -JAC
+        - #1340: Allows secretaries and admin to fully edit profiles' name -JAC
+        - #1354: Do not notify death to a deceased user                    -JAC
+        - #1356: Indicates delivery issues on addresses                    -JAC
+        - #1360: Default profile publicity is now ax                       -JAC
+        - #1361: Allows secretaries to validate entreprises                -JAC
+        - #1363: Prevents deletion of private information by secretaries   -JAC
+        - #1364: Only admin can edit original corps                        -JAC
+        - #1367: Improves postal address formatting                        -JAC
+        - #1368: Allows admin profile edition even if birthdate is unknown -JAC
+        - #1369: Properly displays moderated jobs                          -JAC
+
+    * Register:
+        - #1374: Adapts registration for master and doctorate              -JAC
+
+    * Search:
+        - #1365: Outputs csv of postal addresses for advanced search       -JAC
+        - #1366: Adds 'by AX id' advanced search for admins                -Xel
+
+    * XnetEvent:
+        - #1373: Fixes acceptance of non member in xnet events.            -JAC
+
+================================================================================
 VERSION 1.0.1                                                         26 10 2010
 
 New:
index 8d4b4d0..ef7cbdf 100755 (executable)
@@ -31,7 +31,8 @@ $res = XDB::iterator('SELECT  p.hrpid, pm.pid, a.full_name, pm.field, pm.oldText
                   INNER JOIN  profile_display       AS pd ON (pm.pid = pd.pid)
                   INNER JOIN  account_profiles      AS ap ON (pm.pid = ap.pid AND FIND_IN_SET(\'owner\', ap.perms))
                   INNER JOIN  aliases               AS al ON (ap.uid = al.uid AND FIND_IN_SET(\'bestalias\', al.flags))
-                    ORDER BY  pm.pid, pm.field');
+                       WHERE  pm.type = \'third_party\' AND pm.field != \'deathdate\'
+                    ORDER BY  pm.pid, pm.field, pm.timestamp');
 
 if ($res->total() > 0) {
     $date = time();
@@ -83,7 +84,8 @@ if ($res->total() > 0) {
     $mailer->assign('date', $date);
     $mailer->send();
 
-    XDB::execute('DELETE FROM  profile_modifications');
+    XDB::execute('DELETE FROM  profile_modifications
+                        WHERE  type = \'third_party\'');
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
diff --git a/bin/formatAddresses.php b/bin/formatAddresses.php
new file mode 100755 (executable)
index 0000000..a32a17a
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/php5 -q
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2010 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_once '../classes/address.php';
+
+$globals->debug = 0; // Do not store backtraces
+
+print "(Re)Formats postal addresses for all addresses in the database.\n";
+$it = XDB::rawIterator('SELECT  *
+                          FROM  profile_addresses
+                      ORDER BY  pid, jobid, type, id');
+$total = $it->total();
+$i = 0;
+$j = 0;
+printf("\r%u / %u",  $i, $total);
+while ($item = $it->next()) {
+    $address = new Address($item);
+    $address->format(array('postalText' => true));
+    $address->delete();
+    $address->save();
+
+    ++$i;
+    if ($i == 100) {
+        ++$j;
+        $i = 0;
+        printf("\r%u / %u",  $i + 100 * $j, $total);
+    }
+}
+print "Done.\n";
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
index c3c0dea..f4a951e 100644 (file)
@@ -49,6 +49,238 @@ class Address
     const LINK_COMPANY = 'hq';
     const LINK_PROFILE = 'home';
 
+    // List of all available postal formattings.
+    private static $formattings = array('FRANCE' => 'FR');
+
+    // Abbreviations to be used to format French postal addresses.
+    private static $streetAbbreviations = array(
+        'ALLEE'                        => 'ALL',
+        'AVENUE'                       => 'AV',
+        'BOULEVARD'                    => 'BD',
+        'CENTRE'                       => 'CTRE',
+        'CENTRE COMMERCIAL'            => 'CCAL',
+        'IMMEUBLE'                     => 'IMM',
+        'IMMEUBLES'                    => 'IMM',
+        'IMPASSE'                      => 'IMP',
+        'LIEU-DIT'                     => 'LD',
+        'LOTISSEMENT'                  => 'LOT',
+        'PASSAGE'                      => 'PAS',
+        'PLACE'                        => 'PL',
+        'RESIDENCE'                    => 'RES',
+        'ROND-POINT'                   => 'RPT',
+        'ROUTE'                        => 'RTE',
+        'SQUARE'                       => 'SQ',
+        'VILLAGE'                      => 'VLGE',
+        'ZONE D\'ACTIVITE'             => 'ZA',
+        'ZONE D\'AMENAGEMENT CONCERTE' => 'ZAC',
+        'ZONE D\'AMENAGEMENT DIFFERE'  => 'ZAD',
+        'ZONE INDUSTRIELLE'            => 'ZI'
+    );
+    private static $otherAbbreviations = array(
+        'ADJUDANT'               => 'ADJ',
+        'AERODROME'              => 'AERD',
+        'AEROGARE'               => 'AERG',
+        'AERONAUTIQUE'           => 'AERN',
+        'AEROPORT'               => 'AERP',
+        'AGENCE'                 => 'AGCE',
+        'AGRICOLE'               => 'AGRIC',
+        'ANCIEN'                 => 'ANC',
+        'ANCIENNEMENT'           => 'ANC',
+        'APPARTEMENT'            => 'APP',
+        'APPARTEMENTS'           => 'APP',
+        'ARMEMENT'               => 'ARMT',
+        'ARRONDISSEMENT'         => 'ARR',
+        'ASPIRANT'               => 'ASP',
+        'ASSOCIATION'            => 'ASSOC',
+        'ASSURANCE'              => 'ASSUR',
+        'ATELIER'                => 'AT',
+        'BARAQUEMENT'            => 'BRQ',
+        'BAS'                    => 'BAS',
+        'BASSE'                  => 'BAS',
+        'BASSES'                 => 'BAS',
+        'BATAILLON'              => 'BTN',
+        'BATAILLONS'             => 'BTN',
+        'BATIMENT'               => 'BAT',
+        'BATIMENTS'              => 'BAT',
+        'BIS'                    => 'B',
+        'BOITE POSTALE'          => 'BP',
+        'CABINET'                => 'CAB',
+        'CANTON'                 => 'CANT',
+        'CARDINAL'               => 'CDL',
+        'CASE POSTALE'           => 'CP',
+        'CHAMBRE'                => 'CHBR',
+        'CITADELLE'              => 'CTD',
+        'COLLEGE'                => 'COLL',
+        'COLONEL'                => 'CNL',
+        'COLONIE'                => 'COLO',
+        'COMITE'                 => 'CTE',
+        'COMMANDANT'             => 'CDT',
+        'COMMERCIAL'             => 'CIAL',
+        'COMMUNE'                => 'COM',
+        'COMMUNAL'               => 'COM',
+        'COMMUNAUX'              => 'COM',
+        'COMPAGNIE'              => 'CIE',
+        'COMPAGNON'              => 'COMP',
+        'COMPAGNONS'             => 'COMP',
+        'COOPERATIVE'            => 'COOP',
+        'COURSE SPECIALE'        => 'CS',
+        'CROIX'                  => 'CRX',
+        'DELEGATION'             => 'DELEG',
+        'DEPARTEMENTAL'          => 'DEP',
+        'DEPARTEMENTAUX'         => 'DEP',
+        'DIRECTEUR'              => 'DIR',
+        'DIRECTECTION'           => 'DIR',
+        'DIVISION'               => 'DIV',
+        'DOCTEUR'                => 'DR',
+        'ECONOMIE'               => 'ECO',
+        'ECONOMIQUE'             => 'ECO',
+        'ECRIVAIN'               => 'ECRIV',
+        'ECRIVAINS'              => 'ECRIV',
+        'ENSEIGNEMENT'           => 'ENST',
+        'ENSEMBLE'               => 'ENS',
+        'ENTREE'                 => 'ENT',
+        'ENTREES'                => 'ENT',
+        'ENTREPRISE'             => 'ENTR',
+        'EPOUX'                  => 'EP',
+        'EPOUSE'                 => 'EP',
+        'ETABLISSEMENT'          => 'ETS',
+        'ETAGE'                  => 'ETG',
+        'ETAT MAJOR'             => 'EM',
+        'EVEQUE'                 => 'EVQ',
+        'FACULTE'                => 'FAC',
+        'FORET'                  => 'FOR',
+        'FORESTIER'              => 'FOR',
+        'FRANCAIS'               => 'FR',
+        'FRANCAISE'              => 'FR',
+        'FUSILIER'               => 'FUS',
+        'GENDARMERIE'            => 'GEND',
+        'GENERAL'                => 'GAL',
+        'GOUVERNEMENTAL'         => 'GOUV',
+        'GOUVERNEUR'             => 'GOU',
+        'GRAND'                  => 'GD',
+        'GRANDE'                 => 'GDE',
+        'GRANDES'                => 'GDES',
+        'GRANDS'                 => 'GDS',
+        'HAUT'                   => 'HT',
+        'HAUTE'                  => 'HTE',
+        'HAUTES'                 => 'HTES',
+        'HAUTS'                  => 'HTS',
+        'HOPITAL'                => 'HOP',
+        'HOPITAUX'               => 'HOP',
+        'HOSPICE'                => 'HOSP',
+        'HOSPITALIER'            => 'HOSP',
+        'HOTEL'                  => 'HOT',
+        'INFANTERIE'             => 'INFANT',
+        'INFERIEUR'              => 'INF',
+        'INFERIEUR'              => 'INF',
+        'INGENIEUR'              => 'ING',
+        'INSPECTEUR'             => 'INSP',
+        'INSTITUT'               => 'INST',
+        'INTERNATIONAL'          => 'INTERN',
+        'INTERNATIONALE'         => 'INTERN',
+        'LABORATOIRE'            => 'LABO',
+        'LIEUTENANT'             => 'LT',
+        'LIEUTENANT DE VAISSEAU' => 'LTDV',
+        'MADAME'                 => 'MME',
+        'MADEMOISELLE'           => 'MLLE',
+        'MAGASIN'                => 'MAG',
+        'MAISON'                 => 'MAIS',
+        'MAITRE'                 => 'ME',
+        'MARECHAL'               => 'MAL',
+        'MARITIME'               => 'MAR',
+        'MEDECIN'                => 'MED',
+        'MEDICAL'                => 'MED',
+        'MESDAMES'               => 'MMES',
+        'MESDEMOISELLES'         => 'MLLES',
+        'MESSIEURS'              => 'MM',
+        'MILITAIRE'              => 'MIL',
+        'MINISTERE'              => 'MIN',
+        'MONSEIGNEUR'            => 'MGR',
+        'MONSIEUR'               => 'M',
+        'MUNICIPAL'              => 'MUN',
+        'MUTUEL'                 => 'MUT',
+        'NATIONAL'               => 'NAL',
+        'NOTRE DAME'             => 'ND',
+        'NOUVEAU'                => 'NOUV',
+        'NOUVEL'                 => 'NOUV',
+        'NOUVELLE'               => 'NOUV',
+        'OBSERVATOIRE'           => 'OBS',
+        'PASTEUR'                => 'PAST',
+        'PETIT'                  => 'PT',
+        'PETITE'                 => 'PTE',
+        'PETITES'                => 'PTES',
+        'PETITS'                 => 'PTS',
+        'POLICE'                 => 'POL',
+        'PREFET'                 => 'PREF',
+        'PREFECTURE'             => 'PREF',
+        'PRESIDENT'              => 'PDT',
+        'PROFESSEUR'             => 'PR',
+        'PROFESSIONNEL'          => 'PROF',
+        'PROFESSIONNELE'         => 'PROF',
+        'PROLONGE'               => 'PROL',
+        'PROLONGEE'              => 'PROL',
+        'PROPRIETE'              => 'PROP',
+        'QUATER'                 => 'Q',
+        'QUINQUIES'              => 'C',
+        'RECTEUR'                => 'RECT',
+        'REGIMENT'               => 'RGT',
+        'REGION'                 => 'REG',
+        'REGIONAL'               => 'REG',
+        'REGIONALE'              => 'REG',
+        'REPUBLIQUE'             => 'REP',
+        'RESTAURANT'             => 'REST',
+        'SAINT'                  => 'ST',
+        'SAINTE'                 => 'STE',
+        'SAINTES'                => 'STES',
+        'SAINTS'                 => 'STS',
+        'SANATORIUM'             => 'SANA',
+        'SERGENT'                => 'SGT',
+        'SERVICE'                => 'SCE',
+        'SOCIETE'                => 'SOC',
+        'SOUS COUVERT'           => 'SC',
+        'SOUS-PREFET'            => 'SPREF',
+        'SUPERIEUR'              => 'SUP',
+        'SUPERIEURE'             => 'SUP',
+        'SYNDICAT'               => 'SYND',
+        'TECHNICIEN'             => 'TECH',
+        'TECHNICIENNE'           => 'TECH',
+        'TECHNICIQUE'            => 'TECH',
+        'TER'                    => 'T',
+        'TRI SERVICE ARRIVEE'    => 'TSA',
+        'TUNNEL'                 => 'TUN',
+        'UNIVERSITAIRE'          => 'UNVT',
+        'UNIVERSITE'             => 'UNIV',
+        'VELODROME'              => 'VELOD',
+        'VEUVE'                  => 'VVE',
+        'VIEILLE'                => 'VIEL',
+        'VIEILLES'               => 'VIEL',
+        'VIEUX'                  => 'VX'
+    );
+    private static $entrepriseAbbreviations = array(
+        'COOPERATIVE D\'UTILISATION DE MATERIEL AGRICOLE EN COMMUN' => 'CUMA',
+        'ETABLISSEMENT PUBLIC A CARACTERE INDUSTRIEL ET COMMERCIAL' => 'EPIC',
+        'ETABLISSEMENT PUBLIC ADMINISTRATIF'                        => 'EPA',
+        'GROUPEMENT AGRICOLE D\'EXPLOITATION EN COMMUN'             => 'GAEC',
+        'GROUPEMENT D\'INTERET ECONOMIQUE'                          => 'GIE',
+        'GROUPEMENT D\'INTERET PUBLIC'                              => 'GIP',
+        'GROUPEMENT EUROPEEN D\'INTERET ECONOMIQUE'                 => 'GEIE',
+        'OFFICE PUBLIC D\'HABITATION A LOYER MODERE'                => 'OPHLM',
+        'SOCIETE A RESPONSABILITE LIMITEE'                          => 'SARL',
+        'SOCIETE ANONYME'                                           => 'SA',
+        'SOCIETE CIVILE DE PLACEMENT COLLECTIF IMMOBILIER'          => 'SCPI',
+        'SOCIETE CIVILE PROFESSIONNELLE'                            => 'SCP',
+        'SOCIETE COOPERATIVE OUVRIERE DE PRODUCTION ET DE CREDIT'   => 'SCOP',
+        'SOCIETE D\'AMENAGEMENT FONCIER ET D\'EQUIPEMENT RURAL'     => 'SAFER',
+        'SOCIETE D\'ECONOMIE MIXTE'                                 => 'SEM',
+        'SOCIETE D\'INTERET COLLECTIF AGRICOLE'                     => 'SICA',
+        'SOCIETE D\'INVESTISSEMENT A CAPITAL VARIABLE'              => 'SICAV',
+        'SOCIETE EN NOM COLLECTIF'                                  => 'SNC',
+        'SOCIETE IMMOBILIERE POUR LE COMMERCE ET L\'INDUSTRIE'      => 'SICOMI',
+        'SOCIETE MIXTE D\'INTERET AGRICOLE'                         => 'SMIA',
+        'SYNDICAT INTERCOMMUNAL A VOCATION MULTIPLE'                => 'SIVOM',
+        'SYNDICAT INTERCOMMUNAL A VOCATION UNIQUE'                  => 'SIVU'
+    );
+
     // Primary key fields: the quadruplet ($pid, $jobid, $type, $id) defines a unique address.
     public $pid = 0;
     public $jobid = 0;
@@ -66,6 +298,9 @@ class Address
     public $localityName = null;
     public $subAdministrativeAreaName = null;
     public $administrativeAreaName = null;
+    public $localityNameLocal = null;
+    public $subAdministrativeAreaNameLocal = null;
+    public $administrativeAreaNameLocal = null;
     public $countryId = null;
     public $latitude = null;
     public $longitude = null;
@@ -74,19 +309,19 @@ class Address
     public $east = null;
     public $west = null;
     public $geocodedText = null;
-    public $geocodedPostalText = null;
     public $geocodeChosen = null;
 
     // Database's field required for both 'home' and 'job' addresses.
-    public $pub = 'private';
+    public $pub = 'ax';
 
     // Database's fields required for 'home' addresses.
-    public $flags = null; // 'current', 'temporary', 'secondary', 'mail', 'cedex'
+    public $flags = null; // 'current', 'temporary', 'secondary', 'mail', 'cedex', 'deliveryIssue'
     public $comment = null;
     public $current = null;
     public $temporary = null;
     public $secondary = null;
     public $mail = null;
+    public $deliveryIssue = null;
 
     // Remaining fields that do not belong to profile_addresses.
     public $phones = array();
@@ -105,7 +340,7 @@ class Address
         if (!is_null($this->flags)) {
             $this->flags = new PlFlagSet($this->flags);
         } else {
-            static $flags = array('current', 'temporary', 'secondary', 'mail');
+            static $flags = array('current', 'temporary', 'secondary', 'mail', 'deliveryIssue');
 
             $this->flags = new PlFlagSet();
             foreach ($flags as $flag) {
@@ -141,11 +376,212 @@ class Address
         return ($this->flags != null && $this->flags->hasFlag($flag));
     }
 
+    public function addFlag($flag)
+    {
+        $this->flags->addFlag($flag);
+    }
+
+    /** Auxilary function for formatting postal addresses.
+     * If the needle is found in the haystack, it notifies the substitution's
+     * success, modifies the length accordingly and returns either the matching
+     * substitution or the needle.
+     */
+    private function substitute($needle, $haystack, &$length, &$success, $trim = false)
+    {
+        if (array_key_exists($needle, $haystack)) {
+            $success = true;
+            $length -= (strlen($needle) - strlen($haystack[$needle]));
+            return $haystack[$needle];
+        } elseif ($trim) {
+            $success = true;
+            if (strlen($needle) > 4) {
+                $length -= (strlen($needle) - 4);
+                $needle = $needle{4};
+            }
+        }
+        return $needle;
+    }
+
+    /** Checks if the line corresponds to a French street line.
+     * A line is considered a French street line if it starts by between 1 and 4 numbers.
+     */
+    private function isStreetFR($line)
+    {
+        return preg_match('/^\d{1,4}\D/', $line);
+    }
+
+    /** Retrieves a French street number and slit the rest of the line into an array.
+     * @param $words: array containing the rest of the line (a word per cell).
+     * @param $line: line to consider.
+     * Returns the street number.
+     */
+    private function getStreetNumberFR(&$line)
+    {
+        // First we define numbers and separators.
+        $numberReq = '(\d{1,4})\s*(BIS|TER|QUATER|[A-Z])?';
+        $separatorReq = '\s*(?:\\|-|&|A|ET)?\s*';
+
+        // Then we retrieve the number(s) and the rest of the line.
+        // $matches contains:
+        //  -0: the full patern, here the given line,
+        //  -1: the number,
+        //  -2: its optionnal quantifier,
+        //  -3: an optionnal second number,
+        //  -4: the second number's optionnal quantifier,
+        //  -5: the rest of the line.
+        preg_match('/^' . $numberReq . '(?:' . $separatorReq . $numberReq . ')?\s+(.*)/', $line, $matches);
+        $number = $matches[1];
+        $line = $matches[5];
+
+        // If there is a precision on the address, we concatenate it to the number.
+        if ($matches[2] != '') {
+            $number .= $matches[2]{0};
+        } elseif ($matches[4] != '') {
+            $number .= $matches[4]{0};
+        }
+
+        return $number;
+    }
+
+    /** Checks if the line corresponds to a French locality line.
+     * A line is considered a French locality line if it starts by exactly a
+     * postal code of exactly 5 numbers.
+     */
+    private function isLocalityFR($line)
+    {
+        return preg_match('/^\d{5}\D/', $line);
+    }
+
+    /** Retrieves a French postal code and slit the rest of the line into an array.
+     * @param $words: array containing the rest of the line (a word per cell).
+     * @param $line: line to consider.
+     * Returns the postal code, and cuts it out from the line.
+     */
+    private function getPostalCodeFR(&$line)
+    {
+        $number = substr($line, 0, 5);
+        $line = trim(substr($line, 5));
+        return $number;
+    }
+
+    /** Returns the address formated for French postal use (cf AFNOR XPZ 10-011).
+     * A postal addresse containts at most 6 lines of at most 38 characters each:
+     *  - addressee's identification ("MONSIEUR JEAN DURAND", "DURAND SA"…),
+     *  - delivery point identification ("CHEZ TOTO APPARTEMENT 2", "SERVICE ACHAT"…),
+     *  - building localisation complement ("ENTREE A BATIMENT DES JONQUILLES", "ZONE INDUSTRIELLE OUEST"…),
+     *  - N° and street name ("25 RUE DES FLEURS", "LES VIGNES"…),
+     *  - delivery service, street localisation complement ("BP 40122", "BP 40112 AREYRES"…),
+     *  - postal code and locality or cedex code and cedex ("33500 LIBOURNE", "33506 LIBOURNE CEDEX"…).
+     * Punctuation must be removed, all leters must be uppercased.
+     * Both locality and street name must not take more than 32 characters.
+     *
+     * @param $arrayText: array containing the address to be formated, one
+     * address line per array line.
+     * @param $count: array size.
+     */
+    private function formatPostalAddressFR($arrayText)
+    {
+        // First removes country if any.
+        $count = count($arrayText);
+        if ($arrayText[$count - 1] == 'FRANCE') {
+            unset($arrayText[$count - 1]);
+            --$count;
+        }
+
+        // All the lines must have less than 38 characters but street and
+        // locality lines whose limit is 32 characters.
+        foreach ($arrayText as $lineNumber => $line) {
+            if ($isStreetLine = $this->isStreetFR($line)) {
+                $formattedLine = $this->getStreetNumberFR($line) . ' ';
+                $limit = 32;
+            } elseif ($this->isLocalityFR($line)) {
+                $formattedLine = $this->getPostalCodeFR($line) . ' ';
+                $limit = 32;
+            } else {
+                $formattedLine = '';
+                $limit = 38;
+            }
+
+            $words = explode(' ', $line);
+            $count = count($words);
+            $length = $count - 1;
+            foreach ($words as $word) {
+                $length += strlen($word);
+            }
+
+            // Checks is length is ok. Otherwise, we try to shorten words and
+            // update the length of the current line accordingly.
+            for ($i = 0; $i < $count && $length > $limit; ++$i) {
+                $success = false;
+                if ($isStreetLine) {
+                    $sub = $this->substitute($words[$i], Address::$streetAbbreviations, $length, $success, ($i == 0));
+                }
+                // Entreprises' substitution are only suitable for the first two lines.
+                if ($lineNumber <= 2 && !$success) {
+                    $sub = $this->substitute($words[$i], Address::$entrepriseAbbreviations, $length, $success);
+                }
+                if (!$success) {
+                    $sub = $this->substitute($words[$i], Address::$otherAbbreviations, $length, $success);
+                }
+
+                $formattedLine .= $sub . ' ';
+            }
+            for (; $i < $count; ++$i) {
+                $formattedLine .= $words[$i] . ' ';
+            }
+            $arrayText[$lineNumber] = trim($formattedLine);
+        }
+
+        return implode("\n", $arrayText);
+    }
+
+    // Formats postal addresses.
+    // First erases punctuation, accents… Then uppercase the address and finally
+    // calls the country's dedicated formatting function.
+    public function formatPostalAddress()
+    {
+        // Performs rough formatting.
+        $text = mb_strtoupper(replace_accent($this->text));
+        $text = str_replace(array(',', ';', '.', ':', '!', '?', '"', '«', '»'), '', $text);
+        $text = preg_replace('/( |\t)+/', ' ', $text);
+        $arrayText = explode("\n", $text);
+        $arrayText = array_map('trim', $arrayText);
+
+        // Formats according to country rules. Thus we first identify the
+        // country, then apply corresponding formatting or translate country
+        // into default language.
+        $count = count($arrayText);
+        if (in_array(strtoupper($this->countryId), Address::$formattings)) {
+            $text = call_user_func(array($this, 'formatPostalAddress' . strtoupper($this->countryId)), $arrayText);
+        } else {
+            list($countryId, $country) = XDB::fetchOneRow('SELECT  gc.iso_3166_1_a2, gc.country
+                                                             FROM  geoloc_countries AS gc
+                                                       INNER JOIN  geoloc_languages AS gl ON (gc.iso_3166_1_a2 = gl.iso_3166_1_a2)
+                                                            WHERE  gc.iso_3166_1_a2 = {?} OR gl.countryPlain = {?} OR gc.countryPlain = {?}',
+                                                          $this->countryId, $arrayText[$count - 1], $arrayText[$count - 1]);
+            if (is_null($countryId)) {
+                $text = $this->formatPostalAddressFR($arrayText);
+            } elseif (in_array(strtoupper($countryId), Address::$formattings)) {
+                $text = call_user_func(array($this, 'formatPostalAddress' . strtoupper($countryId)), $arrayText);
+            } else {
+                $arrayText[$count - 1] = mb_strtoupper(replace_accent($country));
+                $text = implode("\n", $arrayText);
+            }
+        }
+
+        $this->postalText = $text;
+    }
+
     public function format(array $format = array())
     {
         if (empty($format)) {
             $format['requireGeocoding'] = false;
             $format['stripGeocoding'] = false;
+            $format['postalText'] = false;
+        } else {
+            foreach (array('requireGeocoding', 'stripGeocoding', 'postalText') as $type) {
+                $format[$type] = (isset($format[$type])) ? $format[$type] : false;
+            }
         }
         $this->text = trim($this->text);
         if ($this->removed == 1) {
@@ -173,37 +609,42 @@ class Address
             $this->countryId = null;
         }
         $this->geocodeChosen = null;
-        $this->phones = Phone::formatFormArray($this->phones, $this->error);
+        $this->phones = Phone::formatFormArray($this->phones, $this->error, new ProfileVisibility($this->pub));
+        if ($format['postalText']) {
+            $this->formatPostalAddress();
+        }
         return !$this->error;
     }
 
     public function toFormArray()
     {
         $address = array(
-            'accuracy'                  => $this->accuracy,
-            'text'                      => $this->text,
-            'postalText'                => $this->postalText,
-            'postalCode'                => $this->postalCode,
-            'localityId'                => $this->localityId,
-            'subAdministrativeAreaId'   => $this->subAdministrativeAreaId,
-            'administrativeAreaId'      => $this->administrativeAreaId,
-            'countryId'                 => $this->countryId,
-            'localityName'              => $this->localityName,
-            'subAdministrativeAreaName' => $this->subAdministrativeAreaName,
-            'administrativeAreaName'    => $this->administrativeAreaName,
-            'latitude'                  => $this->latitude,
-            'longitude'                 => $this->longitude,
-            'north'                     => $this->north,
-            'south'                     => $this->south,
-            'east'                      => $this->east,
-            'west'                      => $this->west,
-            'error'                     => $this->error,
-            'changed'                   => $this->changed,
-            'removed'                   => $this->removed,
+            'accuracy'                       => $this->accuracy,
+            'text'                           => $this->text,
+            'postalText'                     => $this->postalText,
+            'postalCode'                     => $this->postalCode,
+            'localityId'                     => $this->localityId,
+            'subAdministrativeAreaId'        => $this->subAdministrativeAreaId,
+            'administrativeAreaId'           => $this->administrativeAreaId,
+            'countryId'                      => $this->countryId,
+            'localityName'                   => $this->localityName,
+            'subAdministrativeAreaName'      => $this->subAdministrativeAreaName,
+            'administrativeAreaName'         => $this->administrativeAreaName,
+            'localityNameLocal'              => $this->localityNameLocal,
+            'subAdministrativeAreaNameLocal' => $this->subAdministrativeAreaNameLocal,
+            'administrativeAreaNameLocal'    => $this->administrativeAreaNameLocal,
+            'latitude'                       => $this->latitude,
+            'longitude'                      => $this->longitude,
+            'north'                          => $this->north,
+            'south'                          => $this->south,
+            'east'                           => $this->east,
+            'west'                           => $this->west,
+            'error'                          => $this->error,
+            'changed'                        => $this->changed,
+            'removed'                        => $this->removed,
         );
         if (!is_null($this->geocodedText)) {
             $address['geocodedText'] = $this->geocodedText;
-            $address['geocodedPostalText'] = $this->geocodedPostalText;
             $address['geocodeChosen'] = $this->geocodeChosen;
         }
 
@@ -211,7 +652,7 @@ class Address
             $address['pub'] = $this->pub;
         }
         if ($this->type == self::LINK_PROFILE) {
-            static $flags = array('current', 'temporary', 'secondary', 'mail', 'cedex');
+            static $flags = array('current', 'temporary', 'secondary', 'mail', 'cedex', 'deliveryIssue');
 
             foreach ($flags as $flag) {
                 $address[$flag] = $this->flags->hasFlag($flag);
@@ -225,28 +666,40 @@ class Address
 
     private function toString()
     {
-        $address = 'Adresse : ' . $this->text;
+        $address = $this->text;
         if ($this->type == self::LINK_PROFILE || $this->type == self::LINK_JOB) {
-            $address .= ', affichage : ' . $this->pub;
+            static $pubs = array('public' => 'publique', 'ax' => 'annuaire AX', 'private' => 'privé');
+            $address .= ' (affichage ' . $pubs[$this->pub];
         }
         if ($this->type == self::LINK_PROFILE) {
             static $flags = array(
-                'current'   => 'actuelle',
-                'temporary' => 'temporaire',
-                'secondary' => 'secondaire',
-                'mail'      => 'conctactable par courier',
-                'cedex'     => 'type cédex',
+                'current'       => 'actuelle',
+                'temporary'     => 'temporaire',
+                'secondary'     => 'secondaire',
+                'mail'          => 'conctactable par courier',
+                'deliveryIssue' => 'n\'habite pas à l\'adresse indiquée',
+                'cedex'         => 'type cédex',
             );
 
-            $address .= ', commentaire : ' . $this->comment;
+            if (!$this->flags->hasFlag('temporary')) {
+                $address .= ', permanente';
+            }
+            if (!$this->flags->hasFlag('secondary')) {
+                $address .= ', principale';
+            }
             foreach ($flags as $flag => $flagName) {
                 if ($this->flags->hasFlag($flag)) {
                     $address .= ', ' . $flagName;
                 }
             }
+            if ($this->comment) {
+                $address .= ', commentaire : ' . $this->comment;
+            }
             if ($phones = Phone::formArrayToString($this->phones)) {
                 $address .= ', ' . $phones;
             }
+        } elseif ($this->type == self::LINK_JOB) {
+            $address .= ')';
         }
         return $address;
     }
@@ -260,7 +713,7 @@ class Address
     {
         static $areas = array('administrativeArea', 'subAdministrativeArea', 'locality');
 
-        $this->format();
+        $this->format(array('postalText' => true));
         if (!$this->isEmpty()) {
             foreach ($areas as $area) {
                 Geocoder::getAreaId($this, $area);
@@ -293,7 +746,7 @@ class Address
                      $this->pid, $this->jobid, $this->type, $this->id);
     }
 
-    static public function deleteAddresses($pid, $type, $jobid = null)
+    static public function deleteAddresses($pid, $type, $jobid = null, $deletePrivate = true)
     {
         $where = '';
         if (!is_null($pid)) {
@@ -303,10 +756,10 @@ class Address
             $where = XDB::format(' AND jobid = {?}', $jobid);
         }
         XDB::execute('DELETE FROM  profile_addresses
-                            WHERE  type = {?}' . $where,
+                            WHERE  type = {?}' . $where . (($deletePrivate) ? '' : ' AND pub IN (\'public\', \'ax\')'),
                      $type);
         if ($type == self::LINK_PROFILE) {
-            Phone::deletePhones($pid, Phone::LINK_ADDRESS);
+            Phone::deletePhones($pid, Phone::LINK_ADDRESS, null, $deletePrivate);
         }
     }
 
@@ -376,7 +829,7 @@ class Address
 
     static public function formArrayToString(array $data)
     {
-        return implode(' ; ', self::formArrayWalk($data, 'toString'));
+        return implode(', ', self::formArrayWalk($data, 'toString'));
     }
 
     static public function iterate(array $pids = array(), array $types = array(),
@@ -418,8 +871,10 @@ class AddressIterator implements PlIterator
                         pa.administrativeAreaId, pa.countryId,
                         pa.latitude, pa.longitude, pa.north, pa.south, pa.east, pa.west,
                         pa.pub, pa.comment,
-                        gl.name AS locality, gs.name AS subAdministrativeArea,
-                        ga.name AS administrativeArea, gc.countryFR AS country
+                        gl.name AS locality, gl.nameLocal AS localityLocal,
+                        gs.name AS subAdministrativeArea, gs.nameLocal AS subAdministrativeAreaLocal,
+                        ga.name AS administrativeArea, ga.nameLocal AS administrativeAreaLocal,
+                        gc.country
                   FROM  profile_addresses             AS pa
              LEFT JOIN  geoloc_localities             AS gl ON (gl.id = pa.localityId)
              LEFT JOIN  geoloc_administrativeareas    AS ga ON (ga.id = pa.administrativeAreaId)
index 5350f0e..0268ca9 100644 (file)
@@ -578,8 +578,8 @@ class DE_Nationalities extends DirEnumeration
 class DE_Countries extends DirEnumeration
 {
     protected $idfield   = 'geoloc_countries.iso_3166_1_a2';
-    protected $valfield  = 'geoloc_countries.countryFR';
-    protected $valfield2 = 'geoloc_countries.country';
+    protected $valfield  = 'geoloc_countries.country';
+    protected $valfield2 = 'geoloc_countries.countryEn';
     protected $from      = 'geoloc_countries';
 
     protected $ac_join   = 'INNER JOIN profile_addresses ON (geoloc_countries.iso_3166_1_a2 = profile_addresses.countryId)';
index 357891e..89727a1 100644 (file)
@@ -39,21 +39,40 @@ abstract class Geocoder {
             'subAdministrativeArea' => 'geoloc_subadministrativeareas',
             'locality'              => 'geoloc_localities',
         );
+        static $extras = array(
+            'subAdministrativeArea' => array(
+                'field' => 'administrativearea',
+                'name'  => 'administrativeAreaName'
+            )
+        );
 
         $areaName = $area . 'Name';
+        $areaNameLocal = $areaName . 'Local';
         $areaId = $area . 'Id';
         if (!is_null($address->$areaName) && isset($databases[$area])) {
-            $res = XDB::query('SELECT  id
+            $extra = (isset($extras[$area]) ? $extras[$area]['administrativeAreaName'] : false);
+
+            $res = XDB::query('SELECT  id, nameLocal
                                  FROM  ' . $databases[$area] . '
                                 WHERE  name = {?}',
                               $address->$areaName);
             if ($res->numRows() == 0) {
-                XDB::execute('INSERT INTO  ' . $databases[$area] . ' (name, country)
-                                   VALUES  ({?}, {?})',
-                             $address->$areaName, $address->countryId);
+                XDB::execute('INSERT INTO  ' . $databases[$area] . ' (name, nameLocal, country' .
+                                           ($extra ? ', ' . $extras[$area]['field'] : '') . ')
+                                   VALUES  ({?}, {?}, {?}' . ($extra ? ', {?}' : '') . ')',
+                             $address->$areaName, $address->$areaNameLocal, $address->countryId,
+                             ($extra ? $address->$extra : null));
                 $address->$areaId = XDB::insertId();
             } else {
-                $address->$areaId = $res->fetchOneCell();
+                // XXX: remove this once all areas have both nameLocal and name.
+                list($id, $name) = $res->fetchOneRow();
+                if (is_null($name) && !is_null($address->$areaNameLocal)) {
+                    XDB::execute('UPDATE  ' . $databases[$area] . '
+                                     SET  nameLocal = {?}
+                                   WHERE  id = {?}',
+                                 $address->$areaNameLocal, $id);
+                }
+                $address->$areaId = $id;
             }
         } elseif (empty($address->$areaId)) {
             $address->$areaId = null;
@@ -64,14 +83,23 @@ abstract class Geocoder {
     // and the city name, within the limit of $limit number of lines.
     static public function getFirstLines($text, $postalCode, $limit)
     {
-        $textArray  = explode("\n", $text);
+        $text = str_replace("\r", '', $text);
+        $textArray = explode("\n", $text);
+        $linesNb = $limit;
+
         for ($i = 0; $i < count($textArray); ++$i) {
-            if ($i > $limit || strpos($textLine, $postalCode) !== false) {
-                $limit = $i;
+            if ($i > $limit || strpos($textArray[$i], $postalCode) !== false) {
+                $linesNb = $i;
                 break;
             }
         }
-        return implode("\n", array_slice($textArray, 0, $limit));
+        $firstLines = implode("\n", array_slice($textArray, 0, $linesNb));
+
+        // Adds empty lines to complete the $limit lines required.
+        for (; $i < $limit; ++$i) {
+            $firstLines .= "\n";
+        }
+        return $firstLines;
     }
 
     // Returns the number of non geocoded addresses for a user.
index 8347026..a48c9b6 100644 (file)
@@ -36,13 +36,16 @@ class GMapsGeocoder extends Geocoder {
     // Maximum levenshtein distance authorized between input and geocoded text in the whole text.
     const MAX_TOTAL_DISTANCE = 6;
 
-    public function getGeocodedAddress(Address &$address) {
+    public function getGeocodedAddress(Address &$address, $defaultLanguage = null, $forceLanguage = false) {
         $this->prepareAddress($address);
         $textAddress = $this->getTextToGeocode($address->text);
+        if (is_null($defaultLanguage)) {
+            $defaultLanguage = Platal::globals()->geocoder->gmaps_hl;
+        }
 
         // Try to geocode the full address.
-        if (($geocodedData = $this->getPlacemarkForAddress($textAddress))) {
-            $this->getUpdatedAddress($address, $geocodedData, null);
+        if (($geocodedData = $this->getPlacemarkForAddress($textAddress, $defaultLanguage))) {
+            $this->getUpdatedAddress($address, $geocodedData, null, $forceLanguage);
             return;
         }
 
@@ -55,8 +58,8 @@ class GMapsGeocoder extends Geocoder {
         for ($i = max(1, $linesCount - self::MAX_GMAPS_RPC_CALLS + 1); $i < $linesCount; ++$i) {
             $extraLines = implode("\n", array_slice($addressLines, 0, $i));
             $toGeocode  = implode("\n", array_slice($addressLines, $i));
-            if (($geocodedData = $this->getPlacemarkForAddress($toGeocode))) {
-                $this->getUpdatedAddress($address, $geocodedData, $extraLines);
+            if (($geocodedData = $this->getPlacemarkForAddress($toGeocode, $defaultLanguage))) {
+                $this->getUpdatedAddress($address, $geocodedData, $extraLines, $forceLanguage);
                 return;
             }
         }
@@ -64,7 +67,6 @@ class GMapsGeocoder extends Geocoder {
 
     public function stripGeocodingFromAddress(Address &$address) {
         $address->geocodedText = null;
-        $address->geocodedPostalText = null;
         $address->geoloc_choice = null;
         $address->countryId = null;
         $address->country = null;
@@ -78,16 +80,16 @@ class GMapsGeocoder extends Geocoder {
 
     // Updates the address with the geocoded information from Google Maps. Also
     // cleans up the final informations.
-    private function getUpdatedAddress(Address &$address, array $geocodedData, $extraLines) {
-        $this->fillAddressWithGeocoding($address, $geocodedData);
-        $this->formatAddress($address, $extraLines);
+    private function getUpdatedAddress(Address &$address, array $geocodedData, $extraLines, $forceLanguage) {
+        $this->fillAddressWithGeocoding($address, $geocodedData, false);
+        $this->formatAddress($address, $extraLines, $forceLanguage);
     }
 
     // Retrieves the Placemark object (see #getPlacemarkFromJson()) for the @p
     // address, by querying the Google Maps API. Returns the array on success,
     // and null otherwise.
-    private function getPlacemarkForAddress($address) {
-        $url     = $this->getGeocodingUrl($address);
+    private function getPlacemarkForAddress($address, $defaultLanguage) {
+        $url     = $this->getGeocodingUrl($address, $defaultLanguage);
         $geoData = $this->getGeoJsonFromUrl($url);
 
         return ($geoData ? $this->getPlacemarkFromJson($geoData) : null);
@@ -96,21 +98,20 @@ class GMapsGeocoder extends Geocoder {
     // Prepares address to be geocoded
     private function prepareAddress(Address &$address) {
         $address->text = preg_replace('/\s*\n\s*/m', "\n", trim($address->text));
-        $address->postalText = $this->getPostalAddress($address->text);
     }
 
     // Builds the Google Maps geocoder url to fetch information about @p address.
     // Returns the built url.
-    private function getGeocodingUrl($address) {
+    private function getGeocodingUrl($address, $defaultLanguage) {
         global $globals;
 
         $parameters = array(
             'key'    => $globals->geocoder->gmaps_key,
             'sensor' => 'false',   // The queried address wasn't obtained from a GPS sensor.
-            'hl'     => 'fr',      // Output langage.
+            'hl'     => $defaultLanguage,
             'oe'     => 'utf8',    // Output encoding.
             'output' => 'json',    // Output format.
-            'gl'     => 'fr',      // Location preferences (addresses are in France by default).
+            'gl'     => $globals->geocoder->gmaps_gl,
             'q'      => $address,  // The queries address.
         );
 
@@ -180,38 +181,45 @@ class GMapsGeocoder extends Geocoder {
     }
 
     // Fills the address with the geocoded data
-    private function fillAddressWithGeocoding(Address &$address, $geocodedData) {
+    private function fillAddressWithGeocoding(Address &$address, $geocodedData, $isLocal) {
         // The geocoded address three is
         // Country -> AdministrativeArea -> SubAdministrativeArea -> Locality -> Thoroughfare
         // with all the possible shortcuts
         // The address is formatted as xAL, or eXtensible Address Language, an international
         // standard for address formatting.
         // xAL documentation: http://www.oasis-open.org/committees/ciq/ciq.html#6
-        $address->geocodedText = str_replace(', ', "\n", $geocodedData['address']);
+        if ($isLocal) {
+            $ext = 'Local';
+        } else {
+            $ext = ucfirst(Platal::globals()->geocoder->gmaps_hl);
+            $address->geocodedText = str_replace(', ', "\n", $geocodedData['address']);
+        }
+
         if (isset($geocodedData['AddressDetails']['Accuracy'])) {
             $address->accuracy = $geocodedData['AddressDetails']['Accuracy'];
         }
 
         $currentPosition = $geocodedData['AddressDetails'];
         if (isset($currentPosition['Country'])) {
+            $country = 'country' . $ext;
             $currentPosition    = $currentPosition['Country'];
             $address->countryId = $currentPosition['CountryNameCode'];
-            $address->country   = $currentPosition['CountryName'];
+            $address->$country  = $currentPosition['CountryName'];
         }
         if (isset($currentPosition['AdministrativeArea'])) {
-            $currentPosition                 = $currentPosition['AdministrativeArea'];
-            $address->administrativeAreaName = $currentPosition['AdministrativeAreaName'];
+            $administrativeAreaName = 'administrativeAreaName' . $ext;
+            $currentPosition                  = $currentPosition['AdministrativeArea'];
+            $address->$administrativeAreaName = $currentPosition['AdministrativeAreaName'];
         }
         if (isset($currentPosition['SubAdministrativeArea'])) {
-            $currentPosition                    = $currentPosition['SubAdministrativeArea'];
-            $address->subAdministrativeAreaName = $currentPosition['SubAdministrativeAreaName'];
+            $subAdministrativeAreaName = 'subAdministrativeAreaName' . $ext;
+            $currentPosition                     = $currentPosition['SubAdministrativeArea'];
+            $address->$subAdministrativeAreaName = $currentPosition['SubAdministrativeAreaName'];
         }
         if (isset($currentPosition['Locality'])) {
-            $currentPosition       = $currentPosition['Locality'];
-            $address->localityName = $currentPosition['LocalityName'];
-        }
-        if (isset($currentPosition['Thoroughfare'])) {
-            $address->thoroughfareName = $currentPosition['Thoroughfare']['ThoroughfareName'];
+            $localityName = 'localityName' . $ext;
+            $currentPosition        = $currentPosition['Locality'];
+            $address->$localityName = $currentPosition['LocalityName'];
         }
         if (isset($currentPosition['PostalCode'])) {
             $address->postalCode = $currentPosition['PostalCode']['PostalCodeNumber'];
@@ -238,15 +246,11 @@ class GMapsGeocoder extends Geocoder {
         }
     }
 
-    // Formats the text of the geocoded address using the unused data and
-    // compares it to the given address. If they are too different, the user
-    // will be asked to choose between them.
-    private function formatAddress(Address &$address, $extraLines) {
+    // Compares the geocoded address with the given address and returns true
+    // iff their are close enough to be considered as equals or not.
+    private function compareAddress($address)
+    {
         $same = true;
-        if ($extraLines) {
-            $address->geocodedText = $extraLines . "\n" . $address->geocodedText;
-        }
-        $address->geocodedPostalText = $this->getPostalAddress($address->geocodedText);
         $geoloc = strtoupper(preg_replace(array("/[0-9,\"'#~:;_\- ]/", "/\r\n/"),
                                           array('', "\n"), $address->geocodedText));
         $text   = strtoupper(preg_replace(array("/[0-9,\"'#~:;_\- ]/", "/\r\n/"),
@@ -272,59 +276,46 @@ class GMapsGeocoder extends Geocoder {
             }
         }
 
-        if ($same) {
-            $address->geocodedText = null;
-            $address->geocodedPostalText = null;
-        } else {
-            $address->geocodedText = str_replace("\n", "\r\n", $address->geocodedText);
-            $address->geocodedPostalText = str_replace("\n", "\r\n", $address->geocodedPostalText);
-        }
-        $address->text = str_replace("\n", "\r\n", $address->text);
-        $address->postalText = str_replace("\n", "\r\n", $address->postalText);
+        return $same;
     }
 
-    // Returns the address formated for postal use.
-    // The main rules are (cf AFNOR XPZ 10-011):
-    // -everything in upper case;
-    // -if there are more then than 38 characters in a line, split it;
-    // -if there are more then than 32 characters in the description of the "street", use abbreviations.
-    private function getPostalAddress($text) {
-         static $abbreviations = array(
-             'IMPASSE'   => 'IMP',
-             'RUE'       => 'R',
-             'AVENUE'    => 'AV',
-             'BOULEVARD' => 'BVD',
-             'ROUTE'     => 'R',
-             'STREET'    => 'ST',
-             'ROAD'      => 'RD',
-             );
-
-        $text = strtoupper($text);
-        $arrayText = explode("\n", $text);
-        $postalText = '';
-
-        foreach ($arrayText as $i => $line) {
-            $postalText .= (($i == 0) ? '' : "\n");
-            if (($length = strlen($line)) > 32) {
-                $words = explode(' ', $line);
-                $count = 0;
-                foreach ($words as $word) {
-                    if (isset($abbreviations[$word])) {
-                        $word = $abbreviations[$word];
+    // Formats the text of the geocoded address using the unused data and
+    // compares it to the given address. If they are too different, the user
+    // will be asked to choose between them.
+    private function formatAddress(Address &$address, $extraLines, $forceLanguage)
+    {
+        if ($extraLines) {
+            $address->geocodedText = $extraLines . "\n" . $address->geocodedText;
+        }
+
+        if ($this->compareAddress($address)) {
+            $address->geocodedText = null;
+        } elseif (!$forceLanguage) {
+            $languages = XDB::fetchOneCell('SELECT  IF(ISNULL(gc1.belongsTo), gl1.language, gl2.language)
+                                              FROM  geoloc_countries AS gc1
+                                        INNER JOIN  geoloc_languages AS gl1 ON (gc1.iso_3166_1_a2 = gl1.iso_3166_1_a2)
+                                         LEFT JOIN  geoloc_countries AS gc2 ON (gc1.belongsTo = gc2.iso_3166_1_a2)
+                                         LEFT JOIN  geoloc_languages AS gl2 ON (gc2.iso_3166_1_a2 = gl2.iso_3166_1_a2)
+                                             WHERE  gc1.iso_3166_1_a2 = {?}',
+                                           $address->countryId);
+            $toGeocode = substr($address->text, strlen($extraLines));
+            foreach (explode(',', $languages) as $language) {
+                if ($language != Platal::globals()->geocoder->gmaps_hl) {
+                    $geocodedData = $this->getPlacemarkForAddress($toGeocode, $language);
+                    $address->geocodedText = str_replace(', ', "\n", $geocodedData['address']);
+                    if ($extraLines) {
+                        $address->geocodedText = $extraLines . "\n" . $address->geocodedText;
                     }
-                    if ($count + ($wordLength = strlen($word)) <= 38) {
-                        $postalText .= (($count == 0) ? '' : ' ') . $word;
-                        $count += (($count == 0) ? 0 : 1) + $wordLength;
-                    } else {
-                        $postalText .= "\n" . $word;
-                        $count = strlen($word);
+                    if ($this->compareAddress($address)) {
+                        $this->fillAddressWithGeocoding($address, $geocodedData, true);
+                        $address->geocodedText = null;
+                        break;
                     }
                 }
-            } else {
-                $postalText .= $line;
             }
+            $address->geocodedText = str_replace("\n", "\r\n", $address->geocodedText);
         }
-        return $postalText;
+        $address->text = str_replace("\n", "\r\n", $address->text);
     }
 
     // Trims the name of the real country if it contains an ISO 3166-1 non-country
@@ -332,7 +323,7 @@ class GMapsGeocoder extends Geocoder {
     // all non-country items of ISO 3166-1.
     private function getTextToGeocode($text)
     {
-        $res = XDB::iterator('SELECT  country, countryFR
+        $res = XDB::iterator('SELECT  countryEn, country
                                 FROM  geoloc_countries
                                WHERE  belongsTo IS NOT NULL');
         $countries = array();
@@ -344,10 +335,12 @@ class GMapsGeocoder extends Geocoder {
         $countLines = count($textLines);
         $needle     = strtoupper(trim($textLines[$countLines - 2]));
         $isPseudoCountry = false;
-        foreach ($countries as $country) {
-            if (strtoupper($country) == $needle) {
-                $isPseudoCountry = true;
-                break;
+        if ($needle) {
+            foreach ($countries as $country) {
+                if (strtoupper($country) === $needle) {
+                    $isPseudoCountry = true;
+                    break;
+                }
             }
         }
 
index 948894f..64dfe0e 100644 (file)
@@ -67,7 +67,7 @@ class Phone
     // The following fields are the fields of the form in the profile edition.
     private $type = 'fixed';
     public $display = '';
-    private $pub = 'private';
+    public $pub = 'ax';
     public $comment = '';
     private $error = false;
 
@@ -286,8 +286,10 @@ class Phone
 
     private function toString()
     {
-        return 'type : ' . $this->type .', numéro : ' . $this->display
-            . ', commentaire : « ' . $this->comment . ' », affichage : ' . $this->pub;
+        static $pubs = array('public' => 'publique', 'ax' => 'annuaire AX', 'private' => 'privé');
+        static $types = array('fax' => 'fax', 'fixed' => 'fixe', 'mobile' => 'mobile');
+        return $this->display . ' (' . $types[$this->type] . (($this->comment) ? ', commentaire : « ' . $this->comment . ' »' : '')
+            . ', affichage ' . $pubs[$this->pub] . ')';
     }
 
     private function isEmpty()
@@ -314,14 +316,14 @@ class Phone
                      $this->pid, $this->link_type, $this->link_id, $this->id);
     }
 
-    static public function deletePhones($pid, $link_type, $link_id = null)
+    static public function deletePhones($pid, $link_type, $link_id = null, $deletePrivate = true)
     {
         $where = '';
         if (!is_null($link_id)) {
             $where = XDB::format(' AND link_id = {?}', $link_id);
         }
         XDB::execute('DELETE FROM  profile_phones
-                            WHERE  pid = {?} AND link_type = {?}' . $where,
+                            WHERE  pid = {?} AND link_type = {?}' . $where . (($deletePrivate) ? '' : ' AND pub IN (\'public\', \'ax\')'),
                      $pid, $link_type);
     }
 
@@ -347,32 +349,38 @@ class Phone
         }
     }
 
-    static private function formArrayWalk(array $data, $function, &$success = true, $requiresEmptyPhone = false)
+    static private function formArrayWalk(array $data, $function, &$success = true, $requiresEmptyPhone = false, $maxPublicity = null)
     {
         $phones = array();
         foreach ($data as $item) {
             $phone = new Phone($item);
             $success = (!$phone->error && ($phone->format() || $phone->isEmpty()) && $success);
             if (!$phone->isEmpty()) {
+                if (!is_null($maxPublicity) && $maxPublicity->isVisible($phone->pub)) {
+                    $phone->pub = $maxPublicity->level();
+                }
                 $phones[] = call_user_func(array($phone, $function));
             }
         }
         if (count($phones) == 0 && $requiresEmptyPhone) {
             $phone = new Phone();
+            if (!is_null($maxPublicity) && $maxPublicity->isVisible($phone->pub)) {
+                $phone->pub = $maxPublicity->level();
+            }
             $phones[] = call_user_func(array($phone, $function));
         }
         return $phones;
     }
 
     // Formats an array of form phones into an array of form formatted phones.
-    static public function formatFormArray(array $data, &$success = true)
+    static public function formatFormArray(array $data, &$success = true, $maxPublicity = null)
     {
-        return self::formArrayWalk($data, 'toFormArray', $success, true);
+        return self::formArrayWalk($data, 'toFormArray', $success, true, $maxPublicity);
     }
 
     static public function formArrayToString(array $data)
     {
-        return implode(' ; ', self::formArrayWalk($data, 'toString'));
+        return implode(', ', self::formArrayWalk($data, 'toString'));
     }
 
     static public function iterate(array $pids = array(), array $link_types = array(),
index 9b2e4b0..3ca5679 100644 (file)
@@ -103,6 +103,38 @@ class Profile
 
     const FETCH_ALL          = 0x0007FF; // OR of FETCH_*
 
+    static public $descriptions = array(
+        'search_names'    => 'Noms',
+        'nationality1'    => 'Nationalité',
+        'nationality2'    => '2e nationalité',
+        'nationality3'    => '3e nationalité',
+        'promo_display'   => 'Promotion affichée',
+        'email_directory' => 'Email annuaire papier',
+        'networking'      => 'Messageries…',
+        'tels'            => 'Téléphones',
+        'edus'            => 'Formations',
+        'promo'           => 'Promotion de sortie',
+        'birthdate'       => 'Date de naissance',
+        'yourself'        => 'Nom affiché',
+        'freetext'        => 'Commentaire',
+        'freetext_pub'    => 'Affichage du commentaire',
+        'photo'           => 'Photographie',
+        'photo_pub'       => 'Affichage de la photographie',
+        'addresses'       => 'Adresses',
+        'corps'           => 'Corps',
+        'cv'              => 'CV',
+        'jobs'            => 'Emplois',
+        'section'         => 'Section',
+        'binets'          => 'Binets',
+        'medals'          => 'Décorations',
+        'medals_pub'      => 'Affichage des décorations',
+        'competences'     => 'Compétences',
+        'langues'         => 'Langues',
+        'expertise'       => 'Expertises (mentoring)',
+        'terms'           => 'Compétences (mentoring)',
+        'countries'       => 'Pays (mentoring)'
+    );
+
     private $fetched_fields  = 0x000000;
 
     private $pid;
@@ -486,17 +518,19 @@ class Profile
     {
         if ($this->has_photo) {
             if ($data && ($this->photo == null || $this->photo->mimeType == null)) {
-                $res = XDB::fetchOneAssoc('SELECT  attach, attachmime, x, y
+                $res = XDB::fetchOneAssoc('SELECT  attach, attachmime, x, y, last_update
                                              FROM  profile_photos
                                             WHERE  pid = {?}', $this->pid);
-                $this->photo = PlImage::fromData($res['attach'], $res['attachmime'], $res['x'], $res['y']);
+                $this->photo = PlImage::fromData($res['attach'], 'image/' .$res['attachmime'], $res['x'], $res['y'], $res['last_update']);
             } else if ($this->photo == null) {
                 $this->photo = PlImage::fromData(null, null, $this->photo_width, $this->photo_height);
             }
             return $this->photo;
         } else if ($fallback) {
-            return PlImage::fromFile(dirname(__FILE__).'/../htdocs/images/none.png',
-                                     'image/png');
+            if ($this->mainEducation() == 'X') {
+                return PlImage::fromFile(dirname(__FILE__) . '/../htdocs/images/none_x.png', 'image/png');
+            }
+            return PlImage::fromFile(dirname(__FILE__) . '/../htdocs/images/none_md.png', 'image/png');
         }
         return null;
     }
index 14e9557..03a88a0 100644 (file)
@@ -228,7 +228,7 @@ class UFC_Promo implements UserFilterCondition
 // {{{ class UFC_SchoolId
 /** Filters users based on their shoold identifier
  * @param type Parameter type (Xorg, AX, School)
- * @param value School id value
+ * @param value Array of school ids
  */
 class UFC_SchoolId implements UserFilterCondition
 {
@@ -246,23 +246,30 @@ class UFC_SchoolId implements UserFilterCondition
         }
     }
 
-    public function __construct($type, $id)
+    /** Construct a UFC_SchoolId
+     * The first argument is the type, all following arguments can be either ids
+     * or arrays of ids to use:
+     * $ufc = new UFC_SchoolId(UFC_SchoolId::AX, $id1, $id2, array($id3, $id4));
+     */
+    public function __construct($type)
     {
         $this->type = $type;
-        $this->id   = $id;
+        $ids = func_get_args();
+        array_shift($ids);
+        $this->ids   = pl_flatten($ids);
         self::assertType($type);
     }
 
     public function buildCondition(PlFilter &$uf)
     {
         $uf->requireProfiles();
-        $id = $this->id;
+        $ids = $this->ids;
         $type = $this->type;
         if ($type == self::School) {
             $type = self::Xorg;
-            $id   = Profile::getXorgId($id);
+            $ids  = array_map(array('Profile', 'getXorgId'), $ids);
         }
-        return XDB::format('p.' . $type . '_id = {?}', $id);
+        return XDB::format('p.' . $type . '_id IN {?}', $ids);
     }
 }
 // }}}
@@ -2001,6 +2008,10 @@ class UserFilter extends PlFilter
         return $this->getUsers($limit);
     }
 
+    public function getIds($limit = null)
+    {
+        return $this->getUIDs();
+    }
 
     public function getTotalCount()
     {
@@ -2871,6 +2882,11 @@ class ProfileFilter extends UserFilter
         return $this->getProfiles($limit);
     }
 
+    public function getIds($limit = null)
+    {
+        return $this->getPIDs();
+    }
+
     public function filter(array $profiles, $limit = null)
     {
         return $this->filterProfiles($profiles, self::defaultLimit($limit));
index a8cb4c2..4fcbe42 100644 (file)
@@ -198,6 +198,13 @@ gmaps_key = ""
 ; URL of geocoding webservice
 gmaps_url = "http://maps.google.com/maps/geo"
 
+; $globals->geocoder->gmaps_hl
+; Default output language.
+gmaps_hl = "fr"
+
+; $globals->geocoder->gmaps_gl
+; Default location preference.
+gmaps_gl = "fr"
 
 ; The lists section contains parameters used to interact with mailman.
 [Lists]
diff --git a/core b/core
index 798c1f4..80c3b57 160000 (submodule)
--- a/core
+++ b/core
@@ -1 +1 @@
-Subproject commit 798c1f4b15f14569c1f37d848db93ec4f65518b6
+Subproject commit 80c3b5792bea15876ef8f79b8a64421733c1c001
diff --git a/htdocs/images/none_md.png b/htdocs/images/none_md.png
new file mode 100644 (file)
index 0000000..a44f9f5
Binary files /dev/null and b/htdocs/images/none_md.png differ
index 7e6b683..a173e4b 100644 (file)
@@ -45,7 +45,7 @@ function wizPage_onLoad(id)
         }
         break;
       case 'emploi':
-        if ($('#job_0').find("[name='jobs[0][name]']").val() == '') {
+        if ($('#jobs_0').find("[name='jobs[0][name]']").val() == '') {
             registerEnterpriseAutocomplete(0);
         }
         break;
@@ -58,6 +58,12 @@ var educationDegreeName;
 var subgrades;
 var names;
 
+// Publicity follows the following ordering: private < ax < public.
+var publicity = [];
+publicity['private'] = 0;
+publicity['ax']      = 1;
+publicity['public']  = 2;
+
 // Names {{{1
 
 function toggleNamesAdvanced()
@@ -327,11 +333,10 @@ function validGeoloc(prefid, id, geoloc)
 {
     if (geoloc == 1) {
         $('#' + prefid + '_cont').find('[name*=text]').val($('#' + prefid + '_cont').find('[name*=geocodedText]').val());
-        $('#' + prefid + '_cont').find('[name*=postalText]').val($('#' + prefid + '_cont').find('[name*=geocodedPostalText]').val());
+        $('#' + prefid + '_cont').find('[name*=postalText]').val('');
     }
     if (geoloc > 0) {
         $('#' + prefid + '_cont').find("[name*='[geocodedText]']").remove();
-        $('#' + prefid + '_cont').find("[name*='[geocodedPostalText]']").remove();
     }
     $('#' + prefid + '_cont').find('[name*=text]').removeClass('error');
     $('#' + prefid + '_cont').find('[name*=geocodeChosen]').val(geoloc);
@@ -340,7 +345,7 @@ function validGeoloc(prefid, id, geoloc)
 
 // {{{1 Phones
 
-function addTel(prefid, prefname)
+function addTel(prefid, prefname, subField, mainField, mainId)
 {
     var i = 0;
     var prefix  = prefid + '_';
@@ -348,7 +353,7 @@ function addTel(prefid, prefname)
         i++;
     }
     $('#' + prefix + 'add').before('<div id="' + prefix + i + '" style="clear: both; padding-top: 4px; padding-bottom: 4px"></div>');
-    Ajax.update_html(prefix + i, 'profile/ajax/tel/' + prefid + '/' + prefname + '/' + i);
+    Ajax.update_html(prefix + i, 'profile/ajax/tel/' + prefid + '/' + prefname + '/' + i + '/' + subField + '/' + mainField + '/' + mainId);
 }
 
 function removeTel(prefname, prefid, id)
@@ -520,7 +525,7 @@ function makeAddJob(id)
 function addJob()
 {
     var i = 0;
-    while ($('#job_' + i).length != 0) {
+    while ($('#jobs_' + i).length != 0) {
         ++i;
     }
     $.get(platal_baseurl + 'profile/ajax/job/' + i, makeAddJob(i));
@@ -548,23 +553,23 @@ function addJobTerm(jobid, jtid, full_name)
         jobid = '';
         formvarname = 'terms';
     } else {
-        parentpath = '#job_'+jobid+' ';
+        parentpath = '#jobs_'+jobid+' ';
         formvarname = 'jobs['+jobid+'][terms]';
     }
-    var lastJobTerm = $(parentpath + '.job_term:last');
+    var lastJobTerm = $(parentpath + '.jobs_term:last');
     if (lastJobTerm.length != 0) {
         termid = parseInt(lastJobTerm.children('input').attr('name').replace(/^(jobs\[[0-9]+\]\[terms\]|terms)\[([0-9]+)\]\[jtid\]/, '$2')) + 1;
         if ($('#job'+jobid+'_term'+jtid).length > 0) {
             return false;
         }
     }
-    var newdiv = '<div class="job_term" id="job'+jobid+'_term'+jtid+'">'+
+    var newdiv = '<div class="jobs_term" id="job'+jobid+'_term'+jtid+'">'+
         '<span>'+full_name+'</span>'+
         '<input type="hidden" name="'+formvarname+'['+termid+'][jtid]" value="'+jtid+'" />'+
         '<img title="Retirer ce mot-clef" alt="retirer" src="images/icons/cross.gif" />'+
         '</div>';
     if (lastJobTerm.length == 0) {
-        $(parentpath + '.job_terms').prepend(newdiv);
+        $(parentpath + '.jobs_terms').prepend(newdiv);
     } else {
         lastJobTerm.after(newdiv);
     }
@@ -612,7 +617,7 @@ function selectJobTerm(li)
     if (jobid < 0) {
         search_input = $('.term_search')[0];
     } else {
-        search_input = $('#job_'+jobid+' .term_search')[0];
+        search_input = $('#jobs_'+jobid+' .term_search')[0];
     }
     if (li.extra[0] >= 0) {
         search_input.value = '';
@@ -633,7 +638,7 @@ function toggleJobTermsTree(jobid, textfilter)
     if (jobid < 0) {
         treepath = '';
     } else {
-        treepath = '#job_'+jobid+' ';
+        treepath = '#jobs_'+jobid+' ';
     }
     treepath += '.term_tree';
     if ($(treepath + ' ul').length > 0) {
@@ -734,4 +739,42 @@ function removeElement(cat, id)
     updateElement(cat);
 }
 
+function updateSubPublicity(subFieldId, name, mainPub)
+{
+    var subPub = $(subFieldId).find("[name='" + name + "']:checked").val();
+    if (publicity[subPub] > publicity[mainPub]) {
+        $(subFieldId).find("[name='" + name + "']:checked").removeAttr('checked');
+        $(subFieldId).find('[value=' + mainPub + ']').attr('checked', 'checked');
+    }
+}
+
+function updatePublicity(mainField, mainId, subField, subId)
+{
+    var mainFieldId = '#' + mainField + '_' + mainId;
+    var mainPub = $(mainFieldId).find("[name='" + mainField + "[" + mainId + "][pub]']:checked").val();
+    if (subId == -1) {
+        var subFields = subField.split(',');
+        for (var i =0; i < subFields.length; ++i) {
+            var subFieldBaseId = mainFieldId + '_' + subFields[i];
+            var name = mainField + '[' + mainId + '][' + subFields[i] + ']';
+            if ($(subFieldBaseId).length != 0) {
+                updateSubPublicity(subFieldBaseId, name + '[pub]', mainPub);
+                updateSubPublicity(subFieldBaseId, mainField + '[' + mainId + '][' + subFields[i] + '_pub]', mainPub);
+            }
+            subId = 0;
+            while ($(subFieldBaseId + '_' + subId).length != 0) {
+                updateSubPublicity(subFieldBaseId + '_' + subId, name + '[' + subId + '][pub]', mainPub);
+                ++subId;
+            }
+        }
+    } else {
+        if (subId == '') {
+            updateSubPublicity(mainFieldId + '_' + subField, mainField + '[' + mainId + '][' + subField + '_pub]', mainPub);
+            updateSubPublicity(mainFieldId + '_' + subField, mainField + '[' + mainId + '][' + subField + '][pub]', mainPub);
+        } else {
+            updateSubPublicity(mainFieldId + '_' + subField + '_' + subId, mainField + '[' + mainId + '][' + subField + '][' + subId + '][pub]', mainPub);
+        }
+    }
+}
+
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index dbfba28..51437db 100644 (file)
 function education_options($current = 0)
 {
     $html = '<option value="-1">&nbsp;</option>';
-    $res  = XDB::iterator("SELECT  e.id AS id, gc.countryFR AS country,
+    $res  = XDB::iterator("SELECT  e.id AS id, gc.country,
                                    IF(CHAR_LENGTH(e.name) > 76, e.abbreviation, e.name) AS name
                              FROM  profile_education_enum AS e
                         LEFT JOIN  geoloc_countries       AS gc ON (e.country = gc.iso_3166_1_a2)
                      WHERE EXISTS  (SELECT  *
                                       FROM  profile_education_degree AS d
                                      WHERE  e.id = d.eduid)
-                         ORDER BY  gc.countryFR, e.name");
+                         ORDER BY  gc.country, e.name");
     $country = "";
     while ($arr_edu = $res->next()) {
         if ($arr_edu["country"] != $country) {
index b23fdff..7fd7623 100644 (file)
@@ -252,18 +252,12 @@ function set_alias_names(&$sn_new, $sn_old, $pid, $uid, $update_new = false, $ne
     $has_new = false;
     foreach ($sn_new as $typeid => $sn) {
         if (isset($sn['pub'])) {
-            if (isset($sn_old[$typeid]) && ($sn_old[$typeid]['fullname'] == $sn['fullname'] && $update_new)) {
+            if (isset($sn_old[$typeid]) && $update_new) {
                 XDB::execute("UPDATE  profile_name
                                  SET  particle = {?}, name = {?}, typeid = {?}
                                WHERE  id = {?} AND pid = {?}",
                              $sn['particle'], $sn['name'], $typeid, $sn_old[$typeid]['id'], $pid);
                 unset($sn_old[$typeid]);
-            } elseif ($update_new
-                      || (isset($sn_old[$typeid]) && compare_basename($sn_old[$typeid]['fullname'], $sn['fullname']))) {
-                XDB::execute("INSERT INTO  profile_name (particle, name, typeid, pid)
-                                   VALUES  ({?}, {?}, {?}, {?})",
-                             $sn['particle'], $sn['name'], $typeid, $pid);
-                unset($sn_old[$typeid]);
             } else {
                 $has_new = true;
             }
index 0d2c5e2..b114ae5 100644 (file)
@@ -100,23 +100,6 @@ class WatchProfileUpdate extends WatchOperation
         return $user->profile()->last_change;
     }
 
-    static private $descriptions = array('search_names' => 'L\'un de ses noms',
-                                         'freetext'     => 'Le texte libre',
-                                         'mobile'       => 'Son numéro de téléphone portable',
-                                         'nationalite'  => 'Sa nationalité',
-                                         'nationalite2' => 'Sa seconde nationalité',
-                                         'nationalite3' => 'Sa troisième nationalité',
-                                         'nick'         => 'Son surnom',
-                                         'networking'   => 'La liste de ses adresses de networking',
-                                         'edus'         => 'Ses formations',
-                                         'addresses'    => 'Ses adresses',
-                                         'section'      => 'Sa section sportive',
-                                         'binets'       => 'La liste de ses binets',
-                                         'medals'       => 'Ses décorations',
-                                         'cv'           => 'Son Curriculum Vitae',
-                                         'corps'        => 'Son Corps d\'État',
-                                         'jobs'         => 'Ses informations professionnelles',
-                                         'photo'        => 'Sa photographie');
     public function getData(PlUser &$user)
     {
         $data = XDB::fetchColumn("SELECT  field
@@ -129,7 +112,7 @@ class WatchProfileUpdate extends WatchOperation
         } else {
             $text = array();
             foreach ($data as $f) {
-                $text[] = self::$descriptions[$f];
+                $text[] = Profile::$descriptions[$f];
             }
             return $text;
         }
index 559686d..b39b8f9 100644 (file)
@@ -202,8 +202,12 @@ class Job
         }
         $this->company = CompanyList::get($this->jobid);
         if (is_null($this->company)) {
-            $entreprise = ProfileValidate::get_typed_requests($this->pid, 'entreprise');
-            $this->company = new Company(array('name' =>  $entreprise[$this->id]->name));
+            $entreprises = ProfileValidate::get_typed_requests($this->pid, 'entreprise');
+            foreach ($entreprises as $entreprise) {
+                if ($entreprise->id == $this->id) {
+                    $this->company = new Company(array('name' => $entreprise->name));
+                }
+            }
         }
     }
 
@@ -334,7 +338,7 @@ class ProfileEducation extends ProfileField
         $data = XDB::iterator('SELECT  pe.id, pe.pid,
                                        pe.entry_year, pe.grad_year, pe.program, pe.flags,
                                        pee.name AS school, pee.abbreviation AS school_short,
-                                       pee.url AS school_url, gc.countryFR AS country,
+                                       pee.url AS school_url, gc.country,
                                        pede.degree, pede.abbreviation AS degree_short, pede.level AS degree_level,
                                        pefe.field
                                  FROM  profile_education AS pe
@@ -485,7 +489,7 @@ class ProfileMentoringCountries extends ProfileField
 
     public static function fetchData(array $pids, ProfileVisibility $visibility)
     {
-        $data = XDB::iterator('SELECT  pmc.pid, pmc.country AS id, gc.countryFR AS name
+        $data = XDB::iterator('SELECT  pmc.pid, pmc.country AS id, gc.country AS name
                                  FROM  profile_mentor_country AS pmc
                             LEFT JOIN  geoloc_countries AS gc ON (gc.iso_3166_1_a2 = pmc.country)
                                 WHERE  pmc.pid IN {?}
@@ -766,7 +770,10 @@ class CompanyList
         if (!array_key_exists($id, self::$companies)) {
             self::preload();
         }
-        return self::$companies[$id];
+        if (isset(self::$companies[$id])) {
+            return self::$companies[$id];
+        }
+        return null;
     }
 }
 
index a28a10a..f189ca3 100644 (file)
@@ -166,6 +166,7 @@ class UFB_QuickSearch extends UserFilterBuilder
     {
         $fields = array(
             new UFBF_Quick('quick', 'Recherche rapide'),
+            new UFBF_NotRegistered('nonins', 'Non inscrits'),
         );
         parent::__construct($fields, $envprefix);
     }
@@ -175,7 +176,12 @@ class UFB_QuickSearch extends UserFilterBuilder
 // {{{ class UFB_AdvancedSearch
 class UFB_AdvancedSearch extends UserFilterBuilder
 {
-    public function __construct($envprefix = '')
+    /** Create a UFB_AdvancedSearch.
+     * @param $include_admin Whether to include 'admin-only' fields
+     * @param $include_ax Whether to include 'ax-only' fields
+     * @param $envprefix Optional prefix for form field names.
+     */
+    public function __construct($include_admin = false, $include_ax = false, $envprefix = '')
     {
         $fields = array(
             new UFBF_Name('name', 'Nom'),
@@ -209,6 +215,11 @@ class UFB_AdvancedSearch extends UserFilterBuilder
 
             new UFBF_Mentor('only_referent', 'Référent'),
         );
+
+        if ($include_admin || $include_ax) {
+            $fields[] = new UFBF_SchoolIds('schoolid_ax', 'Matricule AX', UFC_SchoolId::AX);
+        }
+
         parent::__construct($fields, $envprefix);
     }
 }
@@ -563,6 +574,48 @@ class UFBF_Quick extends UFB_Field
 }
 // }}}
 
+// {{{ class UFBF_SchoolIds
+class UFBF_SchoolIds extends UFB_Field
+{
+    // One of UFC_SchoolId types
+    protected $type;
+
+    public function __construct($envfield, $formtext, $type = UFC_SchoolId::AX)
+    {
+        parent::__construct($envfield, $formtext);
+        $this->type = $type;
+    }
+
+    protected function check(UserFilterBuilder &$ufb)
+    {
+        if ($ufb->blank($this->envfield)) {
+            $this->empty = true;
+            return true;
+        }
+
+        $value = $ufb->t($this->envfield);
+        $values = explode("\n", $value);
+        $ids = array();
+        foreach ($values as $val) {
+            if (preg_match('/^[0-9A-Z]{0,8}$/', $val)) {
+                $ids[] = $val;
+            }
+        }
+        if (count($ids) == 0) {
+            return $this->raise("Le champ %s ne contient aucune valeur valide.");
+        }
+
+        $this->val = $ids;
+        return true;
+    }
+
+    protected function buildUFC(UserFilterBuilder &$ufb)
+    {
+        return new UFC_SchoolId($this->type, $this->val);
+    }
+}
+// }}}
+
 // {{{ class UFBF_Name
 class UFBF_Name extends UFBF_Text
 {
@@ -655,6 +708,22 @@ class UFBF_Sex extends UFBF_Enum
 }
 // }}}
 
+// {{{ class UFBF_NotRegistered
+// Simple field for selecting only alive, not registered users (for quick search)
+class UFBF_NotRegistered extends UFBF_Bool
+{
+    protected function buildUFC(UserFilterBuilder &$ufb)
+    {
+        if ($this->val) {
+            return new PFC_And(
+                new PFC_Not(new UFC_Dead()),
+                new PFC_Not(new UFC_Registered())
+            );
+        }
+    }
+}
+// }}}
+
 // {{{ class UFBF_Registered
 class UFBF_Registered extends UFBF_Enum
 {
index 7ffe768..11f49e4 100644 (file)
@@ -45,21 +45,15 @@ class ProfileSet extends PlSet
     }
 }
 
+require_once "ufbuilder.inc.php";
+
 class SearchSet extends ProfileSet
 {
-    public  $advanced = false;
-    private $score    = null;
-    private $quick    = false;
-    private $valid    = true;
+    protected $score    = null;
+    protected $valid    = true;
 
-    public function __construct($quick = false, PlFilterCondition $cond = null)
+    public function __construct(UserFilterBuilder &$ufb, PlFilterCondition $cond = null)
     {
-        if ($no_search) {
-            return;
-        }
-
-        $this->quick = $quick;
-
         if (is_null($cond)) {
             $conds = new PFC_And();
         } else if ($cond instanceof PFC_And) {
@@ -68,30 +62,6 @@ class SearchSet extends ProfileSet
             $conds = new PFC_And($cond);
         }
 
-        if ($quick) {
-            $this->getQuick($conds);
-        } else {
-            $this->getAdvanced($conds);
-        }
-    }
-
-    public function isValid()
-    {
-        return $this->valid;
-    }
-
-    /** Sets up the conditions for a Quick Search
-     * @param $conds Additional conds (as a PFC_And)
-     */
-    private function getQuick($conds)
-    {
-        if (!S::logged()) {
-            Env::kill('with_soundex');
-        }
-
-        require_once 'ufbuilder.inc.php';
-        $ufb = new UFB_QuickSearch();
-
         if (!$ufb->isValid()) {
             $this->valid = false;
             return;
@@ -102,36 +72,12 @@ class SearchSet extends ProfileSet
 
         $orders = $ufb->getOrders();
 
-        if (S::logged() && Env::has('nonins')) {
-            $conds = new PFC_And($conds,
-                new PFC_Not(new UFC_Dead()),
-                new PFC_Not(new UFC_Registered())
-            );
-        }
-
         parent::__construct($conds, $orders);
     }
 
-    /** Sets up the conditions for an Advanced Search
-     * @param $conds Additional conds (as a PFC_And)
-     */
-    private function getAdvanced($conds)
+    public function isValid()
     {
-        $this->advanced = true;
-        require_once 'ufbuilder.inc.php';
-        $ufb = new UFB_AdvancedSearch();
-
-        if (!$ufb->isValid()) {
-            $this->valid = false;
-            return;
-        }
-
-        $ufc = $ufb->getUFC();
-        $conds->addChild($ufc);
-
-        $orders = $ufb->getOrders();
-
-        parent::__construct($conds, $orders);
+        return $this->valid;
     }
 
     /** Add a "rechercher=Chercher" field to the query to simulate the POST
@@ -153,6 +99,30 @@ class SearchSet extends ProfileSet
     }
 }
 
+// Specialized SearchSet for quick search.
+class QuickSearchSet extends SearchSet
+{
+    public function __construct(PlFilterCondition $cond = null)
+    {
+        if (!S::logged()) {
+            Env::kill('with_soundex');
+        }
+
+        parent::__construct(new UFB_QuickSearch(), $cond);
+    }
+}
+
+// Specialized SearchSet for advanced search.
+class AdvancedSearchSet extends SearchSet
+{
+    public function __construct($xorg_admin_fields, $ax_admin_fields,
+                                PlFilterCondition $cond = null)
+    {
+        parent::__construct(new UFB_AdvancedSearch($xorg_admin_fields, $ax_admin_fields),
+                            $cond);
+    }
+}
+
 /** Simple set based on an array of User objects
  */
 class ArraySet extends ProfileSet
@@ -350,5 +320,40 @@ class GadgetView implements PlView
     }
 }
 
+class AddressesView implements PlView
+{
+    private $set;
+
+    public function __construct(PlSet &$set, array $params)
+    {
+        $this->set =& $set;
+    }
+
+    public function apply(PlPage &$page)
+    {
+        $pids = $this->set->getIds(new PlLimit());
+        $visibility = new ProfileVisibility(ProfileVisibility::VIS_AX);
+        pl_cached_content_headers('text/x-csv', 1);
+
+        $csv = fopen('php://output', 'w');
+        fputcsv($csv, array('adresses'), ';');
+        $res = XDB::query('SELECT  pd.public_name, pa.postalText
+                             FROM  profile_addresses AS pa
+                       INNER JOIN  profile_display   AS pd ON (pd.pid = pa.pid)
+                            WHERE  pa.type = \'home\' AND pa.pub IN (\'public\', \'ax\') AND FIND_IN_SET(\'mail\', pa.flags) AND pa.pid IN {?}
+                         GROUP BY  pa.pid', $pids);
+        foreach ($res->fetchAllAssoc() as $item) {
+            fputcsv($csv, $item, ';');
+        }
+        fclose($csv);
+        exit();
+    }
+
+    public function args()
+    {
+        return $this->set->args();
+    }
+}
+
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
 ?>
index d5678bd..1600a1b 100644 (file)
@@ -42,6 +42,9 @@ abstract class Validate
     // Validations rules: comments for administrators.
     public $rules = 'Mieux vaut laisser une demande de validation à un autre administrateur que de valider une requête illégale ou que de refuser une demande légitime.';
 
+    // Unless differently stated, a validation must be done by a site administrator.
+    public $requireAdmin = true;
+
     // }}}
     // {{{ constructor
 
@@ -126,6 +129,11 @@ abstract class Validate
      */
     public function handle_formu()
     {
+        if ($this->requireAdmin && !S::admin()) {
+            $this->trigError('Vous n\'avez pas les permissions nécessaires pour valider cette demande.');
+            return false;
+        }
+
         if (Env::has('delete')) {
             $this->clean();
             $this->trigSuccess('Requête supprimée.');
@@ -598,7 +606,8 @@ abstract class ProfileValidate extends Validate
     {
         $res = XDB::iterRow('SELECT  data
                                FROM  requests
-                              WHERE  pid = {?} and type = {?}',
+                              WHERE  pid = {?} and type = {?}
+                           ORDER BY  stamp',
                             $pid, $type);
         $array = array();
         while (list($data) = $res->next()) {
index da2e65e..671d93f 100644 (file)
@@ -41,6 +41,8 @@ class EntrReq extends ProfileValidate
     public $suggestions;
     public $rules = 'Si l\'entreprise est déjà présente sous un autre nom dans la liste des suggestions, remplacer son nom par celui-ci avant de valider. Laisser les autres champs tels quels.';
 
+    public $requireAdmin = false;
+
     // }}}
     // {{{ constructor
 
index a88ac5f..38d3f65 100644 (file)
@@ -42,7 +42,7 @@ class AdminModule extends PLModule
             'admin/skins'                  => $this->make_hook('skins',                  AUTH_MDP, 'admin'),
             'admin/user'                   => $this->make_hook('user',                   AUTH_MDP, 'admin'),
             'admin/add_accounts'           => $this->make_hook('add_accounts',           AUTH_MDP, 'admin'),
-            'admin/validate'               => $this->make_hook('validate',               AUTH_MDP, 'admin'),
+            'admin/validate'               => $this->make_hook('validate',               AUTH_MDP, 'admin,edit_directory'),
             'admin/validate/answers'       => $this->make_hook('validate_answers',       AUTH_MDP, 'admin'),
             'admin/wiki'                   => $this->make_hook('wiki',                   AUTH_MDP, 'admin'),
             'admin/ipwatch'                => $this->make_hook('ipwatch',                AUTH_MDP, 'admin'),
@@ -50,7 +50,8 @@ class AdminModule extends PLModule
             'admin/accounts'               => $this->make_hook('accounts',               AUTH_MDP, 'admin'),
             'admin/account/watch'          => $this->make_hook('account_watch',          AUTH_MDP, 'admin'),
             'admin/account/types'          => $this->make_hook('account_types',          AUTH_MDP, 'admin'),
-            'admin/jobs'                   => $this->make_hook('jobs',                   AUTH_MDP, 'admin'),
+            'admin/jobs'                   => $this->make_hook('jobs',                   AUTH_MDP, 'admin,edit_directory'),
+            'admin/profile'                => $this->make_hook('profile',                AUTH_MDP, 'admin,edit_directory')
         );
     }
 
@@ -1125,6 +1126,7 @@ class AdminModule extends PLModule
         global $globals;
         $globals->updateNbValid();
         $page->assign('vit', Validate::iterate());
+        $page->assign('isAdmin', S::admin());
     }
 
     function handler_validate_answers(&$page, $action = 'list', $id = null)
@@ -1511,7 +1513,7 @@ class AdminModule extends PLModule
                                          'link_type' => Phone::LINK_COMPANY, 'pub' => 'public'));
                 $fax = new Phone(array('display' => Env::v('fax'), 'link_id' => $id, 'id' => 1, 'type' => 'fax',
                                          'link_type' => Phone::LINK_COMPANY, 'pub' => 'public'));
-                $address = new Address(array('jobid' => $jobid, 'type' => Address::LINK_COMPANY, 'text' => Env::t('address')));
+                $address = new Address(array('jobid' => $id, 'type' => Address::LINK_COMPANY, 'text' => Env::t('address')));
                 $phone->save();
                 $fax->save();
                 $address->save();
@@ -1539,6 +1541,37 @@ class AdminModule extends PLModule
             }
         }
     }
+
+    function handler_profile(&$page)
+    {
+        $page->changeTpl('admin/profile.tpl');
+
+        if (Post::has('checked')) {
+            S::assert_xsrf_token();
+            $res = XDB::iterator('SELECT  DISTINCT(pm.pid), pd.public_name
+                                    FROM  profile_modifications AS pm
+                              INNER JOIN  profile_display       AS pd ON (pm.pid = pd.pid)
+                                   WHERE  pm.type = \'self\'');
+
+            while ($profile = $res->next()) {
+                if (Post::has('checked_' . $profile['pid'])) {
+                    XDB::execute('DELETE FROM  profile_modifications
+                                        WHERE  type = \'self\' AND pid = {?}', $profile['pid']);
+
+                    $page->trigSuccess('Profil de ' . $profile['public_name'] . ' vérifié.');
+                }
+            }
+        }
+
+        $res = XDB::iterator('SELECT  p.hrpid, pm.pid, pd.directory_name, GROUP_CONCAT(pm.field SEPARATOR \', \') AS field
+                                FROM  profile_modifications AS pm
+                          INNER JOIN  profiles              AS p  ON (pm.pid = p.pid)
+                          INNER JOIN  profile_display       AS pd ON (pm.pid = pd.pid)
+                               WHERE  pm.type = \'self\'
+                            GROUP BY  pd.directory_name
+                            ORDER BY  pd.directory_name');
+        $page->assign('updates', $res);
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
index 9454062..ba5e1df 100644 (file)
@@ -316,7 +316,7 @@ class CarnetModule extends PLModule
         }
         if ($search && trim(Env::v('quick'))) {
             $base = 'carnet/contacts/search';
-            $view = new SearchSet(true, new UFC_Contact($user));
+            $view = new QuickSearchSet(new UFC_Contact($user));
         } else {
             $base = 'carnet/contacts';
             $view = new ProfileSet(new UFC_Contact($user));
index a3f7b2b..b97b6c9 100644 (file)
@@ -852,8 +852,6 @@ class EmailModule extends PLModule
             if ($list == '') {
                 $page->trigError('La liste est vide.');
             } else {
-                global $platal;
-
                 $broken_user_list = array();
                 $broken_list = explode("\n", $list);
                 sort($broken_list);
@@ -891,7 +889,7 @@ class EmailModule extends PLModule
                         if (!empty($x['nb_mails'])) {
                             $mail = new PlMailer('emails/broken.mail.tpl');
                             $mail->addTo("\"{$x['full_name']}\" <{$x['alias']}@"
-                                         . $globals->mail->domain . '>');
+                                         . Platal::globals()->mail->domain . '>');
                             $mail->assign('x', $x);
                             $mail->assign('email', $email);
                             $mail->send();
@@ -917,21 +915,27 @@ class EmailModule extends PLModule
                 // Output the list of users with recently broken addresses,
                 // along with the count of valid redirections.
                 require_once 'notifs.inc.php';
-                pl_content_headers("text/x-csv");
+                pl_cached_content_headers('text/x-csv', 1);
 
                 $csv = fopen('php://output', 'w');
-                fputcsv($csv, array('nom', 'promo', 'alias', 'bounce', 'nbmails', 'url'), ';');
+                fputcsv($csv, array('nom', 'promo', 'alias', 'bounce', 'nbmails', 'url', 'corps', 'job', 'networking'), ';');
                 foreach ($broken_user_list as $alias => $mails) {
                     $sel = Xdb::query(
-                        "SELECT  acc.uid, count(e.email) AS nb_mails,
+                        "SELECT  acc.uid, count(DISTINCT(e.email)) AS nb_mails,
                                  IFNULL(pd.public_name, acc.full_name) AS fullname,
-                                 IFNULL(pd.promo, 0) AS promo
-                           FROM  aliases          AS a
-                     INNER JOIN  accounts         AS acc ON (a.uid = acc.uid)
-                      LEFT JOIN  emails           AS e   ON (e.uid = acc.uid
-                                                             AND FIND_IN_SET('active', e.flags) AND e.panne = 0)
-                      LEFT JOIN  account_profiles AS ap  ON (acc.uid = ap.uid AND FIND_IN_SET('owner', ap.perms))
-                      LEFT JOIN  profile_display  AS pd  ON (pd.pid = ap.pid)
+                                 IFNULL(pd.promo, 0) AS promo, IFNULL(pce.name, 'Aucun') AS corps,
+                                 IFNULL(pje.name, 'Aucun') AS job, GROUP_CONCAT(pn.address SEPARATOR ', ') AS networking
+                           FROM  aliases            AS a
+                     INNER JOIN  accounts           AS acc ON (a.uid = acc.uid)
+                      LEFT JOIN  emails             AS e   ON (e.uid = acc.uid
+                                                               AND FIND_IN_SET('active', e.flags) AND e.panne = 0)
+                      LEFT JOIN  account_profiles   AS ap  ON (acc.uid = ap.uid AND FIND_IN_SET('owner', ap.perms))
+                      LEFT JOIN  profile_display    AS pd  ON (pd.pid = ap.pid)
+                      LEFT JOIN  profile_corps      AS pc  ON (pc.pid = ap.pid)
+                      LEFT JOIN  profile_corps_enum AS pce ON (pc.current_corpsid = pce.id)
+                      LEFT JOIN  profile_job        AS pj  ON (pj.pid = ap.pid)
+                      LEFT JOIN  profile_job_enum   AS pje ON (pj.jobid = pje.id)
+                      LEFT JOIN  profile_networking AS pn  ON (pn.pid = ap.pid)
                           WHERE  a.alias = {?}
                        GROUP BY  acc.uid", $alias);
 
@@ -943,7 +947,8 @@ class EmailModule extends PLModule
                         }
                         fputcsv($csv, array($x['fullname'], $x['promo'], $alias,
                                             join(',', $mails), $x['nb_mails'],
-                                            'https://www.polytechnique.org/marketing/broken/' . $alias), ';');
+                                            'https://www.polytechnique.org/marketing/broken/' . $alias,
+                                            $x['corps'], $x['job'], $x['networking']), ';');
                     }
                 }
                 fclose($csv);
index 8a4f9c9..1b07698 100644 (file)
@@ -42,7 +42,8 @@ class FusionAxModule extends PLModule
                 'fusionax/deceased'         => $this->make_hook('deceased', AUTH_MDP, 'admin'),
                 'fusionax/promo'            => $this->make_hook('promo',    AUTH_MDP, 'admin'),
                 'fusionax/names'            => $this->make_hook('names',    AUTH_MDP, 'admin'),
-                'fusionax/edu'              => $this->make_hook('edu',      AUTH_MDP, 'admin')
+                'fusionax/edu'              => $this->make_hook('edu',      AUTH_MDP, 'admin'),
+                'fusionax/corps'            => $this->make_hook('corps',    AUTH_MDP, 'admin')
             );
         } elseif (Platal::globals()->merge->state == 'done') {
             return array(
@@ -110,17 +111,17 @@ class FusionAxModule extends PLModule
             } else {
                 // séparation de l'archive en fichiers par tables
                 $file = $spoolpath . $file;
-                // Removes master and doctorate students
-                exec('grep -v "^[A-Z]\{2\}.[0-9]\{4\}[MD][0-9]\{3\}" ' . $file . ' > ' . $file . '.tmp');
-                exec('mv -f ' . $file . '.tmp ' . $file);
                 // Split export into specialised files
                 exec('grep "^AD" ' . $file . ' > ' . $spoolpath . 'Adresses.txt');
                 exec('grep "^AN" ' . $file . ' > ' . $spoolpath . 'Anciens.txt');
+                exec('grep "^FO.[0-9]\{4\}[MD][0-9]\{3\}.Etudiant" ' . $file . ' > ' . $spoolpath . 'Formations_MD.txt');
+                exec('grep "^FO.[0-9]\{4\}[MD][0-9]\{3\}.Doct. de" ' . $file . ' >> ' . $spoolpath . 'Formations_MD.txt');
                 exec('grep "^FO" ' . $file . ' > ' . $spoolpath . 'Formations.txt');
                 exec('grep "^AC" ' . $file . ' > ' . $spoolpath . 'Activites.txt');
                 exec('grep "^EN" ' . $file . ' > ' . $spoolpath . 'Entreprises.txt');
                 exec($modulepath . 'formation.pl');
                 exec('mv -f ' . $spoolpath . 'Formations_out.txt ' . $spoolpath . 'Formations.txt');
+                exec('mv -f ' . $spoolpath . 'Formations_MD_out.txt ' . $spoolpath . 'Formations_MD.txt');
                 $report[] = 'Fichier parsé.';
                 $report[] = 'Import dans la base en cours...';
                 $next = 'integrateSQL';
@@ -133,7 +134,8 @@ class FusionAxModule extends PLModule
                 1 => 'Adresses.sql',
                 2 => 'Anciens.sql',
                 3 => 'Formations.sql',
-                4 => 'Entreprises.sql'
+                4 => 'Entreprises.sql',
+                5 => 'Formations_MD.sql'
             );
             if ($file != '') {
                 // récupère le contenu du fichier sql
@@ -156,7 +158,7 @@ class FusionAxModule extends PLModule
             } else {
                 $nextfile = 0;
             }
-            if ($nextfile > 4) {
+            if ($nextfile > 5) {
                 // tous les fichiers ont été exécutés, on passe à l'étape suivante
                 $next = 'adds1920';
             } else {
@@ -235,7 +237,7 @@ class FusionAxModule extends PLModule
             $next = 'clean';
         } elseif ($action == 'clean') {
             // nettoyage du fichier temporaire
-            exec('rm -Rf ' . $spoolpath);
+            //exec('rm -Rf ' . $spoolpath);
             $report[] = 'Import finit.';
         }
         foreach($report as $t) {
@@ -580,20 +582,20 @@ class FusionAxModule extends PLModule
     {
         $page->changeTpl('fusionax/education.tpl');
 
-        $missingEducation = XDB::rawIterator("SELECT  DISTINCT(f.Intitule_diplome)
+        $missingEducation = XDB::rawIterator("SELECT  DISTINCT(f.Intitule_formation)
                                                 FROM  fusionax_formations AS f
-                                               WHERE  f.Intitule_diplome != '' AND NOT EXISTS (SELECT  *
-                                                                                                 FROM  profile_education_enum AS e
-                                                                                                WHERE  f.Intitule_diplome = e.name)");
-        $missingDegree = XDB::rawIterator("SELECT  DISTINCT(f.Intitule_formation)
+                                               WHERE  f.Intitule_formation != '' AND NOT EXISTS (SELECT  *
+                                                                                                   FROM  profile_education_enum AS e
+                                                                                                  WHERE  f.Intitule_formation = e.name)");
+        $missingDegree = XDB::rawIterator("SELECT  DISTINCT(f.Intitule_diplome)
                                              FROM  fusionax_formations AS f
-                                            WHERE  f.Intitule_formation != '' AND NOT EXISTS (SELECT  *
-                                                                                                FROM  profile_education_degree_enum AS e
-                                                                                               WHERE  f.Intitule_formation = e.abbreviation)");
-        $missingCouple = XDB::rawIterator("SELECT  DISTINCT(f.Intitule_diplome) AS edu, f.Intitule_formation AS degree, ee.id AS eduid, de.id AS degreeid
+                                            WHERE  f.Intitule_diplome != '' AND NOT EXISTS (SELECT  *
+                                                                                              FROM  profile_education_degree_enum AS e
+                                                                                             WHERE  f.Intitule_diplome = e.abbreviation)");
+        $missingCouple = XDB::rawIterator("SELECT  DISTINCT(f.Intitule_formation) AS edu, f.Intitule_diplome AS degree, ee.id AS eduid, de.id AS degreeid
                                              FROM  fusionax_formations           AS f
-                                       INNER JOIN  profile_education_enum        AS ee ON (f.Intitule_diplome = ee.name)
-                                       INNER JOIN  profile_education_degree_enum AS de ON (f.Intitule_formation = de.abbreviation)
+                                       INNER JOIN  profile_education_enum        AS ee ON (f.Intitule_formation = ee.name)
+                                       INNER JOIN  profile_education_degree_enum AS de ON (f.Intitule_diplome = de.abbreviation)
                                             WHERE  f.Intitule_diplome != '' AND f.Intitule_formation != ''
                                                    AND NOT EXISTS (SELECT  *
                                                                      FROM  profile_education_degree AS d
@@ -607,6 +609,27 @@ class FusionAxModule extends PLModule
         $page->assign('missingCoupleCount', $missingCouple->total());
     }
 
+    function handler_corps(&$page)
+    {
+        $page->changeTpl('fusionax/corps.tpl');
+
+        $missingCorps = XDB::rawIterator('SELECT  DISTINCT(f.corps_sortie) AS name
+                                            FROM  fusionax_anciens AS f
+                                           WHERE  NOT EXISTS (SELECT  *
+                                                                FROM  profile_corps_enum AS c
+                                                               WHERE  f.corps_sortie = c.abbreviation)');
+        $missingGrade = XDB::rawIterator('SELECT  DISTINCT(f.grade) AS name
+                                            FROM  fusionax_anciens AS f
+                                           WHERE  NOT EXISTS (SELECT  *
+                                                                FROM  profile_corps_rank_enum AS c
+                                                               WHERE  f.grade = c.name)');
+
+        $page->assign('missingCorps', $missingCorps);
+        $page->assign('missingGrade', $missingGrade);
+        $page->assign('missingCorpsCount', $missingCorps->total());
+        $page->assign('missingGradeCount', $missingGrade->total());
+    }
+
     function handler_issues_deathdate(&$page, $action = '')
     {
         $page->changeTpl('fusionax/deathdate_issues.tpl');
index e412b15..03c3449 100644 (file)
@@ -9,6 +9,7 @@ CREATE TABLE IF NOT EXISTS `fusionax_activites` (
   `Raison_sociale` VARCHAR(255) NOT NULL COMMENT 'Raison sociale de l''établissement',
   `Libelle_fonctio` VARCHAR(255) NOT NULL COMMENT 'Libéllé de la fonction',
   `Annuaire` BOOLEAN NOT NULL COMMENT 'publiable dans l''annuaire papier',
+  `Date_maj` DATE NOT NULL COMMENT 'Date de mise à jour de ces informations',
   pid INT(11) UNSIGNED DEFAULT NULL,
   jobid INT(6) UNSIGNED DEFAULT NULL,
   description VARCHAR(255) DEFAULT NULL,
@@ -20,7 +21,9 @@ CREATE TABLE IF NOT EXISTS `fusionax_activites` (
 
 LOAD DATA LOCAL INFILE '{?}Activites.txt' INTO TABLE `fusionax_activites` CHARACTER SET utf8 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\r\n'
 (AC, ax_id, Code_etab, Raison_sociale, Libelle_fonctio, Annuaire,
-@Ligne1, @Ligne2, @Ligne3, @code_postal, @ville, @zip_cedex, @etat_distr, @pays, @tel, @fax, @StringDate_maj);
+@Ligne1, @Ligne2, @Ligne3, @code_postal, @ville, @zip_cedex, @etat_distr, @pays, @tel, @fax, @StringDate_maj)
+SET
+`Date_maj` = CONCAT(SUBSTRING(@StringDate_maj,7),'-',SUBSTRING(@StringDate_maj,4,2),'-',SUBSTRING(@StringDate_maj,1,2));
 
 
 UPDATE fusionax_activites SET Raison_sociale = TRIM(Raison_sociale), Libelle_fonctio = TRIM(Libelle_fonctio);
index e450574..6e2b2fe 100644 (file)
@@ -16,6 +16,7 @@ CREATE TABLE IF NOT EXISTS fusionax_adresses (
   pays VARCHAR(50) NOT NULL,
   tel VARCHAR(30) NOT NULL,
   fax VARCHAR(30) NOT NULL,
+  Date_maj DATE NOT NULL COMMENT 'Date de mise à jour de ces informations',
   Code_etab BIGINT(10) DEFAULT NULL,
   pid INT(11) UNSIGNED DEFAULT NULL,
   jobid INT(6) UNSIGNED DEFAULT NULL,
@@ -28,21 +29,24 @@ CREATE TABLE IF NOT EXISTS fusionax_adresses (
 LOAD DATA LOCAL INFILE '{?}Adresses.txt' INTO TABLE `fusionax_adresses` CHARACTER SET utf8 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\r\n'
 (provenance, ax_id, @Type_adr, Ligne1, Ligne2, Ligne3, code_postal, ville, zip_cedex, etat_distr, pays, tel, fax, @StringDate_maj)
 SET
-`Type_adr` = IF(@Type_adr = 'E', 'E', IF(@Type_adr = '', '', 'P'));
+`Type_adr` = IF(@Type_adr = 'E', 'E', IF(@Type_adr = '', '', 'P')),
+`Date_maj` = CONCAT(SUBSTRING(@StringDate_maj,7),'-',SUBSTRING(@StringDate_maj,4,2),'-',SUBSTRING(@StringDate_maj,1,2));
 
 LOAD DATA LOCAL INFILE '{?}Anciens.txt' INTO TABLE `fusionax_adresses` CHARACTER SET utf8 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\r\n'
 (provenance, ax_id, @login, @password, @promotion_etude, @gpe_promo, @Nom_patronymique, @partic_patro, @prenom, @Nom_usuel, @partic_nom,
   @Nom_complet, @civilite, @Code_nationalite, @type, @corps_sortie, @StringDate_deces, @grade, @Mel_usage, @Mel_publiable, @xxx, @xxx,
   @tel_mobile, @xxx, @xxx, @xxx, @xxx, @xxx, @xxx, @xxx, @X_M_D, @xxx, @xxx, @xxx, @xxx, @xxx, @xxx, @Type_adr,
-  Ligne1, Ligne2, Ligne3, code_postal, ville, zip_cedex, etat_distr, pays, tel, fax, @date_MAJ)
+  Ligne1, Ligne2, Ligne3, code_postal, ville, zip_cedex, etat_distr, pays, tel, fax, @StringDate_maj)
 SET
-Type_adr = IF(@Type_adr = 'E', 'E', IF(@Type_adr = '', '', 'P'));
+Type_adr = IF(@Type_adr = 'E', 'E', IF(@Type_adr = '', '', 'P')),
+`Date_maj` = CONCAT(SUBSTRING(@StringDate_maj,7),'-',SUBSTRING(@StringDate_maj,4,2),'-',SUBSTRING(@StringDate_maj,1,2));
 
 LOAD DATA LOCAL INFILE '{?}Activites.txt' INTO TABLE `fusionax_adresses` CHARACTER SET utf8 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\r\n'
 (provenance, ax_id, Code_etab, @Raison_sociale, @Libelle_fonctio, @Annuaire,
 Ligne1, Ligne2, Ligne3, code_postal, ville, zip_cedex, etat_distr, pays, tel, fax, @StringDate_maj)
 SET
-`Type_adr` = 'E';
+`Type_adr` = 'E',
+`Date_maj` = CONCAT(SUBSTRING(@StringDate_maj,7),'-',SUBSTRING(@StringDate_maj,4,2),'-',SUBSTRING(@StringDate_maj,1,2));
 
 UPDATE fusionax_adresses SET Ligne1 = TRIM(Ligne1), Ligne2 = TRIM(Ligne2), Ligne3 = TRIM(Ligne3), pays = TRIM(pays),
                              code_postal = TRIM(code_postal), ville = TRIM(ville), zip_cedex = TRIM(zip_cedex),
index af12e11..5e50eab 100644 (file)
@@ -20,6 +20,7 @@ CREATE TABLE IF NOT EXISTS fusionax_anciens (
   Mel_publiable TINYINT(4) NOT NULL COMMENT 'Autorisation d''utiliser le mail',
   Mob_publiable TINYINT(4) NOT NULL COMMENT 'Autorisation d''utiliser le mobile',
   tel_mobile VARCHAR(30) NOT NULL COMMENT 'Numéro de téléphone mobile',
+  Date_maj DATE NOT NULL COMMENT 'Date de mise à jour de ces informations',
   pid INT(11) UNSIGNED DEFAULT NULL,
   PRIMARY KEY  (ax_id),
   INDEX (pid)
@@ -29,12 +30,14 @@ LOAD DATA LOCAL INFILE '{?}Anciens.txt' INTO TABLE `fusionax_anciens` CHARACTER
 (AN, ax_id, @login, @password, promotion_etude, @gpe_promo, Nom_patronymique, partic_patro, prenom, Nom_usuel, partic_nom,
   Nom_complet, @civilite, Code_nationalite, @type, corps_sortie, @StringDate_deces, grade, Mel_usage, Mel_publiable, @xxx, Mob_publiable,
   tel_mobile, @xxx, @xxx, @xxx, @xxx, @xxx, @xxx, @xxx, @X_M_D, @xxx, @xxx, @xxx, @xxx, @xxx, @xxx, @Type_adr,
-  @Ligne1, @Ligne2, @Ligne3, @code_postal, @ville, @zip_cedex, @etat_distr, @pays, @tel, @fax, @date_MAJ)
+  @Ligne1, @Ligne2, @Ligne3, @code_postal, @ville, @zip_cedex, @etat_distr, @pays, @tel, @fax, @StringDate_maj)
 SET
-    Date_deces = CONCAT(SUBSTRING(@StringDate_deces,7),'-',SUBSTRING(@StringDate_deces,4,2),'-',SUBSTRING(@StringDate_deces,1,2));
+    Date_deces = CONCAT(SUBSTRING(@StringDate_deces,7),'-',SUBSTRING(@StringDate_deces,4,2),'-',SUBSTRING(@StringDate_deces,1,2)),
+    Date_maj = CONCAT(SUBSTRING(@StringDate_maj,7),'-',SUBSTRING(@StringDate_maj,4,2),'-',SUBSTRING(@StringDate_maj,1,2));
 -- Mel_publiable is not certain yet :/
 
 ALTER TABLE fusionax_anciens ADD INDEX (ax_id);
+UPDATE fusionax_anciens SET corps_sortie = TRIM(corps_sortie), grade = TRIM(grade);
 
 -- Correspondances entre fiches X.org et fiches AX
 DROP TABLE IF EXISTS `fusionax_import`;
index c1c2222..6d02a59 100644 (file)
@@ -3,10 +3,11 @@
 DROP TABLE IF EXISTS `fusionax_formations`;
 
 CREATE TABLE IF NOT EXISTS `fusionax_formations` (
+  Date_maj DATE NOT NULL COMMENT 'Date de mise à jour de ces informations',
   FO CHAR(2) NOT NULL COMMENT 'Vaut toujours FO pour cette table',
   ax_id VARCHAR(8) NOT NULL COMMENT 'Id unique de l''ancien',
-  Intitule_diplome VARCHAR(255) NOT NULL DEFAULT 0 COMMENT 'Intitulé du diplôme',
   Intitule_formation VARCHAR(255) NOT NULL DEFAULT 0 COMMENT 'Intitulé de la formation',
+  Intitule_diplome VARCHAR(255) NOT NULL DEFAULT 0 COMMENT 'Intitulé du diplôme',
   Descr_formation VARCHAR(255) NOT NULL COMMENT 'Description de la formation',
   pid INT(11) UNSIGNED DEFAULT NULL,
   eduid INT(4) DEFAULT NULL,
@@ -23,9 +24,12 @@ CREATE TABLE IF NOT EXISTS `fusionax_formations` (
 ) ENGINE=InnoDB, CHARSET=utf8;
 
 LOAD DATA LOCAL INFILE  '{?}Formations.txt' INTO TABLE  fusionax_formations CHARACTER SET utf8 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'
-(FO, ax_id, Intitule_diplome, Intitule_formation, Descr_formation);
+(@StringDate_maj, FO, ax_id, Intitule_formation, Intitule_diplome, Descr_formation)
+SET
+Date_maj = CONCAT(SUBSTRING(@StringDate_maj,7),'-',SUBSTRING(@StringDate_maj,4,2),'-',SUBSTRING(@StringDate_maj,1,2));
+
 
     UPDATE  fusionax_formations    AS f
-INNER JOIN  profile_education_enum AS e ON (f.Intitule_diplome = e.abbreviation)
-       SET  f.Intitule_diplome = e.name
-     WHERE  f.Intitule_diplome != '';
+INNER JOIN  profile_education_enum AS e ON (f.Intitule_formation = e.abbreviation)
+       SET  f.Intitule_formation = e.name
+     WHERE  f.Intitule_formation != '';
diff --git a/modules/fusionax/Formations_MD.sql b/modules/fusionax/Formations_MD.sql
new file mode 100644 (file)
index 0000000..cad2d6c
--- /dev/null
@@ -0,0 +1,22 @@
+-- Import complet des formations
+
+DROP TABLE IF EXISTS `fusionax_formations_md`;
+
+CREATE TABLE IF NOT EXISTS `fusionax_formations_md` (
+  FO CHAR(2) NOT NULL COMMENT 'Vaut toujours FO pour cette table',
+  ax_id VARCHAR(8) NOT NULL COMMENT 'Id unique de l''ancien',
+  field VARCHAR(255) DEFAULT NULL COMMENT 'Domaine de la formation',
+  pid INT(11) UNSIGNED DEFAULT NULL,
+  fieldid INT(2) DEFAULT NULL,
+  PRIMARY KEY (ax_id),
+  INDEX (pid),
+  INDEX (fieldid)
+) ENGINE=InnoDB, CHARSET=utf8;
+
+LOAD DATA LOCAL INFILE  '{?}Formations.txt' INTO TABLE  fusionax_formations_md CHARACTER SET utf8 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'
+(FO, ax_id, field);
+
+UPDATE fusionax_formations_md SET field = TRIM(field);
+    UPDATE  fusionax_formations_md       AS f
+INNER JOIN  profile_education_field_enum AS e ON (f.field = e.field)
+       SET  f.fieldid = e.id, f.field = NULL;
index 19f435a..d10ce65 100755 (executable)
@@ -12,7 +12,7 @@ while (<FILE>)
 {
   # Dates removal.
   s/\r$//;
-  s/(\t)*[0-9]+\t[0-9]+\t([0-9]{2}\/){2}[0-9]+$//;
+  s/^(FO\t\w{8}\t[^\t]*)\t[0-9]+\t[0-9]+\t([0-9]{2}\/[0-9]{2}\/[0-9]+)$/\2\t\1/;
   # Trailing tab, spaces and dot removal.
   s/(\t| )*$//;
   s/( \t|\t )/\t/g;
@@ -20,50 +20,50 @@ while (<FILE>)
   s/ +/ /g;
 
   # Removes empty educations and jobs (they have nothing to do there).
-  s/^FO\t\w{8}$//;
-  s/^FO\t\w{8}\tProfdes Universités$//;
-  s/^FO\t\w{8}\tPréshonColonie Frdu Caire$//;
-  s/^FO\t\w{8}\tInspgénhonCEA$//;
-  s/^FO\t\w{8}\tProf Emérite Gén Méca$//;
-  s/^FO\t\w{8}\tAncDG Dassault Aviation$//;
-  s/^FO\t\w{8}\tPilote militaire Hélicoptère$//;
-  s/^FO\t\w{8}\tProfHonSupAéro$//;
-  s/^FO\t\w{8}\tPilote de chasse$//;
-  s/^FO\t\w{8}\tProf ENSMP$//;
-  s/^FO\t\w{8}\tProf hon Univ Bordeaux I$//;
-  s/^FO\t\w{8}\tProf$//;
-  s/^FO\t\w{8}\tIng Navigant d'Essais Hélicoptère$//;
-  s/^FO\t\w{8}\tMandataire agrée OEB$//;
-  s/^FO\t\w{8}\tIngSt$//;
-  s/^FO\t\w{8}\tIngretrAérospatiale$//;
-  s/^FO\t\w{8}\tIngénieur$//;
-  s/^FO\t\w{8}\tIng EURATOM$//;
-  s/^FO\t\w{8}\tInspGénCRdes Affd'OM$//;
-  s/^FO\t\w{8}\tAvocat au Barreau de Paris$//;
-  s/^FO\t\w{8}\tCambridge Profic$//;
-  s/^FO\t\w{8}\tPilotage militaire$//;
-  s/^FO\t\w{8}\tDirectHonBNP$//;
-  s/^FO\t\w{8}\tInspecteur des Finances$//;
-  s/^FO\t\w{8}\tMITI Japon$//;
-  s/^FO\t\w{8}\tEuropean Patent Attorney$//;
-  s/^FO\t\w{8}\tAdmciv$//;
-  s/^FO\t\w{8}\tDirecthon SNCF$//;
-  s/^FO\t\w{8}\tDDI Informatique$//;
-  s/^FO\t\w{8}\tDDI$//;
-  s/^FO\t\w{8}\tSFAF$//;
-  s/^FO\t\w{8}\tGestalt praticien$//;
-  s/^FO\t\w{8}\tAdmciv HC$//;
-  s/^FO\t\w{8}\tPsychologue Clinicien$//;
-  s/^FO\t\w{8}\tAnc Avocat au Bareau de Toulon$//;
-  s/^FO\t\w{8}\tAnalyste SFAF$//;
-  s/^FO\t\w{8}\tEcole de Chasse$//;
-  s/^FO\t\w{8}\tPost Doc$//;
-  s/^FO\t\w{8}\tSFAF CIIA$//;
-  s/^FO\t\w{8}\tINSEE$//;
-  s/^FO\t\w{8}\tEconomiste Statisticien$//;
+  s/^.*\tFO\t\w{8}$//;
+  s/^.*\tFO\t\w{8}\tProfdes Universités$//;
+  s/^.*\tFO\t\w{8}\tPréshonColonie Frdu Caire$//;
+  s/^.*\tFO\t\w{8}\tInspgénhonCEA$//;
+  s/^.*\tFO\t\w{8}\tProf Emérite Gén Méca$//;
+  s/^.*\tFO\t\w{8}\tAncDG Dassault Aviation$//;
+  s/^.*\tFO\t\w{8}\tPilote militaire Hélicoptère$//;
+  s/^.*\tFO\t\w{8}\tProfHonSupAéro$//;
+  s/^.*\tFO\t\w{8}\tPilote de chasse$//;
+  s/^.*\tFO\t\w{8}\tProf ENSMP$//;
+  s/^.*\tFO\t\w{8}\tProf hon Univ Bordeaux I$//;
+  s/^.*\tFO\t\w{8}\tProf$//;
+  s/^.*\tFO\t\w{8}\tIng Navigant d'Essais Hélicoptère$//;
+  s/^.*\tFO\t\w{8}\tMandataire agrée OEB$//;
+  s/^.*\tFO\t\w{8}\tIngSt$//;
+  s/^.*\tFO\t\w{8}\tIngretrAérospatiale$//;
+  s/^.*\tFO\t\w{8}\tIngénieur$//;
+  s/^.*\tFO\t\w{8}\tIng EURATOM$//;
+  s/^.*\tFO\t\w{8}\tInspGénCRdes Affd'OM$//;
+  s/^.*\tFO\t\w{8}\tAvocat au Barreau de Paris$//;
+  s/^.*\tFO\t\w{8}\tCambridge Profic$//;
+  s/^.*\tFO\t\w{8}\tPilotage militaire$//;
+  s/^.*\tFO\t\w{8}\tDirectHonBNP$//;
+  s/^.*\tFO\t\w{8}\tInspecteur des Finances$//;
+  s/^.*\tFO\t\w{8}\tMITI Japon$//;
+  s/^.*\tFO\t\w{8}\tEuropean Patent Attorney$//;
+  s/^.*\tFO\t\w{8}\tAdmciv$//;
+  s/^.*\tFO\t\w{8}\tDirecthon SNCF$//;
+  s/^.*\tFO\t\w{8}\tDDI Informatique$//;
+  s/^.*\tFO\t\w{8}\tDDI$//;
+  s/^.*\tFO\t\w{8}\tSFAF$//;
+  s/^.*\tFO\t\w{8}\tGestalt praticien$//;
+  s/^.*\tFO\t\w{8}\tAdmciv HC$//;
+  s/^.*\tFO\t\w{8}\tPsychologue Clinicien$//;
+  s/^.*\tFO\t\w{8}\tAnc Avocat au Bareau de Toulon$//;
+  s/^.*\tFO\t\w{8}\tAnalyste SFAF$//;
+  s/^.*\tFO\t\w{8}\tEcole de Chasse$//;
+  s/^.*\tFO\t\w{8}\tPost Doc$//;
+  s/^.*\tFO\t\w{8}\tSFAF CIIA$//;
+  s/^.*\tFO\t\w{8}\tINSEE$//;
+  s/^.*\tFO\t\w{8}\tEconomiste Statisticien$//;
   s/^\n//;
   # Places education in third place as if it is not reconized, it will only be stored as a description.
-  s/^(FO\t\w{8}\t)/\1\t\t/;
+  s/^(.*\tFO\t\w{8}\t)/\1\t\t/;
 
   # Fixes what can be fixed.
   # École d'Ingénieurs
@@ -1543,87 +1543,87 @@ while (<FILE>)
   s/\t\t\tInstForm SupBiomédicale$/\t\t\tBiomédical/;
 
   # Double diploma that need to be splitted.
-  s/^(FO\t\w{8}\t\t)\tDoct HDR Ecotoxicologie$/\1PhD\tÉcotoxicologie\n\1HDR\tÉcotoxicologie/;
-  s/^(FO\t\w{8}\t\t)\tAgrégé et Doct en Génie civil$/\1PhD\tGénie civil\n\1Agr.\tGénie civil/;
-  s/^(FO\t\w{8}\t\t)\tDoct Habilité à la dir de rech en Philosophie$/\1PhD\tPhilosophie\n\1HDR\tPhilosophie/;
-  s/^(FO\t\w{8}\t\t)\tDEA\+ Thèse Doctorat Pharmacochimie moléculaire$/\1PhD\tPharmacochimie moléculaire\n\1DEA\tPharmacochimie moléculaire/;
-  s/^(FO\t\w{8}\t\t)\tDoctorat\, HDR Informatique$/\1PhD\tInformatique\n\1HDR\tInformatique/;
-  s/^(FO\t\w{8}\t\t)\tDoctorat et Habilitation$/\1PhD\t\n\1HDR\t/;
-  s/^(FO\t\w{8}\t)\t\tPhD et Habil à diriger les RechUniv Paris 6$/\1UPMC\tPhD\t\n\1UPMC\tHDR\t/;
-  s/^(FO\t\w{8}\t)\t\tMS & PhD EHESS$/\1EHESS\tPhD\t\n\1EHESS\tMSc\t/;
-  s/^(FO\t\w{8}\t)\t\tMBAIEP Paris Lic de Droit Assas$/\1Sciences Po\tDipl.\t\n\1Assas\tLic.\tDroit/;
-  s/^(FO\t\w{8}\t)\t\tIEP Paris Lic de Droit Assas$/\1Sciences Po\tDipl.\t\n\1Assas\tLic.\tDroit/;
-  s/^(FO\t\w{8}\t)\t\tIngENST licencié sciences économiques$/\1Télécom\tIng.\t\n\1\tLic.\tÉconomie/;
-  s/^(FO\t\w{8}\t\t)\tMastère Aménagement et Maitrise d'Ouvrage Urbaine$/\1M\tAménagement\n\1Maîtr.\tOuvrage Urbain/;
-  s/^(FO\t\w{8}\t\t)\tDEA et Thèse de Biologie$/\1PhD\tBiologie\n\1DEA\tBiologie/;
-  s/^(FO\t\w{8}\t)\t\tDEA Thèse Jussieu$/\1UPMC\tPhD\t\n\1UPMC\tDEA\t/;
-  s/^(FO\t\w{8}\t\t)\tDESS CAAE MBA$/\1DESS\t\n\1MBA\t/;
-  s/^(FO\t\w{8}\t)\t\tIngSupelec 86 - EMBA HEC 04$/\1Supélec\tIng.\t\n\1HEC\tMBA\t/;
-  s/^(FO\t\w{8}\t)\t\tMBA MscMassachus$/\1MIT\tMBA\t\n\1MIT\tMSc\t/;
-  s/^(FO\t\w{8}\t)\t\tMBA Columbia \+ LBS/\1Columbia University\tMBA\t\n\1London Business School\tM\t/;
-  s/^(FO\t\w{8}\t)\t\tMS Columbia & sciences Po/\1Columbia University\tMSc\t\n\1Sciences Po\tDipl.\t/;
+  s/^(.*\tFO\t\w{8}\t\t)\tDoct HDR Ecotoxicologie$/\1PhD\tÉcotoxicologie\n\1HDR\tÉcotoxicologie/;
+  s/^(.*\tFO\t\w{8}\t\t)\tAgrégé et Doct en Génie civil$/\1PhD\tGénie civil\n\1Agr.\tGénie civil/;
+  s/^(.*\tFO\t\w{8}\t\t)\tDoct Habilité à la dir de rech en Philosophie$/\1PhD\tPhilosophie\n\1HDR\tPhilosophie/;
+  s/^(.*\tFO\t\w{8}\t\t)\tDEA\+ Thèse Doctorat Pharmacochimie moléculaire$/\1PhD\tPharmacochimie moléculaire\n\1DEA\tPharmacochimie moléculaire/;
+  s/^(.*\tFO\t\w{8}\t\t)\tDoctorat\, HDR Informatique$/\1PhD\tInformatique\n\1HDR\tInformatique/;
+  s/^(.*\tFO\t\w{8}\t\t)\tDoctorat et Habilitation$/\1PhD\t\n\1HDR\t/;
+  s/^(.*\tFO\t\w{8}\t)\t\tPhD et Habil à diriger les RechUniv Paris 6$/\1UPMC\tPhD\t\n\1UPMC\tHDR\t/;
+  s/^(.*\tFO\t\w{8}\t)\t\tMS & PhD EHESS$/\1EHESS\tPhD\t\n\1EHESS\tMSc\t/;
+  s/^(.*\tFO\t\w{8}\t)\t\tMBAIEP Paris Lic de Droit Assas$/\1Sciences Po\tDipl.\t\n\1Assas\tLic.\tDroit/;
+  s/^(.*\tFO\t\w{8}\t)\t\tIEP Paris Lic de Droit Assas$/\1Sciences Po\tDipl.\t\n\1Assas\tLic.\tDroit/;
+  s/^(.*\tFO\t\w{8}\t)\t\tIngENST licencié sciences économiques$/\1Télécom\tIng.\t\n\1\tLic.\tÉconomie/;
+  s/^(.*\tFO\t\w{8}\t\t)\tMastère Aménagement et Maitrise d'Ouvrage Urbaine$/\1M\tAménagement\n\1Maîtr.\tOuvrage Urbain/;
+  s/^(.*\tFO\t\w{8}\t\t)\tDEA et Thèse de Biologie$/\1PhD\tBiologie\n\1DEA\tBiologie/;
+  s/^(.*\tFO\t\w{8}\t)\t\tDEA Thèse Jussieu$/\1UPMC\tPhD\t\n\1UPMC\tDEA\t/;
+  s/^(.*\tFO\t\w{8}\t\t)\tDESS CAAE MBA$/\1DESS\t\n\1MBA\t/;
+  s/^(.*\tFO\t\w{8}\t)\t\tIngSupelec 86 - EMBA HEC 04$/\1Supélec\tIng.\t\n\1HEC\tMBA\t/;
+  s/^(.*\tFO\t\w{8}\t)\t\tMBA MscMassachus$/\1MIT\tMBA\t\n\1MIT\tMSc\t/;
+  s/^(.*\tFO\t\w{8}\t)\t\tMBA Columbia \+ LBS/\1Columbia University\tMBA\t\n\1London Business School\tM\t/;
+  s/^(.*\tFO\t\w{8}\t)\t\tMS Columbia & sciences Po/\1Columbia University\tMSc\t\n\1Sciences Po\tDipl.\t/;
 
   #############################################################################
   # Devel formatting.
   # # Both university and diploma missing.
-  #s/^FO\t\w{8}\t\t\tExpertise comptable$//;
-  #s/^FO\t\w{8}\t\t\tLangues orientales \(Chinois\)$//;
-  #s/^FO\t\w{8}\t\t\tÉducateur spécialisé$//;
-  #s/^FO\t\w{8}\t\t\tGestion$//;
-  #s/^FO\t\w{8}\t\t\tBiomédical$//;
-  #s/^FO\t\w{8}\t\t\tBrth$//;
-  #s/^FO\t\w{8}\t\t\tDEM$//;
-  #s/^FO\t\w{8}\t\t\tDT$//;
-  #s/^FO\t\w{8}\t\t\tBESG$//;
-  #s/^FO\t\w{8}\t\t\tESO$//;
-  #s/^FO\t\w{8}\t\t\tBT$//;
-  #s/^FO\t\w{8}\t\t\tBEL$//;
-  #s/^FO\t\w{8}\t\t\tDipl Lt Et Sup Banq$//;
-  #s/^FO\t\w{8}\t\t\tDiplôme Nepali-Tibétain$//;
-  #s/^FO\t\w{8}\t\t\tReact School Harwell$//;
-  #s/^FO\t\w{8}\t\t\tEATG$//;
-  #s/^FO\t\w{8}\t\t\tDESA$//;
-  #s/^FO\t\w{8}\t\t\tDIUUP$//;
-  #s/^FO\t\w{8}\t\t\tDrrerNat$//;
-  #s/^FO\t\w{8}\t\t\tIAC$//;
-  #s/^FO\t\w{8}\t\t\tCESDR$//;
-  #s/^FO\t\w{8}\t\t\tAuditeur ScPolitique$//;
-  #s/^FO\t\w{8}\t\t\tCES Informatique$//;
-  #s/^FO\t\w{8}\t\t\tDon en religion$//;
-  #s/^FO\t\w{8}\t\t\tDSN$//;
-  #s/^FO\t\w{8}\t\t\tBEMS\/CHEM$//;
-  #s/^FO\t\w{8}\t\t\tCESSID$//;
-  #s/^FO\t\w{8}\t\t\tBiologie Moléculaire$//;
-  #s/^FO\t\w{8}\t\t\tMécanique des Transfert$//;
-  #s/^FO\t\w{8}\t\t\tGestion$//;
-  #s/^FO\t\w{8}\t\t\tDECS$//;
-  #s/^FO\t\w{8}\t\t\tCFAF$//;
-  #s/^FO\t\w{8}\t\t\tCRC$//;
-  #s/^FO\t\w{8}\t\t\tMASE$//;
-  #s/^FO\t\w{8}\t\t\tCollège des Sciences Soc et Eco$//;
-  #s/^FO\t\w{8}\t\t\tInstitut de Contrôle de Gestion$//;
-  #s/^FO\t\w{8}\t\t\tICG$//;
-  #s/^FO\t\w{8}\t\t\tETS II$//;
-  #s/^FO\t\w{8}\t\t\tFRM$//;
-  #s/^FO\t\w{8}\t\t\tArchitecte DPLG$//;
-  #s/^FO\t\w{8}\t\t\tCycle des Hautes Etudes CHEE$//;
-  #s/^FO\t\w{8}\t\t\tCHEE&DD Session 9$//;
-  #s/^FO\t\w{8}\t\t\tCSME Session 29$//;
-  #s/^FO\t\w{8}\t\t\tInternat Teachers Progr$//;
-  #s/^FO\t\w{8}\t\t\tCSCP$//;
-  #s/^FO\t\w{8}\t\t\tBaccalauréat canonique$//;
-  #s/^FO\t\w{8}\t\t\tCertif européen de Psychothérapie$//;
-  #s/^FO\t\w{8}\t\t\tIFG$//;
-  #s/^FO\t\w{8}\t\t\tIFP$//;
-  #s/^FO\t\w{8}\t\t\tArchitecte dplg$//;
-  #s/^FO\t\w{8}\t\t\tLLCE Chinois INALCO$//;
-  #s/^FO\t\w{8}\t\t\tInst du Contrôle de Gestion$//;
-  #s/^FO\t\w{8}\t\t\tInstitut Auguste Comte$//;
-  #s/^FO\t\w{8}\t\t\tInst Auguste Comte$//;
-  #s/^FO\t\w{8}\t\t\tUSMC Command & Staff College$//;
-  #s/^FO\t\w{8}\t\t\tISNSE Argunne National Laboratory USA$//;
+  #s/^.*\tFO\t\w{8}\t\t\tExpertise comptable$//;
+  #s/^.*\tFO\t\w{8}\t\t\tLangues orientales \(Chinois\)$//;
+  #s/^.*\tFO\t\w{8}\t\t\tÉducateur spécialisé$//;
+  #s/^.*\tFO\t\w{8}\t\t\tGestion$//;
+  #s/^.*\tFO\t\w{8}\t\t\tBiomédical$//;
+  #s/^.*\tFO\t\w{8}\t\t\tBrth$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDEM$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDT$//;
+  #s/^.*\tFO\t\w{8}\t\t\tBESG$//;
+  #s/^.*\tFO\t\w{8}\t\t\tESO$//;
+  #s/^.*\tFO\t\w{8}\t\t\tBT$//;
+  #s/^.*\tFO\t\w{8}\t\t\tBEL$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDipl Lt Et Sup Banq$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDiplôme Nepali-Tibétain$//;
+  #s/^.*\tFO\t\w{8}\t\t\tReact School Harwell$//;
+  #s/^.*\tFO\t\w{8}\t\t\tEATG$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDESA$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDIUUP$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDrrerNat$//;
+  #s/^.*\tFO\t\w{8}\t\t\tIAC$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCESDR$//;
+  #s/^.*\tFO\t\w{8}\t\t\tAuditeur ScPolitique$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCES Informatique$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDon en religion$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDSN$//;
+  #s/^.*\tFO\t\w{8}\t\t\tBEMS\/CHEM$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCESSID$//;
+  #s/^.*\tFO\t\w{8}\t\t\tBiologie Moléculaire$//;
+  #s/^.*\tFO\t\w{8}\t\t\tMécanique des Transfert$//;
+  #s/^.*\tFO\t\w{8}\t\t\tGestion$//;
+  #s/^.*\tFO\t\w{8}\t\t\tDECS$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCFAF$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCRC$//;
+  #s/^.*\tFO\t\w{8}\t\t\tMASE$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCollège des Sciences Soc et Eco$//;
+  #s/^.*\tFO\t\w{8}\t\t\tInstitut de Contrôle de Gestion$//;
+  #s/^.*\tFO\t\w{8}\t\t\tICG$//;
+  #s/^.*\tFO\t\w{8}\t\t\tETS II$//;
+  #s/^.*\tFO\t\w{8}\t\t\tFRM$//;
+  #s/^.*\tFO\t\w{8}\t\t\tArchitecte DPLG$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCycle des Hautes Etudes CHEE$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCHEE&DD Session 9$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCSME Session 29$//;
+  #s/^.*\tFO\t\w{8}\t\t\tInternat Teachers Progr$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCSCP$//;
+  #s/^.*\tFO\t\w{8}\t\t\tBaccalauréat canonique$//;
+  #s/^.*\tFO\t\w{8}\t\t\tCertif européen de Psychothérapie$//;
+  #s/^.*\tFO\t\w{8}\t\t\tIFG$//;
+  #s/^.*\tFO\t\w{8}\t\t\tIFP$//;
+  #s/^.*\tFO\t\w{8}\t\t\tArchitecte dplg$//;
+  #s/^.*\tFO\t\w{8}\t\t\tLLCE Chinois INALCO$//;
+  #s/^.*\tFO\t\w{8}\t\t\tInst du Contrôle de Gestion$//;
+  #s/^.*\tFO\t\w{8}\t\t\tInstitut Auguste Comte$//;
+  #s/^.*\tFO\t\w{8}\t\t\tInst Auguste Comte$//;
+  #s/^.*\tFO\t\w{8}\t\t\tUSMC Command & Staff College$//;
+  #s/^.*\tFO\t\w{8}\t\t\tISNSE Argunne National Laboratory USA$//;
   ## # Formatted stuff.
-  #s/^FO\t\w{8}((\t|\t\t)[a-zA-Z1-9'\.éèêùüàäïîşńÉÈÊÙÀÜÄÏÎŞŃ \-\(\)]+)\t.*//;
+  #s/^.*\tFO\t\w{8}((\t|\t\t)[a-zA-Z1-9'\.éèêùüàäïîşńÉÈÊÙÀÜÄÏÎŞŃ \-\(\)]+)\t.*//;
   # # Removes empty lines.
   s/^\n//;
 
@@ -1632,3 +1632,33 @@ while (<FILE>)
 
 close(FILE);
 close(OUT);
+
+$path = $0;
+$path =~ s/modules\/fusionax\/formation\.pl//;
+$path .= "spool/fusionax/";
+$in = $path . "Formations_MD.txt";
+$out = $path . "Formations_MD_out.txt";
+open(FILE, "<:encoding(UTF-8)", $in) || die ("Formations_MD.txt failed to open.");
+open(OUT, ">:encoding(UTF-8)", $out) || die ("Formations_MD_out.txt failed to open.");
+
+while (<FILE>)
+{
+  # Dates removal.
+  s/\r$//;
+  s/^(FO\t\w{8}\t(\w|\.|'|&| )+)\t.*$/\1/;
+  # Trailing tab, spaces and dot removal.
+  s/(\t| )*$//;
+  s/( \t|\t )/\t/g;
+  s/ +/ /g;
+
+  # Removes diploma
+  s/Doct. de l'Ec. polytechnique//;
+  s/Doct. de l'Ec. Polytechnique//;
+  s/Etudiante en Master de l'Ec. polytechnique//;
+  s/Etudiant en Master de l'Ec. polytechnique//;
+
+  print OUT $_;
+}
+
+close(FILE);
+close(OUT);
index b8700de..d3bbe8b 100644 (file)
@@ -74,7 +74,7 @@ class GadgetsModule extends PLModule
             global $globals;
             require_once 'userset.inc.php';
 
-            $view = new SearchSet(true);
+            $view = new QuickSearchSet();
             $view->addMod('gadget', 'Gadget', true);
             $view->apply(null, $page);
 
index 263a24d..cbbbb11 100644 (file)
@@ -29,7 +29,7 @@ class GoogleAppsModule extends PLModule
         }
 
         return array(
-            'googleapps'            => $this->make_hook('index',      AUTH_MDP),
+            'googleapps'            => $this->make_hook('index',      AUTH_MDP, 'mail'),
             'admin/googleapps'      => $this->make_hook('admin',      AUTH_MDP, 'admin'),
             'admin/googleapps/job'  => $this->make_hook('admin_job',  AUTH_MDP, 'admin'),
             'admin/googleapps/user' => $this->make_hook('admin_user', AUTH_MDP, 'admin'),
index 5587714..2ed4836 100644 (file)
@@ -356,7 +356,7 @@ class ListsModule extends PLModule
         $this->prepare_client($page);
         $members = $this->client->get_members($liste);
         $list = list_fetch_basic_info(list_extract_members($members[1]));
-        pl_content_headers("text/x-csv");
+        pl_cached_content_headers('text/x-csv', 1);
 
         echo "email,nom,promo\n";
         echo implode("\n", $list);
index 0a8e0d2..5f8c2f4 100644 (file)
 
 // {{{ function list_sort_owners
 
-function list_sort_owners(&$members, $tri_promo = true)
+function list_sort_owners($members, $tri_promo = true)
 {
     global $globals;
 
-    $membres = Array();
+    // $membres' structure is the following: $sortKey => $key => $listMember
+    $membres = array();
 
-    foreach($members as $mem) {
-        $user = User::getSilent($mem);
+    foreach($members as $member) {
+        $user = User::getSilent($member);
         if (!$user) {
-            $membres[0][] = array('l' => $mem, 'p' => (!$tri_promo ? 'inconnus' : null), 'n' => null, 'x' => null, 'b' => null);
+            $membres[0][$member] = array('name' => null, 'email' => $member, 'category' => null, 'uid' => null, 'lost' => null, 'hasProfile' => null);
         } else {
+            $hasProfile = $user->hasProfile();
             $uid = $user->id();
-            $nom = $user->directoryName();
-            $promo = $user->category();
-            if (!$promo) {
-                $promo = 'extérieurs';
-            }
-            $key = $tri_promo ? ($promo != 'extérieurs' ? $promo : 0) : strtoupper(@$nom{0});
-            if ($tri_promo) {
-                $promo = null;
+            $name = $user->directoryName();
+            $category = $user->category();
+            $key = $tri_promo ? ($category ? $category : 'AAAAA') : strtoupper($name{0});
+            if (!$category) {
+                $category = 'extérieurs';
             }
-            $membres[$key][$nom.$mem] = array('n' => $nom, 'l' => $mem, 'p' => $promo, 'x' => $uid, 'b' => $user->lost);
+            $membres[$key][$name . $member] = array('name' => $name, 'email' => $member, 'category' => $category,
+                                                    'uid' => $uid, 'lost' => $user->lost, 'hasProfile' => $hasProfile);
         }
     }
 
     ksort($membres);
-    foreach($membres as $key=>$val) ksort($membres[$key]);
+    foreach($membres as $membre)  {
+        ksort($membre);
+    }
     return $membres;
 }
 
index 079e524..543eba1 100644 (file)
@@ -180,6 +180,7 @@ class PaymentModule extends PLModule
         $page->assign('meth', $meth);
         $page->assign('pay',  $pay);
         $page->assign('evtlink', $pay->event());
+        $page->assign('sex', S::user()->isFemale());
     }
 
     function handler_cyber_return(&$page, $uid = null)
index 96fe3c0..3f40979 100644 (file)
@@ -53,7 +53,7 @@ class BPLCCyberPlus
         $this->val = 100 * strtr(sprintf("%.02f", (float)$val), '.', ',');
     }
 
-       // }}}
+    // }}}
     // {{{ function form()
 
     function prepareform(&$pay)
@@ -65,9 +65,9 @@ class BPLCCyberPlus
         $prefix = ($pay->flags->hasflag('unique')) ? str_pad("",15,"0") : rand_url_id();
         $fullref = substr("$prefix-{$pay->id}",-12); // FIXME : check for duplicates
         $ts = time();
-               $trans_date = date("YmdHis", $ts);
-               $trans_id = date("His", $ts); // FIXME : check for duplicates
-                                                               
+        $trans_date = date("YmdHis", $ts);
+        $trans_id = date("His", $ts); // FIXME : check for duplicates
+
         // contenu du formulaire
         $this->urlform = "https://systempay.cyberpluspaiement.com/vads-payment/";
         $this->infos['commercant'] = Array(
@@ -81,8 +81,8 @@ class BPLCCyberPlus
         $this->infos['commande'] = Array(
             'vads_amount' => $this->val,
             'vads_currency' => '978', # Euro
-               'vads_payment_config' => 'SINGLE',
-               'vads_trans_date' => $trans_date,
+            'vads_payment_config' => 'SINGLE',
+            'vads_trans_date' => $trans_date,
             'vads_trans_id' => $trans_id,
             'vads_order_id' => $fullref,
             'vads_order_info' => Env::v('comment'));
index e7ae70d..f0985b5 100644 (file)
@@ -44,29 +44,26 @@ class PayPal
 
         $this->urlform = 'https://' . $globals->money->paypal_site . '/cgi-bin/webscr';
         $user = S::user();
-        $name = $user->lastName();
 
         $roboturl = str_replace("https://","http://",$globals->baseurl)
                   . '/' . $platal->ns . "payment/paypal_return/" . S::v('uid')
                   . "?comment=" . urlencode(Env::v('comment'));
 
-        $this->infos = array();
-
-        $this->infos['commercant'] = array(
-            'business'    => $globals->money->paypal_compte,
-            'rm'          => 2,
-            'return'      => $roboturl,
-            'cn'          => 'Commentaires',
-            'no_shipping' => 1,
-            'cbt'         => empty($GLOBALS['IS_XNET_SITE']) ?
-            'Revenir sur polytechnique.org.' :
-            'Revenir sur polytechnique.net.'
+        $this->infos = array(
+            'commercant' => array(
+                'business'    => $globals->money->paypal_compte,
+                'rm'          => 2,
+                'return'      => $roboturl,
+                'cn'          => 'Commentaires',
+                'no_shipping' => 1,
+                'cbt'         => empty($GLOBALS['IS_XNET_SITE']) ?  'Revenir sur polytechnique.org.' : 'Revenir sur polytechnique.net.'
+            )
         );
 
         $info_client = array(
-            'first_name' => S::v('prenom'),
-            'last_name'  => $name,
-            'email'      => S::user()->bestEmail()
+            'first_name' => $user->firstName(),
+            'last_name'  => $user->lastName(),
+            'email'      => $user->bestEmail()
         );
 
         $res = XDB::query("SELECT  pa.text, gl.name AS city, pa.postalCode AS zip, pa.countryId AS country,
@@ -79,7 +76,7 @@ class PayPal
                         LEFT JOIN  geoloc_localities AS gl  ON (gl.id = pa.localityId)
                             WHERE  pa.pid = {?} AND FIND_IN_SET('current', pa.flags)
                             LIMIT  1",
-                          S::i('pid'));
+                          $user->profile()->id());
         $this->infos['client'] = array_map('replace_accent', array_merge($info_client, $res->fetchOneAssoc()));
         list($this->infos['client']['address1'], $this->infos['client']['address2']) =
             explode("\n", Geocoder::getFirstLines($this->infos['client']['text'],
index f9b08fa..a6fc07f 100644 (file)
@@ -318,6 +318,8 @@ class ProfileModule extends PLModule
             $opened_tab = $hrpid;
             $hrpid = $aux;
             $url_error = true;
+        } else {
+            $url_error = false;
         }
         $profile = $this->findProfile($hrpid);
         if (! ($profile instanceof Profile) && ($profile == PL_NOT_FOUND || $profile == PL_FORBIDDEN)) {
@@ -399,7 +401,7 @@ class ProfileModule extends PLModule
         $page->assign('address', array());
     }
 
-    function handler_ajax_tel(&$page, $prefid, $prefname, $telid)
+    function handler_ajax_tel(&$page, $prefid, $prefname, $telid, $subField, $mainField, $mainId)
     {
         pl_content_headers("text/html");
         $page->changeTpl('profile/phone.tpl', NO_SKIN);
@@ -408,6 +410,11 @@ class ProfileModule extends PLModule
         $page->assign('telid', $telid);
         $phone = new Phone();
         $page->assign('tel', $phone->toFormArray());
+        if ($mainField) {
+            $page->assign('subField', $subField);
+            $page->assign('mainField', $mainField);
+            $page->assign('mainId', $mainId);
+        }
     }
 
     function handler_ajax_edu(&$page, $eduid, $class)
@@ -513,7 +520,7 @@ class ProfileModule extends PLModule
 
         // Retrieves referents' countries.
         $res = XDB::query(
-                "SELECT  gc.countryFR
+                "SELECT  gc.country
                    FROM  profile_mentor_country AS m
               LEFT JOIN  geoloc_countries       AS gc ON (m.country = gc.iso_3166_1_a2)
                   WHERE  pid = {?}", $pf->id());
@@ -527,11 +534,11 @@ class ProfileModule extends PLModule
         pl_content_headers("text/html");
         $page->changeTpl('include/field.select.tpl', NO_SKIN);
         $page->assign('name', 'pays_sel');
-        $it = XDB::iterator("SELECT  gc.iso_3166_1_a2 AS id, gc.countryFR AS field
+        $it = XDB::iterator("SELECT  gc.iso_3166_1_a2 AS id, gc.country AS field
                                FROM  geoloc_countries       AS gc
                          INNER JOIN  profile_mentor_country AS mp ON (mp.country = gc.iso_3166_1_a2)
                            GROUP BY  iso_3166_1_a2
-                           ORDER BY  countryFR");
+                           ORDER BY  country");
         $page->assign('list', $it);
     }
 
@@ -750,10 +757,10 @@ class ProfileModule extends PLModule
         $table_editor->describe('degree', 'niveau', true);
         $table_editor->apply($page, $action, $id);
     }
-    function handler_admin_education_degree_set(&$page, $action = 'list', $id = null) {
+    function handler_admin_education_degree_set(&$page, $action = 'list', $id = null, $id2 = null) {
         $page->setTitle('Administration - Correspondances formations - niveau de formation');
         $page->assign('title', 'Gestion des correspondances formations - niveau de formation');
-        $table_editor = new PLTableEditor('admin/education_degree_set', 'profile_education_degree', 'eduid', true);
+        $table_editor = new PLTableEditor('admin/education_degree_set', 'profile_education_degree', 'eduid', true, 'degreeid');
         $table_editor->describe('eduid', 'id formation', true);
         $table_editor->describe('degreeid', 'id niveau', true);
 
@@ -764,7 +771,7 @@ class ProfileModule extends PLModule
         $table_editor->add_option_table('profile_education_degree_enum','profile_education_degree_enum.id = t.degreeid');
         $table_editor->add_option_field('profile_education_degree_enum.degree', 'degree_name', 'niveau');
 
-        $table_editor->apply($page, $action, $id);
+        $table_editor->apply($page, $action, $id, $id2);
     }
     function handler_admin_sections(&$page, $action = 'list', $id = null) {
         $page->setTitle('Administration - Sections');
index 846fda8..587e0b6 100644 (file)
@@ -43,8 +43,8 @@ class ProfileSettingAddresses implements ProfileSetting
 
     public function save(ProfilePage &$page, $field, $value)
     {
-        Phone::deletePhones($page->pid(), Phone::LINK_ADDRESS);
-        Address::deleteAddresses($page->pid(), Address::LINK_PROFILE);
+        Phone::deletePhones($page->pid(), Phone::LINK_ADDRESS, null, S::user()->isMe($page->owner) || S::admin());
+        Address::deleteAddresses($page->pid(), Address::LINK_PROFILE, null, S::user()->isMe($page->owner) || S::admin());
         Address::saveFromArray($value, $page->pid(), Address::LINK_PROFILE);
     }
 
index bc8582d..ac797c6 100644 (file)
@@ -149,7 +149,7 @@ class ProfileSettingSearchNames implements ProfileSetting
             $this->search_names = array();
             foreach ($value as &$sn) {
                 $sn['name'] = trim($sn['name']);
-                if ($sn['type'] == 'firstname' || $sn['type'] == 'lastname') {
+                if (S::user()->isMe($this->owner) && ($sn['type'] == 'firstname' || $sn['type'] == 'lastname')) {
                     $sn['name'] = $this->prepare($page, $sn['type'], $sn['name'],
                                                  $initial[$sn['type']], $success_tmp);
                     $success = $success && $success_tmp;
@@ -237,7 +237,7 @@ class ProfileSettingSearchNames implements ProfileSetting
         $names = array();
         foreach ($value as $name) {
             if ($name['name'] != '') {
-                $names[] = $name['type_name'] . ' : ' . $name['name'];
+                $names[] = mb_strtolower($name['type_name']) . ' : ' . $name['name'];
             }
         }
         return implode(', ' , $names);
@@ -315,12 +315,32 @@ class ProfileSettingEdu implements ProfileSetting
         $degreesList = DirEnum::getOptions(DirEnum::EDUDEGREES);
         $fieldsList = DirEnum::getOptions(DirEnum::EDUFIELDS);
         $educations = array();
-        foreach ($value as $education) {
-            $educations[] = 'Université : ' . $schoolsList[$education['eduid']]
-                          . ', diplôme : ' . $degreesList[$education['degreeid']]
-                          . ', domaine : ' . $fieldsList[$education['fieldid']]
-                          . ', année d\'obtention : ' . $education['grad_year']
-                          . ', intitulé : ' . $education['program'];
+        foreach ($value as $id => $education) {
+            // XXX: the following condition should be removed once there are no more incomplete educations.
+            if (is_null($education['eduid']) || is_null($education['degreeid'])) {
+                if (is_null($education['eduid']) && is_null($education['degreeid'])) {
+                    $educations[$id] = 'formation manquante';
+                } else {
+                    $educations[$id] = (is_null($education['eduid']) ? 'université manquante' : $schoolsList[$education['eduid']]) . ', '
+                                     . (is_null($education['degreeid']) ? 'diplôme manquant' : $degreesList[$education['degreeid']]);
+                }
+            } else {
+                $educations[$id] = $schoolsList[$education['eduid']] . ', ' . $degreesList[$education['degreeid']];
+            }
+
+            $details = array();
+            if ($education['grad_year']) {
+                $details[] = $education['grad_year'];
+            }
+            if ($education['program']) {
+                $details[] = '« ' . $education['program'] . ' »';
+            }
+            if ($education['fieldid']) {
+                $details[] = $fieldsList[$education['fieldid']];
+            }
+            if (count($details)) {
+                $educations[$id] .= ' (' . implode(', ', $details) . ')';
+            }
         }
         return implode(', ', $educations);
     }
@@ -428,12 +448,12 @@ class ProfileSettingNetworking implements ProfileSetting
     }
 
     public function getText($value) {
+        static $pubs = array('public' => 'publique', 'ax' => 'annuaire AX', 'private' => 'privé');
         $networkings = array();
         foreach ($value as $network) {
-            $networkings[] = 'nom : ' . $network['name'] . ', adresse : ' . $network['address']
-                           . ', affichage : ' . $network['pub'];
+            $networkings[] = $network['name'] . ' : ' . $network['address'] . ' (affichage ' . $pubs[$network['pub']] . ')';
         }
-        return implode(' ; ' , $networkings);
+        return implode(', ' , $networkings);
     }
 }
 
@@ -522,7 +542,6 @@ class ProfilePageGeneral extends ProfilePage
         parent::__construct($wiz);
         $this->settings['search_names']
                                   = new ProfileSettingSearchNames();
-        $this->settings['birthdate'] = new ProfileSettingDate();
         $this->settings['nationality1']
                                   = $this->settings['nationality2']
                                   = $this->settings['nationality3']
@@ -544,9 +563,10 @@ class ProfilePageGeneral extends ProfilePage
         /* Some fields editable under condition */
         if (!S::user()->isMe($this->owner)) {
             $this->settings['deathdate'] = new ProfileSettingDate(true);
-        }
-        if (S::user()->isMe($this->owner)) {
+            $this->settings['birthdate'] = new ProfileSettingDate(true);
+        } else {
             $this->settings['yourself'] = null;
+            $this->settings['birthdate'] = new ProfileSettingDate();
         }
         if (S::user()->checkPerms('directory_private')
             || S::user()->isMyProfile($this->owner)) {
@@ -562,7 +582,7 @@ class ProfilePageGeneral extends ProfilePage
     protected function _fetchData()
     {
         // Checkout all data...
-        $res = XDB::query("SELECT  p.nationality1, p.nationality2, p.nationality3, p.birthdate,
+        $res = XDB::query("SELECT  p.nationality1, p.nationality2, p.nationality3, IF(p.birthdate = 0, '', p.birthdate) AS birthdate,
                                    p.email_directory as email_directory, pd.promo AS promo_display,
                                    p.freetext, p.freetext_pub, p.ax_id AS matricule_ax, pd.yourself,
                                    p.deathdate
index 723370b..4726e94 100644 (file)
@@ -49,13 +49,13 @@ class ProfileSettingJob implements ProfileSetting
         return array(
             'id'               => '0',
             'jobid'            => '',
-            'pub'              => 'private',
+            'pub'              => 'ax',
             'name'             => '',
             'description'      => '',
             'w_url'            => '',
             'w_address'        => $address->toFormArray(),
             'w_email'          => '',
-            'w_email_pub'      => 'private',
+            'w_email_pub'      => 'ax',
             'w_email_new'      => '',
             'w_phone'          => array(0 => $phone->toFormArray()),
             'terms'            => array()
@@ -131,7 +131,7 @@ class ProfileSettingJob implements ProfileSetting
         return $jobs;
     }
 
-    private function cleanJob(ProfilePage &$page, $jobid, array &$job, &$success)
+    private function cleanJob(ProfilePage &$page, $jobid, array &$job, &$success, $maxPublicity)
     {
         if ($job['w_email'] == "new@example.org") {
             $job['w_email'] = $job['w_email_new'];
@@ -149,7 +149,7 @@ class ProfileSettingJob implements ProfileSetting
         if (count($job['terms'])) {
             $termsid = array();
             foreach ($job['terms'] as $term) {
-                if (!$term['full_name']) {
+                if (!isset($term['full_name'])) {
                     $termsid[] = $term['jtid'];
                 }
             }
@@ -160,7 +160,7 @@ class ProfileSettingJob implements ProfileSetting
                                  $termsid);
                 $term_id_to_name = $res->fetchAllAssoc('jtid', false);
                 foreach ($job['terms'] as &$term) {
-                    if (!$term['full_name']) {
+                    if (!isset($term['full_name'])) {
                         $term['full_name'] = $term_id_to_name[$term['jtid']];
                     }
                 }
@@ -181,7 +181,11 @@ class ProfileSettingJob implements ProfileSetting
                 $job['jobid'] = $res->fetchOneCell();
             }
         }
-        $job['w_phone'] = Phone::formatFormArray($job['w_phone'], $s);
+
+        if ($maxPublicity->isVisible($job['w_email_pub'])) {
+            $job['w_email_pub'] = $maxPublicity->level();
+        }
+        $job['w_phone'] = Phone::formatFormArray($job['w_phone'], $s, $maxPublicity);
 
         unset($job['removed']);
         unset($job['new']);
@@ -202,7 +206,7 @@ class ProfileSettingJob implements ProfileSetting
         $success = true;
         foreach ($value as $key => $job) {
             $job['name'] = trim($job['name']);
-            if ($job['name'] == '' && $entreprise) {
+            if ($job['name'] == '' && $entreprise[$entr_val]->id == $key) {
                 $job['tmp_name'] = $entreprise[$entr_val]->name;
                 ++$entr_val;
             } else if ($job['name'] == '') {
@@ -234,8 +238,12 @@ class ProfileSettingJob implements ProfileSetting
         foreach ($value as $key => &$job) {
             $address = new Address($job['w_address']);
             $s = $address->format();
+            $maxPublicity = new ProfileVisibility($job['pub']);
+            if ($maxPublicity->isVisible($address->pub)) {
+                $address->pub = $maxPublicity->level();
+            }
             $job['w_address'] = $address->toFormArray();
-            $this->cleanJob($page, $key, $job, $s);
+            $this->cleanJob($page, $key, $job, $s, $maxPublicity);
             if (!$init) {
                 $success = ($success && $s);
             }
@@ -245,14 +253,14 @@ class ProfileSettingJob implements ProfileSetting
 
     public function save(ProfilePage &$page, $field, $value)
     {
-        XDB::execute("DELETE FROM  profile_job
-                            WHERE  pid = {?}",
-                     $page->pid());
-        XDB::execute("DELETE FROM  profile_job_term
-                            WHERE  pid = {?}",
+        $deletePrivate = S::user()->isMe($page->owner) || S::admin();
+        XDB::execute('DELETE FROM  pj, pjt
+                            USING  profile_job      AS pj
+                        LEFT JOIN  profile_job_term AS pjt ON (pj.pid = pjt.pid AND pj.id = pjt.jid)
+                            WHERE  pj.pid = {?}' . (($deletePrivate) ? '' : ' AND pj.pub IN (\'public\', \'ax\')'),
                      $page->pid());
-        Address::deleteAddresses($page->pid(), Address::LINK_JOB);
-        Phone::deletePhones($page->pid(), Phone::LINK_JOB);
+        Address::deleteAddresses($page->pid(), Address::LINK_JOB, null, $deletePrivate);
+        Phone::deletePhones($page->pid(), Phone::LINK_JOB, null, $deletePrivate);
         $terms_values = array();
         foreach ($value as $id => &$job) {
             if (isset($job['name']) && $job['name']) {
@@ -292,15 +300,34 @@ class ProfileSettingJob implements ProfileSetting
 
     public function getText($value)
     {
+        static $pubs = array('public' => 'publique', 'ax' => 'annuaire AX', 'private' => 'privé');
         $jobs = array();
         foreach ($value as $id => $job) {
             $address = Address::formArrayToString(array($job['w_address']));
             $phones = Phone::formArrayToString($job['w_phone']);
-            // TODO: add jobterms here.
-            $jobs[] = 'Entreprise : ' . $job['name']
-                    . ', description : ' . $job['description'] . ', web : ' . $job['w_url']
-                    . ', email : ' . $job['w_email']
-                    . ($phones ? ', ' . $phones : '') . ($address ? ', ' . $address : '');
+            $jobs[$id] = $job['name'];
+            $jobs[$id] .= ($job['description'] ? (', ' . $job['description']) : '');
+            $jobs[$id] .= ' (affichage ' . $pubs[$job['pub']];
+            if (count($job['terms'])) {
+                $terms = array();
+                foreach ($job['terms'] as $term) {
+                    $terms[] = $term['full_name'];
+                }
+                $jobs[$id] .= ', mots-clefs : ' . implode(', ', $terms);
+            }
+            if ($job['w_url']) {
+                $jobs[$id] .= ', page perso : ' . $job['w_url'];
+            }
+            if ($address) {
+                $jobs[$id] .= ', adresse : ' . $address;
+            }
+            if ($job['w_email']) {
+                $jobs[$id] .= ', email : ' . $job['w_email'];
+            }
+            if ($phones) {
+                $jobs[$id] .= ', téléphones : ' . $phones;
+            }
+            $jobs[$id] .= ')';
         }
         return implode(' ; ' , $jobs);
     }
@@ -312,10 +339,11 @@ class ProfileSettingCorps implements ProfileSetting
     {
         $success = true;
         if (is_null($value)) {
-            $res = XDB::query("SELECT  original_corpsid AS original, current_corpsid AS current,
-                                       rankid AS rank, corps_pub AS pub
-                                 FROM  profile_corps
-                                WHERE  pid = {?}",
+            $res = XDB::query('SELECT  c.original_corpsid AS original, e.name AS originalText,
+                                       c.current_corpsid AS current, c.rankid AS rank, c.corps_pub AS pub
+                                 FROM  profile_corps      AS c
+                           INNER JOIN  profile_corps_enum AS e ON (c.original_corpsid = e.id)
+                                WHERE  c.pid = {?}',
                             $page->pid());
             return $res->fetchOneAssoc();
         }
@@ -324,19 +352,28 @@ class ProfileSettingCorps implements ProfileSetting
 
     public function save(ProfilePage &$page, $field, $value)
     {
-        XDB::execute('INSERT INTO  profile_corps (original_corpsid, current_corpsid, rankid, corps_pub, pid)
-                           VALUES  ({?}, {?}, {?}, {?}, {?})
-          ON DUPLICATE KEY UPDATE  original_corpsid = VALUES(original_corpsid), current_corpsid = VALUES(current_corpsid),
-                                   rankid = VALUES(rankid), corps_pub = VALUES(corps_pub)',
-                      $value['original'], $value['current'], $value['rank'], $value['pub'], $page->pid());
+        if (!S::user()->isMe($page->owner)) {
+            XDB::execute('INSERT INTO  profile_corps (original_corpsid, current_corpsid, rankid, corps_pub, pid)
+                               VALUES  ({?}, {?}, {?}, {?}, {?})
+              ON DUPLICATE KEY UPDATE  original_corpsid = VALUES(original_corpsid), current_corpsid = VALUES(current_corpsid),
+                                       rankid = VALUES(rankid), corps_pub = VALUES(corps_pub)',
+                          $value['original'], $value['current'], $value['rank'], $value['pub'], $page->pid());
+        } else {
+            XDB::execute('INSERT INTO  profile_corps (current_corpsid, rankid, corps_pub, pid)
+                               VALUES  ({?}, {?}, {?}, {?})
+              ON DUPLICATE KEY UPDATE  current_corpsid = VALUES(current_corpsid),
+                                       rankid = VALUES(rankid), corps_pub = VALUES(corps_pub)',
+                          $value['current'], $value['rank'], $value['pub'], $page->pid());
+        }
     }
 
     public function getText($value)
     {
+        static $pubs = array('public' => 'publique', 'ax' => 'annuaire AX', 'private' => 'privé');
         $corpsList = DirEnum::getOptions(DirEnum::CORPS);
         $rankList  = DirEnum::getOptions(DirEnum::CORPSRANKS);
-        return 'Corps actuel : ' . $corpsList[$value['current']] . ' , rang : ' . $corpsList[$value['rank']]
-            . ' , corps d\'origine : ' . $corpsList[$value['original']] . ' , affichage : ' . $value['pub'];
+        return $corpsList[$value['current']] . ', ' . $corpsList[$value['rank']] . ' ('
+            . 'corps d\'origine : ' . $corpsList[$value['original']] . ', affichage ' . $pubs[$value['pub']] . ')';
     }
 }
 
@@ -384,10 +421,12 @@ class ProfilePageJobs extends ProfilePage
         require_once 'emails.combobox.inc.php';
         fill_email_combobox($page, $this->owner);
 
-        $res = XDB::iterator("SELECT  id, name
-                                FROM  profile_corps_enum
-                            ORDER BY  id = 1 DESC, name");
-        $page->assign('original_corps', $res->fetchAllAssoc());
+        if (!S::user()->isMe($this->owner)) {
+            $res = XDB::iterator('SELECT  id, name
+                                    FROM  profile_corps_enum
+                                ORDER BY  id = 1 DESC, name');
+            $page->assign('original_corps', $res->fetchAllAssoc());
+        }
 
         $res = XDB::iterator("SELECT  id, name
                                 FROM  profile_corps_enum
index 14af014..6ad2598 100644 (file)
@@ -97,7 +97,7 @@ class ProfileSettingCountry implements ProfileSetting
         $success = true;
         if (is_null($value)) {
             $value = array();
-            $res = XDB::iterRow("SELECT  m.country, gc.countryFR
+            $res = XDB::iterRow("SELECT  m.country, gc.country
                                    FROM  profile_mentor_country AS m
                              INNER JOIN  geoloc_countries       AS gc ON (m.country = gc.iso_3166_1_a2)
                                   WHERE  m.pid = {?}",
@@ -175,9 +175,9 @@ class ProfilePageMentor extends ProfilePage
 
     public function _prepare(PlPage &$page, $id)
     {
-        $page->assign('countryList', XDB::iterator("SELECT  iso_3166_1_a2, countryFR
+        $page->assign('countryList', XDB::iterator("SELECT  iso_3166_1_a2, country
                                                       FROM  geoloc_countries
-                                                  ORDER BY  countryFR"));
+                                                  ORDER BY  country"));
         $page->assign('hrpid', $this->profile->hrpid);
     }
 }
index ec70a0e..f23919f 100644 (file)
@@ -129,7 +129,7 @@ class ProfileSettingPhones implements ProfileSetting
 
     public function save(ProfilePage &$page, $field, $value)
     {
-        Phone::deletePhones($page->pid(), Phone::LINK_PROFILE);
+        Phone::deletePhones($page->pid(), Phone::LINK_PROFILE, null, S::user()->isMe($page->owner) || S::admin());
         Phone::savePhones($value, $page->pid(), Phone::LINK_PROFILE);
     }
 
@@ -156,7 +156,8 @@ class ProfileSettingPub extends ProfileNoSave
     }
 
     public function getText($value) {
-        return $value;
+        static $pubs = array('public' => 'publique', 'ax' => 'annuaire AX', 'private' => 'privé');
+        return $pubs[$value];
     }
 }
 
@@ -194,7 +195,7 @@ class ProfileSettingDate extends ProfileNoSave
             $success = preg_match('@(\d{2})/(\d{2})/(\d{4})@', $value, $matches);
             if (!$success) {
                 Platal::page()->trigError("Les dates doivent être au format jj/mm/aaaa");
-           } else {
+            } else {
                 $day   = (int)$matches[1];
                 $month = (int)$matches[2];
                 $year  = (int)$matches[3];
@@ -270,13 +271,13 @@ abstract class ProfilePage implements PlWizardPage
             if ($this->changed[$field]) {
                 if (!is_null($setting)) {
                     $changedFields[$field] = array(
-                        str_replace("\n", " - ", $setting->getText($this->orig[$field])),
-                        str_replace("\n", " - ", $setting->getText($this->values[$field])),
+                        preg_replace('/(\r\n|\n|\r)/', ' - ', $setting->getText($this->orig[$field])),
+                        preg_replace('/(\r\n|\n|\r)/', ' - ', $setting->getText($this->values[$field])),
                     );
                 } else {
                     $changedFields[$field] = array(
-                        str_replace("\n", " - ", $this->orig[$field]),
-                        str_replace("\n", " - ", $this->values[$field]),
+                        preg_replace('/(\r\n|\n|\r)/', ' - ', $this->orig[$field]),
+                        preg_replace('/(\r\n|\n|\r)/', ' - ', $this->values[$field]),
                     );
                 }
                 if (!is_null($setting)) {
@@ -296,18 +297,21 @@ abstract class ProfilePage implements PlWizardPage
         global $platal;
         S::logger()->log('profil', $platal->pl_self(2));
 
-        /** If the update was made by a third party and the profile corresponds
-         * to a registered user, stores both former and new text.
-         * This will be daily sent to the user.
+        /** Stores all profile modifications for active users in order to:
+         *  -daily notify the user in case of third party edition,
+         *  -display the modification to the secretaries for verification in
+         *  case of an edition made by the user.
          */
         $owner = $this->profile->owner();
         $user = S::user();
-        if ($owner->isActive() && $owner->id() != $user->id()) {
+        if ($owner->isActive()) {
             foreach ($changedFields as $field => $values) {
-                XDB::execute('INSERT INTO  profile_modifications (pid, uid, field, oldText, newText)
-                                   VALUES  ({?}, {?}, {?}, {?}, {?})
-                  ON DUPLICATE KEY UPDATE  oldText = VALUES(oldText), newText = VALUES(newText)',
-                             $this->pid(), $user->id(), $field, $values[0], $values[1]);
+                XDB::execute('INSERT INTO  profile_modifications (pid, uid, field, oldText, newText, type, timestamp)
+                                   VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, NOW())
+                  ON DUPLICATE KEY UPDATE  uid = VALUES(uid), oldText = IF(VALUES(type) != type, VALUES(oldText), oldText),
+                                           newText = VALUES(newText), type = VALUES(type), timestamp = NOW()',
+                             $this->pid(), $user->id(), Profile::$descriptions[$field], $values[0], $values[1],
+                             ($owner->id() == $user->id()) ? 'self' : 'third_party');
             }
         }
         return true;
index 7fed747..82c30c8 100644 (file)
@@ -79,10 +79,26 @@ class ProfileSettingSkill implements ProfileSetting
 
     public function getText($value) {
         $skills = array();
-        foreach ($value as $skill) {
-            $skills[] = 'Compétance : ' . $skill['text'] . ', niveau : ' . $skill['level'];
+
+        if ($this->table == 'langskill') {
+            static $levels = array(
+                1 => 'connaissance basique',
+                2 => 'maîtrise des bases',
+                3 => 'maîtrise limitée',
+                4 => 'maîtrise générale',
+                5 => 'bonne maîtrise',
+                6 => 'maîtrise complète'
+            );
+            foreach ($value as $skill) {
+                $skills[] = $skill['text'] . ' (' . $levels[$skill['level']] . ')';
+            }
+        } else {
+            foreach ($value as $skill) {
+                $skills[] = $skill['text'] . ' (' . $skill['level'] . ')';
+            }
         }
-        return implode(' ; ' , $skills);
+
+        return implode(', ' , $skills);
     }
 }
 
index 40e5322..9c235f9 100644 (file)
@@ -52,7 +52,7 @@ class RegisterModule extends PLModule
             $nameTypes = DirEnum::getOptions(DirEnum::NAMETYPES);
             $nameTypes = array_flip($nameTypes);
             $res = XDB::query("SELECT  a.uid, pd.promo, pnl.name AS lastname, pnf.name AS firstname, p.xorg_id AS xorgid,
-                                       p.birthdate_ref AS birthdateRef, FIND_IN_SET('watch', a.flags) AS watch, m.hash
+                                       p.birthdate_ref AS birthdateRef, FIND_IN_SET('watch', a.flags) AS watch, m.hash, a.type as eduType
                                  FROM  register_marketing AS m
                            INNER JOIN  accounts           AS a   ON (m.uid = a.uid)
                            INNER JOIN  account_profiles   AS ap  ON (a.uid = ap.uid AND FIND_IN_SET('owner', ap.perms))
@@ -171,8 +171,13 @@ class RegisterModule extends PLModule
                     }
 
                     // Register the optional services requested by the user.
+                    if ($subState->v('eduType') == 'x') {
+                        $proposedServices = array('ax_letter', 'imap', 'ml_promo', 'nl');
+                    } else {
+                        $proposedServices = array('ax_letter', 'nl');
+                    }
                     $services = array();
-                    foreach (array('ax_letter', 'imap', 'ml_promo', 'nl') as $service) {
+                    foreach ($proposedServices as $service) {
                         if (Post::b($service)) {
                             $services[] = $service;
                         }
@@ -277,7 +282,7 @@ class RegisterModule extends PLModule
         $res = XDB::query("SELECT  r.uid, p.pid, r.forlife, r.bestalias, r.mailorg2,
                                    r.password, r.email, r.services, r.naissance,
                                    pnl.name AS lastname, pnf.name AS firstname,
-                                   pd.promo, p.sex, p.birthdate_ref
+                                   pd.promo, p.sex, p.birthdate_ref, a.type AS eduType
                              FROM  register_pending AS r
                        INNER JOIN  accounts         AS a   ON (r.uid = a.uid)
                        INNER JOIN  account_profiles AS ap  ON (a.uid = ap.uid AND FIND_IN_SET('owner', ap.perms))
@@ -303,7 +308,8 @@ class RegisterModule extends PLModule
         }
 
         list($uid, $pid, $forlife, $bestalias, $emailXorg2, $password, $email, $services,
-             $birthdate, $lastname, $firstname, $promo, $sex, $birthdate_ref) = $res->fetchOneRow();
+             $birthdate, $lastname, $firstname, $promo, $sex, $birthdate_ref, $eduType) = $res->fetchOneRow();
+        $isX = ($eduType == 'x');
         $yearpromo = substr($promo, 1, 4);
 
         // Prepare the template for display.
@@ -349,8 +355,14 @@ class RegisterModule extends PLModule
         // Add the registration email address as first and only redirection.
         require_once 'emails.inc.php';
         $user = User::getSilentWithUID($uid);
-        $redirect = new Redirect($user);
-        $redirect->add_email($email);
+        if ($isX) {
+            $redirect = new Redirect($user);
+            $redirect->add_email($email);
+        } else {
+            XDB::execute('UPDATE  accounts
+                             SET  email = {?}
+                           WHERE  uid = {?}', $email, $uid);
+        }
 
         // Try to start a session (so the user don't have to log in); we will use
         // the password available in Post:: to authenticate the user.
@@ -398,6 +410,13 @@ class RegisterModule extends PLModule
 
         // Congratulate our newly registered user by email.
         $mymail = new PlMailer('register/success.mail.tpl');
+        if ($isX) {
+            $mymail->addTo("\"{$user->fullName()}\" <{$user->forlifeEmail()}>");
+            $mymail->setSubject('Bienvenue parmi les X sur le web !');
+        } else {
+            $mymail->addTo($email);
+            $mymail->setSubject('Bienvenue sur Polytechnique.org !');
+        }
         $mymail->assign('forlife', $forlife);
         $mymail->assign('firstname', $firstname);
         $mymail->send();
index 358db58..86ccc55 100644 (file)
@@ -120,7 +120,7 @@ class SearchModule extends PLModule
             $page->assign('formulaire', 0);
 
             require_once 'userset.inc.php';
-            $view = new SearchSet(true);
+            $view = new QuickSearchSet();
             $view->addMod('minifiche', 'Mini-fiches', true, array('with_score' => true, 'starts_with' => $byletter));
             if (S::logged() && !Env::i('nonins')) {
                 $view->addMod('trombi', 'Trombinoscope', false, array('with_promo' => true, 'with_score' => true));
@@ -169,7 +169,10 @@ class SearchModule extends PLModule
             }
 
             require_once 'userset.inc.php';
-            $view = new SearchSet(false);
+            // Enable X.org fields for X.org admins, and AX fields for AX secretaries.
+            $view = new AdvancedSearchSet(S::admin(),
+                                          S::user()->checkPerms(User::PERM_EDIT_DIRECTORY));
+
             if (!$view->isValid()) {
                 $this->form_prepare();
                 $page->trigError('Recherche invalide.');
@@ -178,11 +181,17 @@ class SearchModule extends PLModule
                 $view->addMod('trombi', 'Trombinoscope', false, array('with_promo' => true));
                 // TODO: Reactivate when the new map is completed.
                 // $view->addMod('geoloc', 'Planisphère', false, array('with_annu' => 'search/adv'));
+                if (S::user()->checkPerms(User::PERM_EDIT_DIRECTORY) || S::admin()) {
+                    $view->addMod('addresses', 'Adresses postales', false);
+                }
                 $view->apply('search/adv', $page, $model);
 
                 $nb_tot = $view->count();
                 if ($nb_tot > $globals->search->private_max) {
                     $this->form_prepare();
+                    if ($model != 'addresses' && (S::user()->checkPerms(User::PERM_EDIT_DIRECTORY) || S::admin())) {
+                        $page->assign('suggestAddresses', true);
+                    }
                     $page->trigError('Recherche trop générale.');
                 } else if ($nb_tot == 0) {
                     $this->form_prepare();
@@ -397,14 +406,14 @@ class SearchModule extends PLModule
         pl_content_headers("text/xml");
         $page->changeTpl('include/field.select.tpl', NO_SKIN);
         $page->assign('name', 'country');
-        $it = XDB::iterator("SELECT  gc.iso_3166_1_a2 AS id, gc.countryFR AS field
+        $it = XDB::iterator("SELECT  gc.iso_3166_1_a2 AS id, gc.country AS field
                                FROM  geoloc_countries       AS gc
                          INNER JOIN  profile_mentor_country AS mp ON (mp.country = gc.iso_3166_1_a2)
                          INNER JOIN  profile_mentor_term    AS mt ON (mt.pid = mp.pid)
                          INNER JOIN  profile_job_term_relation AS jtr ON (jtr.jtid_2 = mt.jtid)
                               WHERE  jtr.jtid_1 = {?}
                            GROUP BY  iso_3166_1_a2
-                           ORDER BY  countryFR", $jtid);
+                           ORDER BY  country", $jtid);
         $page->assign('list', $it);
     }
 }
index bae5758..4b2f7d3 100644 (file)
@@ -284,7 +284,7 @@ class XnetEventsModule extends PLModule
             return PL_NOT_FOUND;
         }
 
-        pl_content_headers("text/x-csv");
+        pl_cached_content_headers('text/x-csv', 1);
         $page->changeTpl('xnetevents/csv.tpl', NO_SKIN);
 
         $admin = may_update();
index a558cbf..48e0ce8 100644 (file)
@@ -373,7 +373,7 @@ class XnetGrpModule extends PLModule
             $filename = $globals->asso('diminutif') . '.csv';
         }
         $users = $globals->asso()->getMembersFilter(null, new UFO_Name('directory_name'))->getUsers();
-        pl_content_headers("text/x-csv");
+        pl_cached_content_headers('text/x-csv', 1);
         $page->changeTpl('xnetgrp/annuaire-csv.tpl', NO_SKIN);
         $page->assign('users', $users);
     }
index a9720ed..551e0e6 100644 (file)
 
 
 function select_nat($valeur, $pad=false) {
-    $res = XDB::iterRow("SELECT  iso_3166_1_a2 AS id, nationalityFR AS text
+    $res = XDB::iterRow("SELECT  iso_3166_1_a2 AS id, nationality AS text
                            FROM  geoloc_countries
-                          WHERE  nationalityFR IS NOT NULL
-                       ORDER BY  nationalityFR");
+                          WHERE  nationality IS NOT NULL
+                       ORDER BY  nationality");
     $sel = ' selected="selected"';
 
     // on ajoute une entree vide si $pad est vrai
index 48e621e..d5360c7 100644 (file)
       <a href="admin/names">Noms</a>
       &nbsp;&nbsp;|&nbsp;&nbsp;
       <a href="admin/networking">Networking</a>
+      &nbsp;&nbsp;|&nbsp;&nbsp;
+      <a href="admin/profile">Modifications récentes</a>
     </td>
   </tr>
   <tr class="pair">
diff --git a/templates/admin/profile.tpl b/templates/admin/profile.tpl
new file mode 100644 (file)
index 0000000..03e73de
--- /dev/null
@@ -0,0 +1,65 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2010 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>Modifications récentes de profil</h1>
+
+{if $updates->total() > 0}
+<script type="text/javascript">//<![CDATA[
+{literal}
+  function toggleSelection()
+  {
+    var checked = $(':checkbox.updates:checked');
+    var unchecked = $(':checkbox.updates:not(:checked)');
+    checked.removeAttr('checked');
+    unchecked.attr('checked', 'checked');
+  }
+{/literal}
+//]]></script>
+
+<form action="admin/profile" method="post">
+  {xsrf_token_field}
+  <table class="bicol" summary="liste des modifications de profil récentes">
+    <tr>
+      <th>Nom</th>
+      <th>Éléments modifiés</th>
+      <th>Liens</th>
+      <th><a href="javascript:toggleSelection()">{icon name="arrow_refresh" title="Inverser la sélection"}</a></th>
+    </tr>
+    {iterate item=update from=$updates}
+    <tr class="{cycle values="impair,pair"}">
+      <td>{$update.directory_name}</td>
+      <td class="center">{$update.field|wordwrap:80:'<br />'}</td>
+      <td class="center">
+        <a href="profile/{$update.hrpid}" class="popup2">{icon name=user_suit title="Voir le profil"}</a>
+        <a href="profile/edit/{$update.hrpid}">{icon name=user_edit title="Éditer le profil"}</a>
+      </td>
+      <td class="center"><input type="checkbox" name="checked_{$update.pid}" class="updates" /></td>
+    </tr>
+    {/iterate}
+  </table>
+  <p class="center"><input type="submit" name="checked" value="Valider" /></p>
+</form>
+{else}
+<p>Il n'y a rien à vérifier.</p>
+{/if}
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 1ac43ff..b043382 100644 (file)
@@ -37,7 +37,7 @@ function toggleField(name, id, obj) {
 
 {iterate item=valid from=$vit}
 {assign var=type value=$valid->type}
-{if !t($hide_requests[$type])}
+{if !t($hide_requests[$type]) && !($valid->requireAdmin && !$isAdmin)}
 <br />
 <table class="bicol">
   <tr>
index 3cb9a66..b6cef09 100644 (file)
@@ -42,7 +42,7 @@ Tu trouveras les mêmes informations sur [[https://www.polytechnique.org/carnet/
 {/foreach}
 
 {/foreach}
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 ''Note :''  Tu reçois cet email car tu as activé la notification automatique par email des événements que tu surveilles.\\
 Tu peux changer cette option sur la [[https://www.polytechnique.org/carnet/notifs|page de configuration des notifications]].
 
index af81e26..0e078e6 100644 (file)
@@ -38,7 +38,7 @@ Nous te suggérons de vérifier cette adresse, et le cas échéant de mettre
 
 Pour plus de renseignements sur le service de patte cassée, n'hésite pas à
 consulter [[{$globals->baseurl}/emails/broken|la documentation sur le site]].
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 2e6da4c..231a60a 100644 (file)
@@ -42,7 +42,7 @@ polytechnicienne, il te suffit de te rendre sur la page :
 
     https://www.polytechnique.org/emails/redirect
 
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 ---------------------------------------------------------------------------
 
   PS : si jamais tu ne disposes plus du mot de passe te permettant
index d18e3f2..38be526 100644 (file)
@@ -51,7 +51,7 @@ fonctionnalité complexe tels qu'ils sont décrits sur la page :
 
 Puis cliquez sur le lien suivant pour valider cette demande :
 * {$baseurl}/emails/rewrite/in/{$mail->email|replace:'@':'_'}/{$mail->hash}
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 
 {* vim:set et sw=2 sts=2 sws=2: *}
index 4f40bc7..0f7474f 100644 (file)
@@ -44,7 +44,7 @@ Tu trouveras sur le site divers outils pour gérer ton adresse email :
 N'hésite pas à venir découvrir ou redécouvrir les services du site grâce au [[https://www.polytechnique.org/review|tour d'horizon]].
 
 Merci encore de la confiance que tu portes à nos services.
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 
 {* vim:set et sw=2 sts=2 sws=2: *}
diff --git a/templates/fusionax/corps.tpl b/templates/fusionax/corps.tpl
new file mode 100644 (file)
index 0000000..ce22a0c
--- /dev/null
@@ -0,0 +1,40 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2010 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<h2><a href="fusionax">Fusion des annuaires X.org - AX</a> / corps</h2>
+
+<p>
+  Il y a {$missingCorpsCount} corps manquant{if $missingCorpsCount > 1}s{/if} dans notre base{if $missingCorpsCount eq 0}.</p>{else}&nbsp;:
+</p>
+<ul>
+  {iterate from=$missingCorps item=corps}<li>{$corps.name}</li>{/iterate}
+</ul>{/if}
+
+<p>
+  Il y a {$missingGradeCount} grade{if $missingGradeCount > 1}s{/if} manquant{if $missingGradeCount > 1}s{/if} dans
+  notre base{if $missingGradeCount eq 0}.</p>{else}&nbsp;:
+</p>
+<ul>
+  {iterate from=$missingGrade item=grade}<li>{$grade.name}</li>{/iterate}
+</ul>{/if}
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 39762a3..b8aac7d 100644 (file)
@@ -36,6 +36,7 @@
   <li>Corrélation des <a href="fusionax/promo">promotions</a></li>
   <li>Corrélation des <a href="fusionax/names">noms</a></li>
   <li>Corrélation des <a href="fusionax/edu">formations</a></li>
+  <li>Corrélation des <a href="fusionax/corps">corps</a></li>
 </ul>
 
 <p>
index 2ef9f3c..544eed0 100644 (file)
   <textarea cols="30" rows="4" class="valid {$prefid}_geoloc">{$address.geocodedText}</textarea>
 {/if}
 </div>
+{if !$isMe}<div><small><strong>Adress postale&nbsp;:</strong><br />{$address.postalText|nl2br}</small></div>{/if}
 {if t($address.geocodedText)}
 <input type="hidden" name="{$prefname}[geocodeChosen]" value="1" />
 <input type="hidden" name="{$prefname}[geocodedText]" value="{$address.geocodedText}" />
-<input type="hidden" name="{$prefname}[geocodedPostalText]" value="{$address.geocodedPostalText}" />
 {/if}
 <input type="hidden" name="{$prefname}[accuracy]" value="{$address.accuracy}" />
 <input type="hidden" name="{$prefname}[postalText]" value="{$address.postalText}" />
index d78bdb2..774a3a9 100644 (file)
@@ -46,7 +46,7 @@ et ton mot de passe est celui que tu as choisi lors de ta demande de compte.
 {/if}
 
 Tu trouveras plus d'informations dans la [[https://www.polytechnique.org/Xorg/GoogleApps|documentation]] sur Polytechnique.org.
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 
 {* vim:set et sw=2 sts=2 sws=2: *}
index 86df5a7..8db9aa7 100644 (file)
@@ -38,7 +38,7 @@ et ton mot de passe est celui que tu as choisi lors de ta demande de compte.
 {/if}
 
 Tu trouvera plus d'information dans la [[https://www.polytechnique.org/Xorg/GoogleApps|documentation]] sur Polytechnique.org.
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 
 {* vim:set et sw=2 sts=2 sws=2: *}
index f0b1067..518bda8 100644 (file)
@@ -22,7 +22,7 @@
 
 {assign var=new value="new"|cat:$i}
 {assign var=combobox value="combobox"|cat:$i}
-<tr {if $class}class="{$class}"{/if}>
+<tr{if $class} class="{$class}"{/if}{if t($divId)} id="{$divId}"{/if}>
   <td class="titre">
   {if $name eq "email_directory"}
     Email&nbsp;annuaire&nbsp;AX
       <input type="checkbox" disabled="disabled" checked="checked"/>
       {icon name="flag_orange" title="Visible sur l'annuaire"}
     {elseif $name neq "email"}
+    {if t($mainField)}
+    {include file="include/flags.radio.tpl" name="`$jobpref`[`$prefix`email_pub]" val=$pub
+             mainField=$mainField mainId=$mainId subField=$subField subId=$subId}
+    {else}
     {include file="include/flags.radio.tpl" name="`$jobpref`[`$prefix`email_pub]" val=$pub}
     {/if}
+    {/if}
     </div>
     {/if}
   </td>
index 4ea1998..6059b43 100644 (file)
 {if t($withtext)}
 <a href="Xorg/FAQ?display=light#flags" class="popup_800x240">Quelle couleur ?</a>
 {/if}
-{if !t($val)}{assign var=val value='private'}{/if}
+{if !t($val)}{assign var=val value='ax'}{/if}
 <label><input type="radio" name="{$name}" value="public"{if $val eq 'public'} checked="checked"{/if}
-       {if t($disabled)}disabled="disabled"{/if} />
+       {if t($disabled)}disabled="disabled"{/if}{if t($mainField)} onchange="updatePublicity('{$mainField}','{$mainId}','{$subField}','{$subId}')"{/if} />
 {icon name="flag_green" title="site public"}
 {if t($withtext)}<span class="texte">site public</span>{/if}</label>
 <label><input type="radio" name="{$name}" value="ax"{if $val eq 'ax'} checked="checked"{/if}
-       {if t($disabled)}disabled="disabled"{/if} />
+       {if t($disabled)}disabled="disabled"{/if}{if t($mainField)} onchange="updatePublicity('{$mainField}','{$mainId}','{$subField}','{$subId}')"{/if} />
 {icon name="flag_orange" title="transmis à l'AX"}
 {if t($withtext)}<span class="texte">transmis à l'AX</span>{/if}</label>
 <label><input type="radio" name="{$name}" value="private"{if $val eq 'private'} checked="checked"{/if}
-       {if t($disabled)}disabled="disabled"{/if} />
+       {if t($disabled)}disabled="disabled"{/if}{if t($mainField)} onchange="updatePublicity('{$mainField}','{$mainId}','{$subField}','{$subId}')"{/if} />
 {icon name="flag_red" title="privé"}
 {if t($withtext)}<span class="texte">privé</span>{/if}</label>
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index f5974c6..24d8783 100644 (file)
@@ -108,33 +108,10 @@ emails de marketing. Une fois inscrits à Polytechnique.org, l'inscription à la
 <form method='post' action='{$smarty.server.REQUEST_URI}'>
   {xsrf_token_field}
   <table class='tinybicol' cellpadding='0' cellspacing='0'>
-    {foreach from=$owners item=users key=alpha}
-    {foreach from=$users item=user name=all}
-    <tr>
-      <td class='titre' style="width: 20%">
-        {if $smarty.foreach.all.first}
-        {if $alpha}{$alpha}{/if}
-        {/if}
-      </td>
-      <td>
-        {if t($user.x)}
-        {if t($user.b)}{assign var=lostUsers value=true}{/if}
-        {profile user=$user.x promo=false}
-        {elseif t($user.x)}
-        <a href="{$platal->ns}member/{$user.x}">{if $user.n|trim}{$x.n}{else}{$user.l}{/if}</a>
-        {elseif t($user.n)}
-        {$user.n}
-        {else}
-        {$user.l}
-        {/if}
-        <a href='{$platal->pl_self(1)}?del_owner={$user.l}&amp;token={xsrf_token}'>{icon name=cross title='retirer modérateur'}</a>
-      </td>
-    </tr>
-    {/foreach}
-    {/foreach}
+    {include file='lists/display_list.tpl' list=$owners delete='del_owner' no_sort_key='' promo=true}
     <tr class="pair">
       <td class='titre'>Ajouter</td>
-      <td>
+      <td colspan="2">
         <input type='text' size='30' name='add_owner' />
         <input type='submit' value='ajouter' />
       </td>
@@ -150,47 +127,24 @@ emails de marketing. Une fois inscrits à Polytechnique.org, l'inscription à la
 <form method='post' action='{$smarty.server.REQUEST_URI}' enctype="multipart/form-data">
   {xsrf_token_field}
   <table class='bicol' cellpadding='0' cellspacing='0'>
-    {foreach from=$members item=users key=alpha}
-    {foreach from=$users item=user name=all}
+    {include file='lists/display_list.tpl' list=$members delete='del_member' no_sort_key='' promo=true}
     <tr>
-      <td class='titre' style="width: 20%">
-        {if $smarty.foreach.all.first}
-        {if $alpha}{$alpha}{/if}
-        {/if}
-      </td>
-      <td>
-        {if t($user.x)}
-        {if t($user.b)}{assign var=lostUsers value=true}{/if}
-        {profile user=$user.x promo=false}
-        {elseif t($user.x)}
-        <a href="{$platal->ns}member/{$user.x}">{if $user.n|trim}{$x.n}{else}{$user.l}{/if}</a>
-        {elseif t($user.n)}
-        {$user.n}
-        {else}
-        {$user.l}
-        {/if}
-        <a href='{$platal->pl_self(1)}?del_member={$user.l}&amp;token={xsrf_token}'>{icon name=cross title='retirer membre'}</a>
-      </td>
-    </tr>
-    {/foreach}
-    {/foreach}
-    <tr>
-      <th colspan="2">Ajouter</th>
+      <th colspan="3">Ajouter</th>
     </tr>
     <tr class="pair">
       <td class="titre">Liste</td>
-      <td>
+      <td colspan="2">
         <input type='text' size='40' name='add_member' />
       </td>
     </tr>
     <tr class="pair">
       <td class="titre">ou fichier(*)</td>
-      <td>
+      <td colspan="2">
         <input type="file" name="add_member_file" />*
       </td>
     </tr>
     <tr class="pair">
-      <td colspan="2" class="center">
+      <td colspan="3" class="center">
         <input type='submit' value='ajouter' />
       </td>
     </tr>
diff --git a/templates/lists/display_list.tpl b/templates/lists/display_list.tpl
new file mode 100644 (file)
index 0000000..5b04544
--- /dev/null
@@ -0,0 +1,58 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2010 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.org/                                  *}
+{*                                                                        *}
+{*  This program is free software; you can redistribute it and/or modify  *}
+{*  it under the terms of the GNU General Public License as published by  *}
+{*  the Free Software Foundation; either version 2 of the License, or     *}
+{*  (at your option) any later version.                                   *}
+{*                                                                        *}
+{*  This program is distributed in the hope that it will be useful,       *}
+{*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *}
+{*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *}
+{*  GNU General Public License for more details.                          *}
+{*                                                                        *}
+{*  You should have received a copy of the GNU General Public License     *}
+{*  along with this program; if not, write to the Free Software           *}
+{*  Foundation, Inc.,                                                     *}
+{*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
+{*                                                                        *}
+{**************************************************************************}
+
+{assign var=lostUsers value=false}
+{foreach from=$list item=users key=sort_key}
+{foreach from=$users item=user name=all}
+<tr>
+  <td class='titre' style="width: 20%">
+    {if $smarty.foreach.all.first}
+    {if $sort_key neq 'AAAAA'}{$sort_key}{else}{$no_sort_key}{/if}
+    {/if}
+  </td>
+  <td>
+    {if t($user.hasProfile)}
+    {if t($user.lost)}{assign var=lostUsers value=true}{/if}
+    {profile user=$user.uid promo=$promo}
+    {elseif t($user.uid)}
+    {if t($user.name)}{$user.name}{else}{$user.email}{/if}{if t($promo)} (extérieur){/if}
+    {elseif t($user.name)}
+    {$user.name}
+    {else}
+    {$user.email}
+    {/if}
+  </td>
+  {if t($delete)}
+  <td class="center">
+    {if t($user.uid)}
+    <a href="{$platal->ns}member/{$user.uid}">{icon name=user_edit title='Éditer'}</a>&nbsp;
+    {else}
+    {icon name=null}&nbsp;
+    {/if}
+    <a href='{$platal->pl_self(1)}?{$delete}={$user.email}&amp;token={xsrf_token}'>{icon name=cross title='Retirer'}</a>
+  </td>
+  {/if}
+</tr>
+{/foreach}
+{/foreach}
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index df7d909..f266b49 100644 (file)
 
 {if $owners|@count}
 <table class='tinybicol' cellpadding='0' cellspacing='0'>
-  {foreach from=$owners item=xs key=promo}
-  {foreach from=$xs item=user name=all}
-  <tr>
-    <td class='titre'>
-      {if $smarty.foreach.all.first}
-      {if $promo}{$promo}{else}non-X{/if}
-      {/if}
-    </td>
-    <td>
-      {if $promo && $user.x}
-      {if $user.b}{assign var=lostUsers value=true}{/if}
-      {profile user=$user.x promo=false}
-      {elseif $user.x}
-      <a href="{$platal->ns}member/{$user.x}">{if $user.n|trim}{$x.n}{else}{$user.l}{/if}</a>
-      {elseif $user.n}
-      {$user.n}
-      {else}
-      {$user.l}
-      {/if}
-    </td>
-    {if $user.p}
-    <td class="right">
-      {$user.p}
-    </td>
-    {/if}
-  </tr>
-  {/foreach}
-  {/foreach}
+  {include file='lists/display_list.tpl' list=$owners delete=false no_sort_key='non-X' promo=$smarty.get.alpha}
 </table>
 {/if}
 
 {if $members|@count}
 <table class='bicol' cellpadding='0' cellspacing='0'>
   {if $details.own || hasPerms('admin,groupadmin')}
-  <tr><td colspan="3">
+  <tr><td colspan="2">
   <a href="{$platal->ns}lists/csv/{$platal->argv[1]}/{$platal->argv[1]}.csv">
     {icon name="page_excel" title="Télécharger la liste des membres"}
     Télécharger la liste des membres au format Excel
   </a>
   </td></tr>
   {/if}
-  {assign var=lostUsers value=false}
-  {foreach from=$members item=users key=promo}
-  {foreach from=$users item=user name=all}
-  <tr>
-    <td class='titre' style="width: 20%">
-      {if $smarty.foreach.all.first}
-      {if $promo}{$promo}{else}non-X{/if}
-      {/if}
-    </td>
-    <td>
-      {if $promo && $user.x}
-      {if $user.b}{assign var=lostUsers value=true}{/if}
-      {profile user=$user.x promo=false}
-      {elseif $user.x}
-      <a href="{$platal->ns}member/{$user.x}">{if $user.n|trim}{$x.n}{else}{$user.l}{/if}</a>
-      {elseif $user.n}
-      {$user.n}
-      {else}
-      {$user.l}
-      {/if}
-    </td>
-    {if $user.p}
-    <td class="right">
-      {$user.p}
-    </td>
-    {/if}
-  </tr>
-  {/foreach}
-  {/foreach}
+  {include file='lists/display_list.tpl' list=$members delete=false no_sort_key='non-X' promo=$smarty.get.alpha}
 </table>
 
-{if $lostUsers}
+{if t($lostUsers)}
 <p class="smaller">
   {icon name=error}&nbsp;Un camarade signalé par ce symbole n'a plus d'adresse de redirection et ne peut donc
   plus être contacté via son adresse polytechnique.org. Si tu connais sa nouvelle adresse, tu peux nous la communiquer en
index e6bb7f9..ee7233a 100644 (file)
@@ -46,6 +46,6 @@ Rends-toi sur la page web suivante afin d'achever ton inscription, et de changer
 Si le lien ci-dessus ne fonctionne pas en cliquant dessus, copie le intégralement dans la barre d'adresse de ton navigateur.
 
 En cas de difficulté, nous sommes bien entendu à ton entière disposition !
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 7884b6a..2007a77 100644 (file)
@@ -39,7 +39,7 @@
   </tr>
 {if $comment}
   <tr>
-    <td><b>Commentaire</b>
+    <td><b>Commentaire</b></td>
     <td>{$comment}</td>
   </tr>
 {/if}
@@ -72,7 +72,7 @@
   </tr>
 </table>
 <p>
-En cliquant sur "Valider", tu seras redirigé{if $smarty.session.sexe}e{/if} vers le site de {$pay->api->nomsite}, où il te
+En cliquant sur "Valider", tu seras redirigé{if $sex}e{/if} vers le site de {$pay->api->nomsite}, où il te
 sera demandé de saisir ton numéro de carte bancaire.  Lorsque le paiement aura été effectué, tu
 recevras une confirmation par email.
 </p>
index 82ee6d4..69ebf09 100644 (file)
@@ -59,7 +59,7 @@
   <tr {if $hiddenaddr}style="display: none"{/if}>
     <td>
       <div style="margin-bottom: 0.2em" class="flags">
-        {include file="include/flags.radio.tpl" name="`$prefname`[pub]" val=$address.pub}
+        {include file="include/flags.radio.tpl" name="`$prefname`[pub]" val=$address.pub mainField='addresses' mainId=$i subField='phones' subId=-1}
       </div>
       <div style="clear: both"></div>
       <div style="float: left">
             on peut {if $isMe}m'{/if}y envoyer du courrier par la poste
           </label>
         </div>
+        {if !t($isMe)}
+        <div>
+          <label>
+            <input type="checkbox" name="{$prefname}[deliveryIssue]" {if $address.deliveryIssue}checked="checked"{/if} />
+            n'habite pas à l'adresse indiquée
+          </label>
+        </div>
+        {else}
+        <div style="display: none"><input type="hidden" name="deliveryIssue" value="{$address.deliveryIssue}" /></div>
+        {/if}
         <div>
           <label>
             Commentaire&nbsp;:
   <tr class="pair" {if $hiddenaddr}style="display: none"{/if}>
     <td>
       {foreach from=$address.phones key=t item=tel}
-        <div id="{"`$prefid`_tel_`$t`"}" style="clear: both">
-          {include file="profile/phone.tpl" prefname="`$prefname`[phones]"
-                   prefid="`$prefid`_tel" telid=$t tel=$tel}
+        <div id="{"`$prefid`_phones_`$t`"}" style="clear: both">
+          {include file="profile/phone.tpl" prefname="`$prefname`[phones]" prefid="`$prefid`_phones" telid=$t tel=$tel
+                   subField='phones' mainField='addresses' mainId=$i}
         </div>
       {/foreach}
       {if $address.phones|@count eq 0}
-        <div id="{"`$prefid`_tel_0"}" style="clear: both">
-          {include file="profile/phone.tpl" prefname="`$prefname`[phones]" prefid="`$prefid`_tel" telid=0 tel=0}
+        <div id="{"`$prefid`_phones_0"}" style="clear: both">
+          {include file="profile/phone.tpl" prefname="`$prefname`[phones]" prefid="`$prefid`_phones" telid=0 tel=0
+                   subField='phones' mainField='addresses' mainId=$i}
         </div>
       {/if}
-      <div id="{$prefid}_tel_add" class="center" style="clear: both; padding-top: 4px">
-        <a href="javascript:addTel('{$prefid}_tel','{$prefname}[phones]')">
+      <div id="{$prefid}_phones_add" class="center" style="clear: both; padding-top: 4px">
+        <a href="javascript:addTel('{$prefid}_phones','{$prefname}[phones]','phones','addresses','{$i}')">
           {icon name=add title="Ajouter un numéro de téléphone"} Ajouter un numéro de téléphone
         </a>
       </div>
index 38beb25..5636c15 100644 (file)
         </div>
       {/if}
       <div id="tels_add" class="center" style="clear: both; padding-top: 4px;">
-        <a href="javascript:addTel('tels','tels');">
+        <a href="javascript:addTel('tels','tels',null,null,null);">
           {icon name=add title="Ajouter un téléphone"} Ajouter un téléphone
         </a>
       </div>
index 20ec745..70deab5 100644 (file)
@@ -34,7 +34,7 @@ Un camarade {$smarty.session.hruid} a forcé l'utilisation de l'adresse entrée
 
 '''Version geoloc (refusée) :'''\\
 {$geoloc|replace:"\n":"\\\\\n"}
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 
 {* vim:set et sw=2 sts=2 sws=2: *}
index 0fbb748..a1836c8 100644 (file)
@@ -22,7 +22,7 @@
 
 
 <script type="text/javascript" src="javascript/jquery.jstree.js"></script>
-{assign var=jobid value="job_"|cat:$i}
+{assign var=jobid value="jobs_"|cat:$i}
 {assign var=jobpref value="jobs[`$i`]"}
 {assign var=sector_text value="sector_text_"|cat:$i}
 {assign var=sector value="sector_"|cat:$i}
@@ -52,7 +52,8 @@
     <tr>
       <th colspan="2" style="text-align: right">
         <div class="flags" style="float: left; text-align: left">
-          {include file="include/flags.radio.tpl" name="`$jobpref`[pub]" val=$job.pub disabled=$hiddenjob}
+          {include file="include/flags.radio.tpl" name="`$jobpref`[pub]" val=$job.pub disabled=$hiddenjob
+                   mainField='jobs' mainId=$i subField='w_address,w_email,w_phone' subId=-1}
         </div>
         Entreprise n°{$i+1}&nbsp;:
         {if $hiddenjob}
     </tr>
     <tr class="pair" id="{$sector_text}" {if $hiddenjob}style="display: none"{/if}>
       <td class="titre">Mots-clefs</td>
-      <td class="job_terms">
+      <td class="jobs_terms">
         <input type="text" class="term_search" size="35"/>
         <a href="javascript:toggleJobTermsTree({$i})">{icon name="table" title="Tous les mots-clefs"}</a>
         <script type="text/javascript">
           {foreach from=$job.terms item=term}
           addJobTerm("{$i}", "{$term.jtid}", "{$term.full_name|replace:'"':'\\"'}");
           {/foreach}
-          $('#job_{$i} .term_search').autocomplete(platal_baseurl + 'profile/jobterms',
+          $('#jobs_{$i} .term_search').autocomplete(platal_baseurl + 'profile/jobterms',
             {ldelim}
               "formatItem" : displayJobTerm,
               "extraParams" : {ldelim} "jobid" : "{$i}" {rdelim},
-              "width" : $('#job_{$i} .term_search').width()*2,
+              "width" : $('#jobs_{$i} .term_search').width()*2,
               "onItemSelect" : selectJobTerm,
               "matchSubset" : false
             {rdelim});
                  name="{$jobpref}[w_url]" value="{$job.w_url}" />
       </td>
     </tr>
-    <tr class="pair" {if $hiddenjob}style="display: none"{/if}>
+    <tr id="{$jobid}_w_address" class="pair" {if $hiddenjob}style="display: none"{/if}>
       <td colspan="2">
         <div style="float: left">
           <div class="titre">Adresse</div>
           <div class="flags">
-            {include file="include/flags.radio.tpl" name="`$jobpref`[w_address][pub]" val=$job.w_address.pub}
+            {include file="include/flags.radio.tpl" name="`$jobpref`[w_address][pub]" val=$job.w_address.pub
+                     subField='w_address' mainField='jobs' mainId=$i subId=''}
           </div>
           <div style="margin-top: 20px; clear: both">
             {include file="geoloc/form.address.tpl" prefname="`$jobpref`[w_address]"
     </tr>
     {else}
     {include file="include/emails.combobox.tpl" name=$jobpref|cat:'[w_email]' val=$job.w_email
-             class="pair" i=$i error=$job.w_email_error prefix="w_" pub=$job.w_email_pub id=$i}
+             class="pair" divId="`$jobid`_w_email" i=$i error=$job.w_email_error prefix="w_" pub=$job.w_email_pub id=$i
+             subField='w_email' mainField='jobs' mainId=$i subId=''}
     {/if}
     <tr class="pair" {if $hiddenjob}style="display: none"{/if}>
       <td colspan="2">
         {foreach from=$job.w_phone key=t item=phone}
           <div id="{"`$jobid`_w_phone_`$t`"}" style="clear: both">
-            {include file="profile/phone.tpl" prefname="`$jobpref`[w_phone]" prefid="`$jobid`_w_phone" telid=$t tel=$phone}
+            {include file="profile/phone.tpl" prefname="`$jobpref`[w_phone]" prefid="`$jobid`_w_phone" telid=$t tel=$phone
+                     subField='w_phone' mainField='jobs' mainId=$i}
           </div>
         {/foreach}
         {if $job.w_phone|@count eq 0}
           <div id="{"`$jobid`_w_phone_0"}" style="clear: both">
-            {include file="profile/phone.tpl" prefname="`$jobpref`[w_phone]" prefid="`$jobid`_w_phone" telid=0 tel=0}
+            {include file="profile/phone.tpl" prefname="`$jobpref`[w_phone]" prefid="`$jobid`_w_phone" telid=0 tel=0
+                     subField='w_phone' mainField='jobs' mainId=$i}
           </div>
         {/if}
         <div id="{$jobid}_w_phone_add" class="center" style="clear: both; padding-top: 4px;">
-          <a href="javascript:addTel('{$jobid}_w_phone','{$jobpref}[w_phone]')">
+          <a href="javascript:addTel('{$jobid}_w_phone','{$jobpref}[w_phone]','w_phone','jobs','{$i}')">
             {icon name=add title="Ajouter un numéro de téléphone"} Ajouter un numéro de téléphone
           </a>
         </div>
index aa6e0df..f496e24 100644 (file)
   <tr>
     <td class="titre">Corps d'origine</td>
     <td>
+    {if $isMe}
+      {$corps.originalText}
+      <input type="hidden" name="corps[original]" value="{$corps.original}" />
+      <input type="hidden" name="corps[originalText]" value="{$corps.originalText}" />
+    {else}
       <select name="corps[original]">
         {foreach from=$original_corps item=o_corps}
         <option value="{$o_corps.id}" {if $o_corps.id eq $corps.original}selected="selected"{/if}>{$o_corps.name}</option>
         {/foreach}
       </select>
+      <input type="hidden" name="corps[originalText]" value="{$corps.originalText}" />
+    {/if}
     </td>
   </tr>
   <tr>
index 56951e6..a24d2c1 100644 (file)
@@ -24,7 +24,7 @@
 
 <div>{icon name=information title="Afficher ma fiche référent"}Tu peux consulter ta <a class="popup2" href="referent/{$hrpid}">fiche référent</a> qui n'est accessible que par les X.
 </div>
-{if (!$expertise)||(!($sectors|@count))}
+{if !$expertise || !t($sectors) || !($sectors|@count)}
   <br /><div>
     <strong>{icon name=error title="Attention"} Attention&nbsp;: pour figurer dans la base de données des mentors, il faut remplir la
     dernière case en bas de cette page et avoir au moins un secteur d'activité de prédilection.</strong><br />
index 26c3cb4..83f6223 100644 (file)
@@ -38,7 +38,7 @@ Tu peux voir ta fiche là :
 Tu peux aussi l'éditer toi-même là :
 *{$globals->baseurl}/profile/edit/{$hrpid}
 
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 
 {/if}
 
index 767e3d1..376b956 100644 (file)
   </a>
 </div>
 <div style="float: right" class="flags">
-  {include file="include/flags.radio.tpl" name="`$telpref`[pub]"
-           val=$tel.pub disabled=$hiddentel}
+  {if t($mainField)}
+  {include file="include/flags.radio.tpl" name="`$telpref`[pub]" val=$tel.pub disabled=$hiddentel
+           mainField=$mainField mainId=$mainId subField=$subField subId=$telid}
+  {else}
+  {include file="include/flags.radio.tpl" name="`$telpref`[pub]" val=$tel.pub disabled=$hiddentel}
+  {/if}
 </div>
 <div id="{$id}_comment" style="clear: both;{if $tel.comment eq ''} display:none{/if}">
   Commentaire :
index cc2cd0d..7435fdd 100644 (file)
@@ -42,6 +42,6 @@ Rends-toi maintenant sur la page web suivante afin d'activer ta pré-inscription
 Si en cliquant dessus tu n'y arrives pas, copie intégralement ce lien dans la barre d'adresse de ton navigateur.
 
 Nous espérons que tu profiteras pleinement des services en ligne de Polytechnique.org ; s'ils te convainquent, n'oublie pas d'en parler aux camarades autour de toi !
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index e3c7d96..bd0d62a 100644 (file)
@@ -38,6 +38,6 @@ Pour te connecter au site, tu pourras utiliser comme identifiant n'importe leque
 Commence dès aujourd'hui à communiquer à tes correspondants la nouvelle adresse que tu comptes utiliser !
 
 En nous excusant pour le désagrément occasionné,
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 510386f..fd8eb3a 100644 (file)
@@ -29,6 +29,6 @@
 Nous t'écrivons pour t'informer que {$firstname} {$lastname} ({$promo}), que tu avais incité{if $sex eq 'female'}e{/if} à s'inscrire à Polytechnique.org, vient à l'instant de terminer son inscription.
 
 Merci de ta participation active à la reconnaissance de ce site !!!
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 960b8ef..11ae26c 100644 (file)
           <dd>
             de recevoir les informations importantes de l'AX.
           </dd>
+          {if $smarty.session.subState.eduType eq 'x'}
           <dt><label><input type="checkbox" checked="checked" name="ml_promo" /> ta promotion</label></dt>
           <dd>
             de recevoir les informations plus spécifiques de ta promotion pour pouvoir participer plus facilement aux événements
           <dd>
             d'avoir un accès de secours aux 30 derniers jours d'emails reçus sur ton adresse Polytechnique.org.
           </dd>
+          {/if}
         </dl>
       </td>
     </tr>
index dde4591..6b0df7c 100644 (file)
@@ -23,8 +23,6 @@
 {config_load file="mails.conf" section="inscription"}
 {if $mail_part eq 'head'}
 {from full=#from#}
-{to addr="$forlife@polytechnique.org"}
-{subject text="Bienvenue parmi les X sur le web !"}
 {elseif $mail_part eq 'text'}
 
 {$firstname}, félicitations pour ton inscription !
@@ -32,6 +30,6 @@
 Tu as maintenant accès à l'annuaire en ligne, aux services de listes de
 diffusion, aux infos promo, etc. N'oublie pas de mettre ta fiche-annuaire
 à jour.
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index b99d73d..b239e4e 100644 (file)
 
 <h1>Recherche dans l'annuaire</h1>
 
+{if hasPerm('edit_directory,admin') && t($suggestAddresses)}
+<p class="center"><strong>Voulez-vous télécharger le <a href="{$globals->baseurl}/search/adv/addresses{$plset_args}">tableau des adresses postales</a> pour la recette précédente&nbsp;?</strong></p>
+{/if}
+
 {javascript name=jquery.form}
 
 <script type="text/javascript">// <!--
@@ -483,6 +487,15 @@ function cleanForm(f) {
         </table>
       </td>
     </tr>
+        {if hasPerm('admin,edit_directory')}
+    <tr>
+      <td>Matricule AX</td>
+      <td>
+        <textarea name="schoolid_ax" rows="10" cols="12">{$smarty.request.schoolid_ax}</textarea>
+        <br />
+        <i>Entrer une liste de matricules AX (un par ligne)</i>
+      </td>
+        {/if}
         {if $smarty.session.auth ge AUTH_COOKIE}
     <tr>
       <td colspan="2">
index d069fe0..57b687a 100644 (file)
 </table>
 {/if}
 
+{if hasPerm('edit_directory')}
+<div class="menu_title">Administration</div>
+<div class="menu_item"><a href="admin/profile">Modifications</a></div>
+<div class="menu_item"><a href="admin/jobs">Entreprises</a></div>
+<div class="menu_item"><a href="admin/validate">Validations</a></div>
+{/if}
+
 {/if}
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 13b3f28..a215378 100644 (file)
@@ -31,6 +31,6 @@ Cher {$prenom},
 Nous t'écrivons pour t'informer que le télépaiement associé à l'événement '''{$evt}''' du groupe {$asso} vient d'être activé. Tu peux donc finaliser ton inscription.
 
 Pour ceci, va simplement sur [[http://www.polytechnique.net/{$diminutif}/payment/{$payment}?montant={$topay}|cette page]].
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 {* vim:set et sw=2 sts=2 sws=2: *}
index 5c1a73a..cbfef3d 100644 (file)
@@ -32,6 +32,6 @@ Chers animateurs du groupe {$group},
 {else}
 {$user->fullName()} ({$user->forlifeEmail()}) vient d'être désinscrit du groupe par {$smarty.session.user->fullName()}.
 {/if}
-{include file="signature.mail.tpl"}
+{include file="include/signature.mail.tpl"}
 {/if}
 {* vim:set et sw=2 sts=2 sws=2: *}
index 223249e..19f82a7 100755 (executable)
@@ -12,13 +12,21 @@ XDB::rawExecute('DROP VIEW IF EXISTS fusionax_promo');
 XDB::rawExecute('DROP TABLE IF EXISTS fusionax_import');
 
 // Fills pid fields in all table, to avoid to many joins.
-foreach (array('fusionax_activites', 'fusionax_adresses', 'fusionax_anciens', 'fusionax_formations') as $table) {
+foreach (array('fusionax_activites', 'fusionax_adresses', 'fusionax_anciens', 'fusionax_formations', 'fusionax_formations_md') as $table) {
     XDB::rawExecute("UPDATE  $table   AS f
                  INNER JOIN  profiles AS p ON (f.ax_id = p.ax_id)
                         SET  f.pid = p.pid");
     XDB::rawExecute("DELETE FROM $table WHERE pid IS NULL");
 }
 
+echo "Update timestamp.\n";
+XDB::rawExecute("UPDATE  profiles AS p
+                    SET  p.last_change = GREATEST(COALESCE((SELECT MAX(Date_maj) FROM fusionax_anciens    AS f WHERE f.pid = p.pid), '0000-00-00'),
+                                                  COALESCE((SELECT MAX(Date_maj) FROM fusionax_activites  AS f WHERE f.pid = p.pid), '0000-00-00'),
+                                                  COALESCE((SELECT MAX(Date_maj) FROM fusionax_adresses   AS f WHERE f.pid = p.pid), '0000-00-00'),
+                                                  COALESCE((SELECT MAX(Date_maj) FROM fusionax_formations AS f WHERE f.pid = p.pid), '0000-00-00'),
+                                                  COALESCE(p.last_change, '0000-00-00'))");
+
 // Includes entreprises we do not have into profile_job_enum.
 // We first retrieve AX code, then add missing compagnies.
 echo "Starts jobs inclusions.\n";
@@ -44,7 +52,6 @@ XDB::rawExecute("INSERT IGNORE INTO  profile_job_enum (name, acronym, AX_code)
 //  - the job is incomplete (ie no compagny name) : this is an issue,
 //  - the job is complete but the profile already has a job or more : this is an issue,
 //  - the job is complete and the the profile has no previous job : there is no issue.
-
 // We delete obvious duplicates and avoid multiple joins.
 XDB::rawExecute("DELETE  f
                    FROM  fusionax_activites   AS f
@@ -61,15 +68,12 @@ XDB::rawExecute('ALTER TABLE profile_job_enum DROP INDEX AX_code');
 XDB::rawExecute('DROP TABLE IF EXISTS fusionax_entreprises');
 
 // We first update the issues table.
-XDB::rawExecute("INSERT INTO  profile_merge_issues (pid, issues)
-                      SELECT  DISTINCT(f.pid), 'job'
-                        FROM  fusionax_activites AS f
-                       WHERE  (f.jobid IS NULL AND NOT EXISTS (SELECT  *
-                                                                 FROM  profile_job AS pj
-                                                                WHERE  pj.pid = f.pid))
-                              OR (f.jobid IS NOT NULL AND EXISTS (SELECT  *
-                                                                    FROM  profile_job AS pj
-                                                                   WHERE  pj.pid = f.pid))");
+XDB::rawExecute("INSERT IGNORE INTO  profile_merge_issues (pid, issues)
+                             SELECT  DISTINCT(f.pid), 'job'
+                               FROM  fusionax_activites AS f
+                              WHERE  f.jobid IS NULL OR EXISTS (SELECT  *
+                                                                  FROM  profile_job AS pj
+                                                                 WHERE  pj.pid = f.pid)");
 // We then add new jobs.
 $id = 0;
 $continue = 1;
@@ -79,8 +83,10 @@ while ($continue > 0) {
                                    FROM  fusionax_activites");
     XDB::rawExecute("DELETE  f
                        FROM  fusionax_activites AS f
-                 INNER JOIN  profile_job        AS pj ON (f.pid = pj.pid AND pj.id = $id AND pj.jobid = f.jobid AND pj.description = f.description)");
+                 INNER JOIN  profile_job        AS pj ON (f.pid = pj.pid AND pj.id = $id AND pj.description = f.description)
+                      WHERE  pj.jobid = f.jobid OR (pj.jobid IS NULL AND f.jobid IS NULL)");
     $continue = XDB::affectedRows();
+    ++$id;
 }
 XDB::rawExecute('DROP TABLE IF EXISTS fusionax_activites');
 // We also have to add related phones and addresses.
@@ -140,11 +146,23 @@ XDB::rawExecute('UPDATE  profiles         AS p
 XDB::rawExecute('ALTER TABLE geoloc_countries DROP INDEX licensePlate');
 
 // Updates corps.
+XDB::rawExecute("INSERT IGNORE INTO  profile_corps_enum (name, abbreviation)
+                             VALUES  ('Ancien élève étranger', 'Z')");
+XDB::rawExecute("INSERT IGNORE INTO  profile_corps_rank_enum (name, abbreviation)
+                             VALUES  ('Ing.ch.P.C.hon.', 'DEL1'), ('Ing.Mil.Air Retr.', 'DEL2'),
+                                     ('Col.hon.Tra.', 'DEL3'), ('Colonel CR', 'DEL4'),
+                                     ('Conseil d\'Etat', 'DEL5'), ('Commiss.Gén. Brigade aérienne', 'DEL6'),
+                                     ('Off. Mar. dém.', 'DEL7'), ('Maître des Requêtes', 'DEL8'),
+                                     ('', 'DEL9'), ('autres', 'DEL10')");
+XDB::rawExecute('UPDATE  profile_corps      AS pc
+             INNER JOIN  fusionax_anciens   AS f ON (f.pid = pc.pid)
+             INNER JOIN  profile_corps_enum AS c ON (f.corps_sortie = c.abbreviation)
+                    SET  pc.original_corpsid = c.id');
 XDB::rawExecute("INSERT IGNORE INTO  profile_corps (pid, original_corpsid, current_corpsid, rankid, corps_pub)
                              SELECT  f.pid, c.id, c.id, r.id, 'ax'
                                FROM  fusionax_anciens        AS f
                          INNER JOIN  profile_corps_enum      AS c ON (f.corps_sortie = c.abbreviation)
-                         INNER JOIN  profile_corps_rank_enum AS r ON (f.grade = r.abbreviation)
+                         INNER JOIN  profile_corps_rank_enum AS r ON (f.grade = r.name)
                               WHERE  NOT EXISTS (SELECT  *
                                                    FROM  profile_corps AS pc
                                                   WHERE  f.pid = pc.pid AND pc.original_corpsid != 1)");
@@ -158,6 +176,13 @@ XDB::rawExecute("UPDATE  profile_corps_enum
                   WHERE  name = 'Aucun (anc. démissionnaire)'");
 XDB::rawExecute("DELETE FROM  profile_corps_enum
                        WHERE  name = 'Ancien élève étranger'");
+XDB::rawExecute("UPDATE  profile_corps           AS c
+             INNER JOIN  profile_corps_rank_enum AS r ON (c.rankid = r.id)
+             INNER JOIN  profile_corps_rank_enum AS a ON (a.name = 'Aucun')
+                    SET  c.rankid = a.id
+                  WHERE  r.name LIKE 'DEL%'");
+XDB::rawExecute("DELETE FROM  profile_corps_rank_enum
+                       WHERE  name LIKE 'DEL%'");
 
 // Updates email_directory.
 XDB::rawExecute("UPDATE  profiles         AS p
@@ -238,8 +263,8 @@ XDB::rawExecute("INSERT IGNORE INTO  profile_merge_issues (pid, issues)
                          INNER JOIN  profile_addresses AS pa ON (pa.pid = f.pid AND pa.type = 'home' AND pa.id = 0)
                               WHERE  f.text IS NOT NULL");
 
-XDB::rawExecute("INSERT INTO  profile_addresses (pid, type, id, pub, text)
-                      SELECT  f.pid, 'home', IF(pa.id IS NULL , 0, MAX(pa.id) + 1), 'ax', f.text
+XDB::rawExecute("INSERT INTO  profile_addresses (pid, type, id, pub, text, flags)
+                      SELECT  f.pid, 'home', IF(pa.id IS NULL , 0, MAX(pa.id) + 1), 'ax', f.text, 'mail'
                         FROM  fusionax_adresses AS f
                    LEFT JOIN  profile_addresses AS pa ON (pa.pid = f.pid AND pa.type = 'home')
                        WHERE  f.text IS NOT NULL
@@ -264,15 +289,25 @@ echo "Addresses inclusions finished.\n";
 
 // Retrieves education from AX database. This is the hardest part since AX only kept education as an unformated string.
 echo "Starts educations inclusions.\n";
+// Updates master and doctorate educational fields.
+XDB::rawExecute("UPDATE  profile_education      AS e
+             INNER JOIN  fusionax_formations_md AS f ON (f.pid = e.pid AND FIND_IN_SET('primary', e.flags))
+                    SET  e.program = f.field, e.fieldid = f.fieldid");
+XDB::rawExecute('DROP TABLE IF EXISTS fusionax_formations_md');
+
 // Deletes empty educations.
 XDB::rawExecute("DELETE FROM  fusionax_formations
                        WHERE  Intitule_formation = '' AND Intitule_diplome = '' AND Descr_formation = ''");
 // Insert ids into fusionax_formations to prevent many joins.
+XDB::rawExecute('ALTER TABLE profile_education_enum ADD INDEX (name(60))');
+XDB::rawExecute('ALTER TABLE profile_education_degree_enum ADD INDEX (abbreviation(60))');
 XDB::rawExecute('UPDATE  fusionax_formations           AS f
               LEFT JOIN  profile_education_enum        AS pe ON (pe.name = f.Intitule_formation)
               LEFT JOIN  profile_education_degree_enum AS pd ON (pd.abbreviation = f.Intitule_diplome)
               LEFT JOIN  profile_education_field_enum  AS pf ON (pf.field = f.Descr_formation)
                     SET  f.eduid = pe.id, f.degreeid = pd.id, f.fieldid = pf.id');
+XDB::rawExecute('ALTER TABLE profile_education_enum DROP INDEX name');
+XDB::rawExecute('ALTER TABLE profile_education_degree_enum DROP INDEX abbreviation');
 // Updates non complete educations.
 XDB::rawExecute("UPDATE  profile_education             AS e
              INNER JOIN  fusionax_formations           AS f  ON (f.pid = e.pid)
@@ -307,9 +342,13 @@ while ($continue > 0) {
                                    FROM  fusionax_formations");
     XDB::rawExecute("DELETE  f
                        FROM  fusionax_formations AS f
-                 INNER JOIN  profile_education   AS pe ON (pe.pid = f.pid AND pe.id = $id AND pe.eduid = f.eduid AND pe.degreeid = f.degreeid
-                                                           AND pe.fieldid = f.fieldid AND pe.program = f.Descr_formation)");
+                 INNER JOIN  profile_education   AS pe ON (pe.pid = f.pid AND pe.id = $id)
+                      WHERE  (pe.eduid = f.eduid OR (pe.eduid IS NULL AND f.eduid IS NULL))
+                             AND (pe.degreeid = f.degreeid OR (pe.degreeid IS NULL AND f.degreeid IS NULL))
+                             AND (pe.fieldid = f.fieldid OR (pe.fieldid IS NULL AND f.fieldid IS NULL))
+                             AND (pe.program = f.Descr_formation OR (pe.program IS NULL AND f.Descr_formation IS NULL))");
     $continue = XDB::affectedRows();
+    ++$id;
 }
 // Updates merge_issues table (eduid and degreeid should never be empty).
 XDB::rawExecute("UPDATE  profile_merge_issues AS pm
index ac0c495..1e8fdbb 100755 (executable)
@@ -8,6 +8,99 @@ require_once '../../classes/address.php';
 
 $globals->debug = 0; // Do not store backtraces.
 
+$abbreviations = array(
+    'commandant'    => 'cdt',
+    'docteur'       => 'dr',
+    'haut'          => 'ht',
+    'haute'         => 'ht',
+    'hauts'         => 'ht',
+    'hts'           => 'ht',
+    'general'       => 'gen',
+    'gal '          => 'gen ',
+    'grand'         => 'gd',
+    'grande'        => 'gd',
+    'grands'        => 'gd',
+    'gde '          => 'gd ',
+    'gds '          => 'gd ',
+    'lieutenant'    => 'lt',
+    'marechal'      => 'mal',
+    'notre dame'    => 'n d',
+    'nouveau'       => 'nouv',
+    'president'     => 'pdt',
+    'saint'         => 'st',
+    'sainte'        => 'st',
+    'saintes'       => 'st',
+    'saints'        => 'st',
+    'ste '          => 'st ',
+    'appartement'   => 'app',
+    'apt'           => 'app',
+    'appt'          => 'app',
+    'appart'        => 'app',
+    'arrondissement'=> 'arr',
+    'batiment'      => 'bat',
+    'escalier'      => 'esc',
+    'etage'         => 'etg',
+    'et '           => 'etg',
+    'immeuble'      => 'imm',
+    'lieu dit'      => 'ld',
+    ' lt '          => ' lt ',
+    'porte'         => 'pte',
+    'quartier'      => 'quart',
+    'residence'     => 'res',
+    'resi'          => 'res',
+    'villa'         => 'vla',
+    'village'       => 'vlge',
+    'vil '          => 'vlge ',
+    'allee'         => 'all',
+    'avenue'        => 'av',
+    'boulevard'     => 'bd',
+    'bld'           => 'bd',
+    'chemin'        => 'ch',
+    'chem '         => 'ch ',
+    'che '          => 'ch ',
+    'cours'         => 'crs',
+    'domaine'       => 'dom',
+    'doma '         => 'dom ',
+    'faubourg'      => 'fg',
+    'fbg'           => 'fg',
+    'hameau'        => 'ham',
+    'hame '         => 'ham ',
+    'impasse'       => 'imp',
+    'impa '         => 'imp ',
+    'lotissement'   => 'lot',
+    'montee'        => 'mte',
+    'passage'       => 'pass',
+    'place'         => 'pl',
+    'promenade'     => 'pro ',
+    'prom '         => 'pro ',
+    'quai'          => 'qu',
+    'rue'           => 'r',
+    'route'         => 'rte',
+    ' rde '         => ' rte ',
+    ' rle '         => ' rte ',
+    'sentier'       => 'sen',
+    'sent '         => 'sen ',
+    'square'        => 'sq',
+    'mount'         => 'mt',
+    'road'          => 'rd',
+    'street'        => 'st',
+    'str '          => 'str',
+    'bis'           => 'b',
+    'ter'           => 't'
+);
+$patterns = array();
+$replacements = array();
+foreach ($abbreviations as $key => $abbreviation) {
+    $patterns[] = '/' . $key . '/';
+    $replacements[] = $abbreviation;
+}
+
+function check($address1, $address2)
+{
+    return $address1['short'] == $address2['short'] || $address1['short'] == $address2['long']
+        || $address1['long'] == $address2['short'] || $address1['long'] == $address2['long'];
+}
+
 print "Deletes duplicated addresses. (1/3)\n";
 $pids = XDB::rawFetchColumn("SELECT  DISTINCT(pid)
                                FROM  profile_addresses AS a1
@@ -26,14 +119,25 @@ foreach ($pids as $pid) {
     $count = 0;
     $it = Address::iterate(array($pid), array(Address::LINK_PROFILE), array(0));
     while ($item = $it->next()) {
-        $addresses[] = $item;
-        $rawAddresses[] = preg_replace('/[^a-zA-Z0-9]/', '', replace_accent($item->text));
+        $addresses[$count] = $item;
+        $rawAddress = preg_replace('/[^a-z0-9]/', ' ', mb_strtolower(replace_accent($item->text)));
+        $rawAddresses[$count] = array(
+            'long'  => preg_replace('/\s+/', '', $rawAddress),
+            'short' => preg_replace('/\s+/', '', preg_replace($patterns, $replacements, $rawAddress)),
+        );
         ++$count;
     }
     for ($i = 0; $i < $count; ++$i) {
         for ($j = $i + 1; $j < $count; ++$j) {
-            if ($rawAddresses[$i] == $rawAddresses[$j]) {
-                $duplicates[$i] = true;
+            if (check($rawAddresses[$i], $rawAddresses[$j])) {
+                $duplicates[$j] = true;
+                $minPub = new ProfileVisibility($addresses[$j]->pub);
+                if ($minPub->isVisible($addresses[$i]->pub)) {
+                    $addresses[$i]->pub = $addresses[$j]->pub;
+                }
+                if ($addresses[$j]->hasFlag('mail') && !$addresses[$i]->hasFlag('mail')) {
+                    $addresses[$i]->addFlag('mail');
+                }
             }
         }
     }
@@ -106,7 +210,7 @@ $phones = array();
 $duplicates = array();
 foreach ($pids as $pid) {
     $count = 0;
-    Phone::iterate(array($pid), array(Phone::LINK_PROFILE), array(0));
+    $it = Phone::iterate(array($pid), array(Phone::LINK_PROFILE), array(0));
     while ($item = $it->next()) {
         $phones[] = $item;
         ++$count;
@@ -114,7 +218,12 @@ foreach ($pids as $pid) {
     for ($i = 0; $i < $count; ++$i) {
         for ($j = $i + 1; $j < $count; ++$j) {
             if ($phones[$i]->search() == $phones[$j]->search()) {
-                $duplicates[$i] = true;
+                $duplicates[$j] = true;
+                $minPub = new ProfileVisibility($phones[$j]->pub);
+                if ($minPub->isVisible($phones[$i]->pub)) {
+                    $phones[$i]->pub = $phones[$j]->pub;
+                }
+
             }
         }
     }
index f274e43..6f9016e 100755 (executable)
@@ -23,7 +23,7 @@ $pid = 0;
 $jobid = 0;
 while ($item = $it->next()) {
     $address = new Address($item);
-    $address->format(array(true, true));
+    $address->format(array('requireGeocoding' => true, 'stripGeocoding' => true));
     $address->delete();
     $address->save();
     if (!($pid == $address->pid && $jobid == $address->jobid)) {
diff --git a/upgrade/1.0.2/00_address.sql b/upgrade/1.0.2/00_address.sql
new file mode 100644 (file)
index 0000000..c5621b8
--- /dev/null
@@ -0,0 +1,3 @@
+ALTER TABLE profile_addresses MODIFY COLUMN flags SET('current','temporary','secondary','mail','cedex', 'deliveryIssue') DEFAULT NULL;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.0.2/01_photos.sql b/upgrade/1.0.2/01_photos.sql
new file mode 100644 (file)
index 0000000..62ee66e
--- /dev/null
@@ -0,0 +1,4 @@
+ALTER TABLE  profile_photos
+ ADD COLUMN  last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.0.2/02_modifications.sql b/upgrade/1.0.2/02_modifications.sql
new file mode 100644 (file)
index 0000000..f4965a7
--- /dev/null
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS tmp_profile_modifications;
+CREATE TEMPORARY TABLE tmp_profile_modifications LIKE profile_modifications;
+INSERT INTO tmp_profile_modifications SELECT * FROM profile_modifications;
+DROP TABLE profile_modifications;
+CREATE TABLE profile_modifications (
+  pid INT(11) UNSIGNED NOT NULL DEFAULT 0,
+  uid INT(11) UNSIGNED NOT NULL DEFAULT 0,
+  field VARCHAR(60) NOT NULL,
+  oldText TEXT NOT NULL,
+  newText TEXT NOT NULL,
+  type ENUM('self', 'third_party') NOT NULL DEFAULT 'self',
+  timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  PRIMARY KEY  (pid, field),
+  KEY uid (uid),
+  FOREIGN KEY (uid) REFERENCES accounts (uid) ON DELETE CASCADE ON UPDATE CASCADE,
+  FOREIGN KEY (pid) REFERENCES profiles (pid) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+INSERT INTO  profile_modifications (pid, uid, field, oldText, newText, type)
+     SELECT  pid, uid, field, oldText, newText, 'third_party'
+       FROM  tmp_profile_modifications;
+DROP TABLE IF EXISTS tmp_profile_modifications;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.0.2/03_phones.sql b/upgrade/1.0.2/03_phones.sql
new file mode 100644 (file)
index 0000000..3f48a67
--- /dev/null
@@ -0,0 +1,9 @@
+ALTER TABLE watch_profile MODIFY COLUMN field ENUM('search_names','freetext','mobile','nationality1','nationality2','nationality3','nick','networking','edus','addresses','section','binets','medals','cv','jobs','photo','corps','tels') NOT NULL DEFAULT 'search_names';
+
+UPDATE  watch_profile
+   SET  field = 'tels'
+ WHERE  field = 'mobile';
+
+ALTER TABLE watch_profile MODIFY COLUMN field ENUM('search_names','freetext','nationality1','nationality2','nationality3','nick','networking','edus','addresses','section','binets','medals','cv','jobs','photo','corps','tels') NOT NULL DEFAULT 'search_names';
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.0.2/04_publicity.sql b/upgrade/1.0.2/04_publicity.sql
new file mode 100644 (file)
index 0000000..299e625
--- /dev/null
@@ -0,0 +1,34 @@
+    UPDATE  profile_phones    AS pp
+INNER JOIN  profile_addresses AS pa ON (pp.pid = pa.pid AND pp.link_id = pa.id AND pa.type = 'home' AND pp.tel_type = 'address')
+       SET  pp.pub = 'ax'
+     WHERE  pp.pub != pa.pub AND pa.pub = 'ax' AND pp.pub = 'public';
+    UPDATE  profile_phones    AS pp
+INNER JOIN  profile_addresses AS pa ON (pp.pid = pa.pid AND pp.link_id = pa.id AND pa.type = 'home' AND pp.tel_type = 'address')
+       SET pp.pub = 'private' WHERE pp.pub != pa.pub AND pa.pub = 'private';
+
+    UPDATE  profile_phones AS pp
+INNER JOIN  profile_job    AS pj ON (pp.pid = pj.pid AND pp.link_id = pj.id AND pp.link_type = 'pro')
+       SET  pp.pub = 'ax'
+     WHERE  pp.pub != pj.pub AND  pj.pub = 'ax' AND pp.pub = 'public';
+    UPDATE  profile_phones AS pp
+INNER JOIN  profile_job    AS pj ON (pp.pid = pj.pid AND pp.link_id = pj.id AND pp.link_type = 'pro')
+       SET  pp.pub = 'private'
+     WHERE  pp.pub != pj.pub AND pj.pub = 'private';
+
+    UPDATE  profile_addresses AS pa
+INNER JOIN  profile_job       AS pj ON (pa.pid = pj.pid AND pa.id = pj.id AND pa.type = 'job')
+       SET  pa.pub = 'ax'
+     WHERE  pa.pub != pj.pub AND pj.pub = 'ax' AND pa.pub = 'public';
+    UPDATE  profile_addresses AS pa
+INNER JOIN  profile_job       AS pj ON (pa.pid = pj.pid AND pa.id = pj.id AND pa.type = 'job')
+       SET  pa.pub = 'private'
+     WHERE  pa.pub != pj.pub AND pj.pub = 'private';
+
+UPDATE  profile_job
+   SET  email_pub = 'ax'
+ WHERE  pub != email_pub AND pub = 'ax' AND email_pub = 'public';
+UPDATE  profile_job
+   SET  email_pub = 'private'
+ WHERE pub = 'private';
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.0.2/06_geocoding.sql b/upgrade/1.0.2/06_geocoding.sql
new file mode 100644 (file)
index 0000000..871b20e
--- /dev/null
@@ -0,0 +1,41 @@
+ALTER TABLE geoloc_administrativeareas ADD COLUMN nameLocal VARCHAR(255) DEFAULT NULL;
+ALTER TABLE geoloc_subadministrativeareas ADD COLUMN nameLocal VARCHAR(255) DEFAULT NULL;
+ALTER TABLE geoloc_localities ADD COLUMN nameLocal VARCHAR(255) DEFAULT NULL;
+
+ALTER TABLE geoloc_countries CHANGE COLUMN country countryEn VARCHAR(255) DEFAULT NULL;
+ALTER TABLE geoloc_countries CHANGE COLUMN countryFR country VARCHAR(255) DEFAULT NULL;
+ALTER TABLE geoloc_countries CHANGE COLUMN nationality nationalityEn VARCHAR(255) DEFAULT NULL;
+ALTER TABLE geoloc_countries CHANGE COLUMN nationalityFR nationality VARCHAR(255) DEFAULT NULL;
+ALTER TABLE geoloc_countries ADD COLUMN countryPlain VARCHAR(255) DEFAULT NULL;
+
+INSERT INTO  geoloc_countries (iso_3166_1_a2, iso_3166_1_a3, iso_3166_1_num, worldRegion,
+                               country, countryEn, capital, nationality,
+                               licensePlate, belongsTo, phonePrefix)
+     VALUES  ('AW', 'ABW', 533, 'SA', 'Aruba', 'Aruba', 'Oranjestad', NULL, 'NL', 'NL', 297),
+             ('GW', 'GNB', 624, 'AF', 'Guinée-Bissau', 'Republic of Guinea-Bissau', 'Bissau', 'Bissau-Guinéen', 'GW', NULL, 245);
+
+-- List of supported languages:
+  -- ar  ARABIC -- bg  BULGARIAN -- bn  BENGALI -- ca  CATALAN -- cs  CZECH -- da  DANISH -- de  GERMAN -- el  GREEK -- en  ENGLISH -- es  SPANISH -- eu  BASQUE -- fi  FINNISH -- fil FILIPINO -- fr  FRENCH -- gl  GALICIAN -- gu  GUJARATI -- hi  HINDI -- hr  CROATIAN -- sr  SERBIAN -- hu  HUNGARIAN -- id  INDONESIAN -- it  ITALIAN -- iw  HEBREW -- ja  JAPANESE -- kn  KANNADA -- ko  KOREAN -- lt  LITHUANIAN -- lv  LATVIAN -- ml  MALAYALAM -- mr  MARATHI -- nl  DUTCH -- nn  NORWEGIAN NYNORSK -- no  NORWEGIAN -- or  ORIYA -- pl  POLISH -- pt  PORTUGUESE -- pt-BR PORTUGUESE (BRAZIL) -- pt-PT PORTUGUESE (PORTUGAL) -- ro  ROMANIAN -- ru  RUSSIAN -- sk  SLOVAK -- sl  SLOVENIAN -- sv  SWEDISH -- ta  TAMIL -- te  TELUGU -- th  THAI -- tr  TURKISH -- uk  UKRAINIAN -- vi  VIETNAMESE -- zh-CN CHINESE (SIMPLIFIED) -- zh-TW CHINESE (TRADITIONAL)
+
+DROP TABLE IF EXISTS geoloc_languages;
+CREATE TABLE geoloc_languages (
+  iso_3166_1_a2 CHAR(2) NOT NULL,
+  language CHAR(5) NOT NULL,
+  country VARCHAR(255) DEFAULT NULL,
+  countryPlain VARCHAR(255) DEFAULT NULL,
+  PRIMARY KEY (iso_3166_1_a2, language),
+  FOREIGN KEY (iso_3166_1_a2) REFERENCES geoloc_countries (iso_3166_1_a2) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+INSERT INTO  geoloc_languages (language, iso_3166_1_a2)
+     VALUES  ('ar', 'IL'), ('ar', 'JO'), ('ar', 'SD'), ('ar', 'TD'), ('ar', 'KM'), ('ar', 'DJ'), ('ar', 'LB'), ('ar', 'DZ'), ('ar', 'BH'), ('ar', 'EG'), ('ar', 'ER'), ('ar', 'IQ'), ('ar', 'KW'), ('ar', 'LY'), ('ar', 'MR'), ('ar', 'MA'), ('ar', 'OM'), ('ar', 'PS'), ('ar', 'QA'), ('ar', 'SA'), ('ar', 'SO'), ('ar', 'SY'), ('ar', 'TN'), ('ar', 'AE'),
+             ('bg', 'BG'), ('bn', 'BD'), ('bn', 'IN'), ('ca', 'ES'), ('cs', 'CZ'), ('da', 'DK'), ('de', 'AT'), ('de', 'DE'), ('de', 'LI'), ('de', 'BE'), ('de', 'LU'), ('de', 'CH'), ('el', 'GR'), ('el', 'CY'),
+             ('en', 'IN'), ('en', 'JO'), ('en', 'SD'), ('en', 'PH'), ('en', 'AG'), ('en', 'BS'), ('en', 'BW'), ('en', 'DM'), ('en', 'FJ'), ('en', 'GM'), ('en', 'GH'), ('en', 'GD'), ('en', 'GY'), ('en', 'IE'), ('en', 'JM'), ('en', 'KE'), ('en', 'KI'), ('en', 'LS'), ('en', 'LR'), ('en', 'MW'), ('en', 'MT'), ('en', 'MH'), ('en', 'MU'), ('en', 'FM'), ('en', 'NA'), ('en', 'NR'), ('en', 'NZ'), ('en', 'NG'), ('en', 'PK'), ('en', 'PG'), ('en', 'KN'), ('en', 'LC'), ('en', 'VC'), ('en', 'WS'), ('en', 'SL'), ('en', 'SB'), ('en', 'SZ'), ('en', 'TZ'), ('en', 'TO'), ('en', 'TT'), ('en', 'TV'), ('en', 'UG'), ('en', 'ZM'), ('en', 'ZW'), ('en', 'AU'), ('en', 'GB'), ('en', 'ZA'), ('en', 'BZ'), ('en', 'US'), ('en', 'HN'), ('en', 'CM'), ('en', 'RW'), ('en', 'SC'), ('en', 'CA'), ('en', 'VU'), ('en', 'PW'), ('en', 'SG'),
+             ('en', 'MO'),
+             ('es', 'BZ'), ('es', 'US'), ('es', 'MX'), ('es', 'AR'), ('es', 'CL'), ('es', 'DO'), ('es', 'NI'), ('es', 'CO'), ('es', 'PE'), ('es', 'VE'), ('es', 'EC'), ('es', 'GT'), ('es', 'CU'), ('es', 'BO'), ('es', 'SV'), ('es', 'PY'), ('es', 'CR'), ('es', 'PA'), ('es', 'AD'), ('es', 'ES'), ('es', 'UY'), ('es', 'HN'), ('es', 'GQ'),
+             ('eu', 'ES'), ('fi', 'FI'), ('fil', 'PH'),
+             ('fr', 'CM'), ('fr', 'RW'), ('fr', 'SC'), ('fr', 'CA'), ('fr', 'VU'), ('fr', 'CD'), ('fr', 'FR'), ('fr', 'MG'), ('fr', 'CI'), ('fr', 'BF'), ('fr', 'NE'), ('fr', 'SN'), ('fr', 'ML'), ('fr', 'GN'), ('fr', 'HT'), ('fr', 'BI'), ('fr', 'BJ'), ('fr', 'TG'), ('fr', 'CF'), ('fr', 'CG'), ('fr', 'GA'), ('fr', 'MC'), ('fr', 'TD'), ('fr', 'KM'), ('fr', 'DJ'), ('fr', 'LB'), ('fr', 'BE'), ('fr', 'LU'), ('fr', 'CH'), ('fr', 'GQ'),
+             ('gl', 'ES'), ('gu', 'IN'), ('hi', 'IN'), ('hr', 'HR'), ('hr', 'BA'), ('hu', 'HU'), ('id', 'ID'), ('it', 'CH'), ('it', 'IT'), ('it', 'SM'), ('it', 'VA'), ('it', 'MT'), ('iw', 'IL'), ('ja', 'JP'), ('ja', 'PW'), ('kn', 'IN'), ('ko', 'KP'), ('ko', 'KR'), ('lt', 'LT'), ('lv', 'LV'), ('ml', 'IN'), ('mr', 'IN'), ('nl', 'BE'), ('nl', 'AW'), ('nl', 'NL'), ('nl', 'SR'), ('no', 'NO'), ('nn', 'NO'), ('or', 'IN'), ('pl', 'PL'), ('pt', 'BR'), ('pt-BR', 'BR'), ('pt', 'PT'), ('pt-PT', 'PT'), ('pt', 'MZ'), ('pt', 'AO'), ('pt', 'GW'), ('pt', 'TL'), ('pt', 'CV'), ('pt', 'ST'), ('pt', 'UY'), ('pt', 'MO'), ('rm', 'CH'), ('ro', 'MD'), ('ro', 'RO'), ('ru', 'RU'), ('ru', 'BY'), ('ru', 'KZ'), ('ru', 'KG'), ('sk', 'CZ'), ('sk', 'SK'), ('sl', 'SI'), ('sr', 'BA'), ('sr', 'RS'), ('sv', 'FI'), ('sv', 'SE'), ('ta', 'IN'), ('ta', 'LK'), ('ta', 'SG'), ('te', 'IN'), ('th', 'TH'), ('tr', 'CY'), ('tr', 'TR'), ('ua', 'UA'), ('vi', 'VN'),
+             ('zh-CN', 'SG'), ('zh-CN', 'CN'), ('zh-CN', 'TW'), ('zh-CN', 'MY'), ('zh-CN', 'HK'), ('zh-CN', 'MO'), ('zh-TW', 'SG'), ('zh-TW', 'CN'), ('zh-TW', 'TW'), ('zh-TW', 'MY'), ('zh-TW', 'HK'), ('zh-TW', 'MO');
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.0.2/07_areas.sql b/upgrade/1.0.2/07_areas.sql
new file mode 100644 (file)
index 0000000..6a5b0a0
--- /dev/null
@@ -0,0 +1,7 @@
+ALTER TABLE geoloc_subadministrativeareas ADD COLUMN administrativearea VARCHAR(255) DEFAULT NULL;
+
+    UPDATE  geoloc_subadministrativeareas AS gs
+INNER JOIN  profile_addresses             AS pa ON (gs.id = pa.subAdministrativeAreaId)
+       SET  gs.administrativearea = pa.administrativeAreaId;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.0.2/08_xnet_payments.sql b/upgrade/1.0.2/08_xnet_payments.sql
new file mode 100644 (file)
index 0000000..21aabab
--- /dev/null
@@ -0,0 +1,3 @@
+ALTER TABLE group_event_participants MODIFY COLUMN paid FLOAT(10,2) NOT NULL DEFAULT 0;
+
+-- vim:set syntax=mysql:
diff --git a/upgrade/1.0.2/connect.db.inc.php b/upgrade/1.0.2/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.0.2/geocoding.php b/upgrade/1.0.2/geocoding.php
new file mode 100755 (executable)
index 0000000..8569226
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/php5
+<?php
+
+require_once 'connect.db.inc.php';
+require_once '../../classes/address.php';
+require_once '../../classes/gmapsgeocoder.php';
+require_once '../../classes/geocoder.php';
+
+$globals->debug = 0; // Do not store backtraces.
+
+$it = XDB::iterator('SELECT  gl.language, gc.country, gc.iso_3166_1_a2
+                       FROM  geoloc_languages AS gl
+                 INNER JOIN  geoloc_countries AS gc ON (gl.iso_3166_1_a2 = gc.iso_3166_1_a2)');
+
+echo $it->total() . " pays à remplir.\n";
+while ($item = $it->next()) {
+    if ($item['language'] != 'fr') {
+        $address = new Address(array('text' => $item['country']));
+        $gmapsGeocoder = new GMapsGeocoder();
+        $gmapsGeocoder->getGeocodedAddress($address, $item['language'], true);
+        $country = $address->country;
+    } else {
+        $country = $item['country'];
+    }
+    $countryPlain = mb_strtoupper(replace_accent($country));
+    XDB::execute('UPDATE  geoloc_languages
+                     SET  country = {?}, countryPlain = {?}
+                   WHERE  iso_3166_1_a2 = {?} AND language = {?}',
+                 $country, $countryPlain, $item['iso_3166_1_a2'], $item['language']);
+     sleep(1);
+}
+
+$it = XDB::rawIterator('SELECT  country, iso_3166_1_a2
+                          FROM  geoloc_countries');
+echo $it->total() . " pays à simplifier.\n";
+while ($item = $it->next()) {
+    XDB::execute('UPDATE  geoloc_countries
+                     SET  countryPlain = {?}
+                   WHERE  iso_3166_1_a2 = {?}',
+                 mb_strtoupper(replace_accent($item['country'])), $item['iso_3166_1_a2']);
+}
+
+// Fixes geocoding errors.
+XDB::rawExecute("REPLACE INTO  geoloc_languages (iso_3166_1_a2, language, country, countryPlain)
+                       VALUES  ('FM', 'en', 'Federated States of Micronesia', 'FEDERATED STATES OF MICRONESIA'),
+                               ('MH', 'en', 'Republic of the Marshall Islands', 'REPUBLIC OF THE MARSHALL ISLANDS'),
+                               ('PS', 'ar', 'دولة فلسطين', 'دولة فلسطين'),
+                               ('SB', 'en', 'Solomon Islands', 'SOLOMON ISLANDS'),
+                               ('TW', 'zh-CN', '台湾', '台湾'),
+                               ('TW', 'zh-TW', '台灣', '台灣'),
+                               ('CZ', 'cs', 'Česká Republika', 'CESKA REPUBLIKA'),
+                               ('CZ', 'sk', 'Česká Republika', 'CESKA REPUBLIKA'),
+                               ('DO', 'es', 'República Dominicana', 'REPUBLICA DOMINICANA'),
+                               ('GD', 'en', 'Grenada', 'GRENADA'),
+                               ('MD', 'ro', 'Republica Moldova', 'REPUBLICA MOLDOVA'),
+                               ('RU', 'ru', 'Россия', 'Россия'),
+                               ('SK', 'sk', 'Slovenská Republika', 'SLOVENSKA REPUBLIKA'),
+                               ('TZ', 'en', 'United Republic of Tanzania', 'UNITED REPUBLIC OF TANZANIA')");
+
+/* vim:set et sw=4 sts=4 ts=4: */
+?>
index 47b30f2..b846b39 100644 (file)
@@ -67,7 +67,7 @@ class CheckDB extends PlTestCase
                 array('SELECT  pa.pid, pa.countryId
                          FROM  profile_addresses AS pa
                     LEFT JOIN  geoloc_countries  AS gc ON (pa.countryId = gc.iso_3166_1_a2)
-                        WHERE  gc.countryFR IS NULL OR gc.countryFR = \'\''),
+                        WHERE  gc.country IS NULL OR gc.country = \'\''),
 
             'missing nationalities' =>
                 array('SELECT  p.pid, p.nationality1, p.nationality2, p.nationality3
@@ -75,9 +75,9 @@ class CheckDB extends PlTestCase
                     LEFT JOIN  geoloc_countries AS g1 ON (p.nationality1 = g1.iso_3166_1_a2)
                     LEFT JOIN  geoloc_countries AS g2 ON (p.nationality2 = g2.iso_3166_1_a2)
                     LEFT JOIN  geoloc_countries AS g3 ON (p.nationality3 = g3.iso_3166_1_a2)
-                        WHERE  (p.nationality1 IS NOT NULL AND (g1.nationalityFR IS NULL OR g1.nationalityFR = \'\'))
-                               OR (p.nationality2 IS NOT NULL AND (g2.nationalityFR IS NULL OR g2.nationalityFR = \'\'))
-                               OR (p.nationality3 IS NOT NULL AND (g3.nationalityFR IS NULL OR g3.nationalityFR = \'\'))'),
+                        WHERE  (p.nationality1 IS NOT NULL AND (g1.nationality IS NULL OR g1.nationality = \'\'))
+                               OR (p.nationality2 IS NOT NULL AND (g2.nationality IS NULL OR g2.nationality = \'\'))
+                               OR (p.nationality3 IS NOT NULL AND (g3.nationality IS NULL OR g3.nationality = \'\'))'),
 
             'ax_id' =>
                 array('SELECT  pid, hrpid, ax_id, COUNT(ax_id) AS c