@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator

Allow administrators to configure global default settings

Summary:
Ref T4103. This just adds a single global default setting group, not full profiles.

Primarily, I'm not sure how administrators are supposed to set profiles for users, since most ways user accounts get created don't really support setting roles.. When we figure that out, it should be reasonably easy to extend this. There also isn't much of a need for this now, since pretty much everyone just wants to turn off mail.

Test Plan:
- Edited personal settings.
- Edited global settings.
- Edited a bot's settings.
- Tried to edit some other user's settings.
- Saw defaults change appropriately as I edited global and personal settings.

{F1677266}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4103

Differential Revision: https://secure.phabricator.com/D16048

+464 -96
+2
resources/sql/autopatches/20160605.user.01.prefnulluser.sql
··· 1 + ALTER TABLE {$NAMESPACE}_user.user_preferences 2 + CHANGE userPHID userPHID VARBINARY(64);
+2
resources/sql/autopatches/20160605.user.02.prefbuiltin.sql
··· 1 + ALTER TABLE {$NAMESPACE}_user.user_preferences 2 + ADD builtinKey VARCHAR(32) COLLATE {$COLLATE_TEXT};
+2
resources/sql/autopatches/20160605.user.03.builtinunique.sql
··· 1 + ALTER TABLE {$NAMESPACE}_user.user_preferences 2 + ADD UNIQUE KEY `key_builtin` (builtinKey);
+4
src/__phutil_library_map__.php
··· 3393 3393 'PhabricatorSettingsDeveloperPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsDeveloperPanelGroup.php', 3394 3394 'PhabricatorSettingsEditEngine' => 'applications/settings/editor/PhabricatorSettingsEditEngine.php', 3395 3395 'PhabricatorSettingsEmailPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsEmailPanelGroup.php', 3396 + 'PhabricatorSettingsListController' => 'applications/settings/controller/PhabricatorSettingsListController.php', 3396 3397 'PhabricatorSettingsLogsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsLogsPanelGroup.php', 3397 3398 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', 3398 3399 'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php', ··· 3650 3651 'PhabricatorUserPreferencesEditor' => 'applications/settings/editor/PhabricatorUserPreferencesEditor.php', 3651 3652 'PhabricatorUserPreferencesPHIDType' => 'applications/settings/phid/PhabricatorUserPreferencesPHIDType.php', 3652 3653 'PhabricatorUserPreferencesQuery' => 'applications/settings/query/PhabricatorUserPreferencesQuery.php', 3654 + 'PhabricatorUserPreferencesSearchEngine' => 'applications/settings/query/PhabricatorUserPreferencesSearchEngine.php', 3653 3655 'PhabricatorUserPreferencesTransaction' => 'applications/settings/storage/PhabricatorUserPreferencesTransaction.php', 3654 3656 'PhabricatorUserPreferencesTransactionQuery' => 'applications/settings/query/PhabricatorUserPreferencesTransactionQuery.php', 3655 3657 'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php', ··· 8170 8172 'PhabricatorSettingsDeveloperPanelGroup' => 'PhabricatorSettingsPanelGroup', 8171 8173 'PhabricatorSettingsEditEngine' => 'PhabricatorEditEngine', 8172 8174 'PhabricatorSettingsEmailPanelGroup' => 'PhabricatorSettingsPanelGroup', 8175 + 'PhabricatorSettingsListController' => 'PhabricatorController', 8173 8176 'PhabricatorSettingsLogsPanelGroup' => 'PhabricatorSettingsPanelGroup', 8174 8177 'PhabricatorSettingsMainController' => 'PhabricatorController', 8175 8178 'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', ··· 8470 8473 'PhabricatorUserPreferencesEditor' => 'PhabricatorApplicationTransactionEditor', 8471 8474 'PhabricatorUserPreferencesPHIDType' => 'PhabricatorPHIDType', 8472 8475 'PhabricatorUserPreferencesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 8476 + 'PhabricatorUserPreferencesSearchEngine' => 'PhabricatorApplicationSearchEngine', 8473 8477 'PhabricatorUserPreferencesTransaction' => 'PhabricatorApplicationTransaction', 8474 8478 'PhabricatorUserPreferencesTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 8475 8479 'PhabricatorUserProfile' => 'PhabricatorUserDAO',
+5 -5
src/applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php
··· 3 3 final class PhabricatorConduitTokensSettingsPanel 4 4 extends PhabricatorSettingsPanel { 5 5 6 - public function isEditableByAdministrators() { 6 + public function isManagementPanel() { 7 + if ($this->getUser()->getIsMailingList()) { 8 + return false; 9 + } 10 + 7 11 return true; 8 12 } 9 13 ··· 20 24 } 21 25 22 26 public function isEnabled() { 23 - if ($this->getUser()->getIsMailingList()) { 24 - return false; 25 - } 26 - 27 27 return true; 28 28 } 29 29
+5 -5
src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php
··· 2 2 3 3 final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel { 4 4 5 - public function isEditableByAdministrators() { 5 + public function isManagementPanel() { 6 + if ($this->getUser()->getIsMailingList()) { 7 + return false; 8 + } 9 + 6 10 return true; 7 11 } 8 12 ··· 19 23 } 20 24 21 25 public function isEnabled() { 22 - if ($this->getUser()->getIsMailingList()) { 23 - return false; 24 - } 25 - 26 26 return PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth'); 27 27 } 28 28
+22 -2
src/applications/people/cache/PhabricatorUserPreferencesCacheType.php
··· 24 24 public function newValueForUsers($key, array $users) { 25 25 $viewer = $this->getViewer(); 26 26 27 - $user_phids = mpull($users, 'getPHID'); 27 + $users = mpull($users, null, 'getPHID'); 28 + $user_phids = array_keys($users); 28 29 29 30 $preferences = id(new PhabricatorUserPreferencesQuery()) 30 31 ->setViewer($viewer) 31 32 ->withUserPHIDs($user_phids) 32 33 ->execute(); 33 34 34 - $settings = mpull($preferences, 'getPreferences', 'getUserPHID'); 35 + $all_settings = PhabricatorSetting::getAllSettings(); 36 + 37 + $settings = array(); 38 + foreach ($preferences as $preference) { 39 + $user_phid = $preference->getUserPHID(); 40 + foreach ($all_settings as $key => $setting) { 41 + $value = $preference->getSettingValue($key); 42 + 43 + // As an optimization, we omit the value from the cache if it is 44 + // exactly the same as the hardcoded default. 45 + $default_value = id(clone $setting) 46 + ->setViewer($users[$user_phid]) 47 + ->getSettingDefaultValue(); 48 + if ($value === $default_value) { 49 + continue; 50 + } 51 + 52 + $settings[$user_phid][$key] = $value; 53 + } 54 + } 35 55 36 56 $results = array(); 37 57 foreach ($user_phids as $user_phid) {
+1 -1
src/applications/people/controller/PhabricatorPeopleProfileManageController.php
··· 124 124 ->setName(pht('Edit Settings')) 125 125 ->setDisabled(!$can_edit) 126 126 ->setWorkflow(!$can_edit) 127 - ->setHref('/settings/'.$user->getID().'/')); 127 + ->setHref('/settings/user/'.$user->getUsername().'/')); 128 128 129 129 if ($user->getIsAdmin()) { 130 130 $empower_icon = 'fa-arrow-circle-o-down';
+6 -4
src/applications/settings/application/PhabricatorSettingsApplication.php
··· 27 27 } 28 28 29 29 public function getRoutes() { 30 + $panel_pattern = '(?:page/(?P<pageKey>[^/]+)/(?:(?P<formSaved>saved)/)?)?'; 31 + 30 32 return array( 31 33 '/settings/' => array( 32 - '(?:(?P<id>\d+)/)?'. 33 - '(?:panel/(?P<pageKey>(?P<key>[^/]+))/'. 34 - '(?:(?P<formSaved>saved)/)?'. 35 - ')?' 34 + $this->getQueryRoutePattern() => 'PhabricatorSettingsListController', 35 + 'user/(?P<username>[^/]+)/'.$panel_pattern 36 + => 'PhabricatorSettingsMainController', 37 + 'builtin/(?P<builtin>global)/'.$panel_pattern 36 38 => 'PhabricatorSettingsMainController', 37 39 'adjust/' => 'PhabricatorSettingsAdjustController', 38 40 'timezone/(?P<offset>[^/]+)/'
+48
src/applications/settings/controller/PhabricatorSettingsListController.php
··· 1 + <?php 2 + 3 + final class PhabricatorSettingsListController 4 + extends PhabricatorController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $this->getViewer(); 8 + 9 + // If the viewer isn't an administrator, just redirect them to their own 10 + // settings panel. 11 + if (!$viewer->getIsAdmin()) { 12 + $settings_uri = '/user/'.$viewer->getUsername().'/'; 13 + $settings_uri = $this->getApplicationURI($settings_uri); 14 + return id(new AphrontRedirectResponse()) 15 + ->setURI($settings_uri); 16 + } 17 + 18 + return id(new PhabricatorUserPreferencesSearchEngine()) 19 + ->setController($this) 20 + ->buildResponse(); 21 + } 22 + 23 + protected function buildApplicationCrumbs() { 24 + $crumbs = parent::buildApplicationCrumbs(); 25 + 26 + $viewer = $this->getViewer(); 27 + if ($viewer->getIsAdmin()) { 28 + $builtin_global = PhabricatorUserPreferences::BUILTIN_GLOBAL_DEFAULT; 29 + $global_settings = id(new PhabricatorUserPreferencesQuery()) 30 + ->setViewer($viewer) 31 + ->withBuiltinKeys( 32 + array( 33 + $builtin_global, 34 + )) 35 + ->execute(); 36 + if (!$global_settings) { 37 + $action = id(new PHUIListItemView()) 38 + ->setName(pht('Create Global Defaults')) 39 + ->setHref('/settings/builtin/'.$builtin_global.'/') 40 + ->setIcon('fa-plus'); 41 + $crumbs->addAction($action); 42 + } 43 + } 44 + 45 + return $crumbs; 46 + } 47 + 48 + }
+65 -19
src/applications/settings/controller/PhabricatorSettingsMainController.php
··· 4 4 extends PhabricatorController { 5 5 6 6 private $user; 7 + private $builtinKey; 8 + private $preferences; 7 9 8 10 private function getUser() { 9 11 return $this->user; ··· 21 23 return ($viewer_phid == $user_phid); 22 24 } 23 25 26 + private function isTemplate() { 27 + return ($this->builtinKey !== null); 28 + } 29 + 24 30 public function handleRequest(AphrontRequest $request) { 25 31 $viewer = $this->getViewer(); 26 - $id = $request->getURIData('id'); 27 - $key = $request->getURIData('key'); 32 + 33 + $username = $request->getURIData('username'); 34 + $builtin = $request->getURIData('builtin'); 35 + 36 + $key = $request->getURIData('pageKey'); 28 37 29 - if ($id) { 38 + if ($builtin) { 39 + $this->builtinKey = $builtin; 40 + 41 + $preferences = id(new PhabricatorUserPreferencesQuery()) 42 + ->setViewer($viewer) 43 + ->withBuiltinKeys(array($builtin)) 44 + ->requireCapabilities( 45 + array( 46 + PhabricatorPolicyCapability::CAN_VIEW, 47 + PhabricatorPolicyCapability::CAN_EDIT, 48 + )) 49 + ->executeOne(); 50 + if (!$preferences) { 51 + $preferences = id(new PhabricatorUserPreferences()) 52 + ->attachUser(null) 53 + ->setBuiltinKey($builtin); 54 + } 55 + } else { 30 56 $user = id(new PhabricatorPeopleQuery()) 31 57 ->setViewer($viewer) 32 - ->withIDs(array($id)) 58 + ->withUsernames(array($username)) 33 59 ->requireCapabilities( 34 60 array( 35 61 PhabricatorPolicyCapability::CAN_VIEW, ··· 41 67 return new Aphront404Response(); 42 68 } 43 69 70 + $preferences = PhabricatorUserPreferences::loadUserPreferences($user); 44 71 $this->user = $user; 45 - } else { 46 - $this->user = $viewer; 47 72 } 48 73 49 - $panels = $this->buildPanels(); 74 + if (!$preferences) { 75 + return new Aphront404Response(); 76 + } 77 + 78 + PhabricatorPolicyFilter::requireCapability( 79 + $viewer, 80 + $preferences, 81 + PhabricatorPolicyCapability::CAN_EDIT); 82 + 83 + $this->preferences = $preferences; 84 + 85 + $panels = $this->buildPanels($preferences); 50 86 $nav = $this->renderSideNav($panels); 51 87 52 88 $key = $nav->selectFilter($key, head($panels)->getPanelKey()); 53 89 54 90 $panel = $panels[$key] 55 - ->setUser($this->getUser()) 56 - ->setViewer($viewer) 57 91 ->setController($this) 58 92 ->setNavigation($nav); 59 93 ··· 79 113 80 114 } 81 115 82 - private function buildPanels() { 116 + private function buildPanels(PhabricatorUserPreferences $preferences) { 83 117 $viewer = $this->getViewer(); 84 118 $panels = PhabricatorSettingsPanel::getAllDisplayPanels(); 85 119 86 120 $result = array(); 87 121 foreach ($panels as $key => $panel) { 88 122 $panel 89 - ->setViewer($viewer) 90 - ->setUser($this->user); 123 + ->setPreferences($preferences) 124 + ->setViewer($viewer); 125 + 126 + if ($this->user) { 127 + $panel->setUser($this->user); 128 + } 91 129 92 130 if (!$panel->isEnabled()) { 93 131 continue; 94 132 } 95 133 96 - if (!$this->isSelf()) { 97 - if (!$panel->isEditableByAdministrators()) { 134 + if ($this->isTemplate()) { 135 + if (!$panel->isTemplatePanel()) { 136 + continue; 137 + } 138 + } else { 139 + if (!$this->isSelf() && !$panel->isManagementPanel()) { 98 140 continue; 99 141 } 100 142 } ··· 120 162 private function renderSideNav(array $panels) { 121 163 $nav = new AphrontSideNavFilterView(); 122 164 123 - if ($this->isSelf()) { 124 - $base_uri = 'panel/'; 165 + if ($this->isTemplate()) { 166 + $base_uri = 'builtin/'.$this->builtinKey.'/page/'; 125 167 } else { 126 - $base_uri = $this->getUser()->getID().'/panel/'; 168 + $user = $this->getUser(); 169 + $base_uri = 'user/'.$user->getUsername().'/page/'; 127 170 } 128 171 129 172 $nav->setBaseURI(new PhutilURI($this->getApplicationURI($base_uri))); ··· 143 186 } 144 187 145 188 public function buildApplicationMenu() { 146 - $panels = $this->buildPanels(); 147 - return $this->renderSideNav($panels)->getMenu(); 189 + if ($this->preferences) { 190 + $panels = $this->buildPanels($this->preferences); 191 + return $this->renderSideNav($panels)->getMenu(); 192 + } 193 + return parent::buildApplicationMenu(); 148 194 } 149 195 150 196 protected function buildApplicationCrumbs() {
+19 -4
src/applications/settings/editor/PhabricatorSettingsEditEngine.php
··· 67 67 } 68 68 69 69 protected function getObjectEditShortText($object) { 70 - return pht('Edit Settings'); 70 + if (!$object->getUser()) { 71 + return pht('Global Defaults'); 72 + } else { 73 + if ($this->getIsSelfEdit()) { 74 + return pht('Personal Settings'); 75 + } else { 76 + return pht('Account Settings'); 77 + } 78 + } 71 79 } 72 80 73 81 protected function getObjectCreateShortText() { ··· 85 93 } 86 94 87 95 protected function getEditorURI() { 88 - return '/settings/edit/'; 96 + throw new PhutilMethodNotImplementedException(); 89 97 } 90 98 91 99 protected function getObjectCreateCancelURI($object) { ··· 93 101 } 94 102 95 103 protected function getObjectViewURI($object) { 96 - // TODO: This isn't correct... 97 - return '/settings/user/'.$this->getViewer()->getUsername().'/'; 104 + return $object->getEditURI(); 98 105 } 99 106 100 107 protected function getCreateNewObjectPolicy() { 101 108 return PhabricatorPolicies::POLICY_ADMIN; 102 109 } 103 110 111 + public function getEffectiveObjectEditDoneURI($object) { 112 + return parent::getEffectiveObjectViewURI($object).'saved/'; 113 + } 114 + 104 115 public function getEffectiveObjectEditCancelURI($object) { 116 + if (!$object->getUser()) { 117 + return '/settings/'; 118 + } 119 + 105 120 if ($this->getIsSelfEdit()) { 106 121 return null; 107 122 }
+5 -1
src/applications/settings/panel/PhabricatorAccountSettingsPanel.php
··· 13 13 return PhabricatorSettingsAccountPanelGroup::PANELGROUPKEY; 14 14 } 15 15 16 - public function isEditableByAdministrators() { 16 + public function isManagementPanel() { 17 + return true; 18 + } 19 + 20 + public function isTemplatePanel() { 17 21 return true; 18 22 } 19 23
+4 -4
src/applications/settings/panel/PhabricatorActivitySettingsPanel.php
··· 2 2 3 3 final class PhabricatorActivitySettingsPanel extends PhabricatorSettingsPanel { 4 4 5 - public function isEditableByAdministrators() { 6 - return true; 7 - } 8 - 9 5 public function getPanelKey() { 10 6 return 'activity'; 11 7 } ··· 59 55 ->appendChild($pager); 60 56 61 57 return array($panel, $pager_box); 58 + } 59 + 60 + public function isManagementPanel() { 61 + return true; 62 62 } 63 63 64 64 }
+4
src/applications/settings/panel/PhabricatorConpherencePreferencesSettingsPanel.php
··· 13 13 return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; 14 14 } 15 15 16 + public function isTemplatePanel() { 17 + return true; 18 + } 19 + 16 20 }
+5 -1
src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php
··· 13 13 return PhabricatorSettingsAccountPanelGroup::PANELGROUPKEY; 14 14 } 15 15 16 - public function isEditableByAdministrators() { 16 + public function isManagementPanel() { 17 + return true; 18 + } 19 + 20 + public function isTemplatePanel() { 17 21 return true; 18 22 } 19 23
+1 -1
src/applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php
··· 27 27 28 28 public function processRequest(AphrontRequest $request) { 29 29 $viewer = $this->getViewer(); 30 - $preferences = $this->loadTargetPreferences(); 30 + $preferences = $this->getPreferences(); 31 31 32 32 $notifications_key = PhabricatorDesktopNotificationsSetting::SETTINGKEY; 33 33 $notifications_value = $preferences->getSettingValue($notifications_key);
+4
src/applications/settings/panel/PhabricatorDeveloperPreferencesSettingsPanel.php
··· 13 13 return PhabricatorSettingsDeveloperPanelGroup::PANELGROUPKEY; 14 14 } 15 15 16 + public function isTemplatePanel() { 17 + return true; 18 + } 19 + 16 20 }
+4
src/applications/settings/panel/PhabricatorDiffPreferencesSettingsPanel.php
··· 13 13 return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; 14 14 } 15 15 16 + public function isTemplatePanel() { 17 + return true; 18 + } 19 + 16 20 }
+4
src/applications/settings/panel/PhabricatorDisplayPreferencesSettingsPanel.php
··· 13 13 return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; 14 14 } 15 15 16 + public function isTemplatePanel() { 17 + return true; 18 + } 19 + 16 20 }
+4 -4
src/applications/settings/panel/PhabricatorEditEngineSettingsPanel.php
··· 7 7 $viewer = $this->getViewer(); 8 8 $user = $this->getUser(); 9 9 10 - if ($user->getPHID() === $viewer->getPHID()) { 10 + if ($user && ($user->getPHID() === $viewer->getPHID())) { 11 11 $is_self = true; 12 12 } else { 13 13 $is_self = false; 14 14 } 15 15 16 - if ($user->getPHID()) { 16 + if ($user && $user->getPHID()) { 17 17 $profile_uri = '/people/manage/'.$user->getID().'/'; 18 18 } else { 19 19 $profile_uri = null; ··· 26 26 ->setIsSelfEdit($is_self) 27 27 ->setProfileURI($profile_uri); 28 28 29 - $preferences = $this->loadTargetPreferences(); 29 + $preferences = $this->getPreferences(); 30 30 31 31 $engine->setTargetObject($preferences); 32 32 ··· 47 47 48 48 $key = $this->getPanelKey(); 49 49 $label = $this->getPanelName(); 50 - $panel_uri = $this->getPanelURI().'saved/'; 50 + $panel_uri = $this->getPanelURI(); 51 51 52 52 return id(new PhabricatorEditPage()) 53 53 ->setKey($key)
+5 -1
src/applications/settings/panel/PhabricatorEmailDeliverySettingsPanel.php
··· 13 13 return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY; 14 14 } 15 15 16 - public function isEditableByAdministrators() { 16 + public function isManagementPanel() { 17 17 if ($this->getUser()->getIsMailingList()) { 18 18 return true; 19 19 } 20 20 21 21 return false; 22 + } 23 + 24 + public function isTemplatePanel() { 25 + return true; 22 26 } 23 27 24 28 }
+5 -1
src/applications/settings/panel/PhabricatorEmailFormatSettingsPanel.php
··· 13 13 return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY; 14 14 } 15 15 16 - public function isEditableByAdministrators() { 16 + public function isManagementPanel() { 17 17 if ($this->getUser()->getIsMailingList()) { 18 18 return true; 19 19 } 20 20 21 21 return false; 22 + } 23 + 24 + public function isTemplatePanel() { 25 + return true; 22 26 } 23 27 24 28 }
+8 -4
src/applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php
··· 15 15 return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY; 16 16 } 17 17 18 - public function isEditableByAdministrators() { 18 + public function isManagementPanel() { 19 19 if ($this->getUser()->getIsMailingList()) { 20 20 return true; 21 21 } ··· 23 23 return false; 24 24 } 25 25 26 + public function isTemplatePanel() { 27 + return true; 28 + } 29 + 26 30 public function processRequest(AphrontRequest $request) { 27 31 $viewer = $this->getViewer(); 28 32 $user = $this->getUser(); 29 33 30 - $preferences = $this->loadTargetPreferences(); 34 + $preferences = $this->getPreferences(); 31 35 32 36 $value_email = PhabricatorEmailTagsSetting::VALUE_EMAIL; 33 37 ··· 137 141 return $form_box; 138 142 } 139 143 140 - private function getAllEditorsWithTags(PhabricatorUser $user) { 144 + private function getAllEditorsWithTags(PhabricatorUser $user = null) { 141 145 $editors = id(new PhutilClassMapQuery()) 142 146 ->setAncestorClass('PhabricatorApplicationTransactionEditor') 143 147 ->setFilterMethod('getMailTagsMap') ··· 146 150 foreach ($editors as $key => $editor) { 147 151 // Remove editors for applications which are not installed. 148 152 $app = $editor->getEditorApplicationClass(); 149 - if ($app !== null) { 153 + if ($app !== null && $user !== null) { 150 154 if (!PhabricatorApplication::isClassInstalledForViewer($app, $user)) { 151 155 unset($editors[$key]); 152 156 }
+5 -1
src/applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php
··· 15 15 return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; 16 16 } 17 17 18 + public function isTemplatePanel() { 19 + return true; 20 + } 21 + 18 22 public function processRequest(AphrontRequest $request) { 19 23 $viewer = $this->getViewer(); 20 - $preferences = $this->loadTargetPreferences(); 24 + $preferences = $this->getPreferences(); 21 25 22 26 $pinned_key = PhabricatorPinnedApplicationsSetting::SETTINGKEY; 23 27 $pinned = $preferences->getSettingValue($pinned_key);
+5 -9
src/applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php
··· 2 2 3 3 final class PhabricatorSSHKeysSettingsPanel extends PhabricatorSettingsPanel { 4 4 5 - public function isEditableByAdministrators() { 5 + public function isManagementPanel() { 6 + if ($this->getUser()->getIsMailingList()) { 7 + return false; 8 + } 9 + 6 10 return true; 7 11 } 8 12 ··· 16 20 17 21 public function getPanelGroupKey() { 18 22 return PhabricatorSettingsAuthenticationPanelGroup::PANELGROUPKEY; 19 - } 20 - 21 - public function isEnabled() { 22 - if ($this->getUser()->getIsMailingList()) { 23 - return false; 24 - } 25 - 26 - return true; 27 23 } 28 24 29 25 public function processRequest(AphrontRequest $request) {
+31 -22
src/applications/settings/panel/PhabricatorSettingsPanel.php
··· 18 18 private $controller; 19 19 private $navigation; 20 20 private $overrideURI; 21 + private $preferences; 21 22 22 23 public function setUser(PhabricatorUser $user) { 23 24 $this->user = $user; ··· 58 59 59 60 final public function getNavigation() { 60 61 return $this->navigation; 62 + } 63 + 64 + public function setPreferences(PhabricatorUserPreferences $preferences) { 65 + $this->preferences = $preferences; 66 + return $this; 67 + } 68 + 69 + public function getPreferences() { 70 + return $this->preferences; 61 71 } 62 72 63 73 final public static function getAllPanels() { ··· 145 155 146 156 147 157 /** 148 - * Return true if this panel is available to administrators while editing 149 - * system agent accounts. 158 + * Return true if this panel is available to administrators while managing 159 + * bot and mailing list accounts. 160 + * 161 + * @return bool True to enable management on behalf of accounts. 162 + * @task config 163 + */ 164 + public function isManagementPanel() { 165 + return false; 166 + } 167 + 168 + 169 + /** 170 + * Return true if this panel is available while editing settings templates. 150 171 * 151 - * @return bool True to enable edit by administrators. 172 + * @return bool True to allow editing in templates. 152 173 * @task config 153 174 */ 154 - public function isEditableByAdministrators() { 175 + public function isTemplatePanel() { 155 176 return false; 156 177 } 157 178 ··· 194 215 $key = $this->getPanelKey(); 195 216 $key = phutil_escape_uri($key); 196 217 197 - if ($this->getUser()->getPHID() != $this->getViewer()->getPHID()) { 198 - $user_id = $this->getUser()->getID(); 199 - return "/settings/{$user_id}/panel/{$key}/{$path}"; 218 + $user = $this->getUser(); 219 + if ($user) { 220 + $username = $user->getUsername(); 221 + return "/settings/user/{$username}/page/{$key}/{$path}"; 200 222 } else { 201 - return "/settings/panel/{$key}/{$path}"; 223 + $builtin = $this->getPreferences()->getBuiltinKey(); 224 + return "/settings/builtin/{$builtin}/page/{$key}/{$path}"; 202 225 } 203 226 } 204 227 ··· 215 238 final public function getPanelOrderVector() { 216 239 return id(new PhutilSortVector()) 217 240 ->addString($this->getPanelName()); 218 - } 219 - 220 - protected function loadTargetPreferences() { 221 - $viewer = $this->getViewer(); 222 - $user = $this->getUser(); 223 - 224 - $preferences = PhabricatorUserPreferences::loadUserPreferences($user); 225 - 226 - PhabricatorPolicyFilter::requireCapability( 227 - $viewer, 228 - $preferences, 229 - PhabricatorPolicyCapability::CAN_EDIT); 230 - 231 - return $preferences; 232 241 } 233 242 234 243 protected function newDialog() {
+51
src/applications/settings/query/PhabricatorUserPreferencesQuery.php
··· 6 6 private $ids; 7 7 private $phids; 8 8 private $userPHIDs; 9 + private $builtinKeys; 10 + private $hasUserPHID; 9 11 private $users = array(); 10 12 11 13 public function withIDs(array $ids) { ··· 18 20 return $this; 19 21 } 20 22 23 + public function withHasUserPHID($is_user) { 24 + $this->hasUserPHID = $is_user; 25 + return $this; 26 + } 27 + 21 28 public function withUserPHIDs(array $phids) { 22 29 $this->userPHIDs = $phids; 23 30 return $this; ··· 27 34 assert_instances_of($users, 'PhabricatorUser'); 28 35 $this->users = mpull($users, null, 'getPHID'); 29 36 $this->withUserPHIDs(array_keys($this->users)); 37 + return $this; 38 + } 39 + 40 + public function withBuiltinKeys(array $keys) { 41 + $this->builtinKeys = $keys; 30 42 return $this; 31 43 } 32 44 ··· 64 76 $users = array(); 65 77 } 66 78 79 + $need_global = array(); 67 80 foreach ($prefs as $key => $pref) { 68 81 $user_phid = $pref->getUserPHID(); 69 82 if (!$user_phid) { ··· 71 84 continue; 72 85 } 73 86 87 + $need_global[] = $pref; 88 + 74 89 $user = idx($users, $user_phid); 75 90 if (!$user) { 76 91 $this->didRejectResult($pref); ··· 81 96 $pref->attachUser($user); 82 97 } 83 98 99 + // If we loaded any user preferences, load the global defaults and attach 100 + // them if they exist. 101 + if ($need_global) { 102 + $global = id(new self()) 103 + ->setViewer($this->getViewer()) 104 + ->withBuiltinKeys( 105 + array( 106 + PhabricatorUserPreferences::BUILTIN_GLOBAL_DEFAULT, 107 + )) 108 + ->executeOne(); 109 + if ($global) { 110 + foreach ($need_global as $pref) { 111 + $pref->attachDefaultSettings($global); 112 + } 113 + } 114 + } 115 + 84 116 return $prefs; 85 117 } 86 118 ··· 106 138 $conn, 107 139 'userPHID IN (%Ls)', 108 140 $this->userPHIDs); 141 + } 142 + 143 + if ($this->builtinKeys !== null) { 144 + $where[] = qsprintf( 145 + $conn, 146 + 'builtinKey IN (%Ls)', 147 + $this->builtinKeys); 148 + } 149 + 150 + if ($this->hasUserPHID !== null) { 151 + if ($this->hasUserPHID) { 152 + $where[] = qsprintf( 153 + $conn, 154 + 'userPHID IS NOT NULL'); 155 + } else { 156 + $where[] = qsprintf( 157 + $conn, 158 + 'userPHID IS NULL'); 159 + } 109 160 } 110 161 111 162 return $where;
+86
src/applications/settings/query/PhabricatorUserPreferencesSearchEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorUserPreferencesSearchEngine 4 + extends PhabricatorApplicationSearchEngine { 5 + 6 + public function getResultTypeDescription() { 7 + return pht('User Preferences'); 8 + } 9 + 10 + public function getApplicationClassName() { 11 + return 'PhabricatorSettingApplication'; 12 + } 13 + 14 + public function newQuery() { 15 + return id(new PhabricatorUserPreferencesQuery()) 16 + ->withHasUserPHID(false); 17 + } 18 + 19 + protected function buildQueryFromParameters(array $map) { 20 + $query = $this->newQuery(); 21 + 22 + return $query; 23 + } 24 + 25 + protected function buildCustomSearchFields() { 26 + return array(); 27 + } 28 + 29 + protected function getURI($path) { 30 + return '/settings/list/'.$path; 31 + } 32 + 33 + protected function getBuiltinQueryNames() { 34 + $names = array( 35 + 'all' => pht('All Settings'), 36 + ); 37 + 38 + return $names; 39 + } 40 + 41 + public function buildSavedQueryFromBuiltin($query_key) { 42 + $query = $this->newSavedQuery(); 43 + $query->setQueryKey($query_key); 44 + 45 + switch ($query_key) { 46 + case 'all': 47 + return $query; 48 + } 49 + 50 + return parent::buildSavedQueryFromBuiltin($query_key); 51 + } 52 + 53 + protected function renderResultList( 54 + array $settings, 55 + PhabricatorSavedQuery $query, 56 + array $handles) { 57 + assert_instances_of($settings, 'PhabricatorUserPreferences'); 58 + 59 + $viewer = $this->requireViewer(); 60 + 61 + $list = id(new PHUIObjectItemListView()) 62 + ->setViewer($viewer); 63 + foreach ($settings as $setting) { 64 + 65 + $item = id(new PHUIObjectItemView()) 66 + ->setHeader($setting->getDisplayName()) 67 + ->setHref($setting->getEditURI()) 68 + ->setImageURI(PhabricatorUser::getDefaultProfileImageURI()) 69 + ->setIcon('fa-globe') 70 + ->addAttribute(pht('Edit global default settings for all users.')); 71 + 72 + $list->addItem($item); 73 + } 74 + 75 + $list->addItem( 76 + id(new PHUIObjectItemView()) 77 + ->setHeader(pht('Personal Account Settings')) 78 + ->addAttribute(pht('Edit settings for your personal account.')) 79 + ->setImageURI($viewer->getProfileImageURI()) 80 + ->setHref('/settings/user/'.$viewer->getUsername().'/')); 81 + 82 + return id(new PhabricatorApplicationSearchResultView()) 83 + ->setObjectList($list); 84 + } 85 + 86 + }
+5
src/applications/settings/setting/PhabricatorPinnedApplicationsSetting.php
··· 12 12 public function getSettingDefaultValue() { 13 13 $viewer = $this->getViewer(); 14 14 15 + // If we're editing a template, just show every available application. 16 + if (!$viewer) { 17 + $viewer = PhabricatorUser::getOmnipotentUser(); 18 + } 19 + 15 20 $applications = id(new PhabricatorApplicationQuery()) 16 21 ->setViewer($viewer) 17 22 ->withInstalled(true)
+5 -2
src/applications/settings/setting/PhabricatorSetting.php
··· 2 2 3 3 abstract class PhabricatorSetting extends Phobject { 4 4 5 - private $viewer; 5 + private $viewer = false; 6 6 7 - public function setViewer(PhabricatorUser $viewer) { 7 + public function setViewer(PhabricatorUser $viewer = null) { 8 8 $this->viewer = $viewer; 9 9 return $this; 10 10 } 11 11 12 12 public function getViewer() { 13 + if ($this->viewer === false) { 14 + throw new PhutilInvalidStateException('setViewer'); 15 + } 13 16 return $this->viewer; 14 17 } 15 18
+37 -4
src/applications/settings/storage/PhabricatorUserPreferences.php
··· 7 7 PhabricatorDestructibleInterface, 8 8 PhabricatorApplicationTransactionInterface { 9 9 10 + const BUILTIN_GLOBAL_DEFAULT = 'global'; 11 + 10 12 protected $userPHID; 11 13 protected $preferences = array(); 14 + protected $builtinKey; 12 15 13 16 private $user = self::ATTACHABLE; 17 + private $defaultSettings; 14 18 15 19 protected function getConfiguration() { 16 20 return array( ··· 18 22 self::CONFIG_SERIALIZATION => array( 19 23 'preferences' => self::SERIALIZATION_JSON, 20 24 ), 25 + self::CONFIG_COLUMN_SCHEMA => array( 26 + 'userPHID' => 'phid?', 27 + 'builtinKey' => 'text32?', 28 + ), 21 29 self::CONFIG_KEY_SCHEMA => array( 22 - 'userPHID' => array( 30 + 'key_user' => array( 23 31 'columns' => array('userPHID'), 24 32 'unique' => true, 25 33 ), 34 + 'key_builtin' => array( 35 + 'columns' => array('builtinKey'), 36 + 'unique' => true, 37 + ), 26 38 ), 27 39 ) + parent::getConfiguration(); 28 40 } ··· 47 59 } 48 60 49 61 public function getDefaultValue($key) { 62 + if ($this->defaultSettings) { 63 + return $this->defaultSettings->getSettingValue($key); 64 + } 65 + 50 66 $setting = self::getSettingObject($key); 51 67 52 68 if (!$setting) { ··· 63 79 if (array_key_exists($key, $this->preferences)) { 64 80 return $this->preferences[$key]; 65 81 } 66 - 67 - // TODO: If this setting set inherits from another preference set, 68 - // we would look it up here. 69 82 70 83 return $this->getDefaultValue($key); 71 84 } ··· 75 88 return idx($settings, $key); 76 89 } 77 90 91 + public function attachDefaultSettings(PhabricatorUserPreferences $settings) { 92 + $this->defaultSettings = $settings; 93 + return $this; 94 + } 95 + 78 96 public function attachUser(PhabricatorUser $user = null) { 79 97 $this->user = $user; 80 98 return $this; ··· 127 145 ->setNewValue($value); 128 146 } 129 147 148 + public function getEditURI() { 149 + if ($this->getUser()) { 150 + return '/settings/user/'.$this->getUser()->getUsername().'/'; 151 + } else { 152 + return '/settings/builtin/'.$this->getBuiltinKey().'/'; 153 + } 154 + } 155 + 156 + public function getDisplayName() { 157 + if ($this->getBuiltinKey()) { 158 + return pht('Global Default Settings'); 159 + } 160 + 161 + return pht('Personal Settings'); 162 + } 130 163 131 164 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 132 165
+5 -1
src/applications/transactions/editengine/PhabricatorEditEngine.php
··· 532 532 return $this->getObjectViewURI($object); 533 533 } 534 534 535 + public function getEffectiveObjectEditDoneURI($object) { 536 + return $this->getEffectiveObjectViewURI($object); 537 + } 538 + 535 539 public function getEffectiveObjectEditCancelURI($object) { 536 540 $page = $this->getSelectedPage(); 537 541 if ($page) { ··· 1169 1173 $object, 1170 1174 array $xactions) { 1171 1175 return id(new AphrontRedirectResponse()) 1172 - ->setURI($this->getEffectiveObjectViewURI($object)); 1176 + ->setURI($this->getEffectiveObjectEditDoneURI($object)); 1173 1177 } 1174 1178 1175 1179 private function buildEditForm($object, array $fields) {