Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14904822
D16830.id40530.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
36 KB
Referenced Files
None
Subscribers
None
D16830.id40530.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D16830: Require several advanced postgraduate degrees to understand object policies
Attached
Detach File
Event Timeline
Log In to Comment