X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=classes%2Fuserfilter.php;h=f78635b29f1bff36ffb45f695386dddc4181c93a;hb=5f0ecf6ce6e006d4e494ddc8e126a0695980f173;hp=159c9a108cb1fac2d4822ef438765a46cbfa3955;hpb=2f1c94e0d5a97c554555c3580f483782cb123e20;p=platal.git diff --git a/classes/userfilter.php b/classes/userfilter.php index 159c9a1..f78635b 100644 --- a/classes/userfilter.php +++ b/classes/userfilter.php @@ -52,6 +52,25 @@ class UFC_HasProfile implements UserFilterCondition } // }}} +// {{{ class UFC_AccountType +/** Filters users who have the given account types + */ +class UFC_AccountType implements UserFilterCondition +{ + private $types; + + public function __construct() + { + $this->types = pl_flatten(func_get_args()); + } + + public function buildCondition(PlFilter &$uf) + { + $uf->requireAccounts(); + return XDB::format('a.type IN {?}', $this->types); + } +} + // {{{ class UFC_Hruid /** Filters users based on their hruid * @param $val Either an hruid, or a list of those @@ -129,7 +148,7 @@ class UFC_Comment implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $uf->requireProfiles(); - return 'p.freetext ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->text); + return $uf->getVisibilityCondition('p.freetext_pub') . ' AND p.freetext ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->text); } } // }}} @@ -156,7 +175,8 @@ class UFC_Promo implements UserFilterCondition UserFilter::assertGrade($this->grade); } if ($this->grade == UserFilter::DISPLAY && $this->comparison != '=') { - Platal::page()->killError('Comparison ' . $this->comparison . ' not allowed on displaid promo'); + // XXX: we might try to guess the grade from the first char of the promo and forbid only '<= 2004', but allow '<= X2004' + Platal::page()->killError("Il n'est pas possible d'appliquer la comparaison '" . $this->comparison . "' aux promotions sans spécifier de formation (X/M/D)"); } } @@ -556,6 +576,10 @@ class UFC_Group implements UserFilterCondition public function buildCondition(PlFilter &$uf) { + // Groups have AX visibility. + if ($uf->getVisibilityLevel() == ProfileVisibility::VIS_PUBLIC) { + return PlFilter::COND_TRUE; + } $sub = $uf->addGroupFilter($this->group); $where = 'gpm' . $sub . '.perms IS NOT NULL'; if ($this->anim) { @@ -581,6 +605,10 @@ class UFC_Binet implements UserFilterCondition public function buildCondition(PlFilter &$uf) { + // Binets are private. + if ($uf->getVisibilityLevel() != ProfileVisibility::VIS_PRIVATE) { + return PlFilter::COND_TRUE; + } $sub = $uf->addBinetsFilter(); return XDB::format($sub . '.binet_id IN {?}', $this->val); } @@ -602,6 +630,10 @@ class UFC_Section implements UserFilterCondition public function buildCondition(PlFilter &$uf) { + // Sections are private. + if ($uf->getVisibilityLevel() != ProfileVisibility::VIS_PRIVATE) { + return PlFilter::COND_TRUE; + } $uf->requireProfiles(); return XDB::format('p.section IN {?}', $this->section); } @@ -706,9 +738,10 @@ abstract class UFC_Address implements UserFilterCondition $this->flags = $flags; } - protected function initConds($sub) + protected function initConds($sub, $vis_cond) { - $conds = array(); + $conds = array($vis_cond); + $types = array(); foreach (self::$typetexts as $flag => $type) { if ($flag & $this->type) { @@ -765,7 +798,7 @@ class UFC_AddressText extends UFC_Address public function buildCondition(PlFilter &$uf) { $sub = $uf->addAddressFilter(); - $conds = $this->initConds($sub); + $conds = $this->initConds($sub, $uf->getVisibilityCondition($sub . '.pub')); if ($this->text != null) { $conds[] = $sub . '.text' . $this->mkMatch($this->text); } @@ -822,7 +855,7 @@ class UFC_AddressField extends UFC_Address public function buildCondition(PlFilter &$uf) { $sub = $uf->addAddressFilter(); - $conds = $this->initConds($sub); + $conds = $this->initConds($sub, $uf->getVisibilityCondition($sub . '.pub')); switch ($this->fieldtype) { case self::FIELD_COUNTRY: @@ -878,6 +911,7 @@ class UFC_Corps implements UserFilterCondition */ $sub = $uf->addCorpsFilter($this->type); $cond = $sub . '.abbreviation = ' . $corps; + $cond .= ' AND ' . $uf->getVisibilityCondition($sub . '.corps_pub'); return $cond; } } @@ -898,10 +932,14 @@ class UFC_Corps_Rank implements UserFilterCondition public function buildCondition(PlFilter &$uf) { /** Tables shortcuts: + * pc for profile_corps * pcr for profile_corps_rank */ $sub = $uf->addCorpsRankFilter(); $cond = $sub . '.abbreviation = ' . $rank; + // XXX(x2006barrois): find a way to get rid of that hardcoded + // reference to 'pc'. + $cond .= ' AND ' . $uf->getVisibilityCondition('pc.corps_pub'); return $cond; } } @@ -938,7 +976,9 @@ class UFC_Job_Company implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $sub = $uf->addJobCompanyFilter(); - $cond = $sub . '.' . $this->type . ' = ' . XDB::format('{?}', $this->value); + $cond = $sub . '.' . $this->type . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->value); + $jsub = $uf->addJobFilter(); + $cond .= ' AND ' . $uf->getVisibilityCondition($jsub . '.pub'); return $cond; } } @@ -974,7 +1014,41 @@ class UFC_Job_Sectorization implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $sub = $uf->addJobSectorizationFilter($this->type); - return $sub . '.id = ' . XDB::format('{?}', $this->val); + $cond = $sub . '.id = ' . XDB::format('{?}', $this->val); + $jsub = $uf->addJobFilter(); + $cond .= ' AND ' . $uf->getVisibilityCondition($jsub . '.pub'); + return $cond; + } +} +// }}} + +// {{{ class UFC_Job_Terms +/** Filters users based on the job terms they assigned to one of their + * jobs. + * @param $val The ID of the job term, or an array of such IDs + */ +class UFC_Job_Terms implements UserFilterCondition +{ + private $val; + + public function __construct($val) + { + if (!is_array($val)) { + $val = array($val); + } + $this->val = $val; + } + + public function buildCondition(PlFilter &$uf) + { + $sub = $uf->addJobTermsFilter(count($this->val)); + $conditions = array(); + foreach ($this->val as $i => $jtid) { + $conditions[] = $sub[$i] . '.jtid_1 = ' . XDB::escape($jtid); + } + $jsub = $uf->addJobFilter(); + $conditions[] = $uf->getVisibilityCondition($jsub . '.pub'); + return implode(' AND ', $conditions); } } // }}} @@ -999,11 +1073,22 @@ class UFC_Job_Description implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $conds = array(); + + $jsub = $uf->addJobFilter(); + // CV is private => if only CV requested, and not private, + // don't do anything. Otherwise restrict to standard job visibility. + if ($this->fields == UserFilter::JOB_CV) { + if ($uf->getVisibilityLevel() != ProfileVisibility::VIS_PRIVATE) { + return PlFilter::COND_TRUE; + } + } else { + $conds[] = $uf->getVisibilityCondition($jsub . '.pub'); + } + if ($this->fields & UserFilter::JOB_USERDEFINED) { - $sub = $uf->addJobFilter(); - $conds[] = $sub . '.description ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->description); + $conds[] = $jsub . '.description ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->description); } - if ($this->fields & UserFilter::JOB_CV) { + if ($this->fields & UserFilter::JOB_CV && $uf->getVisibilityLevel == ProfileVisibility::VIS_PRIVATE) { $uf->requireProfiles(); $conds[] = 'p.cv ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->description); } @@ -1046,6 +1131,7 @@ class UFC_Networking implements UserFilterCondition { $sub = $uf->addNetworkingFilter(); $conds = array(); + $conds[] = $uf->getVisibilityCondition($sub . '.pub'); $conds[] = $sub . '.address ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->value); if ($this->type != -1) { $conds[] = $sub . '.nwid = ' . XDB::format('{?}', $this->type); @@ -1079,16 +1165,20 @@ class UFC_Phone implements UserFilterCondition public function __construct($number, $num_type = self::NUM_ANY, $phone_type = self::PHONE_ANY) { - require_once('profil.func.inc.php'); - $this->number = $number; + $phone = new Phone(array('display' => $number)); + $phone->format(); + $this->number = $phone->search(); $this->num_type = $num_type; - $this->phone_type = format_phone_number($phone_type); + $this->phone_type = $phone_type; } public function buildCondition(PlFilter &$uf) { $sub = $uf->addPhoneFilter(); $conds = array(); + + $conds[] = $uf->getVisibilityCondition($sub . '.pub'); + $conds[] = $sub . '.search_tel = ' . XDB::format('{?}', $this->number); if ($this->num_type != self::NUM_ANY) { $conds[] = $sub . '.link_type = ' . XDB::format('{?}', $this->num_type); @@ -1120,7 +1210,12 @@ class UFC_Medal implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $conds = array(); + + // This will require profiles => table 'p' will be available. $sub = $uf->addMedalFilter(); + + $conds[] = $uf->getVisibilityCondition('p.medals_pub'); + $conds[] = $sub . '.mid = ' . XDB::format('{?}', $this->medal); if ($this->grade != null) { $conds[] = $sub . '.gid = ' . XDB::format('{?}', $this->grade); @@ -1137,12 +1232,24 @@ class UFC_Photo implements UserFilterCondition { public function buildCondition(PlFilter &$uf) { - $uf->addPhotoFilter(); - return 'photo.attach IS NOT NULL'; + $sub = $uf->addPhotoFilter(); + return $sub . '.attach IS NOT NULL AND ' . $uf->getVisibilityCondition($sub . '.pub'); } } // }}} +// {{{ class UFC_Mentor +class UFC_Mentor implements UserFilterCondition +{ + public function buildCondition(PlFilter &$uf) + { + $sub = $uf->addMentorFilter(UserFilter::MENTOR); + return $sub . '.expertise IS NOT NULL'; + } +} +// }}} + + // {{{ class UFC_Mentor_Expertise /** Filters users by mentoring expertise * @param $expertise Domain of expertise @@ -1185,6 +1292,27 @@ class UFC_Mentor_Country implements UserFilterCondition } // }}} +// {{{ class UFC_Mentor_Terms +/** Filters users based on the job terms they used in mentoring. + * @param $val The ID of the job term, or an array of such IDs + */ +class UFC_Mentor_Terms implements UserFilterCondition +{ + private $val; + + public function __construct($val) + { + $this->val = $val; + } + + public function buildCondition(PlFilter &$uf) + { + $sub = $uf->addMentorFilter(UserFilter::MENTOR_TERM); + return $sub . '.jtid_1 = ' . XDB::escape($this->val); + } +} +// }}} + // {{{ class UFC_Mentor_Sectorization /** Filters users based on mentoring (sub|)sector * @param $sector ID of (sub)sector @@ -1331,28 +1459,12 @@ class UFC_MarketingHash implements UserFilterCondition * ORDERS ******************/ -// {{{ class UserFilterOrder -/** Base class for ordering results of a query. - * Parameters for the ordering must be given to the constructor ($desc for a - * descending order). - * The getSortTokens function is used to get actual ordering part of the query. - */ -abstract class UserFilterOrder extends PlFilterOrder -{ - /** This function must return the tokens to use for ordering - * @param &$uf The UserFilter whose results must be ordered - * @return The name of the field to use for ordering results - */ -// abstract protected function getSortTokens(UserFilter &$uf); -} -// }}} - // {{{ class UFO_Promo /** Orders users by promotion * @param $grade Formation whose promotion users should be sorted by (restricts results to users of that formation) * @param $desc Whether sort is descending */ -class UFO_Promo extends UserFilterOrder +class UFO_Promo extends PlFilterGroupableOrder { private $grade; @@ -1382,7 +1494,7 @@ class UFO_Promo extends UserFilterOrder * @param $particle Set to true if particles should be included in the sorting order * @param $desc If sort order should be descending */ -class UFO_Name extends UserFilterOrder +class UFO_Name extends PlFilterOrder { private $type; private $variant; @@ -1400,7 +1512,13 @@ class UFO_Name extends UserFilterOrder { if (Profile::isDisplayName($this->type)) { $sub = $uf->addDisplayFilter(); - return 'pd' . $sub . '.' . $this->type; + $token = 'pd' . $sub . '.' . $this->type; + if ($uf->accountsRequired()) { + $account_token = Profile::getAccountEquivalentName($this->type); + return 'IFNULL(' . $token . ', a.' . $account_token . ')'; + } else { + return $token; + } } else { $sub = $uf->addNameFilter($this->type, $this->variant); if ($this->particle) { @@ -1414,7 +1532,7 @@ class UFO_Name extends UserFilterOrder // }}} // {{{ class UFO_Score -class UFO_Score extends UserFilterOrder +class UFO_Score extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { @@ -1437,7 +1555,7 @@ class UFO_Score extends UserFilterOrder // {{{ class UFO_Registration /** Sorts users based on registration date */ -class UFO_Registration extends UserFilterOrder +class UFO_Registration extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { @@ -1450,7 +1568,7 @@ class UFO_Registration extends UserFilterOrder // {{{ class UFO_Birthday /** Sorts users based on next birthday date */ -class UFO_Birthday extends UserFilterOrder +class UFO_Birthday extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { @@ -1463,7 +1581,7 @@ class UFO_Birthday extends UserFilterOrder // {{{ class UFO_ProfileUpdate /** Sorts users based on last profile update */ -class UFO_ProfileUpdate extends UserFilterOrder +class UFO_ProfileUpdate extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { @@ -1476,7 +1594,7 @@ class UFO_ProfileUpdate extends UserFilterOrder // {{{ class UFO_Death /** Sorts users based on death date */ -class UFO_Death extends UserFilterOrder +class UFO_Death extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { @@ -1489,7 +1607,7 @@ class UFO_Death extends UserFilterOrder // {{{ class UFO_Uid /** Sorts users based on their uid */ -class UFO_Uid extends UserFilterOrder +class UFO_Uid extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { @@ -1502,7 +1620,7 @@ class UFO_Uid extends UserFilterOrder // {{{ class UFO_Hruid /** Sorts users based on their hruid */ -class UFO_Hruid extends UserFilterOrder +class UFO_Hruid extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { @@ -1515,7 +1633,7 @@ class UFO_Hruid extends UserFilterOrder // {{{ class UFO_Pid /** Sorts users based on their pid */ -class UFO_Pid extends UserFilterOrder +class UFO_Pid extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { @@ -1528,7 +1646,7 @@ class UFO_Pid extends UserFilterOrder // {{{ class UFO_Hrpid /** Sorts users based on their hrpid */ -class UFO_Hrpid extends UserFilterOrder +class UFO_Hrpid extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { @@ -1577,7 +1695,7 @@ class UFO_Hrpid extends UserFilterOrder * when referring to the joined table. * * For example, if data from profile_job must be available to filter results, - * the UFC object will call $uf-addJobFilter(), which will set the 'with_pj' var and + * the UFC object will call $uf-addJobFilter(), which will set the 'with_pj' var and * return 'pj', the short name to use when referring to profile_job; when building * the query, calling the jobJoins function will return an array containing a single * row: @@ -1597,9 +1715,13 @@ class UserFilter extends PlFilter private $root; private $sort = array(); + private $grouper = null; private $query = null; private $orderby = null; + // Store the current 'search' visibility. + private $profile_visibility = null; + private $lastusercount = null; private $lastprofilecount = null; @@ -1620,7 +1742,7 @@ class UserFilter extends PlFilter } } if (!is_null($sort)) { - if ($sort instanceof UserFilterOrder) { + if ($sort instanceof PlFilterOrder) { $this->addSort($sort); } else if (is_array($sort)) { foreach ($sort as $s) { @@ -1628,6 +1750,29 @@ class UserFilter extends PlFilter } } } + + // This will set the visibility to the default correct level. + $this->profile_visibility = new ProfileVisibility(); + } + + public function getVisibilityLevels() + { + return $this->profile_visibility->levels(); + } + + public function getVisibilityLevel() + { + return $this->profile_visibility->level(); + } + + public function restrictVisibilityTo($level) + { + $this->profile_visibility->setLevel($level); + } + + public function getVisibilityCondition($field) + { + return $field . ' IN ' . XDB::formatArray($this->getVisibilityLevels()); } private function buildQuery() @@ -1668,13 +1813,49 @@ class UserFilter extends PlFilter } } + public function hasGroups() + { + return $this->grouper != null; + } + + public function getGroups() + { + return $this->getUIDGroups(); + } + + public function getUIDGroups() + { + $this->requireAccounts(); + $this->buildQuery(); + $token = $this->grouper->getGroupToken($this); + + $groups = XDB::fetchAllRow('SELECT ' . $token . ', COUNT(a.uid) + ' . $this->query . ' + GROUP BY ' . $token, + 0); + return $groups; + } + + public function getPIDGroups() + { + $this->requireProfiles(); + $this->buildQuery(); + $token = $this->grouper->getGroupToken($this); + + $groups = XDB::fetchAllRow('SELECT ' . $token . ', COUNT(p.pid) + ' . $this->query . ' + GROUP BY ' . $token, + 0); + return $groups; + } + private function getUIDList($uids = null, PlLimit &$limit) { $this->requireAccounts(); $this->buildQuery(); $lim = $limit->getSql(); $cond = ''; - if (!is_null($uids)) { + if (!empty($uids)) { $cond = XDB::format(' AND a.uid IN {?}', $uids); } $fetched = XDB::fetchColumn('SELECT SQL_CALC_FOUND_ROWS a.uid @@ -1908,6 +2089,10 @@ class UserFilter extends PlFilter public function addSort(PlFilterOrder &$sort) { + if (count($this->sort) == 0 && $sort instanceof PlFilterGroupableOrder) + { + $this->grouper = $sort; + } $this->sort[] = $sort; $this->orderby = null; } @@ -1979,11 +2164,21 @@ class UserFilter extends PlFilter $this->with_accounts = true; } + public function accountsRequired() + { + return $this->with_accounts; + } + public function requireProfiles() { $this->with_profiles = true; } + public function profilesRequired() + { + return $this->with_profiles; + } + protected function accountJoins() { $joins = array(); @@ -2285,7 +2480,7 @@ class UserFilter extends PlFilter if (!is_array($key)) { $key = array($key); } - $joins['e' . $sub] = PlSqlJoin::left('emails', '$ME.uid = $UID AND $ME.flags != \'filter\' + $joins['e' . $sub] = PlSqlJoin::left('emails', '$ME.uid = $UID AND $ME.flags != \'filter\' AND $ME.email IN {?}', $key); } } @@ -2300,7 +2495,7 @@ class UserFilter extends PlFilter if (!is_array($key)) { $key = array($key); } - $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\') + $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\') AND $ME.alias IN {?}', $key); } } @@ -2430,6 +2625,7 @@ class UserFilter extends PlFilter * pjsse => profile_job_subsector_enum * pjssse => profile_job_subsubsector_enum * pja => profile_job_alternates + * pjt => profile_job_terms */ private $with_pj = false; private $with_pje = false; @@ -2437,6 +2633,7 @@ class UserFilter extends PlFilter private $with_pjsse = false; private $with_pjssse = false; private $with_pja = false; + private $with_pjt = 0; public function addJobFilter() { @@ -2470,6 +2667,21 @@ class UserFilter extends PlFilter } } + /** + * Adds a filter on job terms of profile. + * @param $nb the number of job terms to use + * @return an array of the fields to filter (one for each term). + */ + public function addJobTermsFilter($nb = 1) + { + $this->with_pjt = $nb; + $jobtermstable = array(); + for ($i = 1; $i <= $nb; ++$i) { + $jobtermstable[] = 'pjtr_'.$i; + } + return $jobtermstable; + } + protected function jobJoins() { $joins = array(); @@ -2491,6 +2703,12 @@ class UserFilter extends PlFilter if ($this->with_pja) { $joins['pja'] = PlSqlJoin::left('profile_job_alternates', '$ME.subsubsectorid = pj.subsubsectorid'); } + if ($this->with_pjt > 0) { + for ($i = 1; $i <= $this->with_pjt; ++$i) { + $joins['pjt_'.$i] = PlSqlJoin::left('profile_job_term', '$ME.pid = $PID'); + $joins['pjtr_'.$i] = PlSqlJoin::left('profile_job_term_relation', '$ME.jtid_2 = pjt_'.$i.'.jtid'); + } + } return $joins; } @@ -2559,14 +2777,20 @@ class UserFilter extends PlFilter */ private $pms = array(); - const MENTOR_EXPERTISE = 1; - const MENTOR_COUNTRY = 2; - const MENTOR_SECTOR = 3; + private $mjtr = false; + const MENTOR = 1; + const MENTOR_EXPERTISE = 2; + const MENTOR_COUNTRY = 3; + const MENTOR_SECTOR = 4; + const MENTOR_TERM = 5; public function addMentorFilter($type) { $this->requireAccounts(); switch($type) { + case self::MENTOR: + $this->pms['pm'] = 'profile_mentor'; + return 'pm'; case self::MENTOR_EXPERTISE: $this->pms['pme'] = 'profile_mentor'; return 'pme'; @@ -2576,6 +2800,10 @@ class UserFilter extends PlFilter case self::MENTOR_SECTOR: $this->pms['pms'] = 'profile_mentor_sector'; return 'pms'; + case self::MENTOR_TERM: + $this->pms['pmt'] = 'profile_mentor_term'; + $this->mjtr = true; + return 'mjtr'; default: Platal::page()->killError("Undefined mentor filter."); } @@ -2587,6 +2815,9 @@ class UserFilter extends PlFilter foreach ($this->pms as $sub => $tab) { $joins[$sub] = PlSqlJoin::left($tab, '$ME.pid = $PID'); } + if ($this->mjtr) { + $joins['mjtr'] = PlSqlJoin::left('profile_job_term_relation', '$ME.jtid_2 = pmt.jtid'); + } return $joins; } @@ -2678,6 +2909,7 @@ class UserFilter extends PlFilter { $this->requireProfiles(); $this->with_photo = true; + return 'photo'; } protected function photoJoins() @@ -2727,6 +2959,11 @@ class ProfileFilter extends UserFilter { return $this->getTotalProfileCount(); } + + public function getGroups() + { + return $this->getPIDGroups(); + } } // }}}