1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 14:00:56 +01:00

Provide better strings in policy errors and exceptions

Summary:
Ref T603. This could probably use a little more polish, but improve the quality of policy error messages.

  - Provide as much detail as possible.
  - Fix all the strings for i18n.
  - Explain special rules to the user.
  - Allow indirect policy filters to raise policy exceptions instead of 404s.

Test Plan: See screenshots.

Reviewers: btrahan, chad

Reviewed By: chad

CC: aran

Maniphest Tasks: T603

Differential Revision: https://secure.phabricator.com/D7151
This commit is contained in:
epriestley 2013-09-27 08:43:50 -07:00
parent 2e5ac128b3
commit 5799e8e2de
6 changed files with 146 additions and 30 deletions

View file

@ -164,9 +164,23 @@ class AphrontDefaultApplicationConfiguration
return $login_controller->processRequest();
}
$content = hsprintf(
'<div class="aphront-policy-exception">%s</div>',
$ex->getMessage());
$list = $ex->getMoreInfo();
foreach ($list as $key => $item) {
$list[$key] = phutil_tag('li', array(), $item);
}
if ($list) {
$list = phutil_tag('ul', array(), $list);
}
$content = phutil_tag(
'div',
array(
'class' => 'aphront-policy-exception',
),
array(
$ex->getMessage(),
$list,
));
$dialog = new AphrontDialogView();
$dialog

View file

@ -416,9 +416,13 @@ final class DifferentialRevisionQuery
// The revision has an associated repository, and the viewer can't see
// it, and the viewer has no special capabilities. Filter out this
// revision.
$this->didRejectResult($revision);
unset($revisions[$key]);
}
if (!$revisions) {
return array();
}
$table = new DifferentialRevision();
$conn_r = $table->establishConnection('r');

View file

@ -338,7 +338,7 @@ final class DifferentialRevision extends DifferentialDAO
case PhabricatorPolicyCapability::CAN_VIEW:
$description[] = pht(
"A revision's reviewers can always view it.");
if ($this->getRepository()) {
if ($this->getRepositoryPHID()) {
$description[] = pht(
'This revision belongs to a repository. Other users must be able '.
'to view the repository in order to view this revision.');

View file

@ -2,4 +2,15 @@
final class PhabricatorPolicyException extends Exception {
private $moreInfo = array();
public function setMoreInfo(array $more_info) {
$this->moreInfo = $more_info;
return $this;
}
public function getMoreInfo() {
return $this->moreInfo;
}
}

View file

@ -248,28 +248,64 @@ final class PhabricatorPolicyFilter {
"This object has an impossible {$verb} policy.");
}
private function rejectObject($object, $policy, $capability) {
public function rejectObject(
PhabricatorPolicyInterface $object,
$policy,
$capability) {
if (!$this->raisePolicyExceptions) {
return;
}
// TODO: clean this up
$verb = $capability;
$message = "You do not have permission to {$verb} this object.";
$more = array();
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
$message = pht(
'This object exists, but you do not have permission to view it.');
break;
case PhabricatorPolicyCapability::CAN_EDIT:
$message = pht('You do not have permission to edit this object.');
break;
case PhabricatorPolicyCapability::CAN_JOIN:
$message = pht('You do not have permission to join this object.');
break;
}
switch ($policy) {
case PhabricatorPolicies::POLICY_PUBLIC:
$who = "This is curious, since anyone can {$verb} the object.";
// Presumably, this is a bug, so we don't bother specializing the
// strings.
$more = pht('This object is public.');
break;
case PhabricatorPolicies::POLICY_USER:
$who = "To {$verb} this object, you must be logged in.";
// We always raise this as "log in", so we don't need to specialize.
$more = pht('This object is available to logged in users.');
break;
case PhabricatorPolicies::POLICY_ADMIN:
$who = "To {$verb} this object, you must be an administrator.";
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
$more = pht('Administrators can view this object.');
break;
case PhabricatorPolicyCapability::CAN_EDIT:
$more = pht('Administrators can edit this object.');
break;
case PhabricatorPolicyCapability::CAN_JOIN:
$more = pht('Administrators can join this object.');
break;
}
break;
case PhabricatorPolicies::POLICY_NOONE:
$who = "No one can {$verb} this object.";
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
$more = pht('By default, no one can view this object.');
break;
case PhabricatorPolicyCapability::CAN_EDIT:
$more = pht('By default, no one can edit this object.');
break;
case PhabricatorPolicyCapability::CAN_JOIN:
$more = pht('By default, no one can join this object.');
break;
}
break;
default:
$handle = id(new PhabricatorHandleQuery())
@ -279,16 +315,55 @@ final class PhabricatorPolicyFilter {
$type = phid_get_type($policy);
if ($type == PhabricatorProjectPHIDTypeProject::TYPECONST) {
$who = "To {$verb} this object, you must be a member of project ".
"'".$handle->getFullName()."'.";
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
$more = pht(
'This object is visible to members of the project "%s".',
$handle->getFullName());
break;
case PhabricatorPolicyCapability::CAN_EDIT:
$more = pht(
'This object can be edited by members of the project "%s".',
$handle->getFullName());
break;
case PhabricatorPolicyCapability::CAN_JOIN:
$more = pht(
'This object can be joined by members of the project "%s".',
$handle->getFullName());
break;
}
} else if ($type == PhabricatorPeoplePHIDTypeUser::TYPECONST) {
$who = "Only '".$handle->getFullName()."' can {$verb} this object.";
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
$more = pht(
'%s can view this object.',
$handle->getFullName());
break;
case PhabricatorPolicyCapability::CAN_EDIT:
$more = pht(
'%s can edit this object.',
$handle->getFullName());
break;
case PhabricatorPolicyCapability::CAN_JOIN:
$more = pht(
'%s can join this object.',
$handle->getFullName());
break;
}
} else {
$who = "It is unclear who can {$verb} this object.";
$who = pht("This object has an unknown policy setting.");
}
break;
}
throw new PhabricatorPolicyException("{$message} {$who}");
$more = array_merge(
array($more),
array_filter((array)$object->describeAutomaticCapability($capability)));
$exception = new PhabricatorPolicyException($message);
$exception->setMoreInfo($more);
throw $exception;
}
}

View file

@ -190,18 +190,7 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
$results = array();
$filter = new PhabricatorPolicyFilter();
$filter->setViewer($this->viewer);
if (!$this->capabilities) {
$capabilities = array(
PhabricatorPolicyCapability::CAN_VIEW,
);
} else {
$capabilities = $this->capabilities;
}
$filter->requireCapabilities($capabilities);
$filter->raisePolicyExceptions($this->shouldRaisePolicyExceptions());
$filter = $this->getPolicyFilter();
$offset = (int)$this->getOffset();
$limit = (int)$this->getLimit();
@ -287,6 +276,29 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
return $results;
}
private function getPolicyFilter() {
$filter = new PhabricatorPolicyFilter();
$filter->setViewer($this->viewer);
if (!$this->capabilities) {
$capabilities = array(
PhabricatorPolicyCapability::CAN_VIEW,
);
} else {
$capabilities = $this->capabilities;
}
$filter->requireCapabilities($capabilities);
$filter->raisePolicyExceptions($this->shouldRaisePolicyExceptions());
return $filter;
}
protected function didRejectResult(PhabricatorPolicyInterface $object) {
$this->getPolicyFilter()->rejectObject(
$object,
$object->getPolicy(PhabricatorPolicyCapability::CAN_VIEW),
PhabricatorPolicyCapability::CAN_VIEW);
}
/* -( Policy Query Implementation )---------------------------------------- */