Drop NAF_code when inappropriate.
[platal.git] / classes / userfilter.php
index d95e9d8..dffa8a7 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /***************************************************************************
- *  Copyright (C) 2003-2011 Polytechnique.org                              *
+ *  Copyright (C) 2003-2014 Polytechnique.org                              *
  *  http://opensource.polytechnique.org/                                   *
  *                                                                         *
  *  This program is free software; you can redistribute it and/or modify   *
@@ -85,7 +85,9 @@ class UserFilter extends PlFilter
     private $orderby = null;
 
     // Store the current 'search' visibility.
-    private $profile_visibility = null;
+    private $visibility = null;
+    // If the 'search' visibility should be based on a DB field instead.
+    private $visibility_field = null;
 
     private $lastusercount = null;
     private $lastprofilecount = null;
@@ -117,27 +119,50 @@ class UserFilter extends PlFilter
         }
 
         // This will set the visibility to the default correct level.
-        $this->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()
@@ -967,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;
     }
 
@@ -1368,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
@@ -1400,5 +1480,5 @@ class ProfileFilter extends UserFilter
 }
 // }}}
 
-// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker fenc=utf-8:
 ?>