diff --git a/resources/sql/autopatches/20160605.user.01.prefnulluser.sql b/resources/sql/autopatches/20160605.user.01.prefnulluser.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20160605.user.01.prefnulluser.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_user.user_preferences + CHANGE userPHID userPHID VARBINARY(64); diff --git a/resources/sql/autopatches/20160605.user.02.prefbuiltin.sql b/resources/sql/autopatches/20160605.user.02.prefbuiltin.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20160605.user.02.prefbuiltin.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_user.user_preferences + ADD builtinKey VARCHAR(32) COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20160605.user.03.builtinunique.sql b/resources/sql/autopatches/20160605.user.03.builtinunique.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20160605.user.03.builtinunique.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_user.user_preferences + ADD UNIQUE KEY `key_builtin` (builtinKey); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3393,6 +3393,7 @@ 'PhabricatorSettingsDeveloperPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsDeveloperPanelGroup.php', 'PhabricatorSettingsEditEngine' => 'applications/settings/editor/PhabricatorSettingsEditEngine.php', 'PhabricatorSettingsEmailPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsEmailPanelGroup.php', + 'PhabricatorSettingsListController' => 'applications/settings/controller/PhabricatorSettingsListController.php', 'PhabricatorSettingsLogsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsLogsPanelGroup.php', 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', 'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php', @@ -3650,6 +3651,7 @@ 'PhabricatorUserPreferencesEditor' => 'applications/settings/editor/PhabricatorUserPreferencesEditor.php', 'PhabricatorUserPreferencesPHIDType' => 'applications/settings/phid/PhabricatorUserPreferencesPHIDType.php', 'PhabricatorUserPreferencesQuery' => 'applications/settings/query/PhabricatorUserPreferencesQuery.php', + 'PhabricatorUserPreferencesSearchEngine' => 'applications/settings/query/PhabricatorUserPreferencesSearchEngine.php', 'PhabricatorUserPreferencesTransaction' => 'applications/settings/storage/PhabricatorUserPreferencesTransaction.php', 'PhabricatorUserPreferencesTransactionQuery' => 'applications/settings/query/PhabricatorUserPreferencesTransactionQuery.php', 'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php', @@ -8170,6 +8172,7 @@ 'PhabricatorSettingsDeveloperPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsEditEngine' => 'PhabricatorEditEngine', 'PhabricatorSettingsEmailPanelGroup' => 'PhabricatorSettingsPanelGroup', + 'PhabricatorSettingsListController' => 'PhabricatorController', 'PhabricatorSettingsLogsPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsMainController' => 'PhabricatorController', 'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', @@ -8470,6 +8473,7 @@ 'PhabricatorUserPreferencesEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorUserPreferencesPHIDType' => 'PhabricatorPHIDType', 'PhabricatorUserPreferencesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorUserPreferencesSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorUserPreferencesTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorUserPreferencesTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorUserProfile' => 'PhabricatorUserDAO', diff --git a/src/applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php b/src/applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php --- a/src/applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php +++ b/src/applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php @@ -3,7 +3,11 @@ final class PhabricatorConduitTokensSettingsPanel extends PhabricatorSettingsPanel { - public function isEditableByAdministrators() { + public function isManagementPanel() { + if ($this->getUser()->getIsMailingList()) { + return false; + } + return true; } @@ -20,10 +24,6 @@ } public function isEnabled() { - if ($this->getUser()->getIsMailingList()) { - return false; - } - return true; } diff --git a/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php b/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php --- a/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php +++ b/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php @@ -2,7 +2,11 @@ final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel { - public function isEditableByAdministrators() { + public function isManagementPanel() { + if ($this->getUser()->getIsMailingList()) { + return false; + } + return true; } @@ -19,10 +23,6 @@ } public function isEnabled() { - if ($this->getUser()->getIsMailingList()) { - return false; - } - return PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth'); } diff --git a/src/applications/people/cache/PhabricatorUserPreferencesCacheType.php b/src/applications/people/cache/PhabricatorUserPreferencesCacheType.php --- a/src/applications/people/cache/PhabricatorUserPreferencesCacheType.php +++ b/src/applications/people/cache/PhabricatorUserPreferencesCacheType.php @@ -24,14 +24,34 @@ public function newValueForUsers($key, array $users) { $viewer = $this->getViewer(); - $user_phids = mpull($users, 'getPHID'); + $users = mpull($users, null, 'getPHID'); + $user_phids = array_keys($users); $preferences = id(new PhabricatorUserPreferencesQuery()) ->setViewer($viewer) ->withUserPHIDs($user_phids) ->execute(); - $settings = mpull($preferences, 'getPreferences', 'getUserPHID'); + $all_settings = PhabricatorSetting::getAllSettings(); + + $settings = array(); + foreach ($preferences as $preference) { + $user_phid = $preference->getUserPHID(); + 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]) + ->getSettingDefaultValue(); + if ($value === $default_value) { + continue; + } + + $settings[$user_phid][$key] = $value; + } + } $results = array(); foreach ($user_phids as $user_phid) { diff --git a/src/applications/people/controller/PhabricatorPeopleProfileManageController.php b/src/applications/people/controller/PhabricatorPeopleProfileManageController.php --- a/src/applications/people/controller/PhabricatorPeopleProfileManageController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileManageController.php @@ -124,7 +124,7 @@ ->setName(pht('Edit Settings')) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit) - ->setHref('/settings/'.$user->getID().'/')); + ->setHref('/settings/user/'.$user->getUsername().'/')); if ($user->getIsAdmin()) { $empower_icon = 'fa-arrow-circle-o-down'; diff --git a/src/applications/settings/application/PhabricatorSettingsApplication.php b/src/applications/settings/application/PhabricatorSettingsApplication.php --- a/src/applications/settings/application/PhabricatorSettingsApplication.php +++ b/src/applications/settings/application/PhabricatorSettingsApplication.php @@ -27,12 +27,14 @@ } public function getRoutes() { + $panel_pattern = '(?:page/(?P[^/]+)/(?:(?Psaved)/)?)?'; + return array( '/settings/' => array( - '(?:(?P\d+)/)?'. - '(?:panel/(?P(?P[^/]+))/'. - '(?:(?Psaved)/)?'. - ')?' + $this->getQueryRoutePattern() => 'PhabricatorSettingsListController', + 'user/(?P[^/]+)/'.$panel_pattern + => 'PhabricatorSettingsMainController', + 'builtin/(?Pglobal)/'.$panel_pattern => 'PhabricatorSettingsMainController', 'adjust/' => 'PhabricatorSettingsAdjustController', 'timezone/(?P[^/]+)/' diff --git a/src/applications/settings/controller/PhabricatorSettingsListController.php b/src/applications/settings/controller/PhabricatorSettingsListController.php new file mode 100644 --- /dev/null +++ b/src/applications/settings/controller/PhabricatorSettingsListController.php @@ -0,0 +1,48 @@ +getViewer(); + + // If the viewer isn't an administrator, just redirect them to their own + // settings panel. + if (!$viewer->getIsAdmin()) { + $settings_uri = '/user/'.$viewer->getUsername().'/'; + $settings_uri = $this->getApplicationURI($settings_uri); + return id(new AphrontRedirectResponse()) + ->setURI($settings_uri); + } + + return id(new PhabricatorUserPreferencesSearchEngine()) + ->setController($this) + ->buildResponse(); + } + + protected function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); + + $viewer = $this->getViewer(); + if ($viewer->getIsAdmin()) { + $builtin_global = PhabricatorUserPreferences::BUILTIN_GLOBAL_DEFAULT; + $global_settings = id(new PhabricatorUserPreferencesQuery()) + ->setViewer($viewer) + ->withBuiltinKeys( + array( + $builtin_global, + )) + ->execute(); + if (!$global_settings) { + $action = id(new PHUIListItemView()) + ->setName(pht('Create Global Defaults')) + ->setHref('/settings/builtin/'.$builtin_global.'/') + ->setIcon('fa-plus'); + $crumbs->addAction($action); + } + } + + return $crumbs; + } + +} diff --git a/src/applications/settings/controller/PhabricatorSettingsMainController.php b/src/applications/settings/controller/PhabricatorSettingsMainController.php --- a/src/applications/settings/controller/PhabricatorSettingsMainController.php +++ b/src/applications/settings/controller/PhabricatorSettingsMainController.php @@ -4,6 +4,8 @@ extends PhabricatorController { private $user; + private $builtinKey; + private $preferences; private function getUser() { return $this->user; @@ -21,15 +23,39 @@ return ($viewer_phid == $user_phid); } + private function isTemplate() { + return ($this->builtinKey !== null); + } + public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); - $id = $request->getURIData('id'); - $key = $request->getURIData('key'); - if ($id) { + $username = $request->getURIData('username'); + $builtin = $request->getURIData('builtin'); + + $key = $request->getURIData('pageKey'); + + if ($builtin) { + $this->builtinKey = $builtin; + + $preferences = id(new PhabricatorUserPreferencesQuery()) + ->setViewer($viewer) + ->withBuiltinKeys(array($builtin)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$preferences) { + $preferences = id(new PhabricatorUserPreferences()) + ->attachUser(null) + ->setBuiltinKey($builtin); + } + } else { $user = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) - ->withIDs(array($id)) + ->withUsernames(array($username)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, @@ -41,19 +67,27 @@ return new Aphront404Response(); } + $preferences = PhabricatorUserPreferences::loadUserPreferences($user); $this->user = $user; - } else { - $this->user = $viewer; } - $panels = $this->buildPanels(); + if (!$preferences) { + return new Aphront404Response(); + } + + PhabricatorPolicyFilter::requireCapability( + $viewer, + $preferences, + PhabricatorPolicyCapability::CAN_EDIT); + + $this->preferences = $preferences; + + $panels = $this->buildPanels($preferences); $nav = $this->renderSideNav($panels); $key = $nav->selectFilter($key, head($panels)->getPanelKey()); $panel = $panels[$key] - ->setUser($this->getUser()) - ->setViewer($viewer) ->setController($this) ->setNavigation($nav); @@ -79,22 +113,30 @@ } - private function buildPanels() { + private function buildPanels(PhabricatorUserPreferences $preferences) { $viewer = $this->getViewer(); $panels = PhabricatorSettingsPanel::getAllDisplayPanels(); $result = array(); foreach ($panels as $key => $panel) { $panel - ->setViewer($viewer) - ->setUser($this->user); + ->setPreferences($preferences) + ->setViewer($viewer); + + if ($this->user) { + $panel->setUser($this->user); + } if (!$panel->isEnabled()) { continue; } - if (!$this->isSelf()) { - if (!$panel->isEditableByAdministrators()) { + if ($this->isTemplate()) { + if (!$panel->isTemplatePanel()) { + continue; + } + } else { + if (!$this->isSelf() && !$panel->isManagementPanel()) { continue; } } @@ -120,10 +162,11 @@ private function renderSideNav(array $panels) { $nav = new AphrontSideNavFilterView(); - if ($this->isSelf()) { - $base_uri = 'panel/'; + if ($this->isTemplate()) { + $base_uri = 'builtin/'.$this->builtinKey.'/page/'; } else { - $base_uri = $this->getUser()->getID().'/panel/'; + $user = $this->getUser(); + $base_uri = 'user/'.$user->getUsername().'/page/'; } $nav->setBaseURI(new PhutilURI($this->getApplicationURI($base_uri))); @@ -143,8 +186,11 @@ } public function buildApplicationMenu() { - $panels = $this->buildPanels(); - return $this->renderSideNav($panels)->getMenu(); + if ($this->preferences) { + $panels = $this->buildPanels($this->preferences); + return $this->renderSideNav($panels)->getMenu(); + } + return parent::buildApplicationMenu(); } protected function buildApplicationCrumbs() { diff --git a/src/applications/settings/editor/PhabricatorSettingsEditEngine.php b/src/applications/settings/editor/PhabricatorSettingsEditEngine.php --- a/src/applications/settings/editor/PhabricatorSettingsEditEngine.php +++ b/src/applications/settings/editor/PhabricatorSettingsEditEngine.php @@ -67,7 +67,15 @@ } protected function getObjectEditShortText($object) { - return pht('Edit Settings'); + if (!$object->getUser()) { + return pht('Global Defaults'); + } else { + if ($this->getIsSelfEdit()) { + return pht('Personal Settings'); + } else { + return pht('Account Settings'); + } + } } protected function getObjectCreateShortText() { @@ -85,7 +93,7 @@ } protected function getEditorURI() { - return '/settings/edit/'; + throw new PhutilMethodNotImplementedException(); } protected function getObjectCreateCancelURI($object) { @@ -93,15 +101,22 @@ } protected function getObjectViewURI($object) { - // TODO: This isn't correct... - return '/settings/user/'.$this->getViewer()->getUsername().'/'; + return $object->getEditURI(); } protected function getCreateNewObjectPolicy() { return PhabricatorPolicies::POLICY_ADMIN; } + public function getEffectiveObjectEditDoneURI($object) { + return parent::getEffectiveObjectViewURI($object).'saved/'; + } + public function getEffectiveObjectEditCancelURI($object) { + if (!$object->getUser()) { + return '/settings/'; + } + if ($this->getIsSelfEdit()) { return null; } diff --git a/src/applications/settings/panel/PhabricatorAccountSettingsPanel.php b/src/applications/settings/panel/PhabricatorAccountSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorAccountSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorAccountSettingsPanel.php @@ -13,7 +13,11 @@ return PhabricatorSettingsAccountPanelGroup::PANELGROUPKEY; } - public function isEditableByAdministrators() { + public function isManagementPanel() { + return true; + } + + public function isTemplatePanel() { return true; } diff --git a/src/applications/settings/panel/PhabricatorActivitySettingsPanel.php b/src/applications/settings/panel/PhabricatorActivitySettingsPanel.php --- a/src/applications/settings/panel/PhabricatorActivitySettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorActivitySettingsPanel.php @@ -2,10 +2,6 @@ final class PhabricatorActivitySettingsPanel extends PhabricatorSettingsPanel { - public function isEditableByAdministrators() { - return true; - } - public function getPanelKey() { return 'activity'; } @@ -61,4 +57,8 @@ return array($panel, $pager_box); } + public function isManagementPanel() { + return true; + } + } diff --git a/src/applications/settings/panel/PhabricatorConpherencePreferencesSettingsPanel.php b/src/applications/settings/panel/PhabricatorConpherencePreferencesSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorConpherencePreferencesSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorConpherencePreferencesSettingsPanel.php @@ -13,4 +13,8 @@ return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; } + public function isTemplatePanel() { + return true; + } + } diff --git a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php @@ -13,7 +13,11 @@ return PhabricatorSettingsAccountPanelGroup::PANELGROUPKEY; } - public function isEditableByAdministrators() { + public function isManagementPanel() { + return true; + } + + public function isTemplatePanel() { return true; } diff --git a/src/applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php b/src/applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php @@ -27,7 +27,7 @@ public function processRequest(AphrontRequest $request) { $viewer = $this->getViewer(); - $preferences = $this->loadTargetPreferences(); + $preferences = $this->getPreferences(); $notifications_key = PhabricatorDesktopNotificationsSetting::SETTINGKEY; $notifications_value = $preferences->getSettingValue($notifications_key); diff --git a/src/applications/settings/panel/PhabricatorDeveloperPreferencesSettingsPanel.php b/src/applications/settings/panel/PhabricatorDeveloperPreferencesSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorDeveloperPreferencesSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorDeveloperPreferencesSettingsPanel.php @@ -13,4 +13,8 @@ return PhabricatorSettingsDeveloperPanelGroup::PANELGROUPKEY; } + public function isTemplatePanel() { + return true; + } + } diff --git a/src/applications/settings/panel/PhabricatorDiffPreferencesSettingsPanel.php b/src/applications/settings/panel/PhabricatorDiffPreferencesSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorDiffPreferencesSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorDiffPreferencesSettingsPanel.php @@ -13,4 +13,8 @@ return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; } + public function isTemplatePanel() { + return true; + } + } diff --git a/src/applications/settings/panel/PhabricatorDisplayPreferencesSettingsPanel.php b/src/applications/settings/panel/PhabricatorDisplayPreferencesSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorDisplayPreferencesSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorDisplayPreferencesSettingsPanel.php @@ -13,4 +13,8 @@ return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; } + public function isTemplatePanel() { + return true; + } + } diff --git a/src/applications/settings/panel/PhabricatorEditEngineSettingsPanel.php b/src/applications/settings/panel/PhabricatorEditEngineSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorEditEngineSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorEditEngineSettingsPanel.php @@ -7,13 +7,13 @@ $viewer = $this->getViewer(); $user = $this->getUser(); - if ($user->getPHID() === $viewer->getPHID()) { + if ($user && ($user->getPHID() === $viewer->getPHID())) { $is_self = true; } else { $is_self = false; } - if ($user->getPHID()) { + if ($user && $user->getPHID()) { $profile_uri = '/people/manage/'.$user->getID().'/'; } else { $profile_uri = null; @@ -26,7 +26,7 @@ ->setIsSelfEdit($is_self) ->setProfileURI($profile_uri); - $preferences = $this->loadTargetPreferences(); + $preferences = $this->getPreferences(); $engine->setTargetObject($preferences); @@ -47,7 +47,7 @@ $key = $this->getPanelKey(); $label = $this->getPanelName(); - $panel_uri = $this->getPanelURI().'saved/'; + $panel_uri = $this->getPanelURI(); return id(new PhabricatorEditPage()) ->setKey($key) diff --git a/src/applications/settings/panel/PhabricatorEmailDeliverySettingsPanel.php b/src/applications/settings/panel/PhabricatorEmailDeliverySettingsPanel.php --- a/src/applications/settings/panel/PhabricatorEmailDeliverySettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorEmailDeliverySettingsPanel.php @@ -13,7 +13,7 @@ return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY; } - public function isEditableByAdministrators() { + public function isManagementPanel() { if ($this->getUser()->getIsMailingList()) { return true; } @@ -21,4 +21,8 @@ return false; } + public function isTemplatePanel() { + return true; + } + } diff --git a/src/applications/settings/panel/PhabricatorEmailFormatSettingsPanel.php b/src/applications/settings/panel/PhabricatorEmailFormatSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorEmailFormatSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorEmailFormatSettingsPanel.php @@ -13,7 +13,7 @@ return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY; } - public function isEditableByAdministrators() { + public function isManagementPanel() { if ($this->getUser()->getIsMailingList()) { return true; } @@ -21,4 +21,8 @@ return false; } + public function isTemplatePanel() { + return true; + } + } diff --git a/src/applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php b/src/applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php @@ -15,7 +15,7 @@ return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY; } - public function isEditableByAdministrators() { + public function isManagementPanel() { if ($this->getUser()->getIsMailingList()) { return true; } @@ -23,11 +23,15 @@ return false; } + public function isTemplatePanel() { + return true; + } + public function processRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $user = $this->getUser(); - $preferences = $this->loadTargetPreferences(); + $preferences = $this->getPreferences(); $value_email = PhabricatorEmailTagsSetting::VALUE_EMAIL; @@ -137,7 +141,7 @@ return $form_box; } - private function getAllEditorsWithTags(PhabricatorUser $user) { + private function getAllEditorsWithTags(PhabricatorUser $user = null) { $editors = id(new PhutilClassMapQuery()) ->setAncestorClass('PhabricatorApplicationTransactionEditor') ->setFilterMethod('getMailTagsMap') @@ -146,7 +150,7 @@ foreach ($editors as $key => $editor) { // Remove editors for applications which are not installed. $app = $editor->getEditorApplicationClass(); - if ($app !== null) { + if ($app !== null && $user !== null) { if (!PhabricatorApplication::isClassInstalledForViewer($app, $user)) { unset($editors[$key]); } diff --git a/src/applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php b/src/applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php @@ -15,9 +15,13 @@ return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; } + public function isTemplatePanel() { + return true; + } + public function processRequest(AphrontRequest $request) { $viewer = $this->getViewer(); - $preferences = $this->loadTargetPreferences(); + $preferences = $this->getPreferences(); $pinned_key = PhabricatorPinnedApplicationsSetting::SETTINGKEY; $pinned = $preferences->getSettingValue($pinned_key); diff --git a/src/applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php b/src/applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php @@ -2,7 +2,11 @@ final class PhabricatorSSHKeysSettingsPanel extends PhabricatorSettingsPanel { - public function isEditableByAdministrators() { + public function isManagementPanel() { + if ($this->getUser()->getIsMailingList()) { + return false; + } + return true; } @@ -18,14 +22,6 @@ return PhabricatorSettingsAuthenticationPanelGroup::PANELGROUPKEY; } - public function isEnabled() { - if ($this->getUser()->getIsMailingList()) { - return false; - } - - return true; - } - public function processRequest(AphrontRequest $request) { $user = $this->getUser(); $viewer = $request->getUser(); diff --git a/src/applications/settings/panel/PhabricatorSettingsPanel.php b/src/applications/settings/panel/PhabricatorSettingsPanel.php --- a/src/applications/settings/panel/PhabricatorSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorSettingsPanel.php @@ -18,6 +18,7 @@ private $controller; private $navigation; private $overrideURI; + private $preferences; public function setUser(PhabricatorUser $user) { $this->user = $user; @@ -60,6 +61,15 @@ return $this->navigation; } + public function setPreferences(PhabricatorUserPreferences $preferences) { + $this->preferences = $preferences; + return $this; + } + + public function getPreferences() { + return $this->preferences; + } + final public static function getAllPanels() { $panels = id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) @@ -145,13 +155,24 @@ /** - * Return true if this panel is available to administrators while editing - * system agent accounts. + * Return true if this panel is available to administrators while managing + * bot and mailing list accounts. * - * @return bool True to enable edit by administrators. + * @return bool True to enable management on behalf of accounts. * @task config */ - public function isEditableByAdministrators() { + public function isManagementPanel() { + return false; + } + + + /** + * Return true if this panel is available while editing settings templates. + * + * @return bool True to allow editing in templates. + * @task config + */ + public function isTemplatePanel() { return false; } @@ -194,11 +215,13 @@ $key = $this->getPanelKey(); $key = phutil_escape_uri($key); - if ($this->getUser()->getPHID() != $this->getViewer()->getPHID()) { - $user_id = $this->getUser()->getID(); - return "/settings/{$user_id}/panel/{$key}/{$path}"; + $user = $this->getUser(); + if ($user) { + $username = $user->getUsername(); + return "/settings/user/{$username}/page/{$key}/{$path}"; } else { - return "/settings/panel/{$key}/{$path}"; + $builtin = $this->getPreferences()->getBuiltinKey(); + return "/settings/builtin/{$builtin}/page/{$key}/{$path}"; } } @@ -217,20 +240,6 @@ ->addString($this->getPanelName()); } - protected function loadTargetPreferences() { - $viewer = $this->getViewer(); - $user = $this->getUser(); - - $preferences = PhabricatorUserPreferences::loadUserPreferences($user); - - PhabricatorPolicyFilter::requireCapability( - $viewer, - $preferences, - PhabricatorPolicyCapability::CAN_EDIT); - - return $preferences; - } - protected function newDialog() { return $this->getController()->newDialog(); } diff --git a/src/applications/settings/query/PhabricatorUserPreferencesQuery.php b/src/applications/settings/query/PhabricatorUserPreferencesQuery.php --- a/src/applications/settings/query/PhabricatorUserPreferencesQuery.php +++ b/src/applications/settings/query/PhabricatorUserPreferencesQuery.php @@ -6,6 +6,8 @@ private $ids; private $phids; private $userPHIDs; + private $builtinKeys; + private $hasUserPHID; private $users = array(); public function withIDs(array $ids) { @@ -18,6 +20,11 @@ return $this; } + public function withHasUserPHID($is_user) { + $this->hasUserPHID = $is_user; + return $this; + } + public function withUserPHIDs(array $phids) { $this->userPHIDs = $phids; return $this; @@ -30,6 +37,11 @@ return $this; } + public function withBuiltinKeys(array $keys) { + $this->builtinKeys = $keys; + return $this; + } + public function newResultObject() { return new PhabricatorUserPreferences(); } @@ -64,6 +76,7 @@ $users = array(); } + $need_global = array(); foreach ($prefs as $key => $pref) { $user_phid = $pref->getUserPHID(); if (!$user_phid) { @@ -71,6 +84,8 @@ continue; } + $need_global[] = $pref; + $user = idx($users, $user_phid); if (!$user) { $this->didRejectResult($pref); @@ -81,6 +96,23 @@ $pref->attachUser($user); } + // If we loaded any user preferences, load the global defaults and attach + // them if they exist. + if ($need_global) { + $global = id(new self()) + ->setViewer($this->getViewer()) + ->withBuiltinKeys( + array( + PhabricatorUserPreferences::BUILTIN_GLOBAL_DEFAULT, + )) + ->executeOne(); + if ($global) { + foreach ($need_global as $pref) { + $pref->attachDefaultSettings($global); + } + } + } + return $prefs; } @@ -108,6 +140,25 @@ $this->userPHIDs); } + if ($this->builtinKeys !== null) { + $where[] = qsprintf( + $conn, + 'builtinKey IN (%Ls)', + $this->builtinKeys); + } + + if ($this->hasUserPHID !== null) { + if ($this->hasUserPHID) { + $where[] = qsprintf( + $conn, + 'userPHID IS NOT NULL'); + } else { + $where[] = qsprintf( + $conn, + 'userPHID IS NULL'); + } + } + return $where; } diff --git a/src/applications/settings/query/PhabricatorUserPreferencesSearchEngine.php b/src/applications/settings/query/PhabricatorUserPreferencesSearchEngine.php new file mode 100644 --- /dev/null +++ b/src/applications/settings/query/PhabricatorUserPreferencesSearchEngine.php @@ -0,0 +1,86 @@ +withHasUserPHID(false); + } + + protected function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); + + return $query; + } + + protected function buildCustomSearchFields() { + return array(); + } + + protected function getURI($path) { + return '/settings/list/'.$path; + } + + protected function getBuiltinQueryNames() { + $names = array( + 'all' => pht('All Settings'), + ); + + return $names; + } + + public function buildSavedQueryFromBuiltin($query_key) { + $query = $this->newSavedQuery(); + $query->setQueryKey($query_key); + + switch ($query_key) { + case 'all': + return $query; + } + + return parent::buildSavedQueryFromBuiltin($query_key); + } + + protected function renderResultList( + array $settings, + PhabricatorSavedQuery $query, + array $handles) { + assert_instances_of($settings, 'PhabricatorUserPreferences'); + + $viewer = $this->requireViewer(); + + $list = id(new PHUIObjectItemListView()) + ->setViewer($viewer); + foreach ($settings as $setting) { + + $item = id(new PHUIObjectItemView()) + ->setHeader($setting->getDisplayName()) + ->setHref($setting->getEditURI()) + ->setImageURI(PhabricatorUser::getDefaultProfileImageURI()) + ->setIcon('fa-globe') + ->addAttribute(pht('Edit global default settings for all users.')); + + $list->addItem($item); + } + + $list->addItem( + id(new PHUIObjectItemView()) + ->setHeader(pht('Personal Account Settings')) + ->addAttribute(pht('Edit settings for your personal account.')) + ->setImageURI($viewer->getProfileImageURI()) + ->setHref('/settings/user/'.$viewer->getUsername().'/')); + + return id(new PhabricatorApplicationSearchResultView()) + ->setObjectList($list); + } + +} diff --git a/src/applications/settings/setting/PhabricatorPinnedApplicationsSetting.php b/src/applications/settings/setting/PhabricatorPinnedApplicationsSetting.php --- a/src/applications/settings/setting/PhabricatorPinnedApplicationsSetting.php +++ b/src/applications/settings/setting/PhabricatorPinnedApplicationsSetting.php @@ -12,6 +12,11 @@ public function getSettingDefaultValue() { $viewer = $this->getViewer(); + // If we're editing a template, just show every available application. + if (!$viewer) { + $viewer = PhabricatorUser::getOmnipotentUser(); + } + $applications = id(new PhabricatorApplicationQuery()) ->setViewer($viewer) ->withInstalled(true) diff --git a/src/applications/settings/setting/PhabricatorSetting.php b/src/applications/settings/setting/PhabricatorSetting.php --- a/src/applications/settings/setting/PhabricatorSetting.php +++ b/src/applications/settings/setting/PhabricatorSetting.php @@ -2,14 +2,17 @@ abstract class PhabricatorSetting extends Phobject { - private $viewer; + private $viewer = false; - public function setViewer(PhabricatorUser $viewer) { + public function setViewer(PhabricatorUser $viewer = null) { $this->viewer = $viewer; return $this; } public function getViewer() { + if ($this->viewer === false) { + throw new PhutilInvalidStateException('setViewer'); + } return $this->viewer; } diff --git a/src/applications/settings/storage/PhabricatorUserPreferences.php b/src/applications/settings/storage/PhabricatorUserPreferences.php --- a/src/applications/settings/storage/PhabricatorUserPreferences.php +++ b/src/applications/settings/storage/PhabricatorUserPreferences.php @@ -7,10 +7,14 @@ PhabricatorDestructibleInterface, PhabricatorApplicationTransactionInterface { + const BUILTIN_GLOBAL_DEFAULT = 'global'; + protected $userPHID; protected $preferences = array(); + protected $builtinKey; private $user = self::ATTACHABLE; + private $defaultSettings; protected function getConfiguration() { return array( @@ -18,11 +22,19 @@ self::CONFIG_SERIALIZATION => array( 'preferences' => self::SERIALIZATION_JSON, ), + self::CONFIG_COLUMN_SCHEMA => array( + 'userPHID' => 'phid?', + 'builtinKey' => 'text32?', + ), self::CONFIG_KEY_SCHEMA => array( - 'userPHID' => array( + 'key_user' => array( 'columns' => array('userPHID'), 'unique' => true, ), + 'key_builtin' => array( + 'columns' => array('builtinKey'), + 'unique' => true, + ), ), ) + parent::getConfiguration(); } @@ -47,6 +59,10 @@ } public function getDefaultValue($key) { + if ($this->defaultSettings) { + return $this->defaultSettings->getSettingValue($key); + } + $setting = self::getSettingObject($key); if (!$setting) { @@ -64,9 +80,6 @@ return $this->preferences[$key]; } - // TODO: If this setting set inherits from another preference set, - // we would look it up here. - return $this->getDefaultValue($key); } @@ -75,6 +88,11 @@ 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; @@ -127,6 +145,21 @@ ->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 )----------------------------------------- */ diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -532,6 +532,10 @@ return $this->getObjectViewURI($object); } + public function getEffectiveObjectEditDoneURI($object) { + return $this->getEffectiveObjectViewURI($object); + } + public function getEffectiveObjectEditCancelURI($object) { $page = $this->getSelectedPage(); if ($page) { @@ -1169,7 +1173,7 @@ $object, array $xactions) { return id(new AphrontRedirectResponse()) - ->setURI($this->getEffectiveObjectViewURI($object)); + ->setURI($this->getEffectiveObjectEditDoneURI($object)); } private function buildEditForm($object, array $fields) {