X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=classes%2Fuserfilter.php;h=f07e2a84eaa1c1b24a326f3e6efd0aef83491f6f;hb=57fc676c5dfbf964c21a6b1a1f6e5abcb08e0b42;hp=1fd27a66717253c19800928835f6e7b138e204da;hpb=5e1513f67936a6c6866113d260746711af4ea2ee;p=platal.git diff --git a/classes/userfilter.php b/classes/userfilter.php index 1fd27a6..f07e2a8 100644 --- a/classes/userfilter.php +++ b/classes/userfilter.php @@ -1,6 +1,6 @@ profile_visibility = new ProfileVisibility(); + $this->visibility = Visibility::defaultForRead(); } - 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); + /** Get the SQL condition to filter by visibility level for a field. + * This will return a SQL condition which evaluates to True if the given + * field display level is available from the current access level. + * @param $field Name of the field holding a display level + * @return string SQL condition, properly escaped, for that field. + */ + public function getVisibilityConditionForField($field) + { + if ($this->visibility_field != null) { + // Use enum 'bit' arithmetic. + // Display levels are ordered as 'hidden, private, ax, public' + // Thus ax > private. + // The $sub.display_level cell will contain the 'most private' display + // level available based on $field. If it is 'ax' and $field is + // 'private','ax' <= 'private' is false. + $sub = $this->addVisibilityFieldFilter($this->visibility_field); + return $sub . '.best_display_level + 0 <= 0 + ' . $field; + } else { + $sub = $this->addVisibilityAbsoluteFilter($this->visibility->level()); + return $sub . '.best_display_level + 0 <= 0 + ' . $field; + } } - public function getVisibilityCondition($field) + /** Get the SQL condition to filter by a given visibility level. + * @param $level One of Visibility::EXPORT_* + * @return string A SQL condition, properly escaped, which evaluates to 'true' if the $level can be viewed with the current access level. + */ + public function getVisibilityConditionAbsolute($level) { - return $field . ' IN ' . XDB::formatArray($this->getVisibilityLevels()); + if ($this->visibility_field != null) { + // The $sub.display_levels cell will contain allowed display levels + // for an access level of $this->visibility_field. + $sub = $this->addVisibilityFieldFilter($this->visibility_field); + return XDB::format('FIND_IN_SET({?}, ' . $sub . '.display_levels)', $level); + } else { + if ($this->visibility->isVisible($level)) { + return 'TRUE'; + } else { + return 'FALSE'; + } + } } private function buildQuery() @@ -214,7 +239,7 @@ class UserFilter extends PlFilter return $groups; } - private function getUIDList($uids = null, PlLimit &$limit) + private function getUIDList($uids = null, PlLimit $limit) { $this->requireAccounts(); $this->buildQuery(); @@ -232,7 +257,7 @@ class UserFilter extends PlFilter return $fetched; } - private function getPIDList($pids = null, PlLimit &$limit) + private function getPIDList($pids = null, PlLimit $limit) { $this->requireProfiles(); $this->buildQuery(); @@ -260,7 +285,7 @@ class UserFilter extends PlFilter /** Check that the user match the given rule. */ - public function checkUser(PlUser &$user) + public function checkUser(PlUser $user) { $this->requireAccounts(); $this->buildQuery(); @@ -272,7 +297,7 @@ class UserFilter extends PlFilter /** Check that the profile match the given rule. */ - public function checkProfile(Profile &$profile) + public function checkProfile(Profile $profile) { $this->requireProfiles(); $this->buildQuery(); @@ -543,12 +568,12 @@ class UserFilter extends PlFilter static public function sortByName() { - return array(new UFO_Name(Profile::LASTNAME), new UFO_Name(Profile::FIRSTNAME)); + return array(new UFO_Name()); } static public function sortByPromo() { - return array(new UFO_Promo(), new UFO_Name(Profile::LASTNAME), new UFO_Name(Profile::FIRSTNAME)); + return array(new UFO_Promo(), new UFO_Name()); } static private function getDBSuffix($string) @@ -676,44 +701,6 @@ class UserFilter extends PlFilter return $joins; } - /** NAMES - */ - - static public function assertName($name) - { - if (!DirEnum::getID(DirEnum::NAMETYPES, $name)) { - Platal::page()->kill('Invalid name type: ' . $name); - } - } - - private $pn = array(); - public function addNameFilter($type, $variant = null) - { - $this->requireProfiles(); - if (!is_null($variant)) { - $ft = $type . '_' . $variant; - } else { - $ft = $type; - } - $sub = '_' . $ft; - self::assertName($ft); - - if (!is_null($variant) && $variant == 'other') { - $sub .= $this->option++; - } - $this->pn[$sub] = DirEnum::getID(DirEnum::NAMETYPES, $ft); - return $sub; - } - - protected function nameJoins() - { - $joins = array(); - foreach ($this->pn as $sub => $type) { - $joins['pn' . $sub] = PlSqlJoin::left('profile_name', '$ME.pid = $PID AND $ME.typeid = {?}', $type); - } - return $joins; - } - /** NAMETOKENS */ private $name_tokens = array(); @@ -764,9 +751,9 @@ class UserFilter extends PlFilter /** EDUCATION */ - const GRADE_ING = 'Ing.'; - const GRADE_PHD = 'PhD'; - const GRADE_MST = 'M%'; + const GRADE_ING = Profile::DEGREE_X; + const GRADE_PHD = Profile::DEGREE_D; + const GRADE_MST = Profile::DEGREE_M; static public function isGrade($grade) { return ($grade !== 0) && ($grade == self::GRADE_ING || $grade == self::GRADE_PHD || $grade == self::GRADE_MST); @@ -813,7 +800,7 @@ class UserFilter extends PlFilter foreach ($this->pepe as $grade => $sub) { if ($this->isGrade($grade)) { $joins['pe' . $sub] = PlSqlJoin::left('profile_education', '$ME.eduid = pee.id AND $ME.pid = $PID'); - $joins['pede' . $sub] = PlSqlJoin::inner('profile_education_degree_enum', '$ME.id = pe' . $sub . '.degreeid AND $ME.abbreviation LIKE {?}', $grade); + $joins['pede' . $sub] = PlSqlJoin::inner('profile_education_degree_enum', '$ME.id = pe' . $sub . '.degreeid AND $ME.degree LIKE {?}', $grade); } else { $joins['pe' . $sub] = PlSqlJoin::left('profile_education', '$ME.pid = $PID'); $joins['pee' . $sub] = PlSqlJoin::inner('profile_education_enum', '$ME.id = pe' . $sub . '.eduid'); @@ -846,6 +833,15 @@ class UserFilter extends PlFilter return $sub; } + private $gpfm = array(); + public function addGroupFormerMemberFilter() + { + $this->requireAccounts(); + $sub = '_' . $this->option++; + $this->gpfm[] = $sub; + return $sub; + } + protected function groupJoins() { $joins = array(); @@ -860,6 +856,29 @@ class UserFilter extends PlFilter $joins['gpm' . $sub] = PlSqlJoin::left('group_members', '$ME.uid = $UID AND $ME.asso_id = gpa' . $sub . '.id'); } } + foreach ($this->gpfm as $sub) { + $joins['gpfm' . $sub] = PlSqlJoin::left('group_former_members', '$ME.uid = $UID'); + } + return $joins; + } + + /** NLS + */ + private $nls = array(); + public function addNewsLetterFilter($nlid) + { + $this->requireAccounts(); + $sub = 'nl_' . $nlid; + $this->nls[$nlid] = $sub; + return $sub; + } + + protected function newsLetterJoins() + { + $joins = array(); + foreach ($this->nls as $key => $sub) { + $joins[$sub] = PlSqlJoin::left('newsletter_ins', '$ME.nlid = {?} AND $ME.uid = $UID', $key); + } return $joins; } @@ -894,74 +913,78 @@ class UserFilter extends PlFilter /** EMAILS */ - private $e = array(); + private $ra = array(); + /** Allows filtering by redirection. + * @param $email If null, enable a left join on the email redirection table + * (email_redirect_account); otherwise, perform a left join on users having + * that email as a redirection. + * @return Suffix to use to access the adequate table. + */ public function addEmailRedirectFilter($email = null) { $this->requireAccounts(); - return $this->register_optional($this->e, $email); - } - - private $ve = array(); - public function addVirtualEmailFilter($email = null) + return $this->register_optional($this->ra, $email); + } + + const ALIAS_BEST = 'bestalias'; + const ALIAS_FORLIFE = 'forlife'; + const ALIAS_AUXILIARY = 'alias_aux'; + private $sa = array(); + /** Allows filtering by source email. + * @param $email If null, enable a left join on the email source table + * (email_source_account); otherwise, perform a left join on users having + * that email as a source email. + * @return Suffix to use to access the adequate table. + */ + public function addAliasFilter($email = null) { - $this->addAliasFilter(self::ALIAS_FORLIFE); - return $this->register_optional($this->ve, $email); + $this->requireAccounts(); + return $this->register_optional($this->sa, $email); } - const ALIAS_BEST = 'bestalias'; - const ALIAS_FORLIFE = 'forlife'; - private $al = array(); - public function addAliasFilter($alias = null) + private $with_rf = false; + /** Allows filtering by active redirection. + * @return Suffix to use to access the adequate table. + */ + public function addActiveEmailRedirectFilter($email = null) { $this->requireAccounts(); - return $this->register_optional($this->al, $alias); + $this->with_rf = true; } protected function emailJoins() { global $globals; $joins = array(); - foreach ($this->e as $sub=>$key) { - if (is_null($key)) { - $joins['e' . $sub] = PlSqlJoin::left('emails', '$ME.uid = $UID AND $ME.flags != \'filter\''); + foreach ($this->ra as $sub => $redirections) { + if (is_null($redirections)) { + $joins['ra' . $sub] = PlSqlJoin::left('email_redirect_account', '$ME.uid = $UID AND $ME.type != \'imap\''); } else { - if (!is_array($key)) { - $key = array($key); + if (!is_array($redirections)) { + $key = array($redirections); } - $joins['e' . $sub] = PlSqlJoin::left('emails', '$ME.uid = $UID AND $ME.flags != \'filter\' - AND $ME.email IN {?}', $key); + $joins['ra' . $sub] = PlSqlJoin::left('email_redirect_account', '$ME.uid = $UID AND $ME.type != \'imap\' + AND $ME.redirect IN {?}', $redirections); } } - foreach ($this->al as $sub=>$key) { - if (is_null($key)) { - $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\')'); - } else if ($key == self::ALIAS_BEST) { - $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\') AND FIND_IN_SET(\'bestalias\', $ME.flags)'); - } else if ($key == self::ALIAS_FORLIFE) { - $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type = \'a_vie\''); + foreach ($this->sa as $sub => $emails) { + if (is_null($emails)) { + $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID'); + } else if ($sub == self::ALIAS_BEST) { + $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID AND FIND_IN_SET(\'bestalias\', $ME.flags)'); + } else if ($sub == self::ALIAS_FORLIFE) { + $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID AND $ME.type = \'forlife\''); + } else if ($sub == self::ALIAS_AUXILIARY) { + $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID AND $ME.type = \'alias_aux\''); } else { - if (!is_array($key)) { - $key = array($key); + if (!is_array($emails)) { + $key = array($emails); } - $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\') - AND $ME.alias IN {?}', $key); + $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID AND $ME.email IN {?}', $emails); } } - foreach ($this->ve as $sub=>$key) { - if (is_null($key)) { - $joins['v' . $sub] = PlSqlJoin::left('virtual', '$ME.type = \'user\''); - } else { - if (!is_array($key)) { - $key = array($key); - } - $joins['v' . $sub] = PlSqlJoin::left('virtual', '$ME.type = \'user\' AND $ME.alias IN {?}', $key); - } - $joins['vr' . $sub] = PlSqlJoin::left('virtual_redirect', - '$ME.vid = v' . $sub . '.vid - AND ($ME.redirect IN (CONCAT(al_forlife.alias, \'@\', {?}), - CONCAT(al_forlife.alias, \'@\', {?}), - a.email))', - $globals->mail->domain, $globals->mail->domain2); + if ($this->with_rf) { + $joins['rf'] = PlSqlJoin::left('email_redirect_account', '$ME.uid = $UID AND $ME.type != \'imap\' AND $ME.flags = \'active\'');; } return $joins; } @@ -969,44 +992,28 @@ class UserFilter extends PlFilter /** ADDRESSES */ - private $with_pa = false; - public function addAddressFilter() + private $types = array(); + public function addAddressFilter($type) { $this->requireProfiles(); $this->with_pa = true; - return 'pa'; - } - - private $with_pac = false; - public function addAddressCountryFilter() - { - $this->requireProfiles(); - $this->addAddressFilter(); - $this->with_pac = true; - return 'gc'; - } - private $with_pal = false; - public function addAddressLocalityFilter() - { - $this->requireProfiles(); - $this->addAddressFilter(); - $this->with_pal = true; - return 'gl'; + $sub = '_' . $this->option++; + $this->types[$type] = $sub; + return $sub; } protected function addressJoins() { $joins = array(); - if ($this->with_pa) { - $joins['pa'] = PlSqlJoin::left('profile_addresses', '$ME.pid = $PID'); - } - if ($this->with_pac) { - $joins['gc'] = PlSqlJoin::left('geoloc_countries', '$ME.iso_3166_1_a2 = pa.countryID'); - } - if ($this->with_pal) { - $joins['gl'] = PlSqlJoin::left('geoloc_localities', '$ME.id = pa.localityID'); + foreach ($this->types as $type => $sub) { + $joins['pa' . $sub] = PlSqlJoin::inner('profile_addresses', '$ME.pid = $PID'); + $joins['pac' . $sub] = PlSqlJoin::inner('profile_addresses_components', + '$ME.pid = pa' . $sub . '.pid AND $ME.jobid = pa' . $sub . '.jobid AND $ME.groupid = pa' . $sub . '.groupid AND $ME.type = pa' . $sub . '.type AND $ME.id = pa' . $sub . '.id'); + $joins['pace' . $sub] = PlSqlJoin::inner('profile_addresses_components_enum', + '$ME.id = pac' . $sub . '.component_id AND FIND_IN_SET({?}, $ME.types)', $type); } + return $joins; } @@ -1022,10 +1029,10 @@ class UserFilter extends PlFilter $this->requireProfiles(); $this->pc = true; if ($type == UFC_Corps::CURRENT) { - $pce['pcec'] = 'current_corpsid'; + $this->pce['pcec'] = 'current_corpsid'; return 'pcec'; } else if ($type == UFC_Corps::ORIGIN) { - $pce['pceo'] = 'original_corpsid'; + $this->pce['pceo'] = 'original_corpsid'; return 'pceo'; } } @@ -1177,6 +1184,37 @@ class UserFilter extends PlFilter return $joins; } + /** DELTATEN + */ + private $dts = array(); + const DELTATEN = 1; + const DELTATEN_MESSAGE = 2; + // TODO: terms + + public function addDeltaTenFilter($type) + { + $this->requireProfiles(); + switch ($type) { + case self::DELTATEN: + $this->dts['pdt'] = 'profile_deltaten'; + return 'pdt'; + case self::DELTATEN_MESSAGE: + $this->dts['pdtm'] = 'profile_deltaten'; + return 'pdtm'; + default: + Platal::page()->killError("Undefined DeltaTen filter."); + } + } + + protected function deltatenJoins() + { + $joins = array(); + foreach ($this->dts as $sub => $tab) { + $joins[$sub] = PlSqlJoin::left($tab, '$ME.pid = $PID'); + } + return $joins; + } + /** MENTORING */ @@ -1189,7 +1227,7 @@ class UserFilter extends PlFilter public function addMentorFilter($type) { - $this->requireAccounts(); + $this->requireProfiles(); switch($type) { case self::MENTOR: $this->pms['pm'] = 'profile_mentor'; @@ -1339,6 +1377,77 @@ class UserFilter extends PlFilter return array(); } } + + + /** PARTNER SHARING + */ + + // Lists partner shortnames in use, as a $partner_shortname => true map. + private $ppss = array(); + + /** Add a filter on user having settings for a given partner. + * @param $partner_id the ID of the partner + * @return the name of the table to use in joins (e.g ppss_$partner_id). + */ + public function addPartnerSharingFilter($partner_id) + { + $this->requireProfiles(); + $sub = "ppss_" . $partner_id; + $this->ppss[$sub] = $partner_id; + return $sub; + } + + protected function partnerSharingJoins() + { + $joins = array(); + foreach ($this->ppss as $sub => $partner_id) { + $joins[$sub] = PlSqlJoin::left('profile_partnersharing_settings', '$ME.pid = $PID AND $ME.partner_id = {?} AND $ME.sharing_level != \'none\'', $partner_id); + } + return $joins; + } + + public function restrictVisibilityForPartner($partner_id) + { + $sub = $this->addPartnerSharingFilter($partner_id); + $this->visibility_field = $sub . '.sharing_level'; + } + + /** VISIBILITY + */ + private $vlevels = array(); + private $vfields = array(); + public function addVisibilityAbsoluteFilter($level) + { + $sub = 'pvel_' . $level; + $this->vlevels[$level] = $sub; + return $sub; + } + + public function addVisibilityFieldFilter($field) + { + $sub = 'pvef_' . self::getDBSuffix($field); + $this->vfields[$field] = $sub; + return $sub; + } + + /** Since this method might perform inner joins on tables which have been + * joined previously (e.g when using addVisibilityFieldFilter), it has to + * come after the Joins() methods for those tables. + * This is due to the implementation logic for discovering joins and the + * ordering used by PHP introspection. + */ + protected function visibilityJoins() + { + $joins = array(); + foreach ($this->vlevels as $level => $sub) { + $joins[$sub] = PlSqlJoin::inner('profile_visibility_enum', '$ME.access_level = {?}', $level); + } + foreach ($this->vfields as $field => $sub) { + $joins[$sub] = PlSqlJoin::inner('profile_visibility_enum', '$ME.access_level = ' . $field); + } + return $joins; + } + } // }}} // {{{ class ProfileFilter