Lists group former members to group admins (Closes #947).
[platal.git] / classes / profile.php
index 3ca5679..177155a 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /***************************************************************************
- *  Copyright (C) 2003-2010 Polytechnique.org                              *
+ *  Copyright (C) 2003-2011 Polytechnique.org                              *
  *  http://opensource.polytechnique.org/                                   *
  *                                                                         *
  *  This program is free software; you can redistribute it and/or modify   *
@@ -19,7 +19,7 @@
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
  ***************************************************************************/
 
-class Profile
+class Profile implements PlExportable
 {
 
     /* name tokens */
@@ -48,6 +48,17 @@ class Profile
     const DEGREE_M = 'Master';
     const DEGREE_D = 'Doctorat';
 
+    static public $cycles = array(
+        self::DEGREE_X => 'polytechnicien',
+        self::DEGREE_M => 'master',
+        self::DEGREE_D => 'docteur'
+    );
+    static public $cycle_prefixes = array(
+        self::DEGREE_X => 'X',
+        self::DEGREE_M => 'M',
+        self::DEGREE_D => 'D'
+    );
+
     static public $name_variants = array(
             self::LASTNAME => array(self::VN_MARITAL, self::VN_ORDINARY),
             self::FIRSTNAME => array(self::VN_ORDINARY, self::VN_INI, self::VN_OTHER)
@@ -98,10 +109,11 @@ class Profile
     const FETCH_PHONES         = 0x000100;
     const FETCH_JOB_TERMS      = 0x000200;
     const FETCH_MENTOR_TERMS   = 0x000400;
+    const FETCH_DELTATEN       = 0x000800;
 
     const FETCH_MINIFICHES   = 0x00012D; // FETCH_ADDRESSES | FETCH_EDU | FETCH_JOBS | FETCH_NETWORKING | FETCH_PHONES
 
-    const FETCH_ALL          = 0x0007FF; // OR of FETCH_*
+    const FETCH_ALL          = 0x000FFF; // OR of FETCH_*
 
     static public $descriptions = array(
         'search_names'    => 'Noms',
@@ -113,6 +125,7 @@ class Profile
         'networking'      => 'Messageries…',
         'tels'            => 'Téléphones',
         'edus'            => 'Formations',
+        'main_edus'       => 'Formations à l\'X',
         'promo'           => 'Promotion de sortie',
         'birthdate'       => 'Date de naissance',
         'yourself'        => 'Nom affiché',
@@ -132,7 +145,8 @@ class Profile
         'langues'         => 'Langues',
         'expertise'       => 'Expertises (mentoring)',
         'terms'           => 'Compétences (mentoring)',
-        'countries'       => 'Pays (mentoring)'
+        'countries'       => 'Pays (mentoring)',
+        'deltaten'        => 'Opération N N-10',
     );
 
     private $fetched_fields  = 0x000000;
@@ -181,14 +195,26 @@ class Profile
         return false;
     }
 
-    public function promo()
+    public function promo($details = false)
     {
+        if ($details && ($this->program || $this->fieldid)) {
+            $text = array();
+            if ($this->program) {
+                $text[] = $this->program;
+            }
+            if ($this->fieldid) {
+                $fieldsList = DirEnum::getOptions(DirEnum::EDUFIELDS);
+                $text[] = $fieldsList[$this->fieldid];
+            }
+            return $this->promo . ' (' . implode(', ', $text) . ')';
+        }
+
         return $this->promo;
     }
 
     public function yearpromo()
     {
-        return intval(substr($this->promo, 1, 4));
+        return $this->promo_year;
     }
 
     /** Check if user is an orange (associated with several promos)
@@ -397,8 +423,8 @@ class Profile
 
     /**
      * Clears a profile.
-     *  *always deletes in: profile_addresses, profile_binets, profile_job,
-     *      profile_langskills, profile_mentor, profile_networking,
+     *  *always deletes in: profile_addresses, profile_binets, profile_deltaten,
+     *      profile_job, profile_langskills, profile_mentor, profile_networking,
      *      profile_phones, profile_skills, watch_profile
      *  *always keeps in: profile_corps, profile_display, profile_education,
      *      profile_medals, profile_name, profile_photos, search_name
@@ -409,7 +435,8 @@ class Profile
         $tables = array(
             'profile_job', 'profile_langskills', 'profile_mentor',
             'profile_networking', 'profile_skills', 'watch_profile',
-            'profile_phones', 'profile_addresses', 'profile_binets');
+            'profile_phones', 'profile_addresses', 'profile_binets',
+            'profile_deltaten');
 
         foreach ($tables as $t) {
             XDB::execute('DELETE FROM  ' . $t . '
@@ -780,6 +807,44 @@ class Profile
         }
     }
 
+    /** DeltaTen
+     */
+
+    /** Find out whether this profile may take part to the "DeltaTen" operation.
+     * @param $role Which role to select ('young' or 'old')
+     * @return Boolean: whether it is enabled.
+     */
+    const DELTATEN_YOUNG = 'young';
+    const DELTATEN_OLD = 'old';
+    public function isDeltaTenEnabled($role)
+    {
+        global $globals;
+        switch ($role) {
+        case self::DELTATEN_YOUNG:
+            return ($this->mainGrade() == UserFilter::GRADE_ING && $this->yearpromo() >= $globals->deltaten->first_promo_young);
+        case self::DELTATEN_OLD:
+            // Roughly compute the current promo in second year on the campus:
+            // Promo 2010 is in second year between 09/2011 and 08/2012 => use 2012.
+            // DeltaTen program begins around January of the second year.
+            $promo_on_platal = ((int) date('Y')) - 2;
+            return ($this->mainGrade() == UserFilter::GRADE_ING && $this->yearpromo() >= $globals->deltaten->first_promo_young - 10 && $this->yearpromo() <= $promo_on_platal - 10);
+        default:
+            Platal::assert(false, "Invalid DeltaTen role $role");
+        }
+    }
+
+    /** Retrieve the "Deltaten" message of the user.
+     * Returns "null" if the message is empty or the user is not taking part to the
+     * DeltaTen operation.
+     */
+    public function getDeltatenMessage()
+    {
+        if ($this->isDeltaTenEnabled(self::DELTATEN_OLD)) {
+            return $this->deltaten_message;
+        } else {
+            return null;
+        }
+    }
 
     /* Binets
      */
@@ -843,6 +908,24 @@ class Profile
         return ($isOk && ($maxlen > 2 || $maxlen == strlen($_lastname)));
     }
 
+    /* Export to JSON
+     */
+    public function export()
+    {
+        return array(
+            'hrpid'        => $this->hrid(),
+            'display_name' => $this->shortName(),
+            'full_name'    => $this->fullName(),
+            'directory_name' => $this->directory_name,
+            'promo'        => $this->promo(),
+            'year_promo'   => $this->yearpromo(),
+            'is_active'    => $this->isActive(),
+            'first_name'   => $this->firstName(),
+            'last_name'    => $this->lastName(),
+            'is_female'    => $this->isFemale(),
+        );
+    }
+
     private static function fetchProfileData(array $pids, $respect_order = true, $fields = 0x0000, $visibility = null)
     {
         if (count($pids) == 0) {
@@ -862,19 +945,20 @@ class Profile
                                      IF ({?}, p.cv, NULL) AS cv, p.medals_pub, p.alias_pub, p.email_directory,
                                      p.last_change, p.nationality1, p.nationality2, p.nationality3,
                                      IF (p.freetext_pub IN {?}, p.freetext, NULL) AS freetext,
-                                     pe.entry_year, pe.grad_year,
+                                     pe.entry_year, pe.grad_year, pe.promo_year, pe.program, pe.fieldid,
                                      IF ({?}, pse.text, NULL) AS section,
                                      pn_f.name AS firstname, pn_l.name AS lastname,
-                                     IF{?}, pn_n.name, NULL) AS nickname,
-                                     IF(pn_uf.name IS NULL, pn_f.name, pn_uf.name) AS firstname_ordinary,
-                                     IF(pn_ul.name IS NULL, pn_l.name, pn_ul.name) AS lastname_ordinary,
+                                     IF ({?}, pn_n.name, NULL) AS nickname,
+                                     IF (pn_uf.name IS NULL, pn_f.name, pn_uf.name) AS firstname_ordinary,
+                                     IF (pn_ul.name IS NULL, pn_l.name, pn_ul.name) AS lastname_ordinary,
                                      pd.yourself, pd.promo, pd.short_name, pd.public_name AS full_name,
                                      pd.directory_name, pd.public_name, pd.private_name,
-                                     IF(pp.pub IN {?}, pp.display_tel, NULL) AS mobile,
+                                     IF (pp.pub IN {?}, pp.display_tel, NULL) AS mobile,
                                      (ph.pub IN {?} AND ph.attach IS NOT NULL) AS has_photo,
                                      ph.x AS photo_width, ph.y AS photo_height,
                                      p.last_change < DATE_SUB(NOW(), INTERVAL 365 DAY) AS is_old,
                                      pm.expertise AS mentor_expertise,
+                                     IF ({?}, pdt.message, NULL) AS deltaten_message,
                                      ap.uid AS owner_id
                                FROM  profiles AS p
                          INNER JOIN  profile_display AS pd ON (pd.pid = p.pid)
@@ -893,6 +977,7 @@ class Profile
                           LEFT JOIN  profile_phones AS pp ON (pp.pid = p.pid AND pp.link_type = \'user\' AND tel_type = \'mobile\')
                           LEFT JOIN  profile_photos AS ph ON (ph.pid = p.pid)
                           LEFT JOIN  profile_mentor AS pm ON (pm.pid = p.pid)
+                          LEFT JOIN  profile_deltaten AS pdt ON (pdt.pid = p.pid)
                           LEFT JOIN  account_profiles AS ap ON (ap.pid = p.pid AND FIND_IN_SET(\'owner\', ap.perms))
                               WHERE  p.pid IN {?}
                            GROUP BY  p.pid
@@ -903,6 +988,7 @@ class Profile
                            $visibility->isVisible(ProfileVisibility::VIS_PRIVATE), // nickname
                            $visibility->levels(), // mobile
                            $visibility->levels(), // photo
+                           $visibility->isVisible(ProfileVisibility::VIS_PRIVATE), // deltaten_message
                            $pids
                        );
         return new ProfileIterator($it, $pids, $fields, $visibility);
@@ -1050,13 +1136,13 @@ class Profile
         if (!is_array($pids)) {
             $pids = array($pids);
         }
-        $keys = XDB::iterator("(SELECT  n.pid AS pid, n.name AS name, e.score AS score,
+        $keys = XDB::iterator("(SELECT  n.pid AS pid, n.name AS name, e.score AS score, e.general_type,
                                         IF(FIND_IN_SET('public', e.flags), 'public', '') AS public
                                   FROM  profile_name      AS n
                             INNER JOIN  profile_name_enum AS e ON (n.typeid = e.id)
                                  WHERE  n.pid IN {?} AND NOT FIND_IN_SET('not_displayed', e.flags))
                                  UNION
-                                (SELECT  n.pid AS pid, n.particle AS name, 0 AS score,
+                                (SELECT  n.pid AS pid, n.particle AS name, 0 AS score, e.general_type,
                                          IF(FIND_IN_SET('public', e.flags), 'public', '') AS public
                                    FROM  profile_name      AS n
                              INNER JOIN  profile_name_enum AS e ON (n.typeid = e.id)
@@ -1069,8 +1155,8 @@ class Profile
                 continue;
             }
             $pid   = $key['pid'];
-            $toks  = preg_split('/[ \'\-]+/', strtolower(replace_accent($key['name'])),
-                                -1, PREG_SPLIT_NO_EMPTY);
+            require_once 'name.func.inc.php';
+            $toks = split_name_for_search($key['name']);
             $toks = array_reverse($toks);
 
             /* Split the score between the tokens to avoid the user to be over-rated.
@@ -1082,9 +1168,9 @@ class Profile
             $token = '';
             foreach ($toks as $tok) {
                 $token = $tok . $token;
-                $names["$pid-$token"] = XDB::format('({?}, {?}, {?}, {?}, {?})',
+                $names["$pid-$token"] = XDB::format('({?}, {?}, {?}, {?}, {?}, {?})',
                                                     $token, $pid, soundex_fr($token),
-                                                    $eltScore, $key['public']);
+                                                    $eltScore, $key['public'], $key['general_type']);
             }
         }
         if ($transaction) {
@@ -1094,7 +1180,7 @@ class Profile
                             WHERE  pid IN {?}',
                      $pids);
         if (count($names) > 0) {
-            XDB::rawExecute('INSERT INTO  search_name (token, pid, soundex, score, flags)
+            XDB::rawExecute('INSERT INTO  search_name (token, pid, soundex, score, flags, general_type)
                                   VALUES  ' . implode(', ', $names));
         }
         if ($transaction) {