diff --git a/src/applications/people/cache/PhabricatorUserPreferencesCacheType.php b/src/applications/people/cache/PhabricatorUserPreferencesCacheType.php index 1e8999837a..015a24cb0f 100644 --- a/src/applications/people/cache/PhabricatorUserPreferencesCacheType.php +++ b/src/applications/people/cache/PhabricatorUserPreferencesCacheType.php @@ -1,65 +1,85 @@ getViewer(); $users = mpull($users, null, 'getPHID'); $user_phids = array_keys($users); $preferences = id(new PhabricatorUserPreferencesQuery()) ->setViewer($viewer) ->withUserPHIDs($user_phids) ->execute(); + $preferences = mpull($preferences, null, 'getUserPHID'); + + // If some users don't have settings of their own yet, we need to load + // the global default settings to generate caches for them. + if (count($preferences) < count($user_phids)) { + $global = id(new PhabricatorUserPreferencesQuery()) + ->setViewer($viewer) + ->withBuiltinKeys( + array( + PhabricatorUserPreferences::BUILTIN_GLOBAL_DEFAULT, + )) + ->executeOne(); + } else { + $global = null; + } $all_settings = PhabricatorSetting::getAllSettings(); $settings = array(); - foreach ($preferences as $preference) { - $user_phid = $preference->getUserPHID(); + foreach ($users as $user_phid => $user) { + $preference = idx($preferences, $user_phid, $global); + + if (!$preference) { + continue; + } + foreach ($all_settings as $key => $setting) { $value = $preference->getSettingValue($key); // As an optimization, we omit the value from the cache if it is // exactly the same as the hardcoded default. $default_value = id(clone $setting) - ->setViewer($users[$user_phid]) + ->setViewer($user) ->getSettingDefaultValue(); if ($value === $default_value) { continue; } $settings[$user_phid][$key] = $value; } } $results = array(); foreach ($user_phids as $user_phid) { $value = idx($settings, $user_phid, array()); $results[$user_phid] = phutil_json_encode($value); } return $results; } } diff --git a/src/applications/settings/storage/PhabricatorUserPreferences.php b/src/applications/settings/storage/PhabricatorUserPreferences.php index 31719c8195..b03365bd32 100644 --- a/src/applications/settings/storage/PhabricatorUserPreferences.php +++ b/src/applications/settings/storage/PhabricatorUserPreferences.php @@ -1,242 +1,256 @@ true, self::CONFIG_SERIALIZATION => array( 'preferences' => self::SERIALIZATION_JSON, ), self::CONFIG_COLUMN_SCHEMA => array( 'userPHID' => 'phid?', 'builtinKey' => 'text32?', ), self::CONFIG_KEY_SCHEMA => array( 'key_user' => array( 'columns' => array('userPHID'), 'unique' => true, ), 'key_builtin' => array( 'columns' => array('builtinKey'), 'unique' => true, ), ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorUserPreferencesPHIDType::TYPECONST); } public function getPreference($key, $default = null) { return idx($this->preferences, $key, $default); } public function setPreference($key, $value) { $this->preferences[$key] = $value; return $this; } public function unsetPreference($key) { unset($this->preferences[$key]); return $this; } public function getDefaultValue($key) { if ($this->defaultSettings) { return $this->defaultSettings->getSettingValue($key); } $setting = self::getSettingObject($key); if (!$setting) { return null; } $setting = id(clone $setting) ->setViewer($this->getUser()); return $setting->getSettingDefaultValue(); } public function getSettingValue($key) { if (array_key_exists($key, $this->preferences)) { return $this->preferences[$key]; } return $this->getDefaultValue($key); } private static function getSettingObject($key) { $settings = PhabricatorSetting::getAllSettings(); return idx($settings, $key); } public function attachDefaultSettings(PhabricatorUserPreferences $settings) { $this->defaultSettings = $settings; return $this; } public function attachUser(PhabricatorUser $user = null) { $this->user = $user; return $this; } public function getUser() { return $this->assertAttached($this->user); } public function hasManagedUser() { $user_phid = $this->getUserPHID(); if (!$user_phid) { return false; } $user = $this->getUser(); if ($user->getIsSystemAgent() || $user->getIsMailingList()) { return true; } return false; } /** * Load or create a preferences object for the given user. * * @param PhabricatorUser User to load or create preferences for. */ public static function loadUserPreferences(PhabricatorUser $user) { $preferences = id(new PhabricatorUserPreferencesQuery()) ->setViewer($user) ->withUsers(array($user)) ->executeOne(); if ($preferences) { return $preferences; } - return id(new self()) + $preferences = id(new self()) ->setUserPHID($user->getPHID()) ->attachUser($user); + + $global = id(new PhabricatorUserPreferencesQuery()) + ->setViewer($user) + ->withBuiltinKeys( + array( + self::BUILTIN_GLOBAL_DEFAULT, + )) + ->executeOne(); + + if ($global) { + $preferences->attachDefaultSettings($global); + } + + return $preferences; } public function newTransaction($key, $value) { $setting_property = PhabricatorUserPreferencesTransaction::PROPERTY_SETTING; $xaction_type = PhabricatorUserPreferencesTransaction::TYPE_SETTING; return id(clone $this->getApplicationTransactionTemplate()) ->setTransactionType($xaction_type) ->setMetadataValue($setting_property, $key) ->setNewValue($value); } public function getEditURI() { if ($this->getUser()) { return '/settings/user/'.$this->getUser()->getUsername().'/'; } else { return '/settings/builtin/'.$this->getBuiltinKey().'/'; } } public function getDisplayName() { if ($this->getBuiltinKey()) { return pht('Global Default Settings'); } return pht('Personal Settings'); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: $user_phid = $this->getUserPHID(); if ($user_phid) { return $user_phid; } return PhabricatorPolicies::getMostOpenPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: if ($this->hasManagedUser()) { return PhabricatorPolicies::POLICY_ADMIN; } $user_phid = $this->getUserPHID(); if ($user_phid) { return $user_phid; } return PhabricatorPolicies::POLICY_ADMIN; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { if ($this->hasManagedUser()) { if ($viewer->getIsAdmin()) { return true; } } return false; } public function describeAutomaticCapability($capability) { return null; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->delete(); } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new PhabricatorUserPreferencesEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new PhabricatorUserPreferencesTransaction(); } public function willRenderTimeline( PhabricatorApplicationTransactionView $timeline, AphrontRequest $request) { return $timeline; } }