diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,7 +7,7 @@ */ return array( 'names' => array( - 'core.pkg.css' => 'd7ecac6d', + 'core.pkg.css' => 'eb51e6dc', 'core.pkg.js' => 'e0117d99', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '02273347', @@ -136,7 +136,7 @@ 'rsrc/css/phui/phui-fontkit.css' => 'dd8ddf27', 'rsrc/css/phui/phui-form-view.css' => '808329f2', 'rsrc/css/phui/phui-form.css' => '25876baf', - 'rsrc/css/phui/phui-header-view.css' => '2dd74fe0', + 'rsrc/css/phui/phui-header-view.css' => 'a8e1d0ac', 'rsrc/css/phui/phui-icon.css' => 'bc766998', 'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8', 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', @@ -779,7 +779,7 @@ 'phui-fontkit-css' => 'dd8ddf27', 'phui-form-css' => '25876baf', 'phui-form-view-css' => '808329f2', - 'phui-header-view-css' => '2dd74fe0', + 'phui-header-view-css' => 'a8e1d0ac', 'phui-icon-view-css' => 'bc766998', 'phui-image-mask-css' => '5a8b09c8', 'phui-info-panel-css' => '27ea50a1', diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -606,6 +606,23 @@ return idx($spec, 'template'); } + final public function getDefaultObjectTypePolicyMap() { + $map = array(); + + foreach ($this->getCustomCapabilities() as $capability => $spec) { + if (empty($spec['template'])) { + continue; + } + if (empty($spec['capability'])) { + continue; + } + $default = $this->getPolicy($capability); + $map[$spec['template']][$spec['capability']] = $default; + } + + return $map; + } + public function getApplicationSearchDocumentTypes() { return array(); } diff --git a/src/applications/countdown/application/PhabricatorCountdownApplication.php b/src/applications/countdown/application/PhabricatorCountdownApplication.php --- a/src/applications/countdown/application/PhabricatorCountdownApplication.php +++ b/src/applications/countdown/application/PhabricatorCountdownApplication.php @@ -53,6 +53,7 @@ PhabricatorCountdownDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for new countdowns.'), 'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), ); } diff --git a/src/applications/differential/application/PhabricatorDifferentialApplication.php b/src/applications/differential/application/PhabricatorDifferentialApplication.php --- a/src/applications/differential/application/PhabricatorDifferentialApplication.php +++ b/src/applications/differential/application/PhabricatorDifferentialApplication.php @@ -187,6 +187,7 @@ DifferentialDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created revisions.'), 'template' => DifferentialRevisionPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), ); } diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php --- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php +++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php @@ -142,10 +142,12 @@ return array( DiffusionDefaultViewCapability::CAPABILITY => array( 'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), DiffusionDefaultEditCapability::CAPABILITY => array( 'default' => PhabricatorPolicies::POLICY_ADMIN, 'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), DiffusionDefaultPushCapability::CAPABILITY => array( 'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST, diff --git a/src/applications/diviner/application/PhabricatorDivinerApplication.php b/src/applications/diviner/application/PhabricatorDivinerApplication.php --- a/src/applications/diviner/application/PhabricatorDivinerApplication.php +++ b/src/applications/diviner/application/PhabricatorDivinerApplication.php @@ -57,10 +57,12 @@ return array( DivinerDefaultViewCapability::CAPABILITY => array( 'template' => DivinerBookPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), DivinerDefaultEditCapability::CAPABILITY => array( 'default' => PhabricatorPolicies::POLICY_ADMIN, 'template' => DivinerBookPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), ); } diff --git a/src/applications/drydock/application/PhabricatorDrydockApplication.php b/src/applications/drydock/application/PhabricatorDrydockApplication.php --- a/src/applications/drydock/application/PhabricatorDrydockApplication.php +++ b/src/applications/drydock/application/PhabricatorDrydockApplication.php @@ -74,10 +74,12 @@ return array( DrydockDefaultViewCapability::CAPABILITY => array( 'template' => DrydockBlueprintPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), DrydockDefaultEditCapability::CAPABILITY => array( 'default' => PhabricatorPolicies::POLICY_ADMIN, 'template' => DrydockBlueprintPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), DrydockCreateBlueprintsCapability::CAPABILITY => array( 'default' => PhabricatorPolicies::POLICY_ADMIN, diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php --- a/src/applications/files/application/PhabricatorFilesApplication.php +++ b/src/applications/files/application/PhabricatorFilesApplication.php @@ -61,6 +61,7 @@ FilesDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created files.'), 'template' => PhabricatorFileFilePHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), ); } diff --git a/src/applications/legalpad/application/PhabricatorLegalpadApplication.php b/src/applications/legalpad/application/PhabricatorLegalpadApplication.php --- a/src/applications/legalpad/application/PhabricatorLegalpadApplication.php +++ b/src/applications/legalpad/application/PhabricatorLegalpadApplication.php @@ -77,9 +77,11 @@ LegalpadCreateDocumentsCapability::CAPABILITY => array(), LegalpadDefaultViewCapability::CAPABILITY => array( 'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), LegalpadDefaultEditCapability::CAPABILITY => array( 'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), ); } diff --git a/src/applications/maniphest/application/PhabricatorManiphestApplication.php b/src/applications/maniphest/application/PhabricatorManiphestApplication.php --- a/src/applications/maniphest/application/PhabricatorManiphestApplication.php +++ b/src/applications/maniphest/application/PhabricatorManiphestApplication.php @@ -132,10 +132,12 @@ ManiphestDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created tasks.'), 'template' => ManiphestTaskPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), ManiphestDefaultEditCapability::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created tasks.'), 'template' => ManiphestTaskPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), ManiphestEditStatusCapability::CAPABILITY => array(), ManiphestEditAssignCapability::CAPABILITY => array(), diff --git a/src/applications/nuance/application/PhabricatorNuanceApplication.php b/src/applications/nuance/application/PhabricatorNuanceApplication.php --- a/src/applications/nuance/application/PhabricatorNuanceApplication.php +++ b/src/applications/nuance/application/PhabricatorNuanceApplication.php @@ -73,10 +73,12 @@ NuanceSourceDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created sources.'), 'template' => NuanceSourcePHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), NuanceSourceDefaultEditCapability::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created sources.'), 'template' => NuanceSourcePHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), NuanceSourceManageCapability::CAPABILITY => array(), ); diff --git a/src/applications/passphrase/application/PhabricatorPassphraseApplication.php b/src/applications/passphrase/application/PhabricatorPassphraseApplication.php --- a/src/applications/passphrase/application/PhabricatorPassphraseApplication.php +++ b/src/applications/passphrase/application/PhabricatorPassphraseApplication.php @@ -71,11 +71,13 @@ PassphraseDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created credentials.'), 'template' => PassphraseCredentialPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, 'default' => $policy_key, ), PassphraseDefaultEditCapability::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created credentials.'), 'template' => PassphraseCredentialPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, 'default' => $policy_key, ), ); diff --git a/src/applications/paste/application/PhabricatorPasteApplication.php b/src/applications/paste/application/PhabricatorPasteApplication.php --- a/src/applications/paste/application/PhabricatorPasteApplication.php +++ b/src/applications/paste/application/PhabricatorPasteApplication.php @@ -65,10 +65,12 @@ PasteDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created pastes.'), 'template' => PhabricatorPastePastePHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), PasteDefaultEditCapability::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created pastes.'), 'template' => PhabricatorPastePastePHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), ); } diff --git a/src/applications/pholio/application/PhabricatorPholioApplication.php b/src/applications/pholio/application/PhabricatorPholioApplication.php --- a/src/applications/pholio/application/PhabricatorPholioApplication.php +++ b/src/applications/pholio/application/PhabricatorPholioApplication.php @@ -73,9 +73,11 @@ return array( PholioDefaultViewCapability::CAPABILITY => array( 'template' => PholioMockPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), PholioDefaultEditCapability::CAPABILITY => array( 'template' => PholioMockPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), ); } diff --git a/src/applications/policy/controller/PhabricatorPolicyEditController.php b/src/applications/policy/controller/PhabricatorPolicyEditController.php --- a/src/applications/policy/controller/PhabricatorPolicyEditController.php +++ b/src/applications/policy/controller/PhabricatorPolicyEditController.php @@ -6,9 +6,6 @@ public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); - // TODO: This doesn't do anything yet, but sets up template policies; see - // T6860. - $is_template = false; $object_phid = $request->getURIData('objectPHID'); if ($object_phid) { @@ -23,7 +20,6 @@ $object_type = $request->getURIData('objectType'); if (!$object_type) { $object_type = $request->getURIData('templateType'); - $is_template = true; } $phid_types = PhabricatorPHIDType::getAllInstalledTypes($viewer); diff --git a/src/applications/policy/controller/PhabricatorPolicyExplainController.php b/src/applications/policy/controller/PhabricatorPolicyExplainController.php --- a/src/applications/policy/controller/PhabricatorPolicyExplainController.php +++ b/src/applications/policy/controller/PhabricatorPolicyExplainController.php @@ -3,24 +3,15 @@ final class PhabricatorPolicyExplainController extends PhabricatorPolicyController { - private $phid; - private $capability; - public function shouldAllowPublic() { return true; } - public function willProcessRequest(array $data) { - $this->phid = $data['phid']; - $this->capability = $data['capability']; - } - - public function processRequest() { - $request = $this->getRequest(); - $viewer = $request->getUser(); + public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); - $phid = $this->phid; - $capability = $this->capability; + $phid = $request->getURIData('phid'); + $capability = $request->getURIData('capability'); $object = id(new PhabricatorObjectQuery()) ->setViewer($viewer) @@ -84,11 +75,15 @@ $handle->getTypeName(), $handle->getObjectName()); - return $dialog + $dialog ->setTitle(pht('Policy Details: %s', $object_name)) ->appendParagraph($intro) ->appendChild($auto_info) ->addCancelButton($object_uri, pht('Done')); + + $this->appendStrengthInformation($dialog, $object, $policy, $capability); + + return $dialog; } private function appendSpaceInformation( @@ -180,4 +175,46 @@ 'object policy checks.')); } + private function appendStrengthInformation( + AphrontDialogView $dialog, + PhabricatorPolicyInterface $object, + PhabricatorPolicy $policy, + $capability) { + $viewer = $this->getViewer(); + + $default_policy = PhabricatorPolicyQuery::getDefaultPolicyForObject( + $viewer, + $object, + $capability); + if (!$default_policy) { + return; + } + + if ($default_policy->getPHID() == $policy->getPHID()) { + return; + } + + if ($default_policy->isStrongerThan($policy)) { + $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)) { + $info = pht( + 'This object has a more restrictive policy ("%s") than the default '. + 'policy for similar objects (which is "%s").', + $policy->getShortName(), + $default_policy->getShortName()); + } else { + $info = pht( + 'This object has a different policy ("%s") than the default policy '. + 'for similar objects (which is "%s").', + $policy->getShortName(), + $default_policy->getShortName()); + } + + $dialog->appendParagraph($info); + } + } diff --git a/src/applications/policy/query/PhabricatorPolicyQuery.php b/src/applications/policy/query/PhabricatorPolicyQuery.php --- a/src/applications/policy/query/PhabricatorPolicyQuery.php +++ b/src/applications/policy/query/PhabricatorPolicyQuery.php @@ -342,5 +342,46 @@ return $results; } + public static function getDefaultPolicyForObject( + PhabricatorUser $viewer, + PhabricatorPolicyInterface $object, + $capability) { + + $phid = $object->getPHID(); + if (!$phid) { + return null; + } + + $type = phid_get_type($phid); + + $map = self::getDefaultObjectTypePolicyMap(); + + if (empty($map[$type][$capability])) { + return null; + } + + $policy_phid = $map[$type][$capability]; + + return id(new PhabricatorPolicyQuery()) + ->setViewer($viewer) + ->withPHIDs(array($policy_phid)) + ->executeOne(); + } + + private static function getDefaultObjectTypePolicyMap() { + static $map; + + if ($map === null) { + $map = array(); + + $apps = PhabricatorApplication::getAllApplications(); + foreach ($apps as $app) { + $map += $app->getDefaultObjectTypePolicyMap(); + } + } + + return $map; + } + } diff --git a/src/applications/project/application/PhabricatorProjectApplication.php b/src/applications/project/application/PhabricatorProjectApplication.php --- a/src/applications/project/application/PhabricatorProjectApplication.php +++ b/src/applications/project/application/PhabricatorProjectApplication.php @@ -121,14 +121,17 @@ ProjectDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created projects.'), 'template' => PhabricatorProjectProjectPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), ProjectDefaultEditCapability::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created projects.'), 'template' => PhabricatorProjectProjectPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), ProjectDefaultJoinCapability::CAPABILITY => array( 'caption' => pht('Default join policy for newly created projects.'), 'template' => PhabricatorProjectProjectPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_JOIN, ), ); } diff --git a/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php b/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php --- a/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php +++ b/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php @@ -65,6 +65,7 @@ PhabricatorSlowvoteDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for new polls.'), 'template' => PhabricatorSlowvotePollPHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), ); } diff --git a/src/applications/spaces/application/PhabricatorSpacesApplication.php b/src/applications/spaces/application/PhabricatorSpacesApplication.php --- a/src/applications/spaces/application/PhabricatorSpacesApplication.php +++ b/src/applications/spaces/application/PhabricatorSpacesApplication.php @@ -74,11 +74,13 @@ PhabricatorSpacesCapabilityDefaultView::CAPABILITY => array( 'caption' => pht('Default view policy for newly created spaces.'), 'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), PhabricatorSpacesCapabilityDefaultEdit::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created spaces.'), 'default' => PhabricatorPolicies::POLICY_ADMIN, 'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST, + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), ); } 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 @@ -292,6 +292,7 @@ // NOTE: We'll do this even if the viewer has access to only one space, and // show them information about the existence of spaces if they click // through. + $use_space_policy = false; if ($object instanceof PhabricatorSpacesInterface) { $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID( $object); @@ -306,13 +307,46 @@ if ($space_policy) { if ($space_policy->isStrongerThan($policy)) { $policy = $space_policy; + $use_space_policy = true; } } } } + $container_classes = array(); + $container_classes[] = 'policy-header-callout'; $phid = $object->getPHID(); + // If we're going to show the object policy, try to determine if the object + // 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'; + } + } + } + } + $icon = id(new PHUIIconView()) ->setIconFont($policy->getIcon().' bluegrey'); @@ -325,7 +359,12 @@ ), $policy->getShortName()); - return array($icon, $link); + return phutil_tag( + 'span', + array( + 'class' => implode(' ', $container_classes), + ), + array($icon, $link)); } } diff --git a/webroot/rsrc/css/phui/phui-header-view.css b/webroot/rsrc/css/phui/phui-header-view.css --- a/webroot/rsrc/css/phui/phui-header-view.css +++ b/webroot/rsrc/css/phui/phui-header-view.css @@ -116,6 +116,41 @@ color: {$darkbluetext}; } +.policy-header-callout.policy-adjusted { + padding: 0 4px; + border-radius: 3px; +} + +.policy-header-callout.policy-adjusted-weaker { + background: {$lightgreen}; + border: 1px solid {$green}; +} + +.policy-header-callout.policy-adjusted-weaker .policy-link, +.policy-header-callout.policy-adjusted-weaker .phui-icon-view { + color: {$green}; +} + +.policy-header-callout.policy-adjusted-stronger { + background: {$lightred}; + border: 1px solid {$red}; +} + +.policy-header-callout.policy-adjusted-stronger .policy-link, +.policy-header-callout.policy-adjusted-stronger .phui-icon-view { + color: {$red}; +} + +.policy-header-callout.policy-adjusted-different { + background: {$lightorange}; + border: 1px solid {$orange}; +} + +.policy-header-callout.policy-adjusted-different .policy-link, +.policy-header-callout.policy-adjusted-different .phui-icon-view { + color: {$orange}; +} + .phui-header-subheader .phui-header-status-dark { color: {$indigo}; text-shadow: 0 1px #fff;