Page MenuHomePhabricator

D8179.id18502.diff
No OneTemporary

D8179.id18502.diff

diff --git a/src/applications/policy/filter/PhabricatorPolicyFilter.php b/src/applications/policy/filter/PhabricatorPolicyFilter.php
--- a/src/applications/policy/filter/PhabricatorPolicyFilter.php
+++ b/src/applications/policy/filter/PhabricatorPolicyFilter.php
@@ -8,6 +8,7 @@
private $raisePolicyExceptions;
private $userProjects;
private $customPolicies = array();
+ private $forcedPolicy;
public static function mustRetainCapability(
PhabricatorUser $user,
@@ -25,11 +26,48 @@
PhabricatorUser $user,
PhabricatorPolicyInterface $object,
$capability) {
- $filter = new PhabricatorPolicyFilter();
- $filter->setViewer($user);
- $filter->requireCapabilities(array($capability));
- $filter->raisePolicyExceptions(true);
- $filter->apply(array($object));
+ $filter = id(new PhabricatorPolicyFilter())
+ ->setViewer($user)
+ ->requireCapabilities(array($capability))
+ ->raisePolicyExceptions(true)
+ ->apply(array($object));
+ }
+
+ /**
+ * Perform a capability check, acting as though an object had a specific
+ * policy. This is primarily used to check if a policy is valid (for example,
+ * to prevent users from editing away their ability to edit an object).
+ *
+ * Specifically, a check like this:
+ *
+ * PhabricatorPolicyFilter::requireCapabilityWithForcedPolicy(
+ * $viewer,
+ * $object,
+ * PhabricatorPolicyCapability::CAN_EDIT,
+ * $potential_new_policy);
+ *
+ * ...will throw a @{class:PhabricatorPolicyException} if the new policy would
+ * remove the user's ability to edit the object.
+ *
+ * @param PhabricatorUser The viewer to perform a policy check for.
+ * @param PhabricatorPolicyInterface The object to perform a policy check on.
+ * @param string Capability to test.
+ * @param string Perform the test as though the object has this
+ * policy instead of the policy it actually has.
+ * @return void
+ */
+ public static function requireCapabilityWithForcedPolicy(
+ PhabricatorUser $viewer,
+ PhabricatorPolicyInterface $object,
+ $capability,
+ $forced_policy) {
+
+ id(new PhabricatorPolicyFilter())
+ ->setViewer($viewer)
+ ->requireCapabilities(array($capability))
+ ->raisePolicyExceptions(true)
+ ->forcePolicy($forced_policy)
+ ->apply(array($object));
}
public static function hasCapability(
@@ -60,6 +98,11 @@
return $this;
}
+ public function forcePolicy($forced_policy) {
+ $this->forcedPolicy = $forced_policy;
+ return $this;
+ }
+
public function apply(array $objects) {
assert_instances_of($objects, 'PhabricatorPolicyInterface');
@@ -96,7 +139,7 @@
"not have that capability!");
}
- $policy = $object->getPolicy($capability);
+ $policy = $this->getObjectPolicy($object, $capability);
$type = phid_get_type($policy);
if ($type == PhabricatorProjectPHIDTypeProject::TYPECONST) {
$need_projects[$policy] = $policy;
@@ -169,7 +212,7 @@
PhabricatorPolicyInterface $object,
$capability) {
- $policy = $object->getPolicy($capability);
+ $policy = $this->getObjectPolicy($object, $capability);
if (!$policy) {
// TODO: Formalize this somehow?
@@ -402,4 +445,15 @@
return false;
}
+ private function getObjectPolicy(
+ PhabricatorPolicyInterface $object,
+ $capability) {
+
+ if ($this->forcedPolicy) {
+ return $this->forcedPolicy;
+ } else {
+ return $object->getPolicy($capability);
+ }
+ }
+
}
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -1144,6 +1144,29 @@
$errors = array();
switch ($type) {
+ case PhabricatorTransactions::TYPE_EDIT_POLICY:
+ // Make sure the user isn't editing away their ability to edit this
+ // object.
+ foreach ($xactions as $xaction) {
+ try {
+ PhabricatorPolicyFilter::requireCapabilityWithForcedPolicy(
+ $this->requireActor(),
+ $object,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ $xaction->getNewValue());
+ } catch (PhabricatorPolicyException $ex) {
+ $errors[] = array(
+ new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Invalid'),
+ pht(
+ 'You can not select this edit policy, because you would '.
+ 'no longer be able to edit the object.'),
+ $xaction),
+ );
+ }
+ }
+ break;
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
$groups = array();
foreach ($xactions as $xaction) {

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 11, 3:34 AM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6728842
Default Alt Text
D8179.id18502.diff (4 KB)

Event Timeline