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 @@ -1594,6 +1594,7 @@ 'PhabricatorCustomFieldNumericIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldNumericIndexStorage.php', 'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php', 'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php', + 'PhabricatorCustomHeaderConfigType' => 'applications/config/custom/PhabricatorCustomHeaderConfigType.php', 'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php', 'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/PhabricatorDaemonConsoleController.php', 'PhabricatorDaemonController' => 'applications/daemon/controller/PhabricatorDaemonController.php', @@ -4853,6 +4854,7 @@ 'PhabricatorCustomFieldNumericIndexStorage' => 'PhabricatorCustomFieldIndexStorage', 'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO', 'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage', + 'PhabricatorCustomHeaderConfigType' => 'PhabricatorConfigOptionType', 'PhabricatorDaemon' => 'PhutilDaemon', 'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController', 'PhabricatorDaemonController' => 'PhabricatorController', diff --git a/src/applications/config/custom/PhabricatorCustomHeaderConfigType.php b/src/applications/config/custom/PhabricatorCustomHeaderConfigType.php new file mode 100644 --- /dev/null +++ b/src/applications/config/custom/PhabricatorCustomHeaderConfigType.php @@ -0,0 +1,42 @@ +setViewer(PhabricatorUser::getOmnipotentUser()) + ->withPHIDs(array($value)) + ->executeOne(); + if (!$file) { + throw new Exception(pht( + '%s is not a valid file phid.', $value)); + } + + $most_open_policy = PhabricatorPolicies::getMostOpenPolicy(); + if ($file->getViewPolicy() != $most_open_policy) { + throw new Exception(pht( + 'Specified file %s has policy "%s" but should have policy "%s".', + $value, + $file->getViewPolicy(), + $most_open_policy)); + } + + if (!$file->isViewableImage()) { + throw new Exception(pht( + 'Specified file %s is not a viewable image.', + $value)); + } + } + + public static function getExampleConfig() { + $config = 'PHID-FILE-abcd1234abcd1234abcd'; + return $config; + } + +} diff --git a/src/applications/config/option/PhabricatorCoreConfigOptions.php b/src/applications/config/option/PhabricatorCoreConfigOptions.php --- a/src/applications/config/option/PhabricatorCoreConfigOptions.php +++ b/src/applications/config/option/PhabricatorCoreConfigOptions.php @@ -36,6 +36,8 @@ 'User Guide: Prototype Applications'); $proto_doc_name = pht('User Guide: Prototype Applications'); $applications_app_href = '/applications/'; + $custom_header_example = + PhabricatorCustomHeaderConfigType::getExampleConfig(); return array( $this->newOption('phabricator.base-uri', 'string', null) @@ -209,6 +211,27 @@ ->setLocked(true) ->setDescription( pht('Custom HTML to show on the main Phabricator dashboard.')), + $this->newOption( + 'ui.custom-header', + 'custom:PhabricatorCustomHeaderConfigType', + null) + ->setSummary( + pht('Customize the Phabricator logo.')) + ->setDescription( + pht('You can customize the Phabricator logo by specifying the '. + 'phid for a viewable image you have uploaded to Phabricator '. + 'via the [[ /file/ | Files application]]. This image should '. + 'be:'."\n". + ' - 192px X 80px; while not enforced, images with these '. + 'dimensions will look best across devices.'."\n". + ' - have view policy public if [[ '. + '/config/edit/policy.allow-public | `policy.allow-public`]] '. + 'is true and otherwise view policy user; mismatches in these '. + 'policy settings will result in a broken logo for some users.'. + "\n\n". + 'You should restart your webserver after updating this value '. + 'to see this change take effect.')) + ->addExample($custom_header_example, pht('Valid Config')), $this->newOption('phabricator.cache-namespace', 'string', null) ->setLocked(true) ->setDescription(pht('Cache namespace.')), diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -236,6 +236,29 @@ } private function renderPhabricatorLogo() { + $style_logo = null; + $custom_header = PhabricatorEnv::getEnvConfig('ui.custom-header'); + if ($custom_header) { + $cache = PhabricatorCaches::getImmutableCache(); + $cache_key_logo = 'ui.custom-header.logo-phid.v1'; + $logo_uri = $cache->getKey($cache_key_logo); + if (!$logo_uri) { + $file = id(new PhabricatorFileQuery()) + ->setViewer($this->getUser()) + ->withPHIDs(array($custom_header)) + ->executeOne(); + if ($file) { + $logo_uri = $file->getViewURI(); + $cache->setKey($cache_key_logo, $logo_uri); + } + } + if ($logo_uri) { + $style_logo = + 'background-size: 96px 40px; '. + 'background-position: 0px 0px; '. + 'background-image: url('.$logo_uri.');'; + } + } return phutil_tag( 'a', @@ -260,6 +283,7 @@ 'span', array( 'class' => 'sprite-menu phabricator-main-menu-logo', + 'style' => $style_logo, ), ''), ));