1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-24 21:48:21 +01:00

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
This commit is contained in:
epriestley 2016-06-05 12:38:04 -07:00
parent c9ef7aeaa3
commit 421bf2e548
33 changed files with 464 additions and 96 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_user.user_preferences
CHANGE userPHID userPHID VARBINARY(64);

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_user.user_preferences
ADD builtinKey VARCHAR(32) COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_user.user_preferences
ADD UNIQUE KEY `key_builtin` (builtinKey);

View file

@ -3393,6 +3393,7 @@ phutil_register_library_map(array(
'PhabricatorSettingsDeveloperPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsDeveloperPanelGroup.php', 'PhabricatorSettingsDeveloperPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsDeveloperPanelGroup.php',
'PhabricatorSettingsEditEngine' => 'applications/settings/editor/PhabricatorSettingsEditEngine.php', 'PhabricatorSettingsEditEngine' => 'applications/settings/editor/PhabricatorSettingsEditEngine.php',
'PhabricatorSettingsEmailPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsEmailPanelGroup.php', 'PhabricatorSettingsEmailPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsEmailPanelGroup.php',
'PhabricatorSettingsListController' => 'applications/settings/controller/PhabricatorSettingsListController.php',
'PhabricatorSettingsLogsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsLogsPanelGroup.php', 'PhabricatorSettingsLogsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsLogsPanelGroup.php',
'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php',
'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php', 'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php',
@ -3650,6 +3651,7 @@ phutil_register_library_map(array(
'PhabricatorUserPreferencesEditor' => 'applications/settings/editor/PhabricatorUserPreferencesEditor.php', 'PhabricatorUserPreferencesEditor' => 'applications/settings/editor/PhabricatorUserPreferencesEditor.php',
'PhabricatorUserPreferencesPHIDType' => 'applications/settings/phid/PhabricatorUserPreferencesPHIDType.php', 'PhabricatorUserPreferencesPHIDType' => 'applications/settings/phid/PhabricatorUserPreferencesPHIDType.php',
'PhabricatorUserPreferencesQuery' => 'applications/settings/query/PhabricatorUserPreferencesQuery.php', 'PhabricatorUserPreferencesQuery' => 'applications/settings/query/PhabricatorUserPreferencesQuery.php',
'PhabricatorUserPreferencesSearchEngine' => 'applications/settings/query/PhabricatorUserPreferencesSearchEngine.php',
'PhabricatorUserPreferencesTransaction' => 'applications/settings/storage/PhabricatorUserPreferencesTransaction.php', 'PhabricatorUserPreferencesTransaction' => 'applications/settings/storage/PhabricatorUserPreferencesTransaction.php',
'PhabricatorUserPreferencesTransactionQuery' => 'applications/settings/query/PhabricatorUserPreferencesTransactionQuery.php', 'PhabricatorUserPreferencesTransactionQuery' => 'applications/settings/query/PhabricatorUserPreferencesTransactionQuery.php',
'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php', 'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php',
@ -8170,6 +8172,7 @@ phutil_register_library_map(array(
'PhabricatorSettingsDeveloperPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsDeveloperPanelGroup' => 'PhabricatorSettingsPanelGroup',
'PhabricatorSettingsEditEngine' => 'PhabricatorEditEngine', 'PhabricatorSettingsEditEngine' => 'PhabricatorEditEngine',
'PhabricatorSettingsEmailPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsEmailPanelGroup' => 'PhabricatorSettingsPanelGroup',
'PhabricatorSettingsListController' => 'PhabricatorController',
'PhabricatorSettingsLogsPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsLogsPanelGroup' => 'PhabricatorSettingsPanelGroup',
'PhabricatorSettingsMainController' => 'PhabricatorController', 'PhabricatorSettingsMainController' => 'PhabricatorController',
'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension',
@ -8470,6 +8473,7 @@ phutil_register_library_map(array(
'PhabricatorUserPreferencesEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorUserPreferencesEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorUserPreferencesPHIDType' => 'PhabricatorPHIDType', 'PhabricatorUserPreferencesPHIDType' => 'PhabricatorPHIDType',
'PhabricatorUserPreferencesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorUserPreferencesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorUserPreferencesSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorUserPreferencesTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorUserPreferencesTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorUserPreferencesTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorUserPreferencesTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorUserProfile' => 'PhabricatorUserDAO', 'PhabricatorUserProfile' => 'PhabricatorUserDAO',

View file

@ -3,7 +3,11 @@
final class PhabricatorConduitTokensSettingsPanel final class PhabricatorConduitTokensSettingsPanel
extends PhabricatorSettingsPanel { extends PhabricatorSettingsPanel {
public function isEditableByAdministrators() { public function isManagementPanel() {
if ($this->getUser()->getIsMailingList()) {
return false;
}
return true; return true;
} }
@ -20,10 +24,6 @@ final class PhabricatorConduitTokensSettingsPanel
} }
public function isEnabled() { public function isEnabled() {
if ($this->getUser()->getIsMailingList()) {
return false;
}
return true; return true;
} }

View file

@ -2,7 +2,11 @@
final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel { final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel {
public function isEditableByAdministrators() { public function isManagementPanel() {
if ($this->getUser()->getIsMailingList()) {
return false;
}
return true; return true;
} }
@ -19,10 +23,6 @@ final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel {
} }
public function isEnabled() { public function isEnabled() {
if ($this->getUser()->getIsMailingList()) {
return false;
}
return PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth'); return PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth');
} }

View file

@ -24,14 +24,34 @@ final class PhabricatorUserPreferencesCacheType
public function newValueForUsers($key, array $users) { public function newValueForUsers($key, array $users) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$user_phids = mpull($users, 'getPHID'); $users = mpull($users, null, 'getPHID');
$user_phids = array_keys($users);
$preferences = id(new PhabricatorUserPreferencesQuery()) $preferences = id(new PhabricatorUserPreferencesQuery())
->setViewer($viewer) ->setViewer($viewer)
->withUserPHIDs($user_phids) ->withUserPHIDs($user_phids)
->execute(); ->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(); $results = array();
foreach ($user_phids as $user_phid) { foreach ($user_phids as $user_phid) {

View file

@ -124,7 +124,7 @@ final class PhabricatorPeopleProfileManageController
->setName(pht('Edit Settings')) ->setName(pht('Edit Settings'))
->setDisabled(!$can_edit) ->setDisabled(!$can_edit)
->setWorkflow(!$can_edit) ->setWorkflow(!$can_edit)
->setHref('/settings/'.$user->getID().'/')); ->setHref('/settings/user/'.$user->getUsername().'/'));
if ($user->getIsAdmin()) { if ($user->getIsAdmin()) {
$empower_icon = 'fa-arrow-circle-o-down'; $empower_icon = 'fa-arrow-circle-o-down';

View file

@ -27,12 +27,14 @@ final class PhabricatorSettingsApplication extends PhabricatorApplication {
} }
public function getRoutes() { public function getRoutes() {
$panel_pattern = '(?:page/(?P<pageKey>[^/]+)/(?:(?P<formSaved>saved)/)?)?';
return array( return array(
'/settings/' => array( '/settings/' => array(
'(?:(?P<id>\d+)/)?'. $this->getQueryRoutePattern() => 'PhabricatorSettingsListController',
'(?:panel/(?P<pageKey>(?P<key>[^/]+))/'. 'user/(?P<username>[^/]+)/'.$panel_pattern
'(?:(?P<formSaved>saved)/)?'. => 'PhabricatorSettingsMainController',
')?' 'builtin/(?P<builtin>global)/'.$panel_pattern
=> 'PhabricatorSettingsMainController', => 'PhabricatorSettingsMainController',
'adjust/' => 'PhabricatorSettingsAdjustController', 'adjust/' => 'PhabricatorSettingsAdjustController',
'timezone/(?P<offset>[^/]+)/' 'timezone/(?P<offset>[^/]+)/'

View file

@ -0,0 +1,48 @@
<?php
final class PhabricatorSettingsListController
extends PhabricatorController {
public function handleRequest(AphrontRequest $request) {
$viewer = $this->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;
}
}

View file

@ -4,6 +4,8 @@ final class PhabricatorSettingsMainController
extends PhabricatorController { extends PhabricatorController {
private $user; private $user;
private $builtinKey;
private $preferences;
private function getUser() { private function getUser() {
return $this->user; return $this->user;
@ -21,15 +23,39 @@ final class PhabricatorSettingsMainController
return ($viewer_phid == $user_phid); return ($viewer_phid == $user_phid);
} }
private function isTemplate() {
return ($this->builtinKey !== null);
}
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer(); $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()) $user = id(new PhabricatorPeopleQuery())
->setViewer($viewer) ->setViewer($viewer)
->withIDs(array($id)) ->withUsernames(array($username))
->requireCapabilities( ->requireCapabilities(
array( array(
PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_VIEW,
@ -41,19 +67,27 @@ final class PhabricatorSettingsMainController
return new Aphront404Response(); return new Aphront404Response();
} }
$preferences = PhabricatorUserPreferences::loadUserPreferences($user);
$this->user = $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); $nav = $this->renderSideNav($panels);
$key = $nav->selectFilter($key, head($panels)->getPanelKey()); $key = $nav->selectFilter($key, head($panels)->getPanelKey());
$panel = $panels[$key] $panel = $panels[$key]
->setUser($this->getUser())
->setViewer($viewer)
->setController($this) ->setController($this)
->setNavigation($nav); ->setNavigation($nav);
@ -79,22 +113,30 @@ final class PhabricatorSettingsMainController
} }
private function buildPanels() { private function buildPanels(PhabricatorUserPreferences $preferences) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$panels = PhabricatorSettingsPanel::getAllDisplayPanels(); $panels = PhabricatorSettingsPanel::getAllDisplayPanels();
$result = array(); $result = array();
foreach ($panels as $key => $panel) { foreach ($panels as $key => $panel) {
$panel $panel
->setViewer($viewer) ->setPreferences($preferences)
->setUser($this->user); ->setViewer($viewer);
if ($this->user) {
$panel->setUser($this->user);
}
if (!$panel->isEnabled()) { if (!$panel->isEnabled()) {
continue; continue;
} }
if (!$this->isSelf()) { if ($this->isTemplate()) {
if (!$panel->isEditableByAdministrators()) { if (!$panel->isTemplatePanel()) {
continue;
}
} else {
if (!$this->isSelf() && !$panel->isManagementPanel()) {
continue; continue;
} }
} }
@ -120,10 +162,11 @@ final class PhabricatorSettingsMainController
private function renderSideNav(array $panels) { private function renderSideNav(array $panels) {
$nav = new AphrontSideNavFilterView(); $nav = new AphrontSideNavFilterView();
if ($this->isSelf()) { if ($this->isTemplate()) {
$base_uri = 'panel/'; $base_uri = 'builtin/'.$this->builtinKey.'/page/';
} else { } else {
$base_uri = $this->getUser()->getID().'/panel/'; $user = $this->getUser();
$base_uri = 'user/'.$user->getUsername().'/page/';
} }
$nav->setBaseURI(new PhutilURI($this->getApplicationURI($base_uri))); $nav->setBaseURI(new PhutilURI($this->getApplicationURI($base_uri)));
@ -143,8 +186,11 @@ final class PhabricatorSettingsMainController
} }
public function buildApplicationMenu() { public function buildApplicationMenu() {
$panels = $this->buildPanels(); if ($this->preferences) {
return $this->renderSideNav($panels)->getMenu(); $panels = $this->buildPanels($this->preferences);
return $this->renderSideNav($panels)->getMenu();
}
return parent::buildApplicationMenu();
} }
protected function buildApplicationCrumbs() { protected function buildApplicationCrumbs() {

View file

@ -67,7 +67,15 @@ final class PhabricatorSettingsEditEngine
} }
protected function getObjectEditShortText($object) { 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() { protected function getObjectCreateShortText() {
@ -85,7 +93,7 @@ final class PhabricatorSettingsEditEngine
} }
protected function getEditorURI() { protected function getEditorURI() {
return '/settings/edit/'; throw new PhutilMethodNotImplementedException();
} }
protected function getObjectCreateCancelURI($object) { protected function getObjectCreateCancelURI($object) {
@ -93,15 +101,22 @@ final class PhabricatorSettingsEditEngine
} }
protected function getObjectViewURI($object) { protected function getObjectViewURI($object) {
// TODO: This isn't correct... return $object->getEditURI();
return '/settings/user/'.$this->getViewer()->getUsername().'/';
} }
protected function getCreateNewObjectPolicy() { protected function getCreateNewObjectPolicy() {
return PhabricatorPolicies::POLICY_ADMIN; return PhabricatorPolicies::POLICY_ADMIN;
} }
public function getEffectiveObjectEditDoneURI($object) {
return parent::getEffectiveObjectViewURI($object).'saved/';
}
public function getEffectiveObjectEditCancelURI($object) { public function getEffectiveObjectEditCancelURI($object) {
if (!$object->getUser()) {
return '/settings/';
}
if ($this->getIsSelfEdit()) { if ($this->getIsSelfEdit()) {
return null; return null;
} }

View file

@ -13,7 +13,11 @@ final class PhabricatorAccountSettingsPanel
return PhabricatorSettingsAccountPanelGroup::PANELGROUPKEY; return PhabricatorSettingsAccountPanelGroup::PANELGROUPKEY;
} }
public function isEditableByAdministrators() { public function isManagementPanel() {
return true;
}
public function isTemplatePanel() {
return true; return true;
} }

View file

@ -2,10 +2,6 @@
final class PhabricatorActivitySettingsPanel extends PhabricatorSettingsPanel { final class PhabricatorActivitySettingsPanel extends PhabricatorSettingsPanel {
public function isEditableByAdministrators() {
return true;
}
public function getPanelKey() { public function getPanelKey() {
return 'activity'; return 'activity';
} }
@ -61,4 +57,8 @@ final class PhabricatorActivitySettingsPanel extends PhabricatorSettingsPanel {
return array($panel, $pager_box); return array($panel, $pager_box);
} }
public function isManagementPanel() {
return true;
}
} }

View file

@ -13,4 +13,8 @@ final class PhabricatorConpherencePreferencesSettingsPanel
return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY;
} }
public function isTemplatePanel() {
return true;
}
} }

View file

@ -13,7 +13,11 @@ final class PhabricatorDateTimeSettingsPanel
return PhabricatorSettingsAccountPanelGroup::PANELGROUPKEY; return PhabricatorSettingsAccountPanelGroup::PANELGROUPKEY;
} }
public function isEditableByAdministrators() { public function isManagementPanel() {
return true;
}
public function isTemplatePanel() {
return true; return true;
} }

View file

@ -27,7 +27,7 @@ final class PhabricatorDesktopNotificationsSettingsPanel
public function processRequest(AphrontRequest $request) { public function processRequest(AphrontRequest $request) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$preferences = $this->loadTargetPreferences(); $preferences = $this->getPreferences();
$notifications_key = PhabricatorDesktopNotificationsSetting::SETTINGKEY; $notifications_key = PhabricatorDesktopNotificationsSetting::SETTINGKEY;
$notifications_value = $preferences->getSettingValue($notifications_key); $notifications_value = $preferences->getSettingValue($notifications_key);

View file

@ -13,4 +13,8 @@ final class PhabricatorDeveloperPreferencesSettingsPanel
return PhabricatorSettingsDeveloperPanelGroup::PANELGROUPKEY; return PhabricatorSettingsDeveloperPanelGroup::PANELGROUPKEY;
} }
public function isTemplatePanel() {
return true;
}
} }

View file

@ -13,4 +13,8 @@ final class PhabricatorDiffPreferencesSettingsPanel
return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY;
} }
public function isTemplatePanel() {
return true;
}
} }

View file

@ -13,4 +13,8 @@ final class PhabricatorDisplayPreferencesSettingsPanel
return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY;
} }
public function isTemplatePanel() {
return true;
}
} }

View file

@ -7,13 +7,13 @@ abstract class PhabricatorEditEngineSettingsPanel
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$user = $this->getUser(); $user = $this->getUser();
if ($user->getPHID() === $viewer->getPHID()) { if ($user && ($user->getPHID() === $viewer->getPHID())) {
$is_self = true; $is_self = true;
} else { } else {
$is_self = false; $is_self = false;
} }
if ($user->getPHID()) { if ($user && $user->getPHID()) {
$profile_uri = '/people/manage/'.$user->getID().'/'; $profile_uri = '/people/manage/'.$user->getID().'/';
} else { } else {
$profile_uri = null; $profile_uri = null;
@ -26,7 +26,7 @@ abstract class PhabricatorEditEngineSettingsPanel
->setIsSelfEdit($is_self) ->setIsSelfEdit($is_self)
->setProfileURI($profile_uri); ->setProfileURI($profile_uri);
$preferences = $this->loadTargetPreferences(); $preferences = $this->getPreferences();
$engine->setTargetObject($preferences); $engine->setTargetObject($preferences);
@ -47,7 +47,7 @@ abstract class PhabricatorEditEngineSettingsPanel
$key = $this->getPanelKey(); $key = $this->getPanelKey();
$label = $this->getPanelName(); $label = $this->getPanelName();
$panel_uri = $this->getPanelURI().'saved/'; $panel_uri = $this->getPanelURI();
return id(new PhabricatorEditPage()) return id(new PhabricatorEditPage())
->setKey($key) ->setKey($key)

View file

@ -13,7 +13,7 @@ final class PhabricatorEmailDeliverySettingsPanel
return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY; return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY;
} }
public function isEditableByAdministrators() { public function isManagementPanel() {
if ($this->getUser()->getIsMailingList()) { if ($this->getUser()->getIsMailingList()) {
return true; return true;
} }
@ -21,4 +21,8 @@ final class PhabricatorEmailDeliverySettingsPanel
return false; return false;
} }
public function isTemplatePanel() {
return true;
}
} }

View file

@ -13,7 +13,7 @@ final class PhabricatorEmailFormatSettingsPanel
return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY; return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY;
} }
public function isEditableByAdministrators() { public function isManagementPanel() {
if ($this->getUser()->getIsMailingList()) { if ($this->getUser()->getIsMailingList()) {
return true; return true;
} }
@ -21,4 +21,8 @@ final class PhabricatorEmailFormatSettingsPanel
return false; return false;
} }
public function isTemplatePanel() {
return true;
}
} }

View file

@ -15,7 +15,7 @@ final class PhabricatorEmailPreferencesSettingsPanel
return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY; return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY;
} }
public function isEditableByAdministrators() { public function isManagementPanel() {
if ($this->getUser()->getIsMailingList()) { if ($this->getUser()->getIsMailingList()) {
return true; return true;
} }
@ -23,11 +23,15 @@ final class PhabricatorEmailPreferencesSettingsPanel
return false; return false;
} }
public function isTemplatePanel() {
return true;
}
public function processRequest(AphrontRequest $request) { public function processRequest(AphrontRequest $request) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$user = $this->getUser(); $user = $this->getUser();
$preferences = $this->loadTargetPreferences(); $preferences = $this->getPreferences();
$value_email = PhabricatorEmailTagsSetting::VALUE_EMAIL; $value_email = PhabricatorEmailTagsSetting::VALUE_EMAIL;
@ -137,7 +141,7 @@ final class PhabricatorEmailPreferencesSettingsPanel
return $form_box; return $form_box;
} }
private function getAllEditorsWithTags(PhabricatorUser $user) { private function getAllEditorsWithTags(PhabricatorUser $user = null) {
$editors = id(new PhutilClassMapQuery()) $editors = id(new PhutilClassMapQuery())
->setAncestorClass('PhabricatorApplicationTransactionEditor') ->setAncestorClass('PhabricatorApplicationTransactionEditor')
->setFilterMethod('getMailTagsMap') ->setFilterMethod('getMailTagsMap')
@ -146,7 +150,7 @@ final class PhabricatorEmailPreferencesSettingsPanel
foreach ($editors as $key => $editor) { foreach ($editors as $key => $editor) {
// Remove editors for applications which are not installed. // Remove editors for applications which are not installed.
$app = $editor->getEditorApplicationClass(); $app = $editor->getEditorApplicationClass();
if ($app !== null) { if ($app !== null && $user !== null) {
if (!PhabricatorApplication::isClassInstalledForViewer($app, $user)) { if (!PhabricatorApplication::isClassInstalledForViewer($app, $user)) {
unset($editors[$key]); unset($editors[$key]);
} }

View file

@ -15,9 +15,13 @@ final class PhabricatorHomePreferencesSettingsPanel
return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY; return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY;
} }
public function isTemplatePanel() {
return true;
}
public function processRequest(AphrontRequest $request) { public function processRequest(AphrontRequest $request) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$preferences = $this->loadTargetPreferences(); $preferences = $this->getPreferences();
$pinned_key = PhabricatorPinnedApplicationsSetting::SETTINGKEY; $pinned_key = PhabricatorPinnedApplicationsSetting::SETTINGKEY;
$pinned = $preferences->getSettingValue($pinned_key); $pinned = $preferences->getSettingValue($pinned_key);

View file

@ -2,7 +2,11 @@
final class PhabricatorSSHKeysSettingsPanel extends PhabricatorSettingsPanel { final class PhabricatorSSHKeysSettingsPanel extends PhabricatorSettingsPanel {
public function isEditableByAdministrators() { public function isManagementPanel() {
if ($this->getUser()->getIsMailingList()) {
return false;
}
return true; return true;
} }
@ -18,14 +22,6 @@ final class PhabricatorSSHKeysSettingsPanel extends PhabricatorSettingsPanel {
return PhabricatorSettingsAuthenticationPanelGroup::PANELGROUPKEY; return PhabricatorSettingsAuthenticationPanelGroup::PANELGROUPKEY;
} }
public function isEnabled() {
if ($this->getUser()->getIsMailingList()) {
return false;
}
return true;
}
public function processRequest(AphrontRequest $request) { public function processRequest(AphrontRequest $request) {
$user = $this->getUser(); $user = $this->getUser();
$viewer = $request->getUser(); $viewer = $request->getUser();

View file

@ -18,6 +18,7 @@ abstract class PhabricatorSettingsPanel extends Phobject {
private $controller; private $controller;
private $navigation; private $navigation;
private $overrideURI; private $overrideURI;
private $preferences;
public function setUser(PhabricatorUser $user) { public function setUser(PhabricatorUser $user) {
$this->user = $user; $this->user = $user;
@ -60,6 +61,15 @@ abstract class PhabricatorSettingsPanel extends Phobject {
return $this->navigation; return $this->navigation;
} }
public function setPreferences(PhabricatorUserPreferences $preferences) {
$this->preferences = $preferences;
return $this;
}
public function getPreferences() {
return $this->preferences;
}
final public static function getAllPanels() { final public static function getAllPanels() {
$panels = id(new PhutilClassMapQuery()) $panels = id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__) ->setAncestorClass(__CLASS__)
@ -145,13 +155,24 @@ abstract class PhabricatorSettingsPanel extends Phobject {
/** /**
* Return true if this panel is available to administrators while editing * Return true if this panel is available to administrators while managing
* system agent accounts. * 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 * @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; return false;
} }
@ -194,11 +215,13 @@ abstract class PhabricatorSettingsPanel extends Phobject {
$key = $this->getPanelKey(); $key = $this->getPanelKey();
$key = phutil_escape_uri($key); $key = phutil_escape_uri($key);
if ($this->getUser()->getPHID() != $this->getViewer()->getPHID()) { $user = $this->getUser();
$user_id = $this->getUser()->getID(); if ($user) {
return "/settings/{$user_id}/panel/{$key}/{$path}"; $username = $user->getUsername();
return "/settings/user/{$username}/page/{$key}/{$path}";
} else { } else {
return "/settings/panel/{$key}/{$path}"; $builtin = $this->getPreferences()->getBuiltinKey();
return "/settings/builtin/{$builtin}/page/{$key}/{$path}";
} }
} }
@ -217,20 +240,6 @@ abstract class PhabricatorSettingsPanel extends Phobject {
->addString($this->getPanelName()); ->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() { protected function newDialog() {
return $this->getController()->newDialog(); return $this->getController()->newDialog();
} }

View file

@ -6,6 +6,8 @@ final class PhabricatorUserPreferencesQuery
private $ids; private $ids;
private $phids; private $phids;
private $userPHIDs; private $userPHIDs;
private $builtinKeys;
private $hasUserPHID;
private $users = array(); private $users = array();
public function withIDs(array $ids) { public function withIDs(array $ids) {
@ -18,6 +20,11 @@ final class PhabricatorUserPreferencesQuery
return $this; return $this;
} }
public function withHasUserPHID($is_user) {
$this->hasUserPHID = $is_user;
return $this;
}
public function withUserPHIDs(array $phids) { public function withUserPHIDs(array $phids) {
$this->userPHIDs = $phids; $this->userPHIDs = $phids;
return $this; return $this;
@ -30,6 +37,11 @@ final class PhabricatorUserPreferencesQuery
return $this; return $this;
} }
public function withBuiltinKeys(array $keys) {
$this->builtinKeys = $keys;
return $this;
}
public function newResultObject() { public function newResultObject() {
return new PhabricatorUserPreferences(); return new PhabricatorUserPreferences();
} }
@ -64,6 +76,7 @@ final class PhabricatorUserPreferencesQuery
$users = array(); $users = array();
} }
$need_global = array();
foreach ($prefs as $key => $pref) { foreach ($prefs as $key => $pref) {
$user_phid = $pref->getUserPHID(); $user_phid = $pref->getUserPHID();
if (!$user_phid) { if (!$user_phid) {
@ -71,6 +84,8 @@ final class PhabricatorUserPreferencesQuery
continue; continue;
} }
$need_global[] = $pref;
$user = idx($users, $user_phid); $user = idx($users, $user_phid);
if (!$user) { if (!$user) {
$this->didRejectResult($pref); $this->didRejectResult($pref);
@ -81,6 +96,23 @@ final class PhabricatorUserPreferencesQuery
$pref->attachUser($user); $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; return $prefs;
} }
@ -108,6 +140,25 @@ final class PhabricatorUserPreferencesQuery
$this->userPHIDs); $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; return $where;
} }

View file

@ -0,0 +1,86 @@
<?php
final class PhabricatorUserPreferencesSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('User Preferences');
}
public function getApplicationClassName() {
return 'PhabricatorSettingApplication';
}
public function newQuery() {
return id(new PhabricatorUserPreferencesQuery())
->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);
}
}

View file

@ -12,6 +12,11 @@ final class PhabricatorPinnedApplicationsSetting
public function getSettingDefaultValue() { public function getSettingDefaultValue() {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
// If we're editing a template, just show every available application.
if (!$viewer) {
$viewer = PhabricatorUser::getOmnipotentUser();
}
$applications = id(new PhabricatorApplicationQuery()) $applications = id(new PhabricatorApplicationQuery())
->setViewer($viewer) ->setViewer($viewer)
->withInstalled(true) ->withInstalled(true)

View file

@ -2,14 +2,17 @@
abstract class PhabricatorSetting extends Phobject { abstract class PhabricatorSetting extends Phobject {
private $viewer; private $viewer = false;
public function setViewer(PhabricatorUser $viewer) { public function setViewer(PhabricatorUser $viewer = null) {
$this->viewer = $viewer; $this->viewer = $viewer;
return $this; return $this;
} }
public function getViewer() { public function getViewer() {
if ($this->viewer === false) {
throw new PhutilInvalidStateException('setViewer');
}
return $this->viewer; return $this->viewer;
} }

View file

@ -7,10 +7,14 @@ final class PhabricatorUserPreferences
PhabricatorDestructibleInterface, PhabricatorDestructibleInterface,
PhabricatorApplicationTransactionInterface { PhabricatorApplicationTransactionInterface {
const BUILTIN_GLOBAL_DEFAULT = 'global';
protected $userPHID; protected $userPHID;
protected $preferences = array(); protected $preferences = array();
protected $builtinKey;
private $user = self::ATTACHABLE; private $user = self::ATTACHABLE;
private $defaultSettings;
protected function getConfiguration() { protected function getConfiguration() {
return array( return array(
@ -18,11 +22,19 @@ final class PhabricatorUserPreferences
self::CONFIG_SERIALIZATION => array( self::CONFIG_SERIALIZATION => array(
'preferences' => self::SERIALIZATION_JSON, 'preferences' => self::SERIALIZATION_JSON,
), ),
self::CONFIG_COLUMN_SCHEMA => array(
'userPHID' => 'phid?',
'builtinKey' => 'text32?',
),
self::CONFIG_KEY_SCHEMA => array( self::CONFIG_KEY_SCHEMA => array(
'userPHID' => array( 'key_user' => array(
'columns' => array('userPHID'), 'columns' => array('userPHID'),
'unique' => true, 'unique' => true,
), ),
'key_builtin' => array(
'columns' => array('builtinKey'),
'unique' => true,
),
), ),
) + parent::getConfiguration(); ) + parent::getConfiguration();
} }
@ -47,6 +59,10 @@ final class PhabricatorUserPreferences
} }
public function getDefaultValue($key) { public function getDefaultValue($key) {
if ($this->defaultSettings) {
return $this->defaultSettings->getSettingValue($key);
}
$setting = self::getSettingObject($key); $setting = self::getSettingObject($key);
if (!$setting) { if (!$setting) {
@ -64,9 +80,6 @@ final class PhabricatorUserPreferences
return $this->preferences[$key]; return $this->preferences[$key];
} }
// TODO: If this setting set inherits from another preference set,
// we would look it up here.
return $this->getDefaultValue($key); return $this->getDefaultValue($key);
} }
@ -75,6 +88,11 @@ final class PhabricatorUserPreferences
return idx($settings, $key); return idx($settings, $key);
} }
public function attachDefaultSettings(PhabricatorUserPreferences $settings) {
$this->defaultSettings = $settings;
return $this;
}
public function attachUser(PhabricatorUser $user = null) { public function attachUser(PhabricatorUser $user = null) {
$this->user = $user; $this->user = $user;
return $this; return $this;
@ -127,6 +145,21 @@ final class PhabricatorUserPreferences
->setNewValue($value); ->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 )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -532,6 +532,10 @@ abstract class PhabricatorEditEngine
return $this->getObjectViewURI($object); return $this->getObjectViewURI($object);
} }
public function getEffectiveObjectEditDoneURI($object) {
return $this->getEffectiveObjectViewURI($object);
}
public function getEffectiveObjectEditCancelURI($object) { public function getEffectiveObjectEditCancelURI($object) {
$page = $this->getSelectedPage(); $page = $this->getSelectedPage();
if ($page) { if ($page) {
@ -1169,7 +1173,7 @@ abstract class PhabricatorEditEngine
$object, $object,
array $xactions) { array $xactions) {
return id(new AphrontRedirectResponse()) return id(new AphrontRedirectResponse())
->setURI($this->getEffectiveObjectViewURI($object)); ->setURI($this->getEffectiveObjectEditDoneURI($object));
} }
private function buildEditForm($object, array $fields) { private function buildEditForm($object, array $fields) {