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:
parent
2e5ac128b3
commit
5799e8e2de
6 changed files with 146 additions and 30 deletions
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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.');
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 )---------------------------------------- */
|
||||
|
||||
|
|
Loading…
Reference in a new issue