1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-18 04:42:40 +01:00

Add a bunch of Phacility-specific code to the upstream, thinly veiled as generic code

Summary:
Ref T9304. This adds a "GuidanceEngine" which can generate "Guidance".

In practice, this lets third-party code (rSERVICES) remove and replace instructions in the UI, which is basically only usefulf or us to tell users to go read the documentation in the Phacility cluster.

The next diff tailors the help on the "Auth Providers" and "Create New User" pages to say "PHACILITY PHACILITY PHACILITY PHACILITY".

Test Plan: Browed to "Auth Providers" and "Create New User" on instanced and non-instanced installs, saw appropriate guidance.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9304

Differential Revision: https://secure.phabricator.com/D16861
This commit is contained in:
epriestley 2016-11-15 07:52:50 -08:00
parent e6c82c0994
commit 7097abbe57
11 changed files with 333 additions and 64 deletions

View file

@ -1917,6 +1917,8 @@ phutil_register_library_map(array(
'PhabricatorAuthProviderConfigQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigQuery.php',
'PhabricatorAuthProviderConfigTransaction' => 'applications/auth/storage/PhabricatorAuthProviderConfigTransaction.php',
'PhabricatorAuthProviderConfigTransactionQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigTransactionQuery.php',
'PhabricatorAuthProvidersGuidanceContext' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceContext.php',
'PhabricatorAuthProvidersGuidanceEngineExtension' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php',
'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php',
'PhabricatorAuthRegisterController' => 'applications/auth/controller/PhabricatorAuthRegisterController.php',
'PhabricatorAuthRevokeTokenController' => 'applications/auth/controller/PhabricatorAuthRevokeTokenController.php',
@ -2728,6 +2730,10 @@ phutil_register_library_map(array(
'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php',
'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php',
'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php',
'PhabricatorGuidanceContext' => 'applications/guides/guidance/PhabricatorGuidanceContext.php',
'PhabricatorGuidanceEngine' => 'applications/guides/guidance/PhabricatorGuidanceEngine.php',
'PhabricatorGuidanceEngineExtension' => 'applications/guides/guidance/PhabricatorGuidanceEngineExtension.php',
'PhabricatorGuidanceMessage' => 'applications/guides/guidance/PhabricatorGuidanceMessage.php',
'PhabricatorGuideApplication' => 'applications/guides/application/PhabricatorGuideApplication.php',
'PhabricatorGuideController' => 'applications/guides/controller/PhabricatorGuideController.php',
'PhabricatorGuideInstallModule' => 'applications/guides/module/PhabricatorGuideInstallModule.php',
@ -3218,6 +3224,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleApproveController' => 'applications/people/controller/PhabricatorPeopleApproveController.php',
'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php',
'PhabricatorPeopleCreateController' => 'applications/people/controller/PhabricatorPeopleCreateController.php',
'PhabricatorPeopleCreateGuidanceContext' => 'applications/people/guidance/PhabricatorPeopleCreateGuidanceContext.php',
'PhabricatorPeopleDatasource' => 'applications/people/typeahead/PhabricatorPeopleDatasource.php',
'PhabricatorPeopleDeleteController' => 'applications/people/controller/PhabricatorPeopleDeleteController.php',
'PhabricatorPeopleDetailsProfilePanel' => 'applications/people/profilepanel/PhabricatorPeopleDetailsProfilePanel.php',
@ -6730,6 +6737,8 @@ phutil_register_library_map(array(
'PhabricatorAuthProviderConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorAuthProviderConfigTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorAuthProviderConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorAuthProvidersGuidanceContext' => 'PhabricatorGuidanceContext',
'PhabricatorAuthProvidersGuidanceEngineExtension' => 'PhabricatorGuidanceEngineExtension',
'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod',
'PhabricatorAuthRegisterController' => 'PhabricatorAuthController',
'PhabricatorAuthRevokeTokenController' => 'PhabricatorAuthController',
@ -7687,6 +7696,10 @@ phutil_register_library_map(array(
'PhabricatorGlobalLock' => 'PhutilLock',
'PhabricatorGlobalUploadTargetView' => 'AphrontView',
'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider',
'PhabricatorGuidanceContext' => 'Phobject',
'PhabricatorGuidanceEngine' => 'Phobject',
'PhabricatorGuidanceEngineExtension' => 'Phobject',
'PhabricatorGuidanceMessage' => 'Phobject',
'PhabricatorGuideApplication' => 'PhabricatorApplication',
'PhabricatorGuideController' => 'PhabricatorController',
'PhabricatorGuideInstallModule' => 'PhabricatorGuideModule',
@ -8256,6 +8269,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleApproveController' => 'PhabricatorPeopleController',
'PhabricatorPeopleController' => 'PhabricatorController',
'PhabricatorPeopleCreateController' => 'PhabricatorPeopleController',
'PhabricatorPeopleCreateGuidanceContext' => 'PhabricatorGuidanceContext',
'PhabricatorPeopleDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorPeopleDeleteController' => 'PhabricatorPeopleController',
'PhabricatorPeopleDetailsProfilePanel' => 'PhabricatorProfilePanel',

View file

@ -94,58 +94,12 @@ final class PhabricatorAuthListController
$crumbs->addTextCrumb(pht('Auth Providers'));
$crumbs->setBorder(true);
$domains_key = 'auth.email-domains';
$domains_link = $this->renderConfigLink($domains_key);
$domains_value = PhabricatorEnv::getEnvConfig($domains_key);
$guidance_context = new PhabricatorAuthProvidersGuidanceContext();
$approval_key = 'auth.require-approval';
$approval_link = $this->renderConfigLink($approval_key);
$approval_value = PhabricatorEnv::getEnvConfig($approval_key);
$issues = array();
if ($domains_value) {
$issues[] = pht(
'Phabricator is configured with an email domain whitelist (in %s), so '.
'only users with a verified email address at one of these %s '.
'allowed domain(s) will be able to register an account: %s',
$domains_link,
phutil_count($domains_value),
phutil_tag('strong', array(), implode(', ', $domains_value)));
} else {
$issues[] = pht(
'Anyone who can browse to this Phabricator install will be able to '.
'register an account. To add email domain restrictions, configure '.
'%s.',
$domains_link);
}
if ($approval_value) {
$issues[] = pht(
'Administrative approvals are enabled (in %s), so all new users must '.
'have their accounts approved by an administrator.',
$approval_link);
} else {
$issues[] = pht(
'Administrative approvals are disabled, so users who register will '.
'be able to use their accounts immediately. To enable approvals, '.
'configure %s.',
$approval_link);
}
if (!$domains_value && !$approval_value) {
$severity = PHUIInfoView::SEVERITY_WARNING;
$issues[] = pht(
'You can safely ignore this warning if the install itself has '.
'access controls (for example, it is deployed on a VPN) or if all of '.
'the configured providers have access controls (for example, they are '.
'all private LDAP or OAuth servers).');
} else {
$severity = PHUIInfoView::SEVERITY_NOTICE;
}
$warning = id(new PHUIInfoView())
->setSeverity($severity)
->setErrors($issues);
$guidance = id(new PhabricatorGuidanceEngine())
->setViewer($viewer)
->setGuidanceContext($guidance_context)
->newInfoView();
$button = id(new PHUIButtonView())
->setTag('a')
@ -170,7 +124,7 @@ final class PhabricatorAuthListController
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$warning,
$guidance,
$list,
));
@ -180,14 +134,4 @@ final class PhabricatorAuthListController
->appendChild($view);
}
private function renderConfigLink($key) {
return phutil_tag(
'a',
array(
'href' => '/config/edit/'.$key.'/',
'target' => '_blank',
),
$key);
}
}

View file

@ -0,0 +1,4 @@
<?php
final class PhabricatorAuthProvidersGuidanceContext
extends PhabricatorGuidanceContext {}

View file

@ -0,0 +1,88 @@
<?php
final class PhabricatorAuthProvidersGuidanceEngineExtension
extends PhabricatorGuidanceEngineExtension {
const GUIDANCEKEY = 'core.auth.providers';
public function canGenerateGuidance(PhabricatorGuidanceContext $context) {
return ($context instanceof PhabricatorAuthProvidersGuidanceContext);
}
public function generateGuidance(PhabricatorGuidanceContext $context) {
$domains_key = 'auth.email-domains';
$domains_link = $this->renderConfigLink($domains_key);
$domains_value = PhabricatorEnv::getEnvConfig($domains_key);
$approval_key = 'auth.require-approval';
$approval_link = $this->renderConfigLink($approval_key);
$approval_value = PhabricatorEnv::getEnvConfig($approval_key);
$results = array();
if ($domains_value) {
$message = pht(
'Phabricator is configured with an email domain whitelist (in %s), so '.
'only users with a verified email address at one of these %s '.
'allowed domain(s) will be able to register an account: %s',
$domains_link,
phutil_count($domains_value),
phutil_tag('strong', array(), implode(', ', $domains_value)));
$results[] = $this->newGuidance('core.auth.email-domains.on')
->setMessage($message);
} else {
$message = pht(
'Anyone who can browse to this Phabricator install will be able to '.
'register an account. To add email domain restrictions, configure '.
'%s.',
$domains_link);
$results[] = $this->newGuidance('core.auth.email-domains.off')
->setMessage($message);
}
if ($approval_value) {
$message = pht(
'Administrative approvals are enabled (in %s), so all new users must '.
'have their accounts approved by an administrator.',
$approval_link);
$results[] = $this->newGuidance('core.auth.require-approval.on')
->setMessage($message);
} else {
$message = pht(
'Administrative approvals are disabled, so users who register will '.
'be able to use their accounts immediately. To enable approvals, '.
'configure %s.',
$approval_link);
$results[] = $this->newGuidance('core.auth.require-approval.off')
->setMessage($message);
}
if (!$domains_value && !$approval_value) {
$message = pht(
'You can safely ignore these warnings if the install itself has '.
'access controls (for example, it is deployed on a VPN) or if all of '.
'the configured providers have access controls (for example, they are '.
'all private LDAP or OAuth servers).');
$results[] = $this->newWarning('core.auth.warning')
->setMessage($message);
}
return $results;
}
private function renderConfigLink($key) {
return phutil_tag(
'a',
array(
'href' => '/config/edit/'.$key.'/',
'target' => '_blank',
),
$key);
}
}

View file

@ -0,0 +1,4 @@
<?php
abstract class PhabricatorGuidanceContext
extends Phobject {}

View file

@ -0,0 +1,96 @@
<?php
final class PhabricatorGuidanceEngine
extends Phobject {
private $viewer;
private $guidanceContext;
public function setGuidanceContext(
PhabricatorGuidanceContext $guidance_context) {
$this->guidanceContext = $guidance_context;
return $this;
}
public function getGuidanceContext() {
return $this->guidanceContext;
}
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getViewer() {
return $this->viewer;
}
public function newInfoView() {
$extensions = PhabricatorGuidanceEngineExtension::getAllExtensions();
$context = $this->getGuidanceContext();
$keep = array();
foreach ($extensions as $key => $extension) {
if (!$extension->canGenerateGuidance($context)) {
continue;
}
$keep[$key] = id(clone $extension);
}
$guidance_map = array();
foreach ($keep as $extension) {
$guidance_list = $extension->generateGuidance($context);
foreach ($guidance_list as $guidance) {
$key = $guidance->getKey();
if (isset($guidance_map[$key])) {
throw new Exception(
pht(
'Two guidance extensions generated guidance with the same '.
'key ("%s"). Each piece of guidance must have a unique key.',
$key));
}
$guidance_map[$key] = $guidance;
}
}
foreach ($keep as $extension) {
$guidance_map = $extension->didGenerateGuidance($context, $guidance_map);
}
if (!$guidance_map) {
return null;
}
$guidance_map = msortv($guidance_map, 'getSortVector');
$severity = PhabricatorGuidanceMessage::SEVERITY_NOTICE;
$strength = null;
foreach ($guidance_map as $guidance) {
if ($strength !== null) {
if ($guidance->getSeverityStrength() <= $strength) {
continue;
}
}
$strength = $guidance->getSeverityStrength();
$severity = $guidance->getSeverity();
}
$severity_map = array(
PhabricatorGuidanceMessage::SEVERITY_NOTICE
=> PHUIInfoView::SEVERITY_NOTICE,
PhabricatorGuidanceMessage::SEVERITY_WARNING
=> PHUIInfoView::SEVERITY_WARNING,
);
$messages = mpull($guidance_map, 'getMessage', 'getKey');
return id(new PHUIInfoView())
->setViewer($this->getViewer())
->setSeverity(idx($severity_map, $severity, $severity))
->setErrors($messages);
}
}

View file

@ -0,0 +1,39 @@
<?php
abstract class PhabricatorGuidanceEngineExtension
extends Phobject {
final public function getExtensionKey() {
return $this->getPhobjectClassConstant('GUIDANCEKEY', 64);
}
abstract public function canGenerateGuidance(
PhabricatorGuidanceContext $context);
abstract public function generateGuidance(
PhabricatorGuidanceContext $context);
public function didGenerateGuidance(
PhabricatorGuidanceContext $context,
array $guidance) {
return $guidance;
}
final protected function newGuidance($key) {
return id(new PhabricatorGuidanceMessage())
->setKey($key);
}
final protected function newWarning($key) {
return $this->newGuidance($key)
->setSeverity(PhabricatorGuidanceMessage::SEVERITY_WARNING);
}
final public static function getAllExtensions() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getExtensionKey')
->execute();
}
}

View file

@ -0,0 +1,65 @@
<?php
final class PhabricatorGuidanceMessage
extends Phobject {
private $key;
private $message;
private $severity = self::SEVERITY_NOTICE;
private $priority = 1000;
const SEVERITY_NOTICE = 'notice';
const SEVERITY_WARNING = 'warning';
public function setSeverity($severity) {
$this->severity = $severity;
return $this;
}
public function getSeverity() {
return $this->severity;
}
public function setKey($key) {
$this->key = $key;
return $this;
}
public function getKey() {
return $this->key;
}
public function setMessage($message) {
$this->message = $message;
return $this;
}
public function getMessage() {
return $this->message;
}
public function getSortVector() {
return id(new PhutilSortVector())
->addInt($this->getPriority());
}
public function setPriority($priority) {
$this->priority = $priority;
return $this;
}
public function getPriority() {
return $this->priority;
}
public function getSeverityStrength() {
$map = array(
self::SEVERITY_NOTICE => 1,
self::SEVERITY_WARNING => 2,
);
return idx($map, $this->getSeverity(), 0);
}
}

View file

@ -101,9 +101,20 @@ final class PhabricatorPeopleCreateController
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
$guidance_context = new PhabricatorPeopleCreateGuidanceContext();
$guidance = id(new PhabricatorGuidanceEngine())
->setViewer($admin)
->setGuidanceContext($guidance_context)
->newInfoView();
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter($box);
->setFooter(
array(
$guidance,
$box,
));
return $this->newPage()
->setTitle($title)

View file

@ -0,0 +1,4 @@
<?php
final class PhabricatorPeopleCreateGuidanceContext
extends PhabricatorGuidanceContext {}

View file

@ -130,7 +130,7 @@ final class PHUIInfoView extends AphrontTagView {
),
$list);
} else if (count($errors) == 1) {
$list = $this->errors[0];
$list = head($this->errors);
} else {
$list = null;
}