1
0
Fork 0
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:
epriestley 2013-10-03 12:40:08 -07:00
parent bf14d8ef2c
commit c830461b00
5 changed files with 305 additions and 27 deletions

View file

@ -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',

View file

@ -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');
}
}
}

View file

@ -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',
),

View file

@ -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;
}

View file

@ -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,
));
}
}