mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 08:52:39 +01:00
Allow application policies to be edited
Summary: Ref T603. Enables: - Application policies can be edited. - Applications can define custom policies (this will be used for setting defaults, like "what is the default visibiltiy of new tasks", and meta-policies, like "who can create a task?"). Test Plan: Edited application policies. A future diff does more with custom policies. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T603 Differential Revision: https://secure.phabricator.com/D7205
This commit is contained in:
parent
bf14d8ef2c
commit
c830461b00
5 changed files with 305 additions and 27 deletions
|
@ -828,6 +828,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationDiviner' => 'applications/diviner/application/PhabricatorApplicationDiviner.php',
|
||||
'PhabricatorApplicationDoorkeeper' => 'applications/doorkeeper/application/PhabricatorApplicationDoorkeeper.php',
|
||||
'PhabricatorApplicationDrydock' => 'applications/drydock/application/PhabricatorApplicationDrydock.php',
|
||||
'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php',
|
||||
'PhabricatorApplicationFact' => 'applications/fact/application/PhabricatorApplicationFact.php',
|
||||
'PhabricatorApplicationFeed' => 'applications/feed/application/PhabricatorApplicationFeed.php',
|
||||
'PhabricatorApplicationFiles' => 'applications/files/application/PhabricatorApplicationFiles.php',
|
||||
|
@ -2937,6 +2938,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationDiviner' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationDoorkeeper' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationDrydock' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController',
|
||||
'PhabricatorApplicationFact' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationFeed' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationFiles' => 'PhabricatorApplication',
|
||||
|
|
|
@ -321,18 +321,32 @@ abstract class PhabricatorApplication
|
|||
|
||||
|
||||
public function getCapabilities() {
|
||||
return array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
);
|
||||
return array_merge(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
),
|
||||
array_keys($this->getCustomCapabilities()));
|
||||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
$default = $this->getCustomPolicySetting($capability);
|
||||
if ($default) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
switch ($capability) {
|
||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||
return PhabricatorPolicies::POLICY_USER;
|
||||
if (PhabricatorEnv::getEnvConfig('policy.allow-public')) {
|
||||
return PhabricatorPolicies::POLICY_PUBLIC;
|
||||
} else {
|
||||
return PhabricatorPolicies::POLICY_USER;
|
||||
}
|
||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||
return PhabricatorPolicies::POLICY_ADMIN;
|
||||
default:
|
||||
$spec = $this->getCustomCapabilitySpecification($capability);
|
||||
return idx($spec, 'default', PhabricatorPolicies::POLICY_USER);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,4 +359,80 @@ abstract class PhabricatorApplication
|
|||
}
|
||||
|
||||
|
||||
/* -( Policies )----------------------------------------------------------- */
|
||||
|
||||
protected function getCustomCapabilities() {
|
||||
return array();
|
||||
}
|
||||
|
||||
private function getCustomPolicySetting($capability) {
|
||||
if (!$this->isCapabilityEditable($capability)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$config = PhabricatorEnv::getEnvConfig('phabricator.application-settings');
|
||||
|
||||
$app = idx($config, $this->getPHID());
|
||||
if (!$app) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$policy = idx($app, 'policy');
|
||||
if (!$policy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return idx($policy, $capability);
|
||||
}
|
||||
|
||||
|
||||
private function getCustomCapabilitySpecification($capability) {
|
||||
$custom = $this->getCustomCapabilities();
|
||||
if (empty($custom[$capability])) {
|
||||
throw new Exception("Unknown capability '{$capability}'!");
|
||||
}
|
||||
return $custom[$capability];
|
||||
}
|
||||
|
||||
public function getCapabilityLabel($capability) {
|
||||
$map = array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW => pht('Can Use Application'),
|
||||
PhabricatorPolicyCapability::CAN_EDIT => pht('Can Configure Application'),
|
||||
);
|
||||
|
||||
$map += ipull($this->getCustomCapabilities(), 'label');
|
||||
|
||||
return idx($map, $capability);
|
||||
}
|
||||
|
||||
public function isCapabilityEditable($capability) {
|
||||
switch ($capability) {
|
||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||
return $this->canUninstall();
|
||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||
return false;
|
||||
default:
|
||||
$spec = $this->getCustomCapabilitySpecification($capability);
|
||||
return idx($spec, 'edit', true);
|
||||
}
|
||||
}
|
||||
|
||||
public function getCapabilityCaption($capability) {
|
||||
switch ($capability) {
|
||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||
if (!$this->canUninstall()) {
|
||||
return pht(
|
||||
'This application is required for Phabricator to operate, so all '.
|
||||
'users must have access to it.');
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||
return null;
|
||||
default:
|
||||
$spec = $this->getCustomCapabilitySpecification($capability);
|
||||
return idx($spec, 'caption');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ final class PhabricatorApplicationApplications extends PhabricatorApplication {
|
|||
'PhabricatorApplicationsListController',
|
||||
'view/(?P<application>\w+)/' =>
|
||||
'PhabricatorApplicationDetailViewController',
|
||||
'edit/(?P<application>\w+)/' =>
|
||||
'PhabricatorApplicationEditController',
|
||||
'(?P<application>\w+)/(?P<action>install|uninstall)/' =>
|
||||
'PhabricatorApplicationUninstallController',
|
||||
),
|
||||
|
|
|
@ -13,8 +13,10 @@ final class PhabricatorApplicationDetailViewController
|
|||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$selected = PhabricatorApplication::getByClass($this->application);
|
||||
|
||||
$selected = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($user)
|
||||
->withClasses(array($this->application))
|
||||
->executeOne();
|
||||
if (!$selected) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
@ -24,8 +26,7 @@ final class PhabricatorApplicationDetailViewController
|
|||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName(pht('Applications'))
|
||||
->setHref($this->getApplicationURI()));
|
||||
->setName($selected->getName()));
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title);
|
||||
|
@ -70,37 +71,68 @@ final class PhabricatorApplicationDetailViewController
|
|||
));
|
||||
}
|
||||
|
||||
private function buildPropertyView(PhabricatorApplication $selected) {
|
||||
private function buildPropertyView(PhabricatorApplication $application) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$properties = id(new PhabricatorPropertyListView())
|
||||
->addProperty(
|
||||
pht('Description'), $selected->getShortDescription());
|
||||
->addProperty(pht('Description'), $application->getShortDescription());
|
||||
|
||||
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
|
||||
$viewer,
|
||||
$application);
|
||||
|
||||
$properties->addSectionHeader(pht('Policies'));
|
||||
|
||||
foreach ($application->getCapabilities() as $capability) {
|
||||
$properties->addProperty(
|
||||
$application->getCapabilityLabel($capability),
|
||||
idx($descriptions, $capability));
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
private function buildActionView(
|
||||
PhabricatorUser $user, PhabricatorApplication $selected) {
|
||||
PhabricatorUser $user,
|
||||
PhabricatorApplication $selected) {
|
||||
|
||||
$view = id(new PhabricatorActionListView())
|
||||
->setUser($user)
|
||||
->setObjectURI($this->getRequest()->getRequestURI());
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$user,
|
||||
$selected,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$edit_uri = $this->getApplicationURI('edit/'.get_class($selected).'/');
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit Policies'))
|
||||
->setIcon('edit')
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit)
|
||||
->setHref($edit_uri));
|
||||
|
||||
if ($selected->canUninstall()) {
|
||||
if ($selected->isInstalled()) {
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Uninstall'))
|
||||
->setIcon('delete')
|
||||
->setWorkflow(true)
|
||||
->setHref(
|
||||
$this->getApplicationURI(get_class($selected).'/uninstall/')));
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Uninstall'))
|
||||
->setIcon('delete')
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true)
|
||||
->setHref(
|
||||
$this->getApplicationURI(get_class($selected).'/uninstall/')));
|
||||
} else {
|
||||
$action = id(new PhabricatorActionView())
|
||||
->setName(pht('Install'))
|
||||
->setIcon('new')
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true)
|
||||
->setHref(
|
||||
$this->getApplicationURI(get_class($selected).'/install/'));
|
||||
$this->getApplicationURI(get_class($selected).'/install/'));
|
||||
|
||||
$beta_enabled = PhabricatorEnv::getEnvConfig(
|
||||
'phabricator.show-beta-applications');
|
||||
|
@ -112,14 +144,15 @@ final class PhabricatorApplicationDetailViewController
|
|||
}
|
||||
} else {
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Uninstall'))
|
||||
->setIcon('delete')
|
||||
->setWorkflow(true)
|
||||
->setDisabled(true)
|
||||
->setHref(
|
||||
$this->getApplicationURI(get_class($selected).'/uninstall/')));
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Uninstall'))
|
||||
->setIcon('delete')
|
||||
->setWorkflow(true)
|
||||
->setDisabled(true)
|
||||
->setHref(
|
||||
$this->getApplicationURI(get_class($selected).'/uninstall/')));
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorApplicationEditController
|
||||
extends PhabricatorApplicationsController{
|
||||
|
||||
private $application;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->application = $data['application'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$application = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($user)
|
||||
->withClasses(array($this->application))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$application) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$title = $application->getName();
|
||||
|
||||
$view_uri = $this->getApplicationURI('view/'.get_class($application).'/');
|
||||
|
||||
$policies = id(new PhabricatorPolicyQuery())
|
||||
->setViewer($user)
|
||||
->setObject($application)
|
||||
->execute();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$result = array();
|
||||
foreach ($application->getCapabilities() as $capability) {
|
||||
$old = $application->getPolicy($capability);
|
||||
$new = $request->getStr('policy:'.$capability);
|
||||
|
||||
if ($old == $new) {
|
||||
// No change to the setting.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($policies[$new])) {
|
||||
// Can't set the policy to something invalid.
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($new == PhabricatorPolicies::POLICY_PUBLIC &&
|
||||
$capability != PhabricatorPolicyCapability::CAN_VIEW) {
|
||||
// Can't set policies other than "view" to public.
|
||||
continue;
|
||||
}
|
||||
|
||||
$result[$capability] = $new;
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
$key = 'phabricator.application-settings';
|
||||
$config_entry = PhabricatorConfigEntry::loadConfigEntry($key);
|
||||
$value = $config_entry->getValue();
|
||||
|
||||
$phid = $application->getPHID();
|
||||
if (empty($value[$phid])) {
|
||||
$value[$application->getPHID()] = array();
|
||||
}
|
||||
if (empty($value[$phid]['policy'])) {
|
||||
$value[$phid]['policy'] = array();
|
||||
}
|
||||
|
||||
$value[$phid]['policy'] = $result + $value[$phid]['policy'];
|
||||
|
||||
PhabricatorConfigEditor::storeNewValue(
|
||||
$config_entry,
|
||||
$value,
|
||||
$this->getRequest());
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($view_uri);
|
||||
}
|
||||
|
||||
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
|
||||
$user,
|
||||
$application);
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user);
|
||||
|
||||
foreach ($application->getCapabilities() as $capability) {
|
||||
$label = $application->getCapabilityLabel($capability);
|
||||
$can_edit = $application->isCapabilityEditable($capability);
|
||||
$caption = $application->getCapabilityCaption($capability);
|
||||
|
||||
if (!$can_edit) {
|
||||
$form->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel($label)
|
||||
->setValue(idx($descriptions, $capability))
|
||||
->setCaption($caption));
|
||||
} else {
|
||||
$form->appendChild(
|
||||
id(new AphrontFormPolicyControl())
|
||||
->setUser($user)
|
||||
->setCapability($capability)
|
||||
->setPolicyObject($application)
|
||||
->setPolicies($policies)
|
||||
->setLabel($label)
|
||||
->setName('policy:'.$capability)
|
||||
->setCaption($caption));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$form->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save Policies'))
|
||||
->addCancelButton($view_uri));
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName($application->getName())
|
||||
->setHref($view_uri));
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName(pht('Edit Policies')));
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Edit Policies: %s', $application->getName()));
|
||||
|
||||
$object_box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setForm($form);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$object_box,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
'device' => true,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue