Page MenuHomePhabricator

D16830.id40530.diff
No OneTemporary

D16830.id40530.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -9,7 +9,7 @@
'names' => array(
'conpherence.pkg.css' => 'cea72e09',
'conpherence.pkg.js' => '6249a1cf',
- 'core.pkg.css' => '4fc9469e',
+ 'core.pkg.css' => '66739a56',
'core.pkg.js' => '1a77dddf',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => 'a4ba74b5',
@@ -21,7 +21,7 @@
'maniphest.pkg.js' => '949a7498',
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
'rsrc/css/aphront/dark-console.css' => 'f54bf286',
- 'rsrc/css/aphront/dialog-view.css' => '84f1e6a6',
+ 'rsrc/css/aphront/dialog-view.css' => '1e6b8603',
'rsrc/css/aphront/lightbox-attachment.css' => '7acac05d',
'rsrc/css/aphront/list-filter-view.css' => '5d6f0526',
'rsrc/css/aphront/multi-column.css' => '84cc6640',
@@ -142,7 +142,7 @@
'rsrc/css/phui/phui-form-view.css' => '9e22b190',
'rsrc/css/phui/phui-form.css' => 'aac1d51d',
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
- 'rsrc/css/phui/phui-header-view.css' => '06385974',
+ 'rsrc/css/phui/phui-header-view.css' => '6ec8f155',
'rsrc/css/phui/phui-hovercard.css' => 'de1a2119',
'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad',
'rsrc/css/phui/phui-icon.css' => '417f80fb',
@@ -552,7 +552,7 @@
'almanac-css' => 'dbb9b3af',
'aphront-bars' => '231ac33c',
'aphront-dark-console-css' => 'f54bf286',
- 'aphront-dialog-view-css' => '84f1e6a6',
+ 'aphront-dialog-view-css' => '1e6b8603',
'aphront-list-filter-view-css' => '5d6f0526',
'aphront-multi-column-view-css' => '84cc6640',
'aphront-panel-view-css' => '8427b78d',
@@ -865,7 +865,7 @@
'phui-form-css' => 'aac1d51d',
'phui-form-view-css' => '9e22b190',
'phui-head-thing-view-css' => 'fd311e5f',
- 'phui-header-view-css' => '06385974',
+ 'phui-header-view-css' => '6ec8f155',
'phui-hovercard' => '1bd28176',
'phui-hovercard-view-css' => 'de1a2119',
'phui-icon-set-selector-css' => '1ab67aad',
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
@@ -1668,6 +1668,7 @@
'PHUIPagerView' => 'view/phui/PHUIPagerView.php',
'PHUIPinboardItemView' => 'view/phui/PHUIPinboardItemView.php',
'PHUIPinboardView' => 'view/phui/PHUIPinboardView.php',
+ 'PHUIPolicySectionView' => 'applications/policy/view/PHUIPolicySectionView.php',
'PHUIPropertyGroupView' => 'view/phui/PHUIPropertyGroupView.php',
'PHUIPropertyListExample' => 'applications/uiexample/examples/PHUIPropertyListExample.php',
'PHUIPropertyListView' => 'view/phui/PHUIPropertyListView.php',
@@ -2071,6 +2072,7 @@
'PhabricatorCalendarEventNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventNameTransaction.php',
'PhabricatorCalendarEventNotificationView' => 'applications/calendar/notifications/PhabricatorCalendarEventNotificationView.php',
'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php',
+ 'PhabricatorCalendarEventPolicyCodex' => 'applications/calendar/codex/PhabricatorCalendarEventPolicyCodex.php',
'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php',
'PhabricatorCalendarEventRSVPEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventRSVPEmailCommand.php',
'PhabricatorCalendarEventRecurringTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventRecurringTransaction.php',
@@ -3311,6 +3313,9 @@
'PhabricatorPolicyCanViewCapability' => 'applications/policy/capability/PhabricatorPolicyCanViewCapability.php',
'PhabricatorPolicyCapability' => 'applications/policy/capability/PhabricatorPolicyCapability.php',
'PhabricatorPolicyCapabilityTestCase' => 'applications/policy/capability/__tests__/PhabricatorPolicyCapabilityTestCase.php',
+ 'PhabricatorPolicyCodex' => 'applications/policy/codex/PhabricatorPolicyCodex.php',
+ 'PhabricatorPolicyCodexInterface' => 'applications/policy/codex/PhabricatorPolicyCodexInterface.php',
+ 'PhabricatorPolicyCodexRuleDescription' => 'applications/policy/codex/PhabricatorPolicyCodexRuleDescription.php',
'PhabricatorPolicyConfigOptions' => 'applications/policy/config/PhabricatorPolicyConfigOptions.php',
'PhabricatorPolicyConstants' => 'applications/policy/constants/PhabricatorPolicyConstants.php',
'PhabricatorPolicyController' => 'applications/policy/controller/PhabricatorPolicyController.php',
@@ -6447,6 +6452,7 @@
'PHUIPagerView' => 'AphrontView',
'PHUIPinboardItemView' => 'AphrontView',
'PHUIPinboardView' => 'AphrontView',
+ 'PHUIPolicySectionView' => 'AphrontTagView',
'PHUIPropertyGroupView' => 'AphrontTagView',
'PHUIPropertyListExample' => 'PhabricatorUIExample',
'PHUIPropertyListView' => 'AphrontView',
@@ -6870,6 +6876,7 @@
'PhabricatorCalendarDAO',
'PhabricatorPolicyInterface',
'PhabricatorExtendedPolicyInterface',
+ 'PhabricatorPolicyCodexInterface',
'PhabricatorProjectInterface',
'PhabricatorMarkupInterface',
'PhabricatorApplicationTransactionInterface',
@@ -6923,6 +6930,7 @@
'PhabricatorCalendarEventNameTransaction' => 'PhabricatorCalendarEventTransactionType',
'PhabricatorCalendarEventNotificationView' => 'Phobject',
'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType',
+ 'PhabricatorCalendarEventPolicyCodex' => 'PhabricatorPolicyCodex',
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorCalendarEventRSVPEmailCommand' => 'PhabricatorCalendarEventEmailCommand',
'PhabricatorCalendarEventRecurringTransaction' => 'PhabricatorCalendarEventTransactionType',
@@ -8361,6 +8369,8 @@
'PhabricatorPolicyCanViewCapability' => 'PhabricatorPolicyCapability',
'PhabricatorPolicyCapability' => 'Phobject',
'PhabricatorPolicyCapabilityTestCase' => 'PhabricatorTestCase',
+ 'PhabricatorPolicyCodex' => 'Phobject',
+ 'PhabricatorPolicyCodexRuleDescription' => 'Phobject',
'PhabricatorPolicyConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorPolicyConstants' => 'Phobject',
'PhabricatorPolicyController' => 'PhabricatorController',
diff --git a/src/applications/calendar/codex/PhabricatorCalendarEventPolicyCodex.php b/src/applications/calendar/codex/PhabricatorCalendarEventPolicyCodex.php
new file mode 100644
--- /dev/null
+++ b/src/applications/calendar/codex/PhabricatorCalendarEventPolicyCodex.php
@@ -0,0 +1,80 @@
+<?php
+
+final class PhabricatorCalendarEventPolicyCodex
+ extends PhabricatorPolicyCodex {
+
+ public function getPolicyShortName() {
+ $object = $this->getObject();
+
+ if (!$object->isImportedEvent()) {
+ return null;
+ }
+
+ return pht('Uses Import Policy');
+ }
+
+ public function getPolicyIcon() {
+ $object = $this->getObject();
+
+ if (!$object->isImportedEvent()) {
+ return null;
+ }
+
+ return 'fa-download';
+ }
+
+ public function getPolicyTagClasses() {
+ $object = $this->getObject();
+
+ if (!$object->isImportedEvent()) {
+ return array();
+ }
+
+ return array(
+ 'policy-adjusted-special',
+ );
+ }
+
+ public function getPolicySpecialRuleDescriptions() {
+ $object = $this->getObject();
+
+ $rules = array();
+ $rules[] = $this->newRule()
+ ->setDescription(
+ pht('The host of an event can always view and edit it.'));
+
+ $rules[] = $this->newRule()
+ ->setCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ ))
+ ->setDescription(
+ pht('Users who are invited to an event can always view it.'));
+
+
+ $rules[] = $this->newRule()
+ ->setCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ ))
+ ->setIsActive($object->isImportedEvent())
+ ->setDescription(
+ pht(
+ 'Imported events can only be viewed by users who can view '.
+ 'the import source.'));
+
+ $rules[] = $this->newRule()
+ ->setCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->setIsActive($object->isImportedEvent())
+ ->setDescription(
+ pht(
+ 'Imported events can not be edited in Phabricator.'));
+
+ return $rules;
+ }
+
+
+}
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
--- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
@@ -4,6 +4,7 @@
implements
PhabricatorPolicyInterface,
PhabricatorExtendedPolicyInterface,
+ PhabricatorPolicyCodexInterface,
PhabricatorProjectInterface,
PhabricatorMarkupInterface,
PhabricatorApplicationTransactionInterface,
@@ -1217,18 +1218,6 @@
return false;
}
- public function describeAutomaticCapability($capability) {
- if ($this->isImportedEvent()) {
- return pht(
- 'Events imported from external sources can not be edited in '.
- 'Phabricator.');
- }
-
- return pht(
- 'The host of an event can always view and edit it. Users who are '.
- 'invited to an event can always view it.');
- }
-
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
@@ -1251,6 +1240,12 @@
return $extended;
}
+/* -( PhabricatorPolicyCodexInterface )------------------------------------ */
+
+ public function newPolicyCodex() {
+ return new PhabricatorCalendarEventPolicyCodex();
+ }
+
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
diff --git a/src/applications/differential/storage/DifferentialRevision.php b/src/applications/differential/storage/DifferentialRevision.php
--- a/src/applications/differential/storage/DifferentialRevision.php
+++ b/src/applications/differential/storage/DifferentialRevision.php
@@ -370,14 +370,6 @@
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
- // NOTE: In Differential, an automatic capability on a revision (being
- // an author) is sufficient to view it, even if you can not see the
- // repository the revision belongs to. We can bail out early in this
- // case.
- if ($this->hasAutomaticCapability($capability, $viewer)) {
- break;
- }
-
$repository_phid = $this->getRepositoryPHID();
$repository = $this->getRepository();
diff --git a/src/applications/policy/codex/PhabricatorPolicyCodex.php b/src/applications/policy/codex/PhabricatorPolicyCodex.php
new file mode 100644
--- /dev/null
+++ b/src/applications/policy/codex/PhabricatorPolicyCodex.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * Rendering extensions that allows an object to render custom strings,
+ * descriptions and explanations for the policy system to help users
+ * understand complex policies.
+ */
+abstract class PhabricatorPolicyCodex
+ extends Phobject {
+
+ private $viewer;
+ private $object;
+ private $policy;
+ private $capability;
+
+ public function getPolicyShortName() {
+ return null;
+ }
+
+ public function getPolicyIcon() {
+ return null;
+ }
+
+ public function getPolicyTagClasses() {
+ return array();
+ }
+
+ public function getPolicySpecialRuleDescriptions() {
+ return array();
+ }
+
+ final protected function newRule() {
+ return new PhabricatorPolicyCodexRuleDescription();
+ }
+
+ final public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ final public function getViewer() {
+ return $this->viewer;
+ }
+
+ final public function setObject(PhabricatorPolicyCodexInterface $object) {
+ $this->object = $object;
+ return $this;
+ }
+
+ final public function getObject() {
+ return $this->object;
+ }
+
+ final public function setCapability($capability) {
+ $this->capability = $capability;
+ return $this;
+ }
+
+ final public function getCapability() {
+ return $this->capability;
+ }
+
+ final public function setPolicy(PhabricatorPolicy $policy) {
+ $this->policy = $policy;
+ return $this;
+ }
+
+ final public function getPolicy() {
+ return $this->policy;
+ }
+
+ final public static function newFromObject(
+ PhabricatorPolicyCodexInterface $object,
+ PhabricatorUser $viewer) {
+
+ if (!($object instanceof PhabricatorPolicyInterface)) {
+ throw new Exception(
+ pht(
+ 'Object (of class "%s") implements interface "%s", but must also '.
+ 'implement interface "%s".',
+ get_class($object),
+ 'PhabricatorPolicyCodexInterface',
+ 'PhabricatorPolicyInterface'));
+ }
+
+ $codex = $object->newPolicyCodex();
+ if (!($codex instanceof PhabricatorPolicyCodex)) {
+ throw new Exception(
+ pht(
+ 'Object (of class "%s") implements interface "%s", but defines '.
+ 'method "%s" incorrectly: this method must return an object of '.
+ 'class "%s".',
+ get_class($object),
+ 'PhabricatorPolicyCodexInterface',
+ 'newPolicyCodex()',
+ __CLASS__));
+ }
+
+ $codex
+ ->setObject($object)
+ ->setViewer($viewer);
+
+ return $codex;
+ }
+
+}
diff --git a/src/applications/policy/codex/PhabricatorPolicyCodexInterface.php b/src/applications/policy/codex/PhabricatorPolicyCodexInterface.php
new file mode 100644
--- /dev/null
+++ b/src/applications/policy/codex/PhabricatorPolicyCodexInterface.php
@@ -0,0 +1,18 @@
+<?php
+
+interface PhabricatorPolicyCodexInterface {
+
+ public function newPolicyCodex();
+
+}
+
+// TEMPLATE IMPLEMENTATION /////////////////////////////////////////////////////
+
+/* -( PhabricatorPolicyCodexInterface )------------------------------------ */
+/*
+
+ public function newPolicyCodex() {
+ return new <<...>>PolicyCodex();
+ }
+
+*/
diff --git a/src/applications/policy/codex/PhabricatorPolicyCodexRuleDescription.php b/src/applications/policy/codex/PhabricatorPolicyCodexRuleDescription.php
new file mode 100644
--- /dev/null
+++ b/src/applications/policy/codex/PhabricatorPolicyCodexRuleDescription.php
@@ -0,0 +1,37 @@
+<?php
+
+final class PhabricatorPolicyCodexRuleDescription
+ extends Phobject {
+
+ private $description;
+ private $capabilities = array();
+ private $isActive = true;
+
+ public function setDescription($description) {
+ $this->description = $description;
+ return $this;
+ }
+
+ public function getDescription() {
+ return $this->description;
+ }
+
+ public function setCapabilities(array $capabilities) {
+ $this->capabilities = $capabilities;
+ return $this;
+ }
+
+ public function getCapabilities() {
+ return $this->capabilities;
+ }
+
+ public function setIsActive($is_active) {
+ $this->isActive = $is_active;
+ return $this;
+ }
+
+ public function getIsActive() {
+ return $this->isActive;
+ }
+
+}
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
@@ -34,50 +34,136 @@
->setViewer($viewer)
->withPHIDs(array($phid))
->executeOne();
- $object_uri = nonempty($handle->getURI(), '/');
- $explanation = PhabricatorPolicy::getPolicyExplanation(
- $viewer,
- $policy->getPHID());
+ $object_name = $handle->getName();
+ $object_uri = nonempty($handle->getURI(), '/');
- $auto_info = (array)$object->describeAutomaticCapability($capability);
+ $dialog = id(new AphrontDialogView())
+ ->setUser($viewer)
+ ->setClass('aphront-access-dialog')
+ ->setTitle(pht('Policy Details: %s', $object_name))
+ ->addCancelButton($object_uri, pht('Done'));
- $auto_info = array_merge(
- array($explanation),
- $auto_info);
- $auto_info = array_filter($auto_info);
+ $this->appendSpaceInformation($dialog, $object, $policy, $capability);
- $capability_name = $capability;
- $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability);
- if ($capobj) {
- $capability_name = $capobj->getCapabilityName();
+ if ($object instanceof PhabricatorExtendedPolicyInterface) {
+ $extended_rules = $object->getExtendedPolicy($capability, $viewer);
+ if ($extended_rules) {
+ $extended_section = id(new PHUIPolicySectionView())
+ ->setViewer($viewer)
+ ->setIcon('fa-link')
+ ->setHeader(pht('Required Capabilities on Other Objects'))
+ ->appendParagraph(
+ pht(
+ 'To access this object, users must have first have access '.
+ 'capabilties on these other objects:'));
+
+ $items = array();
+ foreach ($extended_rules as $extended_rule) {
+ $extended_target = $extended_rule[0];
+ $extended_capabilities = (array)$extended_rule[1];
+ if (is_object($extended_target)) {
+ $extended_target = $extended_target->getPHID();
+ }
+
+ foreach ($extended_capabilities as $extended_capability) {
+ $ex_name = $this->getCapabilityName($extended_capability);
+ $items[] = array(
+ phutil_tag('strong', array(), pht('%s:', $ex_name)),
+ ' ',
+ $viewer->renderHandle($extended_target)->setAsTag(true),
+ );
+ }
+ }
+
+ $extended_section->appendList($items);
+
+ $dialog->appendChild($extended_section);
+ }
}
- $dialog = id(new AphrontDialogView())
- ->setUser($viewer)
- ->setClass('aphront-access-dialog');
+ if ($object instanceof PhabricatorPolicyCodexInterface) {
+ $codex = PhabricatorPolicyCodex::newFromObject($object, $viewer);
+ $rules = $codex->getPolicySpecialRuleDescriptions();
+
+ $exceptions = array();
+ foreach ($rules as $rule) {
+ $is_active = $rule->getIsActive();
+ if ($is_active) {
+ $rule_capabilities = $rule->getCapabilities();
+ if ($rule_capabilities) {
+ if (!in_array($capability, $rule_capabilities)) {
+ $is_active = false;
+ }
+ }
+ }
+
+ $description = $rule->getDescription();
+
+ if (!$is_active) {
+ $description = phutil_tag(
+ 'span',
+ array(
+ 'class' => 'phui-policy-section-view-inactive-rule',
+ ),
+ $description);
+ }
- $this->appendSpaceInformation($dialog, $object, $policy, $capability);
+ $exceptions[] = $description;
+ }
+ } else if (method_exists($object, 'describeAutomaticCapability')) {
+ $exceptions = (array)$object->describeAutomaticCapability($capability);
+ $exceptions = array_filter($exceptions);
+ } else {
+ $exceptions = array();
+ }
- $intro = pht(
- 'Users with the "%s" capability for this object:',
- $capability_name);
+ if ($exceptions) {
+ $exceptions_section = id(new PHUIPolicySectionView())
+ ->setViewer($viewer)
+ ->setIcon('fa-unlock-alt red')
+ ->setHeader(pht('Special Rules'))
+ ->appendParagraph(
+ pht(
+ 'This object has special rules which override normal object '.
+ 'policy rules:'))
+ ->appendList($exceptions);
- $object_name = pht(
- '%s %s',
- $handle->getTypeName(),
- $handle->getObjectName());
+ $dialog->appendChild($exceptions_section);
+ }
- $dialog
- ->setTitle(pht('Policy Details: %s', $object_name))
- ->appendParagraph($intro)
- ->addCancelButton($object_uri, pht('Done'));
+ $capability_name = $this->getCapabilityName($capability);
- if ($auto_info) {
- $dialog->appendList($auto_info);
+ $object_section = id(new PHUIPolicySectionView())
+ ->setViewer($viewer)
+ ->setIcon($handle->getIcon().' bluegrey')
+ ->setHeader(pht('Object Policy'))
+ ->appendList(
+ array(
+ array(
+ phutil_tag('strong', array(), pht('%s:', $capability_name)),
+ ' ',
+ $policy->getShortName(),
+ ),
+ ))
+ ->appendParagraph(
+ pht(
+ 'In detail, this means that these users can take this action, '.
+ 'provided they pass all of the checks described above first:'))
+ ->appendList(
+ array(
+ PhabricatorPolicy::getPolicyExplanation(
+ $viewer,
+ $policy->getPHID()),
+ ));
+
+ $strength = $this->getStrengthInformation($object, $policy, $capability);
+ if ($strength) {
+ $object_section->appendHint($strength);
}
- $this->appendStrengthInformation($dialog, $object, $policy, $capability);
+ $dialog->appendChild($object_section);
+
return $dialog;
}
@@ -97,35 +183,9 @@
return;
}
- // NOTE: We're intentionally letting users through here, even if they only
- // have access to one space. The intent is to help users in "space jail"
- // understand who objects they create are visible to:
-
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
$object);
- $handles = $viewer->loadHandles(array($space_phid));
- $doc_href = PhabricatorEnv::getDoclink('Spaces User Guide');
-
- $dialog->appendParagraph(
- array(
- pht(
- 'This object is in %s, and can only be seen or edited by users with '.
- 'access to view objects in the space.',
- $handles[$space_phid]->renderLink()),
- ' ',
- phutil_tag(
- 'strong',
- array(),
- phutil_tag(
- 'a',
- array(
- 'href' => $doc_href,
- 'target' => '_blank',
- ),
- pht('Learn More'))),
- ));
-
$spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer);
$space = idx($spaces, $space_phid);
if (!$space) {
@@ -138,20 +198,49 @@
return;
}
+ $handles = $viewer->loadHandles(array($space_phid));
+ $doc_href = PhabricatorEnv::getDoclink('Spaces User Guide');
+ $capability_name = $this->getCapabilityName($capability);
+
+ $space_section = id(new PHUIPolicySectionView())
+ ->setViewer($viewer)
+ ->setIcon('fa-th-large bluegrey')
+ ->setHeader(pht('Space'))
+ ->setDocumentationLink(pht('Spaces Documentation'), $doc_href)
+ ->appendList(
+ array(
+ array(
+ phutil_tag('strong', array(), pht('Space:')),
+ ' ',
+ $viewer->renderHandle($space_phid)->setAsTag(true),
+ ),
+ array(
+ phutil_tag('strong', array(), pht('%s:', $capability_name)),
+ ' ',
+ $space_policy->getShortName(),
+ ),
+ ))
+ ->appendParagraph(
+ pht(
+ 'This object is in %s and can only be seen or edited by users '.
+ 'with access to view objects in the space.',
+ $viewer->renderHandle($space_phid)));
+
$space_explanation = PhabricatorPolicy::getPolicyExplanation(
$viewer,
$space_policy->getPHID());
$items = array();
$items[] = $space_explanation;
- $dialog->appendParagraph(pht('Users who can see objects in this space:'));
- $dialog->appendList($items);
+ $space_section
+ ->appendParagraph(pht('Users who can see objects in this space:'))
+ ->appendList($items);
$view_capability = PhabricatorPolicyCapability::CAN_VIEW;
if ($capability == $view_capability) {
$stronger = $space_policy->isStrongerThan($policy);
if ($stronger) {
- $dialog->appendParagraph(
+ $space_section->appendHint(
pht(
'The space this object is in has a more restrictive view '.
'policy ("%s") than the object does ("%s"), so the space\'s '.
@@ -161,14 +250,16 @@
}
}
- $dialog->appendParagraph(
+ $space_section->appendHint(
pht(
'After a user passes space policy checks, they must still pass '.
'object policy checks.'));
+
+
+ $dialog->appendChild($space_section);
}
- private function appendStrengthInformation(
- AphrontDialogView $dialog,
+ private function getStrengthInformation(
PhabricatorPolicyInterface $object,
PhabricatorPolicy $policy,
$capability) {
@@ -206,7 +297,18 @@
$default_policy->getShortName());
}
- $dialog->appendParagraph($info);
+ return $info;
}
+ private function getCapabilityName($capability) {
+ $capability_name = $capability;
+ $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability);
+ if ($capobj) {
+ $capability_name = $capobj->getCapabilityName();
+ }
+
+ return $capability_name;
+ }
+
+
}
diff --git a/src/applications/policy/interface/PhabricatorPolicyInterface.php b/src/applications/policy/interface/PhabricatorPolicyInterface.php
--- a/src/applications/policy/interface/PhabricatorPolicyInterface.php
+++ b/src/applications/policy/interface/PhabricatorPolicyInterface.php
@@ -6,34 +6,6 @@
public function getPolicy($capability);
public function hasAutomaticCapability($capability, PhabricatorUser $viewer);
- /**
- * Describe exceptions to an object's policy setting.
- *
- * The intent of this method is to explain and inform users about special
- * cases which override configured policy settings. If this object has any
- * such exceptions, explain them by returning one or more human-readable
- * strings which describe the exception in a broad, categorical way. For
- * example:
- *
- * - "The owner of an X can always view and edit it."
- * - "Members of a Y can always view it."
- *
- * You can return `null`, a single string, or a list of strings.
- *
- * The relevant capability to explain (like "view") is passed as a parameter.
- * You should tailor any messages to be relevant to that capability, although
- * they do not need to exclusively describe the capability, and in some cases
- * being more general ("The author can view and edit...") will be more clear.
- *
- * Messages should describe general rules, not specific objects, because the
- * main goal is to teach the user the rules. For example, write "the author",
- * not the specific author's name.
- *
- * @param const @{class:PhabricatorPolicyCapability} constant.
- * @return wild Description of policy exceptions. See above.
- */
- public function describeAutomaticCapability($capability);
-
}
// TEMPLATE IMPLEMENTATION /////////////////////////////////////////////////////
@@ -58,8 +30,4 @@
return false;
}
- public function describeAutomaticCapability($capability) {
- return null;
- }
-
*/
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
@@ -225,7 +225,9 @@
switch ($policy) {
case PhabricatorPolicies::POLICY_PUBLIC:
- return pht('This object is public.');
+ return pht(
+ 'This object is public and can be viewed by anyone, even if they '.
+ 'do not have a Phabricator account.');
case PhabricatorPolicies::POLICY_USER:
return pht('Logged in users can take this action.');
case PhabricatorPolicies::POLICY_ADMIN:
diff --git a/src/applications/policy/view/PHUIPolicySectionView.php b/src/applications/policy/view/PHUIPolicySectionView.php
new file mode 100644
--- /dev/null
+++ b/src/applications/policy/view/PHUIPolicySectionView.php
@@ -0,0 +1,142 @@
+<?php
+
+final class PHUIPolicySectionView
+ extends AphrontTagView {
+
+ private $icon;
+ private $header;
+ private $documentationLink;
+
+ public function setHeader($header) {
+ $this->header = $header;
+ return $this;
+ }
+
+ public function getHeader() {
+ return $this->header;
+ }
+
+ public function setIcon($icon) {
+ $this->icon = $icon;
+ return $this;
+ }
+
+ public function getIcon() {
+ return $this->icon;
+ }
+
+ public function setDocumentationLink($name, $href) {
+ $link = phutil_tag(
+ 'a',
+ array(
+ 'href' => $href,
+ 'target' => '_blank',
+ ),
+ $name);
+
+ $this->documentationLink = phutil_tag(
+ 'div',
+ array(
+ 'class' => 'phui-policy-section-view-link',
+ ),
+ array(
+ id(new PHUIIconView())->setIcon('fa-book'),
+ $link,
+ ));
+
+ return $this;
+ }
+
+ public function getDocumentationLink() {
+ return $this->documentationLink;
+ }
+
+ public function appendList(array $items) {
+ foreach ($items as $key => $item) {
+ $items[$key] = phutil_tag(
+ 'li',
+ array(
+ 'class' => 'remarkup-list-item',
+ ),
+ $item);
+ }
+
+ $list = phutil_tag(
+ 'ul',
+ array(
+ 'class' => 'remarkup-list',
+ ),
+ $items);
+
+ return $this->appendChild($list);
+ }
+
+ public function appendHint($content) {
+ $hint = phutil_tag(
+ 'p',
+ array(
+ 'class' => 'phui-policy-section-view-hint',
+ ),
+ array(
+ id(new PHUIIconView())
+ ->setIcon('fa-sticky-note bluegrey'),
+ ' ',
+ pht('Note:'),
+ ' ',
+ $content,
+ ));
+
+ return $this->appendChild($hint);
+ }
+
+ public function appendParagraph($content) {
+ return $this->appendChild(phutil_tag('p', array(), $content));
+ }
+
+ protected function getTagAttributes() {
+ return array(
+ 'class' => 'phui-policy-section-view',
+ );
+ }
+
+ protected function getTagContent() {
+ require_celerity_resource('phui-header-view-css');
+
+ $icon_view = null;
+ $icon = $this->getIcon();
+ if ($icon !== null) {
+ $icon_view = id(new PHUIIconView())
+ ->setIcon($icon);
+ }
+
+ $header_view = phutil_tag(
+ 'span',
+ array(
+ 'class' => 'phui-policy-section-view-header-text',
+ ),
+ $this->getHeader());
+
+ $header = phutil_tag(
+ 'div',
+ array(
+ 'class' => 'phui-policy-section-view-header',
+ ),
+ array(
+ $icon_view,
+ $header_view,
+ $this->getDocumentationLink(),
+ ));
+
+ return array(
+ $header,
+ phutil_tag(
+ 'div',
+ array(
+ 'class' => 'phui-policy-section-view-body',
+ ),
+ $this->renderChildren()),
+ );
+ }
+
+
+}
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
@@ -452,6 +452,7 @@
// show them information about the existence of spaces if they click
// through.
$use_space_policy = false;
+ $containing_space = null;
if ($object instanceof PhabricatorSpacesInterface) {
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
$object);
@@ -459,6 +460,7 @@
$spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer);
$space = idx($spaces, $space_phid);
if ($space) {
+ $containing_space = $space;
$space_policies = PhabricatorPolicyQuery::loadPolicies(
$viewer,
$space);
@@ -506,8 +508,90 @@
}
}
+ $policy_name = array($policy->getShortName());
+ $policy_icon = $policy->getIcon().' bluegrey';
+
+ if ($object instanceof PhabricatorExtendedPolicyInterface) {
+ $extended_objects = $object->getExtendedPolicy(
+ $view_capability,
+ $viewer);
+ if ($extended_objects) {
+ $extended_phids = array();
+ foreach ($extended_objects as $extended_object) {
+ if (is_object($extended_object[0])) {
+ $extended_phids[] = $extended_object[0]->getPHID();
+ } else {
+ $extended_phids[] = $extended_object[0];
+ }
+ }
+
+ $extended_handles = $viewer->loadHandles($extended_phids);
+
+ $extended_names = array();
+ foreach ($extended_phids as $extended_phid) {
+ // TODO: It would be nice to just show a monogram here, but we don't
+ // currently have that on handles.
+ $extended_names[] = $extended_handles[$extended_phid]->getName();
+ }
+
+ $extended_names = phutil_implode_html(
+ " \xC2\xB7 ",
+ $extended_names);
+
+ array_unshift($policy_name, $extended_names);
+ }
+ }
+
+ if ($object instanceof PhabricatorPolicyCodexInterface) {
+ $codex = PhabricatorPolicyCodex::newFromObject($object, $viewer);
+
+ $codex_name = $codex->getPolicyShortName($policy, $view_capability);
+ if ($codex_name !== null) {
+ $policy_name = $codex_name;
+ }
+
+ $codex_icon = $codex->getPolicyIcon($policy, $view_capability);
+ if ($codex_icon !== null) {
+ $policy_icon = $codex_icon;
+ }
+
+ $codex_classes = $codex->getPolicyTagClasses($policy, $view_capability);
+ foreach ($codex_classes as $codex_class) {
+ $container_classes[] = $codex_class;
+ }
+ }
+
+ if (!is_array($policy_name)) {
+ $policy_name = (array)$policy_name;
+ }
+
+ if ($containing_space) {
+ $default_space = PhabricatorSpacesNamespaceQuery::getDefaultSpace();
+
+ $is_default_space =
+ ($default_space) &&
+ ($default_space->getPHID() == $containing_space->getPHID());
+
+ if (!$is_default_space) {
+ $space_tag = phutil_tag(
+ 'span',
+ array(
+ 'class' => 'policy-space-container',
+ ),
+ $containing_space->getMonogram());
+
+ array_unshift($policy_name, $space_tag);
+ }
+ }
+
+ $arrow = id(new PHUIIconView())
+ ->setIcon('fa-angle-right')
+ ->addClass('policy-tier-separator');
+
+ $policy_name = phutil_implode_html($arrow, $policy_name);
+
$icon = id(new PHUIIconView())
- ->setIcon($policy->getIcon().' bluegrey');
+ ->setIcon($policy_icon);
$link = javelin_tag(
'a',
@@ -516,7 +600,7 @@
'href' => '/policy/explain/'.$phid.'/'.$view_capability.'/',
'sigil' => 'workflow',
),
- $policy->getShortName());
+ $policy_name);
return phutil_tag(
'span',
diff --git a/webroot/rsrc/css/aphront/dialog-view.css b/webroot/rsrc/css/aphront/dialog-view.css
--- a/webroot/rsrc/css/aphront/dialog-view.css
+++ b/webroot/rsrc/css/aphront/dialog-view.css
@@ -128,6 +128,10 @@
width: 50%;
}
+.aphront-access-dialog .aphront-dialog-body {
+ padding: 0 12px;
+}
+
.aphront-policy-rejection {
font-weight: bold;
}
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
@@ -240,6 +240,26 @@
color: {$sh-orangetext};
}
+.policy-header-callout.policy-adjusted-special {
+ background: {$sh-indigobackground};
+}
+
+.policy-header-callout.policy-adjusted-special .policy-link,
+.policy-header-callout.policy-adjusted-special .phui-icon-view {
+ color: {$sh-indigotext};
+}
+
+.policy-header-callout .policy-space-container {
+ font-weight: bold;
+ color: {$sh-redtext};
+}
+
+.policy-header-callout .policy-tier-separator {
+ padding: 0 0 0 4px;
+ color: {$lightgreytext};
+}
+
+
.phui-header-action-links .phui-mobile-menu {
display: none;
}
@@ -333,3 +353,45 @@
.phui-header-view .phui-tag-shade-indigo a {
color: {$sh-indigotext};
}
+
+.phui-policy-section-view {
+ margin-bottom: 24px;
+}
+
+.phui-policy-section-view-header {
+ background: {$bluebackground};
+ border-bottom: 1px solid {$lightblueborder};
+ padding: 4px 8px;
+ color: {$darkbluetext};
+ margin-bottom: 8px;
+}
+
+.phui-policy-section-view-header-text {
+ font-weight: bold;
+}
+
+.phui-policy-section-view-header .phui-icon-view {
+ margin-right: 8px;
+}
+
+.phui-policy-section-view-link {
+ float: right;
+}
+
+.phui-policy-section-view-link .phui-icon-view {
+ color: {$bluetext};
+}
+
+.phui-policy-section-view-hint {
+ color: {$greytext};
+ background: {$lightbluebackground};
+ padding: 8px;
+}
+
+.phui-policy-section-view-body {
+ padding: 0 12px;
+}
+
+.phui-policy-section-view-inactive-rule {
+ color: {$greytext};
+}

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 10, 3:50 PM (6 h, 25 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7112558
Default Alt Text
D16830.id40530.diff (36 KB)

Event Timeline