1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-11 15:21:03 +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(); return $login_controller->processRequest();
} }
$content = hsprintf( $list = $ex->getMoreInfo();
'<div class="aphront-policy-exception">%s</div>', foreach ($list as $key => $item) {
$ex->getMessage()); $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 = new AphrontDialogView();
$dialog $dialog

View file

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

View file

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

View file

@ -2,4 +2,15 @@
final class PhabricatorPolicyException extends Exception { 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."); "This object has an impossible {$verb} policy.");
} }
private function rejectObject($object, $policy, $capability) { public function rejectObject(
PhabricatorPolicyInterface $object,
$policy,
$capability) {
if (!$this->raisePolicyExceptions) { if (!$this->raisePolicyExceptions) {
return; return;
} }
// TODO: clean this up $more = array();
$verb = $capability; switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
$message = "You do not have permission to {$verb} this object."; $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) { switch ($policy) {
case PhabricatorPolicies::POLICY_PUBLIC: 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; break;
case PhabricatorPolicies::POLICY_USER: 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; break;
case PhabricatorPolicies::POLICY_ADMIN: 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; break;
case PhabricatorPolicies::POLICY_NOONE: 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; break;
default: default:
$handle = id(new PhabricatorHandleQuery()) $handle = id(new PhabricatorHandleQuery())
@ -279,16 +315,55 @@ final class PhabricatorPolicyFilter {
$type = phid_get_type($policy); $type = phid_get_type($policy);
if ($type == PhabricatorProjectPHIDTypeProject::TYPECONST) { if ($type == PhabricatorProjectPHIDTypeProject::TYPECONST) {
$who = "To {$verb} this object, you must be a member of project ". switch ($capability) {
"'".$handle->getFullName()."'."; 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) { } 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 { } else {
$who = "It is unclear who can {$verb} this object."; $who = pht("This object has an unknown policy setting.");
} }
break; 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(); $results = array();
$filter = new PhabricatorPolicyFilter(); $filter = $this->getPolicyFilter();
$filter->setViewer($this->viewer);
if (!$this->capabilities) {
$capabilities = array(
PhabricatorPolicyCapability::CAN_VIEW,
);
} else {
$capabilities = $this->capabilities;
}
$filter->requireCapabilities($capabilities);
$filter->raisePolicyExceptions($this->shouldRaisePolicyExceptions());
$offset = (int)$this->getOffset(); $offset = (int)$this->getOffset();
$limit = (int)$this->getLimit(); $limit = (int)$this->getLimit();
@ -287,6 +276,29 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
return $results; 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 )---------------------------------------- */ /* -( Policy Query Implementation )---------------------------------------- */