diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index d9ba87c6b4..e663d3ac1d 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -836,7 +836,7 @@ celerity_register_resource_map(array( ), 'aphront-dialog-view-css' => array( - 'uri' => '/res/337bd2a9/rsrc/css/aphront/dialog-view.css', + 'uri' => '/res/609ccc78/rsrc/css/aphront/dialog-view.css', 'type' => 'css', 'requires' => array( @@ -1176,7 +1176,7 @@ celerity_register_resource_map(array( ), 'herald-rule-editor' => array( - 'uri' => '/res/f8ee0e9c/rsrc/js/application/herald/HeraldRuleEditor.js', + 'uri' => '/res/36222dde/rsrc/js/application/herald/HeraldRuleEditor.js', 'type' => 'js', 'requires' => array( @@ -4162,7 +4162,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - '15affac5' => + 'de5898ae' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -4209,7 +4209,7 @@ celerity_register_resource_map(array( 39 => 'phabricator-property-list-view-css', 40 => 'phabricator-tag-view-css', ), - 'uri' => '/res/pkg/15affac5/core.pkg.css', + 'uri' => '/res/pkg/de5898ae/core.pkg.css', 'type' => 'css', ), '8977e356' => @@ -4399,15 +4399,15 @@ celerity_register_resource_map(array( ), 'reverse' => array( - 'aphront-dialog-view-css' => '15affac5', - 'aphront-error-view-css' => '15affac5', - 'aphront-list-filter-view-css' => '15affac5', - 'aphront-pager-view-css' => '15affac5', - 'aphront-panel-view-css' => '15affac5', - 'aphront-table-view-css' => '15affac5', - 'aphront-tokenizer-control-css' => '15affac5', - 'aphront-tooltip-css' => '15affac5', - 'aphront-typeahead-control-css' => '15affac5', + 'aphront-dialog-view-css' => 'de5898ae', + 'aphront-error-view-css' => 'de5898ae', + 'aphront-list-filter-view-css' => 'de5898ae', + 'aphront-pager-view-css' => 'de5898ae', + 'aphront-panel-view-css' => 'de5898ae', + 'aphront-table-view-css' => 'de5898ae', + 'aphront-tokenizer-control-css' => 'de5898ae', + 'aphront-tooltip-css' => 'de5898ae', + 'aphront-typeahead-control-css' => 'de5898ae', 'differential-changeset-view-css' => '44bfe40c', 'differential-core-view-css' => '44bfe40c', 'differential-inline-comment-editor' => '5e9e5c4e', @@ -4421,7 +4421,7 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => '44bfe40c', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => '15affac5', + 'global-drag-and-drop-css' => 'de5898ae', 'inline-comment-summary-css' => '44bfe40c', 'javelin-aphlict' => '8977e356', 'javelin-behavior' => '9564fa17', @@ -4494,54 +4494,54 @@ celerity_register_resource_map(array( 'javelin-util' => '9564fa17', 'javelin-vector' => '9564fa17', 'javelin-workflow' => '9564fa17', - 'lightbox-attachment-css' => '15affac5', + 'lightbox-attachment-css' => 'de5898ae', 'maniphest-task-summary-css' => '49898640', - 'phabricator-action-list-view-css' => '15affac5', - 'phabricator-application-launch-view-css' => '15affac5', + 'phabricator-action-list-view-css' => 'de5898ae', + 'phabricator-application-launch-view-css' => 'de5898ae', 'phabricator-busy' => '8977e356', 'phabricator-content-source-view-css' => '44bfe40c', - 'phabricator-core-css' => '15affac5', - 'phabricator-crumbs-view-css' => '15affac5', + 'phabricator-core-css' => 'de5898ae', + 'phabricator-crumbs-view-css' => 'de5898ae', 'phabricator-drag-and-drop-file-upload' => '5e9e5c4e', 'phabricator-dropdown-menu' => '8977e356', 'phabricator-file-upload' => '8977e356', - 'phabricator-filetree-view-css' => '15affac5', - 'phabricator-flag-css' => '15affac5', + 'phabricator-filetree-view-css' => 'de5898ae', + 'phabricator-flag-css' => 'de5898ae', 'phabricator-hovercard' => '8977e356', - 'phabricator-jump-nav' => '15affac5', + 'phabricator-jump-nav' => 'de5898ae', 'phabricator-keyboard-shortcut' => '8977e356', 'phabricator-keyboard-shortcut-manager' => '8977e356', - 'phabricator-main-menu-view' => '15affac5', + 'phabricator-main-menu-view' => 'de5898ae', 'phabricator-menu-item' => '8977e356', - 'phabricator-nav-view-css' => '15affac5', + 'phabricator-nav-view-css' => 'de5898ae', 'phabricator-notification' => '8977e356', - 'phabricator-notification-css' => '15affac5', - 'phabricator-notification-menu-css' => '15affac5', + 'phabricator-notification-css' => 'de5898ae', + 'phabricator-notification-menu-css' => 'de5898ae', 'phabricator-object-selector-css' => '44bfe40c', 'phabricator-phtize' => '8977e356', 'phabricator-prefab' => '8977e356', 'phabricator-project-tag-css' => '49898640', - 'phabricator-property-list-view-css' => '15affac5', - 'phabricator-remarkup-css' => '15affac5', + 'phabricator-property-list-view-css' => 'de5898ae', + 'phabricator-remarkup-css' => 'de5898ae', 'phabricator-shaped-request' => '5e9e5c4e', - 'phabricator-side-menu-view-css' => '15affac5', - 'phabricator-standard-page-view' => '15affac5', - 'phabricator-tag-view-css' => '15affac5', + 'phabricator-side-menu-view-css' => 'de5898ae', + 'phabricator-standard-page-view' => 'de5898ae', + 'phabricator-tag-view-css' => 'de5898ae', 'phabricator-textareautils' => '8977e356', 'phabricator-tooltip' => '8977e356', - 'phabricator-transaction-view-css' => '15affac5', - 'phabricator-zindex-css' => '15affac5', - 'phui-button-css' => '15affac5', - 'phui-form-css' => '15affac5', - 'phui-form-view-css' => '15affac5', - 'phui-header-view-css' => '15affac5', - 'phui-icon-view-css' => '15affac5', - 'phui-object-item-list-view-css' => '15affac5', - 'phui-spacing-css' => '15affac5', - 'sprite-apps-large-css' => '15affac5', - 'sprite-gradient-css' => '15affac5', - 'sprite-icons-css' => '15affac5', - 'sprite-menu-css' => '15affac5', - 'syntax-highlighting-css' => '15affac5', + 'phabricator-transaction-view-css' => 'de5898ae', + 'phabricator-zindex-css' => 'de5898ae', + 'phui-button-css' => 'de5898ae', + 'phui-form-css' => 'de5898ae', + 'phui-form-view-css' => 'de5898ae', + 'phui-header-view-css' => 'de5898ae', + 'phui-icon-view-css' => 'de5898ae', + 'phui-object-item-list-view-css' => 'de5898ae', + 'phui-spacing-css' => 'de5898ae', + 'sprite-apps-large-css' => 'de5898ae', + 'sprite-gradient-css' => 'de5898ae', + 'sprite-icons-css' => 'de5898ae', + 'sprite-menu-css' => 'de5898ae', + 'syntax-highlighting-css' => 'de5898ae', ), )); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 881a225ae5..d40f9ff77a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -846,6 +846,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationPhortune' => 'applications/phortune/application/PhabricatorApplicationPhortune.php', 'PhabricatorApplicationPhrequent' => 'applications/phrequent/application/PhabricatorApplicationPhrequent.php', 'PhabricatorApplicationPhriction' => 'applications/phriction/application/PhabricatorApplicationPhriction.php', + 'PhabricatorApplicationPolicy' => 'applications/policy/application/PhabricatorApplicationPolicy.php', 'PhabricatorApplicationPonder' => 'applications/ponder/application/PhabricatorApplicationPonder.php', 'PhabricatorApplicationProject' => 'applications/project/application/PhabricatorApplicationProject.php', 'PhabricatorApplicationReleeph' => 'applications/releeph/application/PhabricatorApplicationReleeph.php', @@ -1459,8 +1460,10 @@ phutil_register_library_map(array( 'PhabricatorPolicyCapability' => 'applications/policy/constants/PhabricatorPolicyCapability.php', 'PhabricatorPolicyConfigOptions' => 'applications/config/option/PhabricatorPolicyConfigOptions.php', 'PhabricatorPolicyConstants' => 'applications/policy/constants/PhabricatorPolicyConstants.php', + 'PhabricatorPolicyController' => 'applications/policy/controller/PhabricatorPolicyController.php', 'PhabricatorPolicyDataTestCase' => 'applications/policy/__tests__/PhabricatorPolicyDataTestCase.php', 'PhabricatorPolicyException' => 'applications/policy/exception/PhabricatorPolicyException.php', + 'PhabricatorPolicyExplainController' => 'applications/policy/controller/PhabricatorPolicyExplainController.php', 'PhabricatorPolicyFilter' => 'applications/policy/filter/PhabricatorPolicyFilter.php', 'PhabricatorPolicyInterface' => 'applications/policy/interface/PhabricatorPolicyInterface.php', 'PhabricatorPolicyQuery' => 'applications/policy/query/PhabricatorPolicyQuery.php', @@ -2941,6 +2944,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationPhortune' => 'PhabricatorApplication', 'PhabricatorApplicationPhrequent' => 'PhabricatorApplication', 'PhabricatorApplicationPhriction' => 'PhabricatorApplication', + 'PhabricatorApplicationPolicy' => 'PhabricatorApplication', 'PhabricatorApplicationPonder' => 'PhabricatorApplication', 'PhabricatorApplicationProject' => 'PhabricatorApplication', 'PhabricatorApplicationReleeph' => 'PhabricatorApplication', @@ -3612,8 +3616,10 @@ phutil_register_library_map(array( 'PhabricatorPolicyAwareTestQuery' => 'PhabricatorPolicyAwareQuery', 'PhabricatorPolicyCapability' => 'PhabricatorPolicyConstants', 'PhabricatorPolicyConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'PhabricatorPolicyController' => 'PhabricatorController', 'PhabricatorPolicyDataTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyException' => 'Exception', + 'PhabricatorPolicyExplainController' => 'PhabricatorPolicyController', 'PhabricatorPolicyQuery' => 'PhabricatorQuery', 'PhabricatorPolicyTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyTestObject' => 'PhabricatorPolicyInterface', diff --git a/src/applications/auth/storage/PhabricatorAuthProviderConfig.php b/src/applications/auth/storage/PhabricatorAuthProviderConfig.php index b4595d96d0..4678e2b170 100644 --- a/src/applications/auth/storage/PhabricatorAuthProviderConfig.php +++ b/src/applications/auth/storage/PhabricatorAuthProviderConfig.php @@ -81,4 +81,8 @@ final class PhabricatorAuthProviderConfig extends PhabricatorAuthDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/chatlog/storage/PhabricatorChatLogChannel.php b/src/applications/chatlog/storage/PhabricatorChatLogChannel.php index 33c6ab09fa..e9ea837379 100644 --- a/src/applications/chatlog/storage/PhabricatorChatLogChannel.php +++ b/src/applications/chatlog/storage/PhabricatorChatLogChannel.php @@ -32,5 +32,9 @@ final class PhabricatorChatLogChannel return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/chatlog/storage/PhabricatorChatLogEvent.php b/src/applications/chatlog/storage/PhabricatorChatLogEvent.php index 94d641a4e9..c889fd19fe 100644 --- a/src/applications/chatlog/storage/PhabricatorChatLogEvent.php +++ b/src/applications/chatlog/storage/PhabricatorChatLogEvent.php @@ -28,6 +28,10 @@ final class PhabricatorChatLogEvent return false; } + public function describeAutomaticCapability($capability) { + return null; + } + public function getConfiguration() { return array( self::CONFIG_TIMESTAMPS => false, diff --git a/src/applications/conduit/method/ConduitAPIMethod.php b/src/applications/conduit/method/ConduitAPIMethod.php index da5c6d7b01..f9537c48da 100644 --- a/src/applications/conduit/method/ConduitAPIMethod.php +++ b/src/applications/conduit/method/ConduitAPIMethod.php @@ -183,4 +183,8 @@ abstract class ConduitAPIMethod return true; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/conduit/storage/PhabricatorConduitMethodCallLog.php b/src/applications/conduit/storage/PhabricatorConduitMethodCallLog.php index 8edbaac7b9..7a2c36277c 100644 --- a/src/applications/conduit/storage/PhabricatorConduitMethodCallLog.php +++ b/src/applications/conduit/storage/PhabricatorConduitMethodCallLog.php @@ -30,4 +30,8 @@ final class PhabricatorConduitMethodCallLog extends PhabricatorConduitDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/config/storage/PhabricatorConfigEntry.php b/src/applications/config/storage/PhabricatorConfigEntry.php index 86d01a37df..a25c7dfec6 100644 --- a/src/applications/config/storage/PhabricatorConfigEntry.php +++ b/src/applications/config/storage/PhabricatorConfigEntry.php @@ -59,4 +59,8 @@ final class PhabricatorConfigEntry extends PhabricatorConfigEntryDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/conpherence/storage/ConpherenceThread.php b/src/applications/conpherence/storage/ConpherenceThread.php index e5657c9232..fd4188e070 100644 --- a/src/applications/conpherence/storage/ConpherenceThread.php +++ b/src/applications/conpherence/storage/ConpherenceThread.php @@ -189,4 +189,8 @@ final class ConpherenceThread extends ConpherenceDAO return isset($participants[$user->getPHID()]); } + public function describeAutomaticCapability($capability) { + return pht("Participants in a thread can always view and edit it."); + } + } diff --git a/src/applications/countdown/storage/PhabricatorCountdown.php b/src/applications/countdown/storage/PhabricatorCountdown.php index ea4999d79a..551c2c848c 100644 --- a/src/applications/countdown/storage/PhabricatorCountdown.php +++ b/src/applications/countdown/storage/PhabricatorCountdown.php @@ -53,4 +53,8 @@ final class PhabricatorCountdown return ($viewer->getPHID() == $this->getAuthorPHID()); } + public function describeAutomaticCapability($capability) { + return pht('The author of a countdown can always view and edit it.'); + } + } diff --git a/src/applications/daemon/storage/PhabricatorDaemonLog.php b/src/applications/daemon/storage/PhabricatorDaemonLog.php index b836d9ae81..f951df99cc 100644 --- a/src/applications/daemon/storage/PhabricatorDaemonLog.php +++ b/src/applications/daemon/storage/PhabricatorDaemonLog.php @@ -41,4 +41,8 @@ final class PhabricatorDaemonLog extends PhabricatorDaemonDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/differential/storage/DifferentialDiff.php b/src/applications/differential/storage/DifferentialDiff.php index 32cded90fe..9e0a36dce9 100644 --- a/src/applications/differential/storage/DifferentialDiff.php +++ b/src/applications/differential/storage/DifferentialDiff.php @@ -320,4 +320,12 @@ final class DifferentialDiff return false; } + public function describeAutomaticCapability($capability) { + if ($this->getRevision()) { + return pht( + 'This diff is attached to a revision, and inherits its policies.'); + } + return null; + } + } diff --git a/src/applications/differential/storage/DifferentialRevision.php b/src/applications/differential/storage/DifferentialRevision.php index ae768b8a6a..ba9e7a0383 100644 --- a/src/applications/differential/storage/DifferentialRevision.php +++ b/src/applications/differential/storage/DifferentialRevision.php @@ -329,6 +329,26 @@ final class DifferentialRevision extends DifferentialDAO return false; } + public function describeAutomaticCapability($capability) { + $description = array( + pht('The owner of a revision can always view and edit it.'), + ); + + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + $description[] = pht( + "A revision's reviewers can always view it."); + if ($this->getRepository()) { + $description[] = pht( + 'This revision belongs to a repository. Other users must be able '. + 'to view the repository in order to view this revision.'); + } + break; + } + + return $description; + } + public function getUsersToNotifyOfTokenGiven() { return array( $this->getAuthorPHID(), diff --git a/src/applications/diviner/storage/DivinerLiveBook.php b/src/applications/diviner/storage/DivinerLiveBook.php index cdf8f10637..70affac00c 100644 --- a/src/applications/diviner/storage/DivinerLiveBook.php +++ b/src/applications/diviner/storage/DivinerLiveBook.php @@ -61,4 +61,8 @@ final class DivinerLiveBook extends DivinerDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/diviner/storage/DivinerLiveSymbol.php b/src/applications/diviner/storage/DivinerLiveSymbol.php index 3ca6cc0798..f2de0d0974 100644 --- a/src/applications/diviner/storage/DivinerLiveSymbol.php +++ b/src/applications/diviner/storage/DivinerLiveSymbol.php @@ -143,6 +143,10 @@ final class DivinerLiveSymbol extends DivinerDAO return $this->getBook()->hasAutomaticCapability($capability, $viewer); } + public function describeAutomaticCapability($capability) { + return pht('Atoms inherit the policies of the books they are part of.'); + } + /* -( Markup Interface )--------------------------------------------------- */ diff --git a/src/applications/doorkeeper/storage/DoorkeeperExternalObject.php b/src/applications/doorkeeper/storage/DoorkeeperExternalObject.php index af46a3e543..0b1934d360 100644 --- a/src/applications/doorkeeper/storage/DoorkeeperExternalObject.php +++ b/src/applications/doorkeeper/storage/DoorkeeperExternalObject.php @@ -77,4 +77,8 @@ final class DoorkeeperExternalObject extends DoorkeeperDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/feed/story/PhabricatorFeedStory.php b/src/applications/feed/story/PhabricatorFeedStory.php index 3d815364ef..eb6b928866 100644 --- a/src/applications/feed/story/PhabricatorFeedStory.php +++ b/src/applications/feed/story/PhabricatorFeedStory.php @@ -324,4 +324,8 @@ abstract class PhabricatorFeedStory implements PhabricatorPolicyInterface { return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index d694f115a5..962e2f14e3 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -830,6 +830,10 @@ final class PhabricatorFile extends PhabricatorFileDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + /* -( PhabricatorSubscribableInterface Implementation )-------------------- */ diff --git a/src/applications/flag/storage/PhabricatorFlag.php b/src/applications/flag/storage/PhabricatorFlag.php index 235260ae32..a1b65911d7 100644 --- a/src/applications/flag/storage/PhabricatorFlag.php +++ b/src/applications/flag/storage/PhabricatorFlag.php @@ -50,4 +50,8 @@ final class PhabricatorFlag extends PhabricatorFlagDAO return ($viewer->getPHID() == $this->getOwnerPHID()); } + public function describeAutomaticCapability($capability) { + return pht('Flags are private. Only you can view or edit your flags.'); + } + } diff --git a/src/applications/herald/storage/HeraldRule.php b/src/applications/herald/storage/HeraldRule.php index dc81e149f6..733de01ccf 100644 --- a/src/applications/herald/storage/HeraldRule.php +++ b/src/applications/herald/storage/HeraldRule.php @@ -202,4 +202,10 @@ final class HeraldRule extends HeraldDAO } } + public function describeAutomaticCapability($capability) { + // TODO: (T603) Sort this out. + return null; + } + + } diff --git a/src/applications/legalpad/storage/LegalpadDocument.php b/src/applications/legalpad/storage/LegalpadDocument.php index 665370333d..45bdbefc87 100644 --- a/src/applications/legalpad/storage/LegalpadDocument.php +++ b/src/applications/legalpad/storage/LegalpadDocument.php @@ -96,6 +96,12 @@ final class LegalpadDocument extends LegalpadDAO return ($user->getPHID() == $this->getCreatorPHID()); } + public function describeAutomaticCapability($capability) { + return pht( + 'The author of a document can always view and edit it.'); + } + + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { diff --git a/src/applications/macro/storage/PhabricatorFileImageMacro.php b/src/applications/macro/storage/PhabricatorFileImageMacro.php index b708bc9668..83527ef294 100644 --- a/src/applications/macro/storage/PhabricatorFileImageMacro.php +++ b/src/applications/macro/storage/PhabricatorFileImageMacro.php @@ -61,5 +61,9 @@ final class PhabricatorFileImageMacro extends PhabricatorFileDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php b/src/applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php index d9034295c2..2770a93b30 100644 --- a/src/applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php +++ b/src/applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php @@ -37,4 +37,8 @@ final class PhabricatorMetaMTAMailingList extends PhabricatorMetaMTADAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index 7b656cb081..b9750b06dd 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -221,6 +221,11 @@ final class ManiphestTask extends ManiphestDAO return false; } + public function describeAutomaticCapability($capability) { + return pht( + 'The owner of a task can always view and edit it.'); + } + /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ diff --git a/src/applications/owners/storage/PhabricatorOwnersPackage.php b/src/applications/owners/storage/PhabricatorOwnersPackage.php index 90af440eec..f4132aa3b1 100644 --- a/src/applications/owners/storage/PhabricatorOwnersPackage.php +++ b/src/applications/owners/storage/PhabricatorOwnersPackage.php @@ -30,6 +30,10 @@ final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + public function getConfiguration() { return array( // This information is better available from the history table. diff --git a/src/applications/paste/storage/PhabricatorPaste.php b/src/applications/paste/storage/PhabricatorPaste.php index ba1081f53a..25678e008f 100644 --- a/src/applications/paste/storage/PhabricatorPaste.php +++ b/src/applications/paste/storage/PhabricatorPaste.php @@ -61,6 +61,11 @@ final class PhabricatorPaste extends PhabricatorPasteDAO return ($user->getPHID() == $this->getAuthorPHID()); } + public function describeAutomaticCapability($capability) { + return pht( + 'The author of a paste can always view and edit it.'); + } + public function getFullName() { $title = $this->getTitle(); if (!$title) { diff --git a/src/applications/people/storage/PhabricatorExternalAccount.php b/src/applications/people/storage/PhabricatorExternalAccount.php index 1e0c347418..94ca59fb02 100644 --- a/src/applications/people/storage/PhabricatorExternalAccount.php +++ b/src/applications/people/storage/PhabricatorExternalAccount.php @@ -102,4 +102,9 @@ final class PhabricatorExternalAccount extends PhabricatorUserDAO return ($viewer->getPHID() == $this->getUserPHID()); } + public function describeAutomaticCapability($capability) { + // TODO: (T603) This is complicated. + return null; + } + } diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php index 921b4a6780..0602ac2175 100644 --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -834,6 +834,15 @@ EOBODY; return $this->getPHID() && ($viewer->getPHID() === $this->getPHID()); } + public function describeAutomaticCapability($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_EDIT: + return pht('Only you can edit your information.'); + default: + return null; + } + } + /* -( PhabricatorCustomFieldInterface )------------------------------------ */ diff --git a/src/applications/phame/storage/PhameBlog.php b/src/applications/phame/storage/PhameBlog.php index a7f37f6781..9270843d5c 100644 --- a/src/applications/phame/storage/PhameBlog.php +++ b/src/applications/phame/storage/PhameBlog.php @@ -188,6 +188,20 @@ final class PhameBlog extends PhameDAO } + public function describeAutomaticCapability($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + return pht( + 'Users who can edit or post on a blog can always view it.'); + case PhabricatorPolicyCapability::CAN_JOIN: + return pht( + 'Users who can edit a blog can always post on it.'); + } + + return null; + } + + /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ diff --git a/src/applications/phame/storage/PhamePost.php b/src/applications/phame/storage/PhamePost.php index f71cb6b2de..fc3b1d1721 100644 --- a/src/applications/phame/storage/PhamePost.php +++ b/src/applications/phame/storage/PhamePost.php @@ -150,6 +150,12 @@ final class PhamePost extends PhameDAO } + public function describeAutomaticCapability($capability) { + return pht( + 'The author of a blog post can always view and edit it.'); + } + + /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ diff --git a/src/applications/phid/PhabricatorObjectHandle.php b/src/applications/phid/PhabricatorObjectHandle.php index 1a31ed91c8..05eddbd592 100644 --- a/src/applications/phid/PhabricatorObjectHandle.php +++ b/src/applications/phid/PhabricatorObjectHandle.php @@ -236,4 +236,8 @@ final class PhabricatorObjectHandle return true; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/phlux/storage/PhluxVariable.php b/src/applications/phlux/storage/PhluxVariable.php index f279700224..2c1b8df12b 100644 --- a/src/applications/phlux/storage/PhluxVariable.php +++ b/src/applications/phlux/storage/PhluxVariable.php @@ -45,4 +45,8 @@ final class PhluxVariable extends PhluxDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/pholio/storage/PholioImage.php b/src/applications/pholio/storage/PholioImage.php index 74d16ef1b7..a77aff84cc 100644 --- a/src/applications/pholio/storage/PholioImage.php +++ b/src/applications/pholio/storage/PholioImage.php @@ -104,4 +104,8 @@ final class PholioImage extends PholioDAO return $this->getMock()->hasAutomaticCapability($capability, $viewer); } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/pholio/storage/PholioMock.php b/src/applications/pholio/storage/PholioMock.php index 8bec0a8e09..814ad99017 100644 --- a/src/applications/pholio/storage/PholioMock.php +++ b/src/applications/pholio/storage/PholioMock.php @@ -149,6 +149,10 @@ final class PholioMock extends PholioDAO return ($viewer->getPHID() == $this->getAuthorPHID()); } + public function describeAutomaticCapability($capability) { + return pht("A mock's owner can always view and edit it."); + } + /* -( PhabricatorMarkupInterface )----------------------------------------- */ diff --git a/src/applications/phortune/storage/PhortuneAccount.php b/src/applications/phortune/storage/PhortuneAccount.php index cdd597d94f..6fbb752d13 100644 --- a/src/applications/phortune/storage/PhortuneAccount.php +++ b/src/applications/phortune/storage/PhortuneAccount.php @@ -46,7 +46,7 @@ final class PhortuneAccount extends PhortuneDAO } public function getPolicy($capability) { - return false; + return PhabricatorPolicies::POLICY_NOONE; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { @@ -54,4 +54,9 @@ final class PhortuneAccount extends PhortuneDAO return isset($members[$viewer->getPHID()]); } + public function describeAutomaticCapability($capability) { + return pht('Members of an account can always view and edit it.'); + } + + } diff --git a/src/applications/phortune/storage/PhortunePaymentMethod.php b/src/applications/phortune/storage/PhortunePaymentMethod.php index 59799fbe11..be71203c98 100644 --- a/src/applications/phortune/storage/PhortunePaymentMethod.php +++ b/src/applications/phortune/storage/PhortunePaymentMethod.php @@ -107,4 +107,9 @@ final class PhortunePaymentMethod extends PhortuneDAO $viewer); } + public function describeAutomaticCapability($capability) { + return pht( + 'Members of an account can always view and edit its payment methods.'); + } + } diff --git a/src/applications/phortune/storage/PhortuneProduct.php b/src/applications/phortune/storage/PhortuneProduct.php index 8bf42a8da9..716ae93486 100644 --- a/src/applications/phortune/storage/PhortuneProduct.php +++ b/src/applications/phortune/storage/PhortuneProduct.php @@ -73,4 +73,8 @@ final class PhortuneProduct extends PhortuneDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/phriction/storage/PhrictionDocument.php b/src/applications/phriction/storage/PhrictionDocument.php index c7b5bd7c0d..24e3e7bfa7 100644 --- a/src/applications/phriction/storage/PhrictionDocument.php +++ b/src/applications/phriction/storage/PhrictionDocument.php @@ -126,6 +126,14 @@ final class PhrictionDocument extends PhrictionDAO return false; } + public function describeAutomaticCapability($capability) { + if ($this->hasProject()) { + return pht( + "This is a project wiki page, and inherits the project's policies."); + } + return null; + } + public function isAutomaticallySubscribed($phid) { return false; } diff --git a/src/applications/policy/__tests__/PhabricatorPolicyTestObject.php b/src/applications/policy/__tests__/PhabricatorPolicyTestObject.php index 826c9c3e54..b010f88d01 100644 --- a/src/applications/policy/__tests__/PhabricatorPolicyTestObject.php +++ b/src/applications/policy/__tests__/PhabricatorPolicyTestObject.php @@ -38,4 +38,8 @@ final class PhabricatorPolicyTestObject return $this; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/policy/application/PhabricatorApplicationPolicy.php b/src/applications/policy/application/PhabricatorApplicationPolicy.php new file mode 100644 index 0000000000..c9eec4bcef --- /dev/null +++ b/src/applications/policy/application/PhabricatorApplicationPolicy.php @@ -0,0 +1,23 @@ + array( + 'explain/(?P[^/]+)/(?P[^/]+)/' + => 'PhabricatorPolicyExplainController', + ), + ); + } + +} + diff --git a/src/applications/policy/controller/PhabricatorPolicyController.php b/src/applications/policy/controller/PhabricatorPolicyController.php new file mode 100644 index 0000000000..26f86b5250 --- /dev/null +++ b/src/applications/policy/controller/PhabricatorPolicyController.php @@ -0,0 +1,5 @@ +phid = $data['phid']; + $this->capability = $data['capability']; + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $phid = $this->phid; + $capability = $this->capability; + + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withPHIDs(array($phid)) + ->executeOne(); + if (!$object) { + return new Aphront404Response(); + } + + $policies = PhabricatorPolicyQuery::loadPolicies( + $viewer, + $object); + + $policy = idx($policies, $capability); + if (!$policy) { + return new Aphront404Response(); + } + + $handle = id(new PhabricatorHandleQuery()) + ->setViewer($viewer) + ->withPHIDs(array($phid)) + ->executeOne(); + $object_uri = $handle->getURI(); + + $explanation = $policy->getExplanation($capability); + $auto_info = (array)$object->describeAutomaticCapability($capability); + + foreach ($auto_info as $key => $info) { + $auto_info[$key] = phutil_tag('li', array(), $info); + } + if ($auto_info) { + $auto_info = phutil_tag('ul', array(), $auto_info); + } + + $content = array( + $explanation, + $auto_info, + ); + + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->setClass('aphront-access-dialog') + ->setTitle(pht('Policy Details')) + ->appendChild($content) + ->addCancelButton($object_uri, pht('Done')); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + +} diff --git a/src/applications/policy/filter/PhabricatorPolicy.php b/src/applications/policy/filter/PhabricatorPolicy.php index c61fce4469..a0bbc5e8ab 100644 --- a/src/applications/policy/filter/PhabricatorPolicy.php +++ b/src/applications/policy/filter/PhabricatorPolicy.php @@ -130,6 +130,35 @@ final class PhabricatorPolicy { return $this->getName(); } + public function getExplanation($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + switch ($this->getPHID()) { + case PhabricatorPolicies::POLICY_PUBLIC: + return pht('Visible to the entire internet.'); + case PhabricatorPolicies::POLICY_USER: + return pht('Visible to all logged in users.'); + case PhabricatorPolicies::POLICY_ADMIN: + return pht('Visible to all administrators.'); + case PhabricatorPolicies::POLICY_NOONE: + return pht('Not visible to anyone by default.'); + } + + switch ($this->getType()) { + case PhabricatorPolicyType::TYPE_PROJECT: + return pht( + 'Visible to members of the project "%s".', + $this->getName()); + case PhabricatorPolicyType::TYPE_MASKED: + return pht('Other: %s', $this->getName()); + } + break; + } + + + return pht('?'); + } + public function getFullName() { switch ($this->getType()) { case PhabricatorPolicyType::TYPE_PROJECT: diff --git a/src/applications/policy/interface/PhabricatorPolicyInterface.php b/src/applications/policy/interface/PhabricatorPolicyInterface.php index b56d223c62..fb64180815 100644 --- a/src/applications/policy/interface/PhabricatorPolicyInterface.php +++ b/src/applications/policy/interface/PhabricatorPolicyInterface.php @@ -6,4 +6,32 @@ interface PhabricatorPolicyInterface { 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); + } diff --git a/src/applications/policy/query/PhabricatorPolicyQuery.php b/src/applications/policy/query/PhabricatorPolicyQuery.php index 93e139fe5b..be35d6c1e4 100644 --- a/src/applications/policy/query/PhabricatorPolicyQuery.php +++ b/src/applications/policy/query/PhabricatorPolicyQuery.php @@ -15,10 +15,9 @@ final class PhabricatorPolicyQuery extends PhabricatorQuery { return $this; } - public static function renderPolicyDescriptions( + public static function loadPolicies( PhabricatorUser $viewer, - PhabricatorPolicyInterface $object, - $icon=false) { + PhabricatorPolicyInterface $object) { $results = array(); $policies = null; @@ -32,7 +31,7 @@ final class PhabricatorPolicyQuery extends PhabricatorQuery { } if (isset($global[$policy])) { - $results[$capability] = $global[$policy]->renderDescription($icon); + $results[$capability] = $global[$policy]; continue; } @@ -45,12 +44,26 @@ final class PhabricatorPolicyQuery extends PhabricatorQuery { ->execute(); } - $results[$capability] = $policies[$policy]->renderDescription($icon); + $results[$capability] = $policies[$policy]; } return $results; } + public static function renderPolicyDescriptions( + PhabricatorUser $viewer, + PhabricatorPolicyInterface $object, + $icon = false) { + + $policies = self::loadPolicies($viewer, $object); + + foreach ($policies as $capability => $policy) { + $policies[$capability] = $policy->renderDescription($icon); + } + + return $policies; + } + public function execute() { if (!$this->viewer) { throw new Exception('Call setViewer() before execute()!'); diff --git a/src/applications/ponder/storage/PonderAnswer.php b/src/applications/ponder/storage/PonderAnswer.php index edaa0f4b8e..0a8d12176c 100644 --- a/src/applications/ponder/storage/PonderAnswer.php +++ b/src/applications/ponder/storage/PonderAnswer.php @@ -145,6 +145,9 @@ final class PonderAnswer extends PonderDAO public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: + if ($this->getAuthorPHID() == $viewer->getPHID()) { + return true; + } return $this->getQuestion()->hasAutomaticCapability( $capability, $viewer); @@ -154,6 +157,19 @@ final class PonderAnswer extends PonderDAO } + public function describeAutomaticCapability($capability) { + $out = array(); + $out[] = pht("The author of an answer can always view and edit it."); + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + $out[] = pht( + "The user who asks a question can always view the answers."); + break; + } + return $out; + } + + /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ diff --git a/src/applications/ponder/storage/PonderQuestion.php b/src/applications/ponder/storage/PonderQuestion.php index 09864aada9..138ddef1f1 100644 --- a/src/applications/ponder/storage/PonderQuestion.php +++ b/src/applications/ponder/storage/PonderQuestion.php @@ -203,6 +203,12 @@ final class PonderQuestion extends PonderDAO return ($viewer->getPHID() == $this->getAuthorPHID()); } + + public function describeAutomaticCapability($capability) { + return pht( + 'The user who asked a question can always view and edit it.'); + } + public function getOriginalTitle() { // TODO: Make this actually save/return the original title. return $this->getTitle(); diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php index cd93909e84..40074e801d 100644 --- a/src/applications/project/storage/PhabricatorProject.php +++ b/src/applications/project/storage/PhabricatorProject.php @@ -60,6 +60,16 @@ final class PhabricatorProject extends PhabricatorProjectDAO return false; } + public function describeAutomaticCapability($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + return pht("Members of a project can always view it."); + case PhabricatorPolicyCapability::CAN_JOIN: + return pht("Users who can edit a project can always join it."); + } + return null; + } + public function isUserMember($user_phid) { return $this->assertAttachedKey($this->sparseMembers, $user_phid); } diff --git a/src/applications/releeph/storage/ReleephBranch.php b/src/applications/releeph/storage/ReleephBranch.php index b373467ee6..799e658b2c 100644 --- a/src/applications/releeph/storage/ReleephBranch.php +++ b/src/applications/releeph/storage/ReleephBranch.php @@ -189,4 +189,9 @@ final class ReleephBranch extends ReleephDAO return $this->getProject()->hasAutomaticCapability($capability, $viewer); } + public function describeAutomaticCapability($capability) { + return null; + } + + } diff --git a/src/applications/releeph/storage/ReleephProject.php b/src/applications/releeph/storage/ReleephProject.php index ec5b0dd085..eed3cca7a9 100644 --- a/src/applications/releeph/storage/ReleephProject.php +++ b/src/applications/releeph/storage/ReleephProject.php @@ -193,4 +193,9 @@ final class ReleephProject extends ReleephDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + + } diff --git a/src/applications/releeph/storage/ReleephRequest.php b/src/applications/releeph/storage/ReleephRequest.php index f8c6de032e..fd2486055b 100644 --- a/src/applications/releeph/storage/ReleephRequest.php +++ b/src/applications/releeph/storage/ReleephRequest.php @@ -306,6 +306,11 @@ final class ReleephRequest extends ReleephDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + + /* -( PhabricatorCustomFieldInterface )------------------------------------ */ diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php index e6b0225189..32782b65d4 100644 --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -701,6 +701,11 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + + /* -( PhabricatorMarkupInterface )----------------------------------------- */ diff --git a/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php b/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php index fc02ffb9c5..37ee0f6ebc 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php +++ b/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php @@ -87,4 +87,8 @@ final class PhabricatorRepositoryArcanistProject return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommit.php b/src/applications/repository/storage/PhabricatorRepositoryCommit.php index a7815a950c..82340ffdb2 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryCommit.php +++ b/src/applications/repository/storage/PhabricatorRepositoryCommit.php @@ -167,6 +167,12 @@ final class PhabricatorRepositoryCommit return $this->getRepository()->hasAutomaticCapability($capability, $viewer); } + public function describeAutomaticCapability($capability) { + return pht( + 'Commits inherit the policies of the repository they belong to.'); + } + + /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { diff --git a/src/applications/search/storage/PhabricatorNamedQuery.php b/src/applications/search/storage/PhabricatorNamedQuery.php index cc1e199336..12c16feb37 100644 --- a/src/applications/search/storage/PhabricatorNamedQuery.php +++ b/src/applications/search/storage/PhabricatorNamedQuery.php @@ -39,4 +39,11 @@ final class PhabricatorNamedQuery extends PhabricatorSearchDAO return false; } + public function describeAutomaticCapability($capability) { + return pht( + 'The queries you have saved are private. Only you can view or edit '. + 'them.'); + } + + } diff --git a/src/applications/search/storage/PhabricatorSavedQuery.php b/src/applications/search/storage/PhabricatorSavedQuery.php index 2421eae11a..0fc1296c86 100644 --- a/src/applications/search/storage/PhabricatorSavedQuery.php +++ b/src/applications/search/storage/PhabricatorSavedQuery.php @@ -63,4 +63,8 @@ final class PhabricatorSavedQuery extends PhabricatorSearchDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + } diff --git a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php index ad55b8bacc..24700fd9c7 100644 --- a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php +++ b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php @@ -96,6 +96,12 @@ final class PhabricatorSlowvotePoll extends PhabricatorSlowvoteDAO return ($viewer->getPHID() == $this->getAuthorPHID()); } + public function describeAutomaticCapability($capability) { + return pht( + 'The author of a poll can always view and edit it.'); + } + + /* -( PhabricatorSubscribableInterface )----------------------------------- */ diff --git a/src/applications/tokens/storage/PhabricatorToken.php b/src/applications/tokens/storage/PhabricatorToken.php index a22db91551..81dbbbbf73 100644 --- a/src/applications/tokens/storage/PhabricatorToken.php +++ b/src/applications/tokens/storage/PhabricatorToken.php @@ -27,6 +27,10 @@ final class PhabricatorToken extends PhabricatorTokenDAO return false; } + public function describeAutomaticCapability($capability) { + return null; + } + public function renderIcon() { // TODO: Maybe move to a View class? diff --git a/src/applications/tokens/storage/PhabricatorTokenGiven.php b/src/applications/tokens/storage/PhabricatorTokenGiven.php index b3f2b21480..0b35e8fcdd 100644 --- a/src/applications/tokens/storage/PhabricatorTokenGiven.php +++ b/src/applications/tokens/storage/PhabricatorTokenGiven.php @@ -48,4 +48,17 @@ final class PhabricatorTokenGiven extends PhabricatorTokenDAO } } + public function describeAutomaticCapability($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + return pht( + 'A token inherits the policies of the object it is awarded to.'); + case PhabricatorPolicyCapability::CAN_EDIT: + return pht( + 'The user who gave a token can always edit it.'); + } + return null; + } + + } diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php index 3ed95c6661..b6f99d33cf 100644 --- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php +++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php @@ -537,4 +537,10 @@ abstract class PhabricatorApplicationTransaction return ($viewer->getPHID() == $this->getAuthorPHID()); } + public function describeAutomaticCapability($capability) { + // TODO: (T603) Exact policies are unclear here. + return null; + } + + } diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransactionComment.php b/src/applications/transactions/storage/PhabricatorApplicationTransactionComment.php index 818beb9c4d..7f0f01af60 100644 --- a/src/applications/transactions/storage/PhabricatorApplicationTransactionComment.php +++ b/src/applications/transactions/storage/PhabricatorApplicationTransactionComment.php @@ -113,4 +113,9 @@ abstract class PhabricatorApplicationTransactionComment return ($viewer->getPHID() == $this->getAuthorPHID()); } + public function describeAutomaticCapability($capability) { + // TODO: (T603) Policies are murky. + return null; + } + } diff --git a/src/view/phui/PHUIHeaderView.php b/src/view/phui/PHUIHeaderView.php index 3242709cdf..c86c10476c 100644 --- a/src/view/phui/PHUIHeaderView.php +++ b/src/view/phui/PHUIHeaderView.php @@ -148,11 +148,7 @@ final class PHUIHeaderView extends AphrontView { } if ($this->policyObject) { - $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( - $this->getUser(), - $this->policyObject, - true); - $property_list[] = $descriptions[PhabricatorPolicyCapability::CAN_VIEW]; + $property_list[] = $this->renderPolicyProperty($this->policyObject); } $header[] = phutil_tag( @@ -179,5 +175,31 @@ final class PHUIHeaderView extends AphrontView { )); } + private function renderPolicyProperty(PhabricatorPolicyInterface $object) { + $policies = PhabricatorPolicyQuery::loadPolicies( + $this->getUser(), + $object); + $view_capability = PhabricatorPolicyCapability::CAN_VIEW; + $policy = idx($policies, $view_capability); + if (!$policy) { + return null; + } + + $phid = $object->getPHID(); + + $icon = id(new PHUIIconView()) + ->setSpriteSheet(PHUIIconView::SPRITE_STATUS) + ->setSpriteIcon($policy->getIcon()); + + $link = javelin_tag( + 'a', + array( + 'href' => '/policy/explain/'.$phid.'/'.$view_capability.'/', + 'sigil' => 'workflow', + ), + $policy->getName()); + + return array($icon, $link); + } } diff --git a/webroot/rsrc/css/aphront/dialog-view.css b/webroot/rsrc/css/aphront/dialog-view.css index 8cc0d58303..e42d1682eb 100644 --- a/webroot/rsrc/css/aphront/dialog-view.css +++ b/webroot/rsrc/css/aphront/dialog-view.css @@ -111,3 +111,8 @@ .aphront-access-dialog { width: 50%; } + +.aphront-access-dialog ul { + margin: 12px 24px; + list-style: circle; +}