diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3867,6 +3867,7 @@ 'PhabricatorPolicyRequestExceptionHandler' => 'aphront/handler/PhabricatorPolicyRequestExceptionHandler.php', 'PhabricatorPolicyRule' => 'applications/policy/rule/PhabricatorPolicyRule.php', 'PhabricatorPolicySearchEngineExtension' => 'applications/policy/engineextension/PhabricatorPolicySearchEngineExtension.php', + 'PhabricatorPolicyStrengthConstants' => 'applications/policy/constants/PhabricatorPolicyStrengthConstants.php', 'PhabricatorPolicyTestCase' => 'applications/policy/__tests__/PhabricatorPolicyTestCase.php', 'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php', 'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php', @@ -4998,6 +4999,7 @@ 'PhrictionDocumentMoveToTransaction' => 'applications/phriction/xaction/PhrictionDocumentMoveToTransaction.php', 'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php', 'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php', + 'PhrictionDocumentPolicyCodex' => 'applications/phriction/codex/PhrictionDocumentPolicyCodex.php', 'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php', 'PhrictionDocumentSearchConduitAPIMethod' => 'applications/phriction/conduit/PhrictionDocumentSearchConduitAPIMethod.php', 'PhrictionDocumentSearchEngine' => 'applications/phriction/query/PhrictionDocumentSearchEngine.php', @@ -9669,6 +9671,7 @@ 'PhabricatorPolicyRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorPolicyRule' => 'Phobject', 'PhabricatorPolicySearchEngineExtension' => 'PhabricatorSearchEngineExtension', + 'PhabricatorPolicyStrengthConstants' => 'PhabricatorPolicyConstants', 'PhabricatorPolicyTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyTestObject' => array( 'Phobject', @@ -11060,6 +11063,7 @@ 'PhabricatorProjectInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorConduitResultInterface', + 'PhabricatorPolicyCodexInterface', ), 'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField', @@ -11076,6 +11080,7 @@ 'PhrictionDocumentMoveToTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType', 'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField', + 'PhrictionDocumentPolicyCodex' => 'PhabricatorPolicyCodex', 'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhrictionDocumentSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhrictionDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine', diff --git a/src/applications/phriction/codex/PhrictionDocumentPolicyCodex.php b/src/applications/phriction/codex/PhrictionDocumentPolicyCodex.php new file mode 100644 --- /dev/null +++ b/src/applications/phriction/codex/PhrictionDocumentPolicyCodex.php @@ -0,0 +1,82 @@ +getObject(); + $strongest_policy = $this->getStrongestPolicy(); + + $rules = array(); + $rules[] = $this->newRule() + ->setDescription( + pht('To view a wiki document, you must also be able to view all '. + 'of its ancestors. The most-restrictive view policy of this '. + 'document\'s ancestors is "%s".', + $strongest_policy->getShortName())) + ->setCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW)); + + $rules[] = $this->newRule() + ->setDescription( + pht('To edit a wiki document, you must also be able to view all '. + 'of its ancestors.')) + ->setCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT)); + + return $rules; + } + + public function getDefaultPolicy() { + $ancestors = $this->getObject()->getAncestors(); + if ($ancestors) { + $root = head($ancestors); + } else { + $root = $this->getObject(); + } + + $root_policy_phid = $root->getPolicy($this->getCapability()); + + return id(new PhabricatorPolicyQuery()) + ->setViewer($this->getViewer()) + ->withPHIDs(array($root_policy_phid)) + ->executeOne(); + } + + public function compareToDefaultPolicy(PhabricatorPolicy $policy) { + $root_policy = $this->getDefaultPolicy(); + $strongest_policy = $this->getStrongestPolicy(); + + // Note that we never return 'weaker', because Phriction documents can + // never have weaker permissions than their parents. If this object has + // been set to weaker permissions anyway, return 'adjusted'. + if ($root_policy == $strongest_policy) { + $strength = null; + } else if ($strongest_policy->isStrongerThan($root_policy)) { + $strength = PhabricatorPolicyStrengthConstants::STRONGER; + } else { + $strength = PhabricatorPolicyStrengthConstants::ADJUSTED; + } + return $strength; + } + + private function getStrongestPolicy() { + $ancestors = $this->getObject()->getAncestors(); + $ancestors[] = $this->getObject(); + + $strongest_policy = $this->getDefaultPolicy(); + foreach ($ancestors as $ancestor) { + $ancestor_policy_phid = $ancestor->getPolicy($this->getCapability()); + + $ancestor_policy = id(new PhabricatorPolicyQuery()) + ->setViewer($this->getViewer()) + ->withPHIDs(array($ancestor_policy_phid)) + ->executeOne(); + + if ($ancestor_policy->isStrongerThan($strongest_policy)) { + $strongest_policy = $ancestor_policy; + } + } + + return $strongest_policy; + } + +} diff --git a/src/applications/phriction/controller/PhrictionEditController.php b/src/applications/phriction/controller/PhrictionEditController.php --- a/src/applications/phriction/controller/PhrictionEditController.php +++ b/src/applications/phriction/controller/PhrictionEditController.php @@ -219,6 +219,13 @@ ->execute(); $view_capability = PhabricatorPolicyCapability::CAN_VIEW; $edit_capability = PhabricatorPolicyCapability::CAN_EDIT; + $codex = id(PhabricatorPolicyCodex::newFromObject($document, $viewer)) + ->setCapability($view_capability); + + $view_capability_description = $codex->getPolicySpecialRuleForCapability( + PhabricatorPolicyCapability::CAN_VIEW)->getDescription(); + $edit_capability_description = $codex->getPolicySpecialRuleForCapability( + PhabricatorPolicyCapability::CAN_EDIT)->getDescription(); $form = id(new AphrontFormView()) ->setUser($viewer) @@ -264,16 +271,14 @@ ->setPolicyObject($document) ->setCapability($view_capability) ->setPolicies($policies) - ->setCaption( - $document->describeAutomaticCapability($view_capability))) + ->setCaption($view_capability_description)) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('editPolicy') ->setPolicyObject($document) ->setCapability($edit_capability) ->setPolicies($policies) - ->setCaption( - $document->describeAutomaticCapability($edit_capability))) + ->setCaption($edit_capability_description)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Edit Notes')) diff --git a/src/applications/phriction/storage/PhrictionDocument.php b/src/applications/phriction/storage/PhrictionDocument.php --- a/src/applications/phriction/storage/PhrictionDocument.php +++ b/src/applications/phriction/storage/PhrictionDocument.php @@ -11,7 +11,8 @@ PhabricatorFerretInterface, PhabricatorProjectInterface, PhabricatorApplicationTransactionInterface, - PhabricatorConduitResultInterface { + PhabricatorConduitResultInterface, + PhabricatorPolicyCodexInterface { protected $slug; protected $depth; @@ -200,22 +201,6 @@ return false; } - public function describeAutomaticCapability($capability) { - - switch ($capability) { - case PhabricatorPolicyCapability::CAN_VIEW: - return pht( - 'To view a wiki document, you must also be able to view all '. - 'of its parents.'); - case PhabricatorPolicyCapability::CAN_EDIT: - return pht( - 'To edit a wiki document, you must also be able to view all '. - 'of its parents.'); - } - - return null; - } - /* -( PhabricatorSubscribableInterface )----------------------------------- */ @@ -328,4 +313,13 @@ ->setAttachmentKey('content'), ); } + +/* -( PhabricatorPolicyCodexInterface )------------------------------------ */ + + + public function newPolicyCodex() { + return new PhrictionDocumentPolicyCodex(); + } + + } diff --git a/src/applications/policy/codex/PhabricatorPolicyCodex.php b/src/applications/policy/codex/PhabricatorPolicyCodex.php --- a/src/applications/policy/codex/PhabricatorPolicyCodex.php +++ b/src/applications/policy/codex/PhabricatorPolicyCodex.php @@ -29,6 +29,27 @@ return array(); } + public function getDefaultPolicy() { + return PhabricatorPolicyQuery::getDefaultPolicyForObject( + $this->viewer, + $this->object, + $this->capability); + } + + public function compareToDefaultPolicy(PhabricatorPolicy $policy) { + return null; + } + + final public function getPolicySpecialRuleForCapability($capability) { + foreach ($this->getPolicySpecialRuleDescriptions() as $rule) { + if (in_array($capability, $rule->getCapabilities())) { + return $rule; + } + } + + return null; + } + final protected function newRule() { return new PhabricatorPolicyCodexRuleDescription(); } diff --git a/src/applications/policy/constants/PhabricatorPolicyStrengthConstants.php b/src/applications/policy/constants/PhabricatorPolicyStrengthConstants.php new file mode 100644 --- /dev/null +++ b/src/applications/policy/constants/PhabricatorPolicyStrengthConstants.php @@ -0,0 +1,9 @@ +getViewer(); - $default_policy = PhabricatorPolicyQuery::getDefaultPolicyForObject( - $viewer, - $object, - $capability); - if (!$default_policy) { - return; + + $strength = null; + if ($object instanceof PhabricatorPolicyCodexInterface) { + $codex = id(PhabricatorPolicyCodex::newFromObject($object, $viewer)) + ->setCapability($capability); + $strength = $codex->compareToDefaultPolicy($policy); + $default_policy = $codex->getDefaultPolicy(); + } else { + $default_policy = PhabricatorPolicyQuery::getDefaultPolicyForObject( + $viewer, + $object, + $capability); + + if ($default_policy) { + if ($default_policy->getPHID() == $policy->getPHID()) { + return; + } + + if ($default_policy->getPHID() != $policy->getPHID()) { + if ($default_policy->isStrongerThan($policy)) { + $strength = PhabricatorPolicyStrengthConstants::WEAKER; + } else if ($policy->isStrongerThan($default_policy)) { + $strength = PhabricatorPolicyStrengthConstants::STRONGER; + } else { + $strength = PhabricatorPolicyStrengthConstants::ADJUSTED; + } + } + } } - if ($default_policy->getPHID() == $policy->getPHID()) { + if (!$strength) { return; } - if ($default_policy->isStrongerThan($policy)) { + if ($strength == PhabricatorPolicyStrengthConstants::WEAKER) { $info = pht( 'This object has a less restrictive policy ("%s") than the default '. 'policy for similar objects (which is "%s").', $policy->getShortName(), $default_policy->getShortName()); - } else if ($policy->isStrongerThan($default_policy)) { + } else if ($strength == PhabricatorPolicyStrengthConstants::STRONGER) { $info = pht( 'This object has a more restrictive policy ("%s") than the default '. 'policy for similar objects (which is "%s").', diff --git a/src/applications/policy/storage/PhabricatorPolicy.php b/src/applications/policy/storage/PhabricatorPolicy.php --- a/src/applications/policy/storage/PhabricatorPolicy.php +++ b/src/applications/policy/storage/PhabricatorPolicy.php @@ -434,11 +434,12 @@ $capability, $active_only) { + $exceptions = array(); if ($object instanceof PhabricatorPolicyCodexInterface) { - $codex = PhabricatorPolicyCodex::newFromObject($object, $viewer); + $codex = id(PhabricatorPolicyCodex::newFromObject($object, $viewer)) + ->setCapability($capability); $rules = $codex->getPolicySpecialRuleDescriptions(); - $exceptions = array(); foreach ($rules as $rule) { $is_active = $rule->getIsActive(); if ($is_active) { @@ -467,11 +468,13 @@ $exceptions[] = $description; } - } else if (method_exists($object, 'describeAutomaticCapability')) { - $exceptions = (array)$object->describeAutomaticCapability($capability); - $exceptions = array_filter($exceptions); - } else { - $exceptions = array(); + } + + if (!$exceptions) { + if (method_exists($object, 'describeAutomaticCapability')) { + $exceptions = (array)$object->describeAutomaticCapability($capability); + $exceptions = array_filter($exceptions); + } } return $exceptions; diff --git a/src/view/phui/PHUIHeaderView.php b/src/view/phui/PHUIHeaderView.php --- a/src/view/phui/PHUIHeaderView.php +++ b/src/view/phui/PHUIHeaderView.php @@ -473,30 +473,47 @@ // policy differs from the default policy. If it does, we'll call it out // as changed. if (!$use_space_policy) { - $default_policy = PhabricatorPolicyQuery::getDefaultPolicyForObject( - $viewer, - $object, - $view_capability); - if ($default_policy) { - if ($default_policy->getPHID() != $policy->getPHID()) { - $container_classes[] = 'policy-adjusted'; - if ($default_policy->isStrongerThan($policy)) { - // The policy has strictly been weakened. For example, the - // default might be "All Users" and the current policy is "Public". - $container_classes[] = 'policy-adjusted-weaker'; - } else if ($policy->isStrongerThan($default_policy)) { - // The policy has strictly been strengthened, and is now more - // restrictive than the default. For example, "All Users" has - // been replaced with "No One". - $container_classes[] = 'policy-adjusted-stronger'; - } else { - // The policy has been adjusted but not strictly strengthened - // or weakened. For example, "Members of X" has been replaced with - // "Members of Y". - $container_classes[] = 'policy-adjusted-different'; + $strength = null; + if ($object instanceof PhabricatorPolicyCodexInterface) { + $codex = id(PhabricatorPolicyCodex::newFromObject($object, $viewer)) + ->setCapability($view_capability); + $strength = $codex->compareToDefaultPolicy($policy); + } else { + $default_policy = PhabricatorPolicyQuery::getDefaultPolicyForObject( + $viewer, + $object, + $view_capability); + + if ($default_policy) { + if ($default_policy->getPHID() != $policy->getPHID()) { + if ($default_policy->isStrongerThan($policy)) { + $strength = PhabricatorPolicyStrengthConstants::WEAKER; + } else if ($policy->isStrongerThan($default_policy)) { + $strength = PhabricatorPolicyStrengthConstants::STRONGER; + } else { + $strength = PhabricatorPolicyStrengthConstants::ADJUSTED; + } } } } + + if ($strength) { + if ($strength == PhabricatorPolicyStrengthConstants::WEAKER) { + // The policy has strictly been weakened. For example, the + // default might be "All Users" and the current policy is "Public". + $container_classes[] = 'policy-adjusted-weaker'; + } else if ($strength == PhabricatorPolicyStrengthConstants::STRONGER) { + // The policy has strictly been strengthened, and is now more + // restrictive than the default. For example, "All Users" has + // been replaced with "No One". + $container_classes[] = 'policy-adjusted-stronger'; + } else { + // The policy has been adjusted but not strictly strengthened + // or weakened. For example, "Members of X" has been replaced with + // "Members of Y". + $container_classes[] = 'policy-adjusted-different'; + } + } } $policy_name = array($policy->getShortName());