mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-24 13:38:19 +01:00
(stable) Promote 2019 Week 6
This commit is contained in:
commit
4974995c30
109 changed files with 1711 additions and 946 deletions
|
@ -9,7 +9,7 @@ return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'conpherence.pkg.css' => '3c8a0668',
|
'conpherence.pkg.css' => '3c8a0668',
|
||||||
'conpherence.pkg.js' => '020aebcf',
|
'conpherence.pkg.js' => '020aebcf',
|
||||||
'core.pkg.css' => 'e0cb8094',
|
'core.pkg.css' => '7a73ffc5',
|
||||||
'core.pkg.js' => '5c737607',
|
'core.pkg.js' => '5c737607',
|
||||||
'differential.pkg.css' => 'b8df73d4',
|
'differential.pkg.css' => 'b8df73d4',
|
||||||
'differential.pkg.js' => '67c9ea4c',
|
'differential.pkg.js' => '67c9ea4c',
|
||||||
|
@ -30,7 +30,7 @@ return array(
|
||||||
'rsrc/css/aphront/notification.css' => '30240bd2',
|
'rsrc/css/aphront/notification.css' => '30240bd2',
|
||||||
'rsrc/css/aphront/panel-view.css' => '46923d46',
|
'rsrc/css/aphront/panel-view.css' => '46923d46',
|
||||||
'rsrc/css/aphront/phabricator-nav-view.css' => 'f8a0c1bf',
|
'rsrc/css/aphront/phabricator-nav-view.css' => 'f8a0c1bf',
|
||||||
'rsrc/css/aphront/table-view.css' => '76eda3f8',
|
'rsrc/css/aphront/table-view.css' => 'daa1f9df',
|
||||||
'rsrc/css/aphront/tokenizer.css' => 'b52d0668',
|
'rsrc/css/aphront/tokenizer.css' => 'b52d0668',
|
||||||
'rsrc/css/aphront/tooltip.css' => 'e3f2412f',
|
'rsrc/css/aphront/tooltip.css' => 'e3f2412f',
|
||||||
'rsrc/css/aphront/typeahead-browse.css' => 'b7ed02d2',
|
'rsrc/css/aphront/typeahead-browse.css' => 'b7ed02d2',
|
||||||
|
@ -133,7 +133,7 @@ return array(
|
||||||
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e',
|
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e',
|
||||||
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '909f3844',
|
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '909f3844',
|
||||||
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46',
|
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46',
|
||||||
'rsrc/css/phui/phui-action-list.css' => 'c1a7631d',
|
'rsrc/css/phui/phui-action-list.css' => 'c4972757',
|
||||||
'rsrc/css/phui/phui-action-panel.css' => '6c386cbf',
|
'rsrc/css/phui/phui-action-panel.css' => '6c386cbf',
|
||||||
'rsrc/css/phui/phui-badge.css' => '666e25ad',
|
'rsrc/css/phui/phui-badge.css' => '666e25ad',
|
||||||
'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d',
|
'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d',
|
||||||
|
@ -157,7 +157,7 @@ return array(
|
||||||
'rsrc/css/phui/phui-header-view.css' => '93cea4ec',
|
'rsrc/css/phui/phui-header-view.css' => '93cea4ec',
|
||||||
'rsrc/css/phui/phui-hovercard.css' => '6ca90fa0',
|
'rsrc/css/phui/phui-hovercard.css' => '6ca90fa0',
|
||||||
'rsrc/css/phui/phui-icon-set-selector.css' => '7aa5f3ec',
|
'rsrc/css/phui/phui-icon-set-selector.css' => '7aa5f3ec',
|
||||||
'rsrc/css/phui/phui-icon.css' => '281f964d',
|
'rsrc/css/phui/phui-icon.css' => '4cbc684a',
|
||||||
'rsrc/css/phui/phui-image-mask.css' => '62c7f4d2',
|
'rsrc/css/phui/phui-image-mask.css' => '62c7f4d2',
|
||||||
'rsrc/css/phui/phui-info-view.css' => '37b8d9ce',
|
'rsrc/css/phui/phui-info-view.css' => '37b8d9ce',
|
||||||
'rsrc/css/phui/phui-invisible-character-view.css' => 'c694c4a4',
|
'rsrc/css/phui/phui-invisible-character-view.css' => 'c694c4a4',
|
||||||
|
@ -519,7 +519,7 @@ return array(
|
||||||
'aphront-list-filter-view-css' => 'feb64255',
|
'aphront-list-filter-view-css' => 'feb64255',
|
||||||
'aphront-multi-column-view-css' => 'fbc00ba3',
|
'aphront-multi-column-view-css' => 'fbc00ba3',
|
||||||
'aphront-panel-view-css' => '46923d46',
|
'aphront-panel-view-css' => '46923d46',
|
||||||
'aphront-table-view-css' => '76eda3f8',
|
'aphront-table-view-css' => 'daa1f9df',
|
||||||
'aphront-tokenizer-control-css' => 'b52d0668',
|
'aphront-tokenizer-control-css' => 'b52d0668',
|
||||||
'aphront-tooltip-css' => 'e3f2412f',
|
'aphront-tooltip-css' => 'e3f2412f',
|
||||||
'aphront-typeahead-control-css' => '8779483d',
|
'aphront-typeahead-control-css' => '8779483d',
|
||||||
|
@ -740,7 +740,7 @@ return array(
|
||||||
'path-typeahead' => 'ad486db3',
|
'path-typeahead' => 'ad486db3',
|
||||||
'people-picture-menu-item-css' => 'fe8e07cf',
|
'people-picture-menu-item-css' => 'fe8e07cf',
|
||||||
'people-profile-css' => '2ea2daa1',
|
'people-profile-css' => '2ea2daa1',
|
||||||
'phabricator-action-list-view-css' => 'c1a7631d',
|
'phabricator-action-list-view-css' => 'c4972757',
|
||||||
'phabricator-busy' => '5202e831',
|
'phabricator-busy' => '5202e831',
|
||||||
'phabricator-chatlog-css' => 'abdc76ee',
|
'phabricator-chatlog-css' => 'abdc76ee',
|
||||||
'phabricator-content-source-view-css' => 'cdf0d579',
|
'phabricator-content-source-view-css' => 'cdf0d579',
|
||||||
|
@ -823,7 +823,7 @@ return array(
|
||||||
'phui-hovercard' => '074f0783',
|
'phui-hovercard' => '074f0783',
|
||||||
'phui-hovercard-view-css' => '6ca90fa0',
|
'phui-hovercard-view-css' => '6ca90fa0',
|
||||||
'phui-icon-set-selector-css' => '7aa5f3ec',
|
'phui-icon-set-selector-css' => '7aa5f3ec',
|
||||||
'phui-icon-view-css' => '281f964d',
|
'phui-icon-view-css' => '4cbc684a',
|
||||||
'phui-image-mask-css' => '62c7f4d2',
|
'phui-image-mask-css' => '62c7f4d2',
|
||||||
'phui-info-view-css' => '37b8d9ce',
|
'phui-info-view-css' => '37b8d9ce',
|
||||||
'phui-inline-comment-view-css' => '48acce5b',
|
'phui-inline-comment-view-css' => '48acce5b',
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
UPDATE {$NAMESPACE}_legalpad.legalpad_documentsignature
|
||||||
|
SET signerPHID = NULL WHERE signerPHID LIKE 'PHID-XUSR-%';
|
2
resources/sql/autopatches/20190206.external.02.email.sql
Normal file
2
resources/sql/autopatches/20190206.external.02.email.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
DELETE FROM {$NAMESPACE}_user.user_externalaccount
|
||||||
|
WHERE accountType = 'email';
|
2
resources/sql/autopatches/20190207.packages.01.state.sql
Normal file
2
resources/sql/autopatches/20190207.packages.01.state.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_owners.owners_package
|
||||||
|
ADD auditingState VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT};
|
|
@ -0,0 +1,2 @@
|
||||||
|
UPDATE {$NAMESPACE}_owners.owners_package
|
||||||
|
SET auditingState = IF(auditingEnabled = 0, 'none', 'audit');
|
2
resources/sql/autopatches/20190207.packages.03.drop.sql
Normal file
2
resources/sql/autopatches/20190207.packages.03.drop.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_owners.owners_package
|
||||||
|
DROP auditingEnabled;
|
41
resources/sql/autopatches/20190207.packages.04.xactions.php
Normal file
41
resources/sql/autopatches/20190207.packages.04.xactions.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$table = new PhabricatorOwnersPackageTransaction();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
$iterator = new LiskRawMigrationIterator($conn, $table->getTableName());
|
||||||
|
|
||||||
|
// Migrate "Auditing State" transactions for Owners Packages from old values
|
||||||
|
// (which were "0" or "1", as JSON integer literals, without quotes) to new
|
||||||
|
// values (which are JSON strings, with quotes).
|
||||||
|
|
||||||
|
foreach ($iterator as $row) {
|
||||||
|
if ($row['transactionType'] !== 'owners.auditing') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$old_value = (int)$row['oldValue'];
|
||||||
|
$new_value = (int)$row['newValue'];
|
||||||
|
|
||||||
|
if (!$old_value) {
|
||||||
|
$old_value = 'none';
|
||||||
|
} else {
|
||||||
|
$old_value = 'audit';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$new_value) {
|
||||||
|
$new_value = 'none';
|
||||||
|
} else {
|
||||||
|
$new_value = 'audit';
|
||||||
|
}
|
||||||
|
|
||||||
|
$old_value = phutil_json_encode($old_value);
|
||||||
|
$new_value = phutil_json_encode($new_value);
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'UPDATE %R SET oldValue = %s, newValue = %s WHERE id = %d',
|
||||||
|
$table,
|
||||||
|
$old_value,
|
||||||
|
$new_value,
|
||||||
|
$row['id']);
|
||||||
|
}
|
|
@ -1,2 +1,2 @@
|
||||||
ALTER IGNORE TABLE `{$NAMESPACE}_file`.`file_imagemacro`
|
ALTER TABLE `{$NAMESPACE}_file`.`file_imagemacro`
|
||||||
ADD UNIQUE `name` (`name`);
|
ADD UNIQUE KEY `name` (`name`);
|
||||||
|
|
|
@ -1,66 +1,14 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// NOTE: We aren't using PhabricatorUserOAuthInfo anywhere here because it is
|
|
||||||
// getting nuked in a future diff.
|
|
||||||
|
|
||||||
$table = new PhabricatorUser();
|
$table = new PhabricatorUser();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
$table_name = 'user_oauthinfo';
|
$table_name = 'user_oauthinfo';
|
||||||
$conn_w = $table->establishConnection('w');
|
|
||||||
|
|
||||||
$xaccount = new PhabricatorExternalAccount();
|
foreach (new LiskRawMigrationIterator($conn, $table_name) as $row) {
|
||||||
|
throw new Exception(
|
||||||
echo pht('Migrating OAuth to %s...', 'ExternalAccount')."\n";
|
pht(
|
||||||
|
'Your Phabricator install has ancient OAuth account data and is '.
|
||||||
$domain_map = array(
|
'too old to upgrade directly to a modern version of Phabricator. '.
|
||||||
'disqus' => 'disqus.com',
|
'Upgrade to a version released between June 2013 and February 2019 '.
|
||||||
'facebook' => 'facebook.com',
|
'first, then upgrade to a modern version.'));
|
||||||
'github' => 'github.com',
|
|
||||||
'google' => 'google.com',
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$phabricator_oauth_uri = new PhutilURI(
|
|
||||||
PhabricatorEnv::getEnvConfig('phabricator.oauth-uri'));
|
|
||||||
$domain_map['phabricator'] = $phabricator_oauth_uri->getDomain();
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
// Ignore; this likely indicates that we have removed `phabricator.oauth-uri`
|
|
||||||
// in some future diff.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$rows = queryfx_all(
|
|
||||||
$conn_w,
|
|
||||||
'SELECT * FROM user_oauthinfo');
|
|
||||||
foreach ($rows as $row) {
|
|
||||||
echo pht('Migrating row ID #%d.', $row['id'])."\n";
|
|
||||||
$user = id(new PhabricatorUser())->loadOneWhere(
|
|
||||||
'id = %d',
|
|
||||||
$row['userID']);
|
|
||||||
if (!$user) {
|
|
||||||
echo pht('Bad user ID!')."\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$domain = idx($domain_map, $row['oauthProvider']);
|
|
||||||
if (empty($domain)) {
|
|
||||||
echo pht('Unknown OAuth provider!')."\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$xaccount = id(new PhabricatorExternalAccount())
|
|
||||||
->setUserPHID($user->getPHID())
|
|
||||||
->setAccountType($row['oauthProvider'])
|
|
||||||
->setAccountDomain($domain)
|
|
||||||
->setAccountID($row['oauthUID'])
|
|
||||||
->setAccountURI($row['accountURI'])
|
|
||||||
->setUsername($row['accountName'])
|
|
||||||
->setDateCreated($row['dateCreated']);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$xaccount->save();
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
phlog($ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo pht('Done.')."\n";
|
|
||||||
|
|
|
@ -1,41 +1,14 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// NOTE: We aren't using PhabricatorUserLDAPInfo anywhere here because it is
|
|
||||||
// being nuked by this change
|
|
||||||
|
|
||||||
$table = new PhabricatorUser();
|
$table = new PhabricatorUser();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
$table_name = 'user_ldapinfo';
|
$table_name = 'user_ldapinfo';
|
||||||
$conn_w = $table->establishConnection('w');
|
|
||||||
|
|
||||||
$xaccount = new PhabricatorExternalAccount();
|
foreach (new LiskRawMigrationIterator($conn, $table_name) as $row) {
|
||||||
|
throw new Exception(
|
||||||
echo pht('Migrating LDAP to %s...', 'ExternalAccount')."\n";
|
pht(
|
||||||
|
'Your Phabricator install has ancient LDAP account data and is '.
|
||||||
$rows = queryfx_all($conn_w, 'SELECT * FROM %T', $table_name);
|
'too old to upgrade directly to a modern version of Phabricator. '.
|
||||||
foreach ($rows as $row) {
|
'Upgrade to a version released between June 2013 and February 2019 '.
|
||||||
echo pht('Migrating row ID #%d.', $row['id'])."\n";
|
'first, then upgrade to a modern version.'));
|
||||||
$user = id(new PhabricatorUser())->loadOneWhere(
|
|
||||||
'id = %d',
|
|
||||||
$row['userID']);
|
|
||||||
if (!$user) {
|
|
||||||
echo pht('Bad user ID!')."\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$xaccount = id(new PhabricatorExternalAccount())
|
|
||||||
->setUserPHID($user->getPHID())
|
|
||||||
->setAccountType('ldap')
|
|
||||||
->setAccountDomain('self')
|
|
||||||
->setAccountID($row['ldapUsername'])
|
|
||||||
->setUsername($row['ldapUsername'])
|
|
||||||
->setDateCreated($row['dateCreated']);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$xaccount->save();
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
phlog($ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
echo pht('Done.')."\n";
|
|
||||||
|
|
|
@ -2272,7 +2272,6 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorAuthLinkController' => 'applications/auth/controller/PhabricatorAuthLinkController.php',
|
'PhabricatorAuthLinkController' => 'applications/auth/controller/PhabricatorAuthLinkController.php',
|
||||||
'PhabricatorAuthListController' => 'applications/auth/controller/config/PhabricatorAuthListController.php',
|
'PhabricatorAuthListController' => 'applications/auth/controller/config/PhabricatorAuthListController.php',
|
||||||
'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php',
|
'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php',
|
||||||
'PhabricatorAuthLoginHandler' => 'applications/auth/handler/PhabricatorAuthLoginHandler.php',
|
|
||||||
'PhabricatorAuthLoginMessageType' => 'applications/auth/message/PhabricatorAuthLoginMessageType.php',
|
'PhabricatorAuthLoginMessageType' => 'applications/auth/message/PhabricatorAuthLoginMessageType.php',
|
||||||
'PhabricatorAuthLogoutConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthLogoutConduitAPIMethod.php',
|
'PhabricatorAuthLogoutConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthLogoutConduitAPIMethod.php',
|
||||||
'PhabricatorAuthMFAEditEngineExtension' => 'applications/auth/engineextension/PhabricatorAuthMFAEditEngineExtension.php',
|
'PhabricatorAuthMFAEditEngineExtension' => 'applications/auth/engineextension/PhabricatorAuthMFAEditEngineExtension.php',
|
||||||
|
@ -2335,6 +2334,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorAuthProviderConfigTransaction' => 'applications/auth/storage/PhabricatorAuthProviderConfigTransaction.php',
|
'PhabricatorAuthProviderConfigTransaction' => 'applications/auth/storage/PhabricatorAuthProviderConfigTransaction.php',
|
||||||
'PhabricatorAuthProviderConfigTransactionQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigTransactionQuery.php',
|
'PhabricatorAuthProviderConfigTransactionQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigTransactionQuery.php',
|
||||||
'PhabricatorAuthProviderController' => 'applications/auth/controller/config/PhabricatorAuthProviderController.php',
|
'PhabricatorAuthProviderController' => 'applications/auth/controller/config/PhabricatorAuthProviderController.php',
|
||||||
|
'PhabricatorAuthProviderViewController' => 'applications/auth/controller/config/PhabricatorAuthProviderViewController.php',
|
||||||
'PhabricatorAuthProvidersGuidanceContext' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceContext.php',
|
'PhabricatorAuthProvidersGuidanceContext' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceContext.php',
|
||||||
'PhabricatorAuthProvidersGuidanceEngineExtension' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php',
|
'PhabricatorAuthProvidersGuidanceEngineExtension' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php',
|
||||||
'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php',
|
'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php',
|
||||||
|
@ -3552,6 +3552,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMetaMTASchemaSpec' => 'applications/metamta/storage/PhabricatorMetaMTASchemaSpec.php',
|
'PhabricatorMetaMTASchemaSpec' => 'applications/metamta/storage/PhabricatorMetaMTASchemaSpec.php',
|
||||||
'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php',
|
'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php',
|
||||||
'PhabricatorMetaMTAWorker' => 'applications/metamta/PhabricatorMetaMTAWorker.php',
|
'PhabricatorMetaMTAWorker' => 'applications/metamta/PhabricatorMetaMTAWorker.php',
|
||||||
|
'PhabricatorMetronome' => 'infrastructure/util/PhabricatorMetronome.php',
|
||||||
|
'PhabricatorMetronomeTestCase' => 'infrastructure/util/__tests__/PhabricatorMetronomeTestCase.php',
|
||||||
'PhabricatorMetronomicTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorMetronomicTriggerClock.php',
|
'PhabricatorMetronomicTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorMetronomicTriggerClock.php',
|
||||||
'PhabricatorModularTransaction' => 'applications/transactions/storage/PhabricatorModularTransaction.php',
|
'PhabricatorModularTransaction' => 'applications/transactions/storage/PhabricatorModularTransaction.php',
|
||||||
'PhabricatorModularTransactionType' => 'applications/transactions/storage/PhabricatorModularTransactionType.php',
|
'PhabricatorModularTransactionType' => 'applications/transactions/storage/PhabricatorModularTransactionType.php',
|
||||||
|
@ -3666,6 +3668,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php',
|
'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php',
|
||||||
'PhabricatorOwnersApplication' => 'applications/owners/application/PhabricatorOwnersApplication.php',
|
'PhabricatorOwnersApplication' => 'applications/owners/application/PhabricatorOwnersApplication.php',
|
||||||
'PhabricatorOwnersArchiveController' => 'applications/owners/controller/PhabricatorOwnersArchiveController.php',
|
'PhabricatorOwnersArchiveController' => 'applications/owners/controller/PhabricatorOwnersArchiveController.php',
|
||||||
|
'PhabricatorOwnersAuditRule' => 'applications/owners/constants/PhabricatorOwnersAuditRule.php',
|
||||||
'PhabricatorOwnersConfigOptions' => 'applications/owners/config/PhabricatorOwnersConfigOptions.php',
|
'PhabricatorOwnersConfigOptions' => 'applications/owners/config/PhabricatorOwnersConfigOptions.php',
|
||||||
'PhabricatorOwnersConfiguredCustomField' => 'applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php',
|
'PhabricatorOwnersConfiguredCustomField' => 'applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php',
|
||||||
'PhabricatorOwnersController' => 'applications/owners/controller/PhabricatorOwnersController.php',
|
'PhabricatorOwnersController' => 'applications/owners/controller/PhabricatorOwnersController.php',
|
||||||
|
@ -3897,6 +3900,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPeopleTransactionQuery' => 'applications/people/query/PhabricatorPeopleTransactionQuery.php',
|
'PhabricatorPeopleTransactionQuery' => 'applications/people/query/PhabricatorPeopleTransactionQuery.php',
|
||||||
'PhabricatorPeopleUserFunctionDatasource' => 'applications/people/typeahead/PhabricatorPeopleUserFunctionDatasource.php',
|
'PhabricatorPeopleUserFunctionDatasource' => 'applications/people/typeahead/PhabricatorPeopleUserFunctionDatasource.php',
|
||||||
'PhabricatorPeopleUserPHIDType' => 'applications/people/phid/PhabricatorPeopleUserPHIDType.php',
|
'PhabricatorPeopleUserPHIDType' => 'applications/people/phid/PhabricatorPeopleUserPHIDType.php',
|
||||||
|
'PhabricatorPeopleUsernameMailEngine' => 'applications/people/mail/PhabricatorPeopleUsernameMailEngine.php',
|
||||||
'PhabricatorPeopleWelcomeController' => 'applications/people/controller/PhabricatorPeopleWelcomeController.php',
|
'PhabricatorPeopleWelcomeController' => 'applications/people/controller/PhabricatorPeopleWelcomeController.php',
|
||||||
'PhabricatorPeopleWelcomeMailEngine' => 'applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php',
|
'PhabricatorPeopleWelcomeMailEngine' => 'applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php',
|
||||||
'PhabricatorPhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorPhabricatorAuthProvider.php',
|
'PhabricatorPhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorPhabricatorAuthProvider.php',
|
||||||
|
@ -5011,6 +5015,7 @@ phutil_register_library_map(array(
|
||||||
'PhortuneCurrencySerializer' => 'applications/phortune/currency/PhortuneCurrencySerializer.php',
|
'PhortuneCurrencySerializer' => 'applications/phortune/currency/PhortuneCurrencySerializer.php',
|
||||||
'PhortuneCurrencyTestCase' => 'applications/phortune/currency/__tests__/PhortuneCurrencyTestCase.php',
|
'PhortuneCurrencyTestCase' => 'applications/phortune/currency/__tests__/PhortuneCurrencyTestCase.php',
|
||||||
'PhortuneDAO' => 'applications/phortune/storage/PhortuneDAO.php',
|
'PhortuneDAO' => 'applications/phortune/storage/PhortuneDAO.php',
|
||||||
|
'PhortuneDisplayException' => 'applications/phortune/exception/PhortuneDisplayException.php',
|
||||||
'PhortuneErrCode' => 'applications/phortune/constants/PhortuneErrCode.php',
|
'PhortuneErrCode' => 'applications/phortune/constants/PhortuneErrCode.php',
|
||||||
'PhortuneInvoiceView' => 'applications/phortune/view/PhortuneInvoiceView.php',
|
'PhortuneInvoiceView' => 'applications/phortune/view/PhortuneInvoiceView.php',
|
||||||
'PhortuneLandingController' => 'applications/phortune/controller/PhortuneLandingController.php',
|
'PhortuneLandingController' => 'applications/phortune/controller/PhortuneLandingController.php',
|
||||||
|
@ -8016,7 +8021,6 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorAuthLinkController' => 'PhabricatorAuthController',
|
'PhabricatorAuthLinkController' => 'PhabricatorAuthController',
|
||||||
'PhabricatorAuthListController' => 'PhabricatorAuthProviderConfigController',
|
'PhabricatorAuthListController' => 'PhabricatorAuthProviderConfigController',
|
||||||
'PhabricatorAuthLoginController' => 'PhabricatorAuthController',
|
'PhabricatorAuthLoginController' => 'PhabricatorAuthController',
|
||||||
'PhabricatorAuthLoginHandler' => 'Phobject',
|
|
||||||
'PhabricatorAuthLoginMessageType' => 'PhabricatorAuthMessageType',
|
'PhabricatorAuthLoginMessageType' => 'PhabricatorAuthMessageType',
|
||||||
'PhabricatorAuthLogoutConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod',
|
'PhabricatorAuthLogoutConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod',
|
||||||
'PhabricatorAuthMFAEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
'PhabricatorAuthMFAEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||||
|
@ -8092,6 +8096,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorAuthProviderConfigTransaction' => 'PhabricatorApplicationTransaction',
|
'PhabricatorAuthProviderConfigTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
'PhabricatorAuthProviderConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhabricatorAuthProviderConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'PhabricatorAuthProviderController' => 'PhabricatorAuthController',
|
'PhabricatorAuthProviderController' => 'PhabricatorAuthController',
|
||||||
|
'PhabricatorAuthProviderViewController' => 'PhabricatorAuthProviderConfigController',
|
||||||
'PhabricatorAuthProvidersGuidanceContext' => 'PhabricatorGuidanceContext',
|
'PhabricatorAuthProvidersGuidanceContext' => 'PhabricatorGuidanceContext',
|
||||||
'PhabricatorAuthProvidersGuidanceEngineExtension' => 'PhabricatorGuidanceEngineExtension',
|
'PhabricatorAuthProvidersGuidanceEngineExtension' => 'PhabricatorGuidanceEngineExtension',
|
||||||
'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod',
|
'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod',
|
||||||
|
@ -9477,6 +9482,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMetaMTASchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
'PhabricatorMetaMTASchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController',
|
'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController',
|
||||||
'PhabricatorMetaMTAWorker' => 'PhabricatorWorker',
|
'PhabricatorMetaMTAWorker' => 'PhabricatorWorker',
|
||||||
|
'PhabricatorMetronome' => 'Phobject',
|
||||||
|
'PhabricatorMetronomeTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorMetronomicTriggerClock' => 'PhabricatorTriggerClock',
|
'PhabricatorMetronomicTriggerClock' => 'PhabricatorTriggerClock',
|
||||||
'PhabricatorModularTransaction' => 'PhabricatorApplicationTransaction',
|
'PhabricatorModularTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
'PhabricatorModularTransactionType' => 'Phobject',
|
'PhabricatorModularTransactionType' => 'Phobject',
|
||||||
|
@ -9608,6 +9615,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorOwnerPathQuery' => 'Phobject',
|
'PhabricatorOwnerPathQuery' => 'Phobject',
|
||||||
'PhabricatorOwnersApplication' => 'PhabricatorApplication',
|
'PhabricatorOwnersApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorOwnersArchiveController' => 'PhabricatorOwnersController',
|
'PhabricatorOwnersArchiveController' => 'PhabricatorOwnersController',
|
||||||
|
'PhabricatorOwnersAuditRule' => 'Phobject',
|
||||||
'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
'PhabricatorOwnersConfiguredCustomField' => array(
|
'PhabricatorOwnersConfiguredCustomField' => array(
|
||||||
'PhabricatorOwnersCustomField',
|
'PhabricatorOwnersCustomField',
|
||||||
|
@ -9891,6 +9899,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPeopleTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhabricatorPeopleTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'PhabricatorPeopleUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'PhabricatorPeopleUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'PhabricatorPeopleUserPHIDType' => 'PhabricatorPHIDType',
|
'PhabricatorPeopleUserPHIDType' => 'PhabricatorPHIDType',
|
||||||
|
'PhabricatorPeopleUsernameMailEngine' => 'PhabricatorPeopleMailEngine',
|
||||||
'PhabricatorPeopleWelcomeController' => 'PhabricatorPeopleController',
|
'PhabricatorPeopleWelcomeController' => 'PhabricatorPeopleController',
|
||||||
'PhabricatorPeopleWelcomeMailEngine' => 'PhabricatorPeopleMailEngine',
|
'PhabricatorPeopleWelcomeMailEngine' => 'PhabricatorPeopleMailEngine',
|
||||||
'PhabricatorPhabricatorAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
'PhabricatorPhabricatorAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
||||||
|
@ -11255,6 +11264,7 @@ phutil_register_library_map(array(
|
||||||
'PhortuneCurrencySerializer' => 'PhabricatorLiskSerializer',
|
'PhortuneCurrencySerializer' => 'PhabricatorLiskSerializer',
|
||||||
'PhortuneCurrencyTestCase' => 'PhabricatorTestCase',
|
'PhortuneCurrencyTestCase' => 'PhabricatorTestCase',
|
||||||
'PhortuneDAO' => 'PhabricatorLiskDAO',
|
'PhortuneDAO' => 'PhabricatorLiskDAO',
|
||||||
|
'PhortuneDisplayException' => 'Exception',
|
||||||
'PhortuneErrCode' => 'PhortuneConstants',
|
'PhortuneErrCode' => 'PhortuneConstants',
|
||||||
'PhortuneInvoiceView' => 'AphrontTagView',
|
'PhortuneInvoiceView' => 'AphrontTagView',
|
||||||
'PhortuneLandingController' => 'PhortuneController',
|
'PhortuneLandingController' => 'PhortuneController',
|
||||||
|
|
|
@ -7,8 +7,4 @@ abstract class AlmanacModularTransaction
|
||||||
return 'almanac';
|
return 'almanac';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,10 @@ final class PhabricatorAuthApplication extends PhabricatorApplication {
|
||||||
'' => 'PhabricatorAuthListController',
|
'' => 'PhabricatorAuthListController',
|
||||||
'config/' => array(
|
'config/' => array(
|
||||||
'new/' => 'PhabricatorAuthNewController',
|
'new/' => 'PhabricatorAuthNewController',
|
||||||
'new/(?P<className>[^/]+)/' => 'PhabricatorAuthEditController',
|
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorAuthEditController',
|
||||||
'edit/(?P<id>\d+)/' => 'PhabricatorAuthEditController',
|
|
||||||
'(?P<action>enable|disable)/(?P<id>\d+)/'
|
'(?P<action>enable|disable)/(?P<id>\d+)/'
|
||||||
=> 'PhabricatorAuthDisableController',
|
=> 'PhabricatorAuthDisableController',
|
||||||
|
'view/(?P<id>\d+)/' => 'PhabricatorAuthProviderViewController',
|
||||||
),
|
),
|
||||||
'login/(?P<pkey>[^/]+)/(?:(?P<extra>[^/]+)/)?'
|
'login/(?P<pkey>[^/]+)/(?:(?P<extra>[^/]+)/)?'
|
||||||
=> 'PhabricatorAuthLoginController',
|
=> 'PhabricatorAuthLoginController',
|
||||||
|
|
|
@ -119,38 +119,9 @@ final class PhabricatorAuthOneTimeLoginController
|
||||||
}
|
}
|
||||||
unset($unguarded);
|
unset($unguarded);
|
||||||
|
|
||||||
$next = '/';
|
$next_uri = $this->getNextStepURI($target_user);
|
||||||
if (!PhabricatorPasswordAuthProvider::getPasswordProvider()) {
|
|
||||||
$next = '/settings/panel/external/';
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// We're going to let the user reset their password without knowing
|
PhabricatorCookies::setNextURICookie($request, $next_uri, $force = true);
|
||||||
// the old one. Generate a one-time token for that.
|
|
||||||
$key = Filesystem::readRandomCharacters(16);
|
|
||||||
$password_type =
|
|
||||||
PhabricatorAuthPasswordResetTemporaryTokenType::TOKENTYPE;
|
|
||||||
|
|
||||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
|
||||||
id(new PhabricatorAuthTemporaryToken())
|
|
||||||
->setTokenResource($target_user->getPHID())
|
|
||||||
->setTokenType($password_type)
|
|
||||||
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
|
|
||||||
->setTokenCode(PhabricatorHash::weakDigest($key))
|
|
||||||
->save();
|
|
||||||
unset($unguarded);
|
|
||||||
|
|
||||||
$panel_uri = '/auth/password/';
|
|
||||||
|
|
||||||
$next = (string)id(new PhutilURI($panel_uri))
|
|
||||||
->setQueryParams(
|
|
||||||
array(
|
|
||||||
'key' => $key,
|
|
||||||
));
|
|
||||||
|
|
||||||
$request->setTemporaryCookie(PhabricatorCookies::COOKIE_HISEC, 'yes');
|
|
||||||
}
|
|
||||||
|
|
||||||
PhabricatorCookies::setNextURICookie($request, $next, $force = true);
|
|
||||||
|
|
||||||
$force_full_session = false;
|
$force_full_session = false;
|
||||||
if ($link_type === PhabricatorAuthSessionEngine::ONETIME_RECOVER) {
|
if ($link_type === PhabricatorAuthSessionEngine::ONETIME_RECOVER) {
|
||||||
|
@ -206,4 +177,57 @@ final class PhabricatorAuthOneTimeLoginController
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getNextStepURI(PhabricatorUser $user) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
|
||||||
|
// If we have password auth, let the user set or reset their password after
|
||||||
|
// login.
|
||||||
|
$have_passwords = PhabricatorPasswordAuthProvider::getPasswordProvider();
|
||||||
|
if ($have_passwords) {
|
||||||
|
// We're going to let the user reset their password without knowing
|
||||||
|
// the old one. Generate a one-time token for that.
|
||||||
|
$key = Filesystem::readRandomCharacters(16);
|
||||||
|
$password_type =
|
||||||
|
PhabricatorAuthPasswordResetTemporaryTokenType::TOKENTYPE;
|
||||||
|
|
||||||
|
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||||
|
id(new PhabricatorAuthTemporaryToken())
|
||||||
|
->setTokenResource($user->getPHID())
|
||||||
|
->setTokenType($password_type)
|
||||||
|
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
|
||||||
|
->setTokenCode(PhabricatorHash::weakDigest($key))
|
||||||
|
->save();
|
||||||
|
unset($unguarded);
|
||||||
|
|
||||||
|
$panel_uri = '/auth/password/';
|
||||||
|
|
||||||
|
$request->setTemporaryCookie(PhabricatorCookies::COOKIE_HISEC, 'yes');
|
||||||
|
|
||||||
|
return (string)id(new PhutilURI($panel_uri))
|
||||||
|
->setQueryParams(
|
||||||
|
array(
|
||||||
|
'key' => $key,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$providers = id(new PhabricatorAuthProviderConfigQuery())
|
||||||
|
->setViewer($user)
|
||||||
|
->withIsEnabled(true)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
// If there are no configured providers and the user is an administrator,
|
||||||
|
// send them to Auth to configure a provider. This is probably where they
|
||||||
|
// want to go. You can end up in this state by accidentally losing your
|
||||||
|
// first session during initial setup, or after restoring exported data
|
||||||
|
// from a hosted instance.
|
||||||
|
if (!$providers && $user->getIsAdmin()) {
|
||||||
|
return '/auth/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find anywhere better to send them, give up and just send
|
||||||
|
// them to the home page.
|
||||||
|
return '/';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,11 @@ final class PhabricatorAuthStartController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$configs = array();
|
||||||
|
foreach ($providers as $provider) {
|
||||||
|
$configs[] = $provider->getProviderConfig();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$providers) {
|
if (!$providers) {
|
||||||
if ($this->isFirstTimeSetup()) {
|
if ($this->isFirstTimeSetup()) {
|
||||||
// If this is a fresh install, let the user register their admin
|
// If this is a fresh install, let the user register their admin
|
||||||
|
@ -172,23 +177,6 @@ final class PhabricatorAuthStartController
|
||||||
$button_columns);
|
$button_columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
$handlers = PhabricatorAuthLoginHandler::getAllHandlers();
|
|
||||||
|
|
||||||
$delegating_controller = $this->getDelegatingController();
|
|
||||||
|
|
||||||
$header = array();
|
|
||||||
foreach ($handlers as $handler) {
|
|
||||||
$handler = clone $handler;
|
|
||||||
|
|
||||||
$handler->setRequest($request);
|
|
||||||
|
|
||||||
if ($delegating_controller) {
|
|
||||||
$handler->setDelegatingController($delegating_controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
$header[] = $handler->getAuthLoginHeaderContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
$invite_message = null;
|
$invite_message = null;
|
||||||
if ($invite) {
|
if ($invite) {
|
||||||
$invite_message = $this->renderInviteHeader($invite);
|
$invite_message = $this->renderInviteHeader($invite);
|
||||||
|
@ -196,16 +184,18 @@ final class PhabricatorAuthStartController
|
||||||
|
|
||||||
$custom_message = $this->newCustomStartMessage();
|
$custom_message = $this->newCustomStartMessage();
|
||||||
|
|
||||||
|
$email_login = $this->newEmailLoginView($configs);
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$crumbs->addTextCrumb(pht('Login'));
|
$crumbs->addTextCrumb(pht('Login'));
|
||||||
$crumbs->setBorder(true);
|
$crumbs->setBorder(true);
|
||||||
|
|
||||||
$title = pht('Login');
|
$title = pht('Login');
|
||||||
$view = array(
|
$view = array(
|
||||||
$header,
|
|
||||||
$invite_message,
|
$invite_message,
|
||||||
$custom_message,
|
$custom_message,
|
||||||
$out,
|
$out,
|
||||||
|
$email_login,
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
|
@ -329,4 +319,43 @@ final class PhabricatorAuthStartController
|
||||||
$remarkup_view);
|
$remarkup_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function newEmailLoginView(array $configs) {
|
||||||
|
assert_instances_of($configs, 'PhabricatorAuthProviderConfig');
|
||||||
|
|
||||||
|
// Check if password auth is enabled. If it is, the password login form
|
||||||
|
// renders a "Forgot password?" link, so we don't need to provide a
|
||||||
|
// supplemental link.
|
||||||
|
|
||||||
|
$has_password = false;
|
||||||
|
foreach ($configs as $config) {
|
||||||
|
$provider = $config->getProvider();
|
||||||
|
if ($provider instanceof PhabricatorPasswordAuthProvider) {
|
||||||
|
$has_password = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($has_password) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$view = array(
|
||||||
|
pht('Trouble logging in?'),
|
||||||
|
' ',
|
||||||
|
phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => '/login/email/',
|
||||||
|
),
|
||||||
|
pht('Send a login link to your email address.')),
|
||||||
|
);
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'auth-custom-message',
|
||||||
|
),
|
||||||
|
$view);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,15 @@ final class PhabricatorAuthUnlinkController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that this account isn't the last account which can be used to
|
$confirmations = $request->getStrList('confirmations');
|
||||||
// login. We prevent you from removing the last account.
|
$confirmations = array_fuse($confirmations);
|
||||||
|
|
||||||
|
if (!$request->isFormPost() || !isset($confirmations['unlink'])) {
|
||||||
|
return $this->renderConfirmDialog($confirmations);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that this account isn't the only account which can be used to
|
||||||
|
// login. We warn you when you remove your only login account.
|
||||||
if ($account->isUsableForLogin()) {
|
if ($account->isUsableForLogin()) {
|
||||||
$other_accounts = id(new PhabricatorExternalAccount())->loadAllWhere(
|
$other_accounts = id(new PhabricatorExternalAccount())->loadAllWhere(
|
||||||
'userPHID = %s',
|
'userPHID = %s',
|
||||||
|
@ -47,22 +54,20 @@ final class PhabricatorAuthUnlinkController
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($valid_accounts < 2) {
|
if ($valid_accounts < 2) {
|
||||||
return $this->renderLastUsableAccountErrorDialog();
|
if (!isset($confirmations['only'])) {
|
||||||
|
return $this->renderOnlyUsableAccountConfirmDialog($confirmations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->isDialogFormPost()) {
|
$account->delete();
|
||||||
$account->delete();
|
|
||||||
|
|
||||||
id(new PhabricatorAuthSessionEngine())->terminateLoginSessions(
|
id(new PhabricatorAuthSessionEngine())->terminateLoginSessions(
|
||||||
$viewer,
|
$viewer,
|
||||||
new PhutilOpaqueEnvelope(
|
new PhutilOpaqueEnvelope(
|
||||||
$request->getCookie(PhabricatorCookies::COOKIE_SESSION)));
|
$request->getCookie(PhabricatorCookies::COOKIE_SESSION)));
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($this->getDoneURI());
|
return id(new AphrontRedirectResponse())->setURI($this->getDoneURI());
|
||||||
}
|
|
||||||
|
|
||||||
return $this->renderConfirmDialog();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDoneURI() {
|
private function getDoneURI() {
|
||||||
|
@ -97,22 +102,27 @@ final class PhabricatorAuthUnlinkController
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderLastUsableAccountErrorDialog() {
|
private function renderOnlyUsableAccountConfirmDialog(array $confirmations) {
|
||||||
$dialog = id(new AphrontDialogView())
|
$confirmations[] = 'only';
|
||||||
->setUser($this->getRequest()->getUser())
|
|
||||||
->setTitle(pht('Last Valid Account'))
|
|
||||||
->appendChild(
|
|
||||||
pht(
|
|
||||||
'You can not unlink this account because you have no other '.
|
|
||||||
'valid login accounts. If you removed it, you would be unable '.
|
|
||||||
'to log in. Add another authentication method before removing '.
|
|
||||||
'this one.'))
|
|
||||||
->addCancelButton($this->getDoneURI());
|
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Unlink Your Only Login Account?'))
|
||||||
|
->addHiddenInput('confirmations', implode(',', $confirmations))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'This is the only external login account linked to your Phabicator '.
|
||||||
|
'account. If you remove it, you may no longer be able to log in.'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'If you lose access to your account, you can recover access by '.
|
||||||
|
'sending yourself an email login link from the login screen.'))
|
||||||
|
->addCancelButton($this->getDoneURI())
|
||||||
|
->addSubmitButton(pht('Unlink External Account'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderConfirmDialog() {
|
private function renderConfirmDialog(array $confirmations) {
|
||||||
|
$confirmations[] = 'unlink';
|
||||||
|
|
||||||
$provider_key = $this->providerKey;
|
$provider_key = $this->providerKey;
|
||||||
$provider = PhabricatorAuthProvider::getEnabledProviderByKey($provider_key);
|
$provider = PhabricatorAuthProvider::getEnabledProviderByKey($provider_key);
|
||||||
|
|
||||||
|
@ -129,9 +139,9 @@ final class PhabricatorAuthUnlinkController
|
||||||
'to Phabricator.');
|
'to Phabricator.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
return $this->newDialog()
|
||||||
->setUser($this->getRequest()->getUser())
|
|
||||||
->setTitle($title)
|
->setTitle($title)
|
||||||
|
->addHiddenInput('confirmations', implode(',', $confirmations))
|
||||||
->appendParagraph($body)
|
->appendParagraph($body)
|
||||||
->appendParagraph(
|
->appendParagraph(
|
||||||
pht(
|
pht(
|
||||||
|
@ -139,8 +149,6 @@ final class PhabricatorAuthUnlinkController
|
||||||
'other active login sessions.'))
|
'other active login sessions.'))
|
||||||
->addSubmitButton(pht('Unlink Account'))
|
->addSubmitButton(pht('Unlink Account'))
|
||||||
->addCancelButton($this->getDoneURI());
|
->addCancelButton($this->getDoneURI());
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,13 @@ final class PhabricatorEmailLoginController
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
if (!PhabricatorPasswordAuthProvider::getPasswordProvider()) {
|
|
||||||
return new Aphront400Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
$e_email = true;
|
$e_email = true;
|
||||||
$e_captcha = true;
|
$e_captcha = true;
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
|
||||||
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
$v_email = $request->getStr('email');
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$e_email = null;
|
$e_email = null;
|
||||||
$e_captcha = pht('Again');
|
$e_captcha = pht('Again');
|
||||||
|
@ -29,8 +25,7 @@ final class PhabricatorEmailLoginController
|
||||||
$e_captcha = pht('Invalid');
|
$e_captcha = pht('Invalid');
|
||||||
}
|
}
|
||||||
|
|
||||||
$email = $request->getStr('email');
|
if (!strlen($v_email)) {
|
||||||
if (!strlen($email)) {
|
|
||||||
$errors[] = pht('You must provide an email address.');
|
$errors[] = pht('You must provide an email address.');
|
||||||
$e_email = pht('Required');
|
$e_email = pht('Required');
|
||||||
}
|
}
|
||||||
|
@ -42,7 +37,7 @@ final class PhabricatorEmailLoginController
|
||||||
|
|
||||||
$target_email = id(new PhabricatorUserEmail())->loadOneWhere(
|
$target_email = id(new PhabricatorUserEmail())->loadOneWhere(
|
||||||
'address = %s',
|
'address = %s',
|
||||||
$email);
|
$v_email);
|
||||||
|
|
||||||
$target_user = null;
|
$target_user = null;
|
||||||
if ($target_email) {
|
if ($target_email) {
|
||||||
|
@ -81,33 +76,10 @@ final class PhabricatorEmailLoginController
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$errors) {
|
if (!$errors) {
|
||||||
$engine = new PhabricatorAuthSessionEngine();
|
$body = $this->newAccountLoginMailBody($target_user);
|
||||||
$uri = $engine->getOneTimeLoginURI(
|
|
||||||
$target_user,
|
|
||||||
null,
|
|
||||||
PhabricatorAuthSessionEngine::ONETIME_RESET);
|
|
||||||
|
|
||||||
if ($is_serious) {
|
|
||||||
$body = pht(
|
|
||||||
"You can use this link to reset your Phabricator password:".
|
|
||||||
"\n\n %s\n",
|
|
||||||
$uri);
|
|
||||||
} else {
|
|
||||||
$body = pht(
|
|
||||||
"Condolences on forgetting your password. You can use this ".
|
|
||||||
"link to reset it:\n\n".
|
|
||||||
" %s\n\n".
|
|
||||||
"After you set a new password, consider writing it down on a ".
|
|
||||||
"sticky note and attaching it to your monitor so you don't ".
|
|
||||||
"forget again! Choosing a very short, easy-to-remember password ".
|
|
||||||
"like \"cat\" or \"1234\" might also help.\n\n".
|
|
||||||
"Best Wishes,\nPhabricator\n",
|
|
||||||
$uri);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$mail = id(new PhabricatorMetaMTAMail())
|
$mail = id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject(pht('[Phabricator] Password Reset'))
|
->setSubject(pht('[Phabricator] Account Login Link'))
|
||||||
->setForceDelivery(true)
|
->setForceDelivery(true)
|
||||||
->addRawTos(array($target_email->getAddress()))
|
->addRawTos(array($target_email->getAddress()))
|
||||||
->setBody($body)
|
->setBody($body)
|
||||||
|
@ -123,44 +95,90 @@ final class PhabricatorEmailLoginController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$error_view = null;
|
$form = id(new AphrontFormView())
|
||||||
if ($errors) {
|
->setViewer($viewer);
|
||||||
$error_view = new PHUIInfoView();
|
|
||||||
$error_view->setErrors($errors);
|
if ($this->isPasswordAuthEnabled()) {
|
||||||
|
$form->appendRemarkupInstructions(
|
||||||
|
pht(
|
||||||
|
'To reset your password, provide your email address. An email '.
|
||||||
|
'with a login link will be sent to you.'));
|
||||||
|
} else {
|
||||||
|
$form->appendRemarkupInstructions(
|
||||||
|
pht(
|
||||||
|
'To access your account, provide your email address. An email '.
|
||||||
|
'with a login link will be sent to you.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$email_auth = new PHUIFormLayoutView();
|
$form
|
||||||
$email_auth->appendChild($error_view);
|
->appendControl(
|
||||||
$email_auth
|
|
||||||
->setUser($request->getUser())
|
|
||||||
->setFullWidth(true)
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel(pht('Email'))
|
->setLabel(pht('Email Address'))
|
||||||
->setName('email')
|
->setName('email')
|
||||||
->setValue($request->getStr('email'))
|
->setValue($v_email)
|
||||||
->setError($e_email))
|
->setError($e_email))
|
||||||
->appendChild(
|
->appendControl(
|
||||||
id(new AphrontFormRecaptchaControl())
|
id(new AphrontFormRecaptchaControl())
|
||||||
->setLabel(pht('Captcha'))
|
->setLabel(pht('Captcha'))
|
||||||
->setError($e_captcha));
|
->setError($e_captcha));
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
if ($this->isPasswordAuthEnabled()) {
|
||||||
$crumbs->addTextCrumb(pht('Reset Password'));
|
$title = pht('Password Reset');
|
||||||
$crumbs->setBorder(true);
|
} else {
|
||||||
|
$title = pht('Email Login');
|
||||||
$dialog = new AphrontDialogView();
|
}
|
||||||
$dialog->setUser($request->getUser());
|
|
||||||
$dialog->setTitle(pht('Forgot Password / Email Login'));
|
|
||||||
$dialog->appendChild($email_auth);
|
|
||||||
$dialog->addSubmitButton(pht('Send Email'));
|
|
||||||
$dialog->setSubmitURI('/login/email/');
|
|
||||||
|
|
||||||
return $this->newPage()
|
|
||||||
->setTitle(pht('Forgot Password'))
|
|
||||||
->setCrumbs($crumbs)
|
|
||||||
->appendChild($dialog);
|
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle($title)
|
||||||
|
->setErrors($errors)
|
||||||
|
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||||
|
->appendForm($form)
|
||||||
|
->addCancelButton('/auth/start/')
|
||||||
|
->addSubmitButton(pht('Send Email'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function newAccountLoginMailBody(PhabricatorUser $user) {
|
||||||
|
$engine = new PhabricatorAuthSessionEngine();
|
||||||
|
$uri = $engine->getOneTimeLoginURI(
|
||||||
|
$user,
|
||||||
|
null,
|
||||||
|
PhabricatorAuthSessionEngine::ONETIME_RESET);
|
||||||
|
|
||||||
|
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
||||||
|
$have_passwords = $this->isPasswordAuthEnabled();
|
||||||
|
|
||||||
|
if ($have_passwords) {
|
||||||
|
if ($is_serious) {
|
||||||
|
$body = pht(
|
||||||
|
"You can use this link to reset your Phabricator password:".
|
||||||
|
"\n\n %s\n",
|
||||||
|
$uri);
|
||||||
|
} else {
|
||||||
|
$body = pht(
|
||||||
|
"Condolences on forgetting your password. You can use this ".
|
||||||
|
"link to reset it:\n\n".
|
||||||
|
" %s\n\n".
|
||||||
|
"After you set a new password, consider writing it down on a ".
|
||||||
|
"sticky note and attaching it to your monitor so you don't ".
|
||||||
|
"forget again! Choosing a very short, easy-to-remember password ".
|
||||||
|
"like \"cat\" or \"1234\" might also help.\n\n".
|
||||||
|
"Best Wishes,\nPhabricator\n",
|
||||||
|
$uri);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$body = pht(
|
||||||
|
"You can use this login link to regain access to your Phabricator ".
|
||||||
|
"account:".
|
||||||
|
"\n\n".
|
||||||
|
" %s\n",
|
||||||
|
$uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $body;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isPasswordAuthEnabled() {
|
||||||
|
return (bool)PhabricatorPasswordAuthProvider::getPasswordProvider();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@ final class PhabricatorAuthDisableController
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$this->requireApplicationCapability(
|
$this->requireApplicationCapability(
|
||||||
AuthManageProvidersCapability::CAPABILITY);
|
AuthManageProvidersCapability::CAPABILITY);
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
$config_id = $request->getURIData('id');
|
$config_id = $request->getURIData('id');
|
||||||
$action = $request->getURIData('action');
|
$action = $request->getURIData('action');
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ final class PhabricatorAuthDisableController
|
||||||
}
|
}
|
||||||
|
|
||||||
$is_enable = ($action === 'enable');
|
$is_enable = ($action === 'enable');
|
||||||
|
$done_uri = $config->getURI();
|
||||||
|
|
||||||
if ($request->isDialogFormPost()) {
|
if ($request->isDialogFormPost()) {
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
|
@ -39,8 +41,7 @@ final class PhabricatorAuthDisableController
|
||||||
->setContinueOnNoEffect(true)
|
->setContinueOnNoEffect(true)
|
||||||
->applyTransactions($config, $xactions);
|
->applyTransactions($config, $xactions);
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI(
|
return id(new AphrontRedirectResponse())->setURI($done_uri);
|
||||||
$this->getApplicationURI());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($is_enable) {
|
if ($is_enable) {
|
||||||
|
@ -64,8 +65,9 @@ final class PhabricatorAuthDisableController
|
||||||
// account and pop a warning like "YOU WILL NO LONGER BE ABLE TO LOGIN
|
// account and pop a warning like "YOU WILL NO LONGER BE ABLE TO LOGIN
|
||||||
// YOU GOOF, YOU PROBABLY DO NOT MEAN TO DO THIS". None of this is
|
// YOU GOOF, YOU PROBABLY DO NOT MEAN TO DO THIS". None of this is
|
||||||
// critical and we can wait to see how users manage to shoot themselves
|
// critical and we can wait to see how users manage to shoot themselves
|
||||||
// in the feet. Shortly, `bin/auth` will be able to recover from these
|
// in the feet.
|
||||||
// types of mistakes.
|
|
||||||
|
// `bin/auth` can recover from these types of mistakes.
|
||||||
|
|
||||||
$title = pht('Disable Provider?');
|
$title = pht('Disable Provider?');
|
||||||
$body = pht(
|
$body = pht(
|
||||||
|
@ -77,14 +79,11 @@ final class PhabricatorAuthDisableController
|
||||||
$button = pht('Disable Provider');
|
$button = pht('Disable Provider');
|
||||||
}
|
}
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
return $this->newDialog()
|
||||||
->setUser($viewer)
|
|
||||||
->setTitle($title)
|
->setTitle($title)
|
||||||
->appendChild($body)
|
->appendChild($body)
|
||||||
->addCancelButton($this->getApplicationURI())
|
->addCancelButton($done_uri)
|
||||||
->addSubmitButton($button);
|
->addSubmitButton($button);
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,9 @@ final class PhabricatorAuthEditController
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$this->requireApplicationCapability(
|
$this->requireApplicationCapability(
|
||||||
AuthManageProvidersCapability::CAPABILITY);
|
AuthManageProvidersCapability::CAPABILITY);
|
||||||
$viewer = $request->getUser();
|
|
||||||
$provider_class = $request->getURIData('className');
|
$viewer = $this->getViewer();
|
||||||
|
$provider_class = $request->getStr('provider');
|
||||||
$config_id = $request->getURIData('id');
|
$config_id = $request->getURIData('id');
|
||||||
|
|
||||||
if ($config_id) {
|
if ($config_id) {
|
||||||
|
@ -155,12 +156,7 @@ final class PhabricatorAuthEditController
|
||||||
->setContinueOnNoEffect(true)
|
->setContinueOnNoEffect(true)
|
||||||
->applyTransactions($config, $xactions);
|
->applyTransactions($config, $xactions);
|
||||||
|
|
||||||
if ($provider->hasSetupStep() && $is_new) {
|
$next_uri = $config->getURI();
|
||||||
$id = $config->getID();
|
|
||||||
$next_uri = $this->getApplicationURI('config/edit/'.$id.'/');
|
|
||||||
} else {
|
|
||||||
$next_uri = $this->getApplicationURI();
|
|
||||||
}
|
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
||||||
}
|
}
|
||||||
|
@ -184,7 +180,7 @@ final class PhabricatorAuthEditController
|
||||||
$crumb = pht('Edit Provider');
|
$crumb = pht('Edit Provider');
|
||||||
$title = pht('Edit Auth Provider');
|
$title = pht('Edit Auth Provider');
|
||||||
$header_icon = 'fa-pencil';
|
$header_icon = 'fa-pencil';
|
||||||
$cancel_uri = $this->getApplicationURI();
|
$cancel_uri = $config->getURI();
|
||||||
}
|
}
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
|
@ -275,6 +271,7 @@ final class PhabricatorAuthEditController
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
$form = id(new AphrontFormView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
|
->addHiddenInput('provider', $provider_class)
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormCheckboxControl())
|
id(new AphrontFormCheckboxControl())
|
||||||
->setLabel(pht('Allow'))
|
->setLabel(pht('Allow'))
|
||||||
|
@ -346,18 +343,6 @@ final class PhabricatorAuthEditController
|
||||||
$crumbs->addTextCrumb($crumb);
|
$crumbs->addTextCrumb($crumb);
|
||||||
$crumbs->setBorder(true);
|
$crumbs->setBorder(true);
|
||||||
|
|
||||||
$timeline = null;
|
|
||||||
if (!$is_new) {
|
|
||||||
$timeline = $this->buildTransactionTimeline(
|
|
||||||
$config,
|
|
||||||
new PhabricatorAuthProviderConfigTransactionQuery());
|
|
||||||
$xactions = $timeline->getTransactions();
|
|
||||||
foreach ($xactions as $xaction) {
|
|
||||||
$xaction->setProvider($provider);
|
|
||||||
}
|
|
||||||
$timeline->setShouldTerminate(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$form_box = id(new PHUIObjectBoxView())
|
$form_box = id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Provider'))
|
->setHeaderText(pht('Provider'))
|
||||||
->setFormErrors($errors)
|
->setFormErrors($errors)
|
||||||
|
@ -369,7 +354,6 @@ final class PhabricatorAuthEditController
|
||||||
->setFooter(array(
|
->setFooter(array(
|
||||||
$form_box,
|
$form_box,
|
||||||
$footer,
|
$footer,
|
||||||
$timeline,
|
|
||||||
));
|
));
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
|
|
|
@ -19,31 +19,18 @@ final class PhabricatorAuthListController
|
||||||
|
|
||||||
$id = $config->getID();
|
$id = $config->getID();
|
||||||
|
|
||||||
$edit_uri = $this->getApplicationURI('config/edit/'.$id.'/');
|
$view_uri = $config->getURI();
|
||||||
$enable_uri = $this->getApplicationURI('config/enable/'.$id.'/');
|
|
||||||
$disable_uri = $this->getApplicationURI('config/disable/'.$id.'/');
|
|
||||||
|
|
||||||
$provider = $config->getProvider();
|
$provider = $config->getProvider();
|
||||||
if ($provider) {
|
$name = $provider->getProviderName();
|
||||||
$name = $provider->getProviderName();
|
|
||||||
} else {
|
|
||||||
$name = $config->getProviderType().' ('.$config->getProviderClass().')';
|
|
||||||
}
|
|
||||||
|
|
||||||
$item->setHeader($name);
|
$item
|
||||||
|
->setHeader($name)
|
||||||
|
->setHref($view_uri);
|
||||||
|
|
||||||
if ($provider) {
|
$domain = $provider->getProviderDomain();
|
||||||
$item->setHref($edit_uri);
|
if ($domain !== 'self') {
|
||||||
} else {
|
$item->addAttribute($domain);
|
||||||
$item->addAttribute(pht('Provider Implementation Missing!'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$domain = null;
|
|
||||||
if ($provider) {
|
|
||||||
$domain = $provider->getProviderDomain();
|
|
||||||
if ($domain !== 'self') {
|
|
||||||
$item->addAttribute($domain);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config->getShouldAllowRegistration()) {
|
if ($config->getShouldAllowRegistration()) {
|
||||||
|
@ -54,21 +41,9 @@ final class PhabricatorAuthListController
|
||||||
|
|
||||||
if ($config->getIsEnabled()) {
|
if ($config->getIsEnabled()) {
|
||||||
$item->setStatusIcon('fa-check-circle green');
|
$item->setStatusIcon('fa-check-circle green');
|
||||||
$item->addAction(
|
|
||||||
id(new PHUIListItemView())
|
|
||||||
->setIcon('fa-times')
|
|
||||||
->setHref($disable_uri)
|
|
||||||
->setDisabled(!$can_manage)
|
|
||||||
->addSigil('workflow'));
|
|
||||||
} else {
|
} else {
|
||||||
$item->setStatusIcon('fa-ban red');
|
$item->setStatusIcon('fa-ban red');
|
||||||
$item->addIcon('fa-ban grey', pht('Disabled'));
|
$item->addIcon('fa-ban grey', pht('Disabled'));
|
||||||
$item->addAction(
|
|
||||||
id(new PHUIListItemView())
|
|
||||||
->setIcon('fa-plus')
|
|
||||||
->setHref($enable_uri)
|
|
||||||
->setDisabled(!$can_manage)
|
|
||||||
->addSigil('workflow'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$list->addItem($item);
|
$list->addItem($item);
|
||||||
|
@ -123,10 +98,11 @@ final class PhabricatorAuthListController
|
||||||
|
|
||||||
$view = id(new PHUITwoColumnView())
|
$view = id(new PHUITwoColumnView())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->setFooter(array(
|
->setFooter(
|
||||||
$guidance,
|
array(
|
||||||
$list,
|
$guidance,
|
||||||
));
|
$list,
|
||||||
|
));
|
||||||
|
|
||||||
$nav = $this->newNavigation()
|
$nav = $this->newNavigation()
|
||||||
->setCrumbs($crumbs)
|
->setCrumbs($crumbs)
|
||||||
|
|
|
@ -6,44 +6,12 @@ final class PhabricatorAuthNewController
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$this->requireApplicationCapability(
|
$this->requireApplicationCapability(
|
||||||
AuthManageProvidersCapability::CAPABILITY);
|
AuthManageProvidersCapability::CAPABILITY);
|
||||||
$request = $this->getRequest();
|
|
||||||
$viewer = $request->getUser();
|
$viewer = $this->getViewer();
|
||||||
|
$cancel_uri = $this->getApplicationURI();
|
||||||
|
|
||||||
$providers = PhabricatorAuthProvider::getAllBaseProviders();
|
$providers = PhabricatorAuthProvider::getAllBaseProviders();
|
||||||
|
|
||||||
$e_provider = null;
|
|
||||||
$errors = array();
|
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
|
||||||
$provider_string = $request->getStr('provider');
|
|
||||||
if (!strlen($provider_string)) {
|
|
||||||
$e_provider = pht('Required');
|
|
||||||
$errors[] = pht('You must select an authentication provider.');
|
|
||||||
} else {
|
|
||||||
$found = false;
|
|
||||||
foreach ($providers as $provider) {
|
|
||||||
if (get_class($provider) === $provider_string) {
|
|
||||||
$found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!$found) {
|
|
||||||
$e_provider = pht('Invalid');
|
|
||||||
$errors[] = pht('You must select a valid provider.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$errors) {
|
|
||||||
return id(new AphrontRedirectResponse())->setURI(
|
|
||||||
$this->getApplicationURI('/config/new/'.$provider_string.'/'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$options = id(new AphrontFormRadioButtonControl())
|
|
||||||
->setLabel(pht('Provider'))
|
|
||||||
->setName('provider')
|
|
||||||
->setError($e_provider);
|
|
||||||
|
|
||||||
$configured = PhabricatorAuthProvider::getAllProviders();
|
$configured = PhabricatorAuthProvider::getAllProviders();
|
||||||
$configured_classes = array();
|
$configured_classes = array();
|
||||||
foreach ($configured as $configured_provider) {
|
foreach ($configured as $configured_provider) {
|
||||||
|
@ -55,57 +23,52 @@ final class PhabricatorAuthNewController
|
||||||
$providers = msort($providers, 'getLoginOrder');
|
$providers = msort($providers, 'getLoginOrder');
|
||||||
$providers = array_diff_key($providers, $configured_classes) + $providers;
|
$providers = array_diff_key($providers, $configured_classes) + $providers;
|
||||||
|
|
||||||
foreach ($providers as $provider) {
|
$menu = id(new PHUIObjectItemListView())
|
||||||
if (isset($configured_classes[get_class($provider)])) {
|
->setViewer($viewer)
|
||||||
$disabled = true;
|
->setBig(true)
|
||||||
$description = pht('This provider is already configured.');
|
->setFlush(true);
|
||||||
|
|
||||||
|
foreach ($providers as $provider_key => $provider) {
|
||||||
|
$provider_class = get_class($provider);
|
||||||
|
|
||||||
|
$provider_uri = id(new PhutilURI('/config/edit/'))
|
||||||
|
->setQueryParam('provider', $provider_class);
|
||||||
|
$provider_uri = $this->getApplicationURI($provider_uri);
|
||||||
|
|
||||||
|
$already_exists = isset($configured_classes[get_class($provider)]);
|
||||||
|
|
||||||
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setHeader($provider->getNameForCreate())
|
||||||
|
->setImageIcon($provider->newIconView())
|
||||||
|
->addAttribute($provider->getDescriptionForCreate());
|
||||||
|
|
||||||
|
if (!$already_exists) {
|
||||||
|
$item
|
||||||
|
->setHref($provider_uri)
|
||||||
|
->setClickable(true);
|
||||||
} else {
|
} else {
|
||||||
$disabled = false;
|
$item->setDisabled(true);
|
||||||
$description = $provider->getDescriptionForCreate();
|
|
||||||
}
|
}
|
||||||
$options->addButton(
|
|
||||||
get_class($provider),
|
if ($already_exists) {
|
||||||
$provider->getNameForCreate(),
|
$messages = array();
|
||||||
$description,
|
$messages[] = pht('You already have a provider of this type.');
|
||||||
$disabled ? 'disabled' : null,
|
|
||||||
$disabled);
|
$info = id(new PHUIInfoView())
|
||||||
|
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
||||||
|
->setErrors($messages);
|
||||||
|
|
||||||
|
$item->appendChild($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
$menu->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
return $this->newDialog()
|
||||||
->setUser($viewer)
|
->setTitle(pht('Add Auth Provider'))
|
||||||
->appendChild($options)
|
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||||
->appendChild(
|
->appendChild($menu)
|
||||||
id(new AphrontFormSubmitControl())
|
->addCancelButton($cancel_uri);
|
||||||
->addCancelButton($this->getApplicationURI())
|
|
||||||
->setValue(pht('Continue')));
|
|
||||||
|
|
||||||
$form_box = id(new PHUIObjectBoxView())
|
|
||||||
->setHeaderText(pht('Provider'))
|
|
||||||
->setFormErrors($errors)
|
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
|
||||||
->setForm($form);
|
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
|
||||||
$crumbs->addTextCrumb(pht('Add Provider'));
|
|
||||||
$crumbs->setBorder(true);
|
|
||||||
|
|
||||||
$title = pht('Add Auth Provider');
|
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
|
||||||
->setHeader($title)
|
|
||||||
->setHeaderIcon('fa-plus-square');
|
|
||||||
|
|
||||||
$view = id(new PHUITwoColumnView())
|
|
||||||
->setHeader($header)
|
|
||||||
->setFooter(array(
|
|
||||||
$form_box,
|
|
||||||
));
|
|
||||||
|
|
||||||
return $this->newPage()
|
|
||||||
->setTitle($title)
|
|
||||||
->setCrumbs($crumbs)
|
|
||||||
->appendChild($view);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorAuthProviderViewController
|
||||||
|
extends PhabricatorAuthProviderConfigController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$this->requireApplicationCapability(
|
||||||
|
AuthManageProvidersCapability::CAPABILITY);
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$id = $request->getURIData('id');
|
||||||
|
|
||||||
|
$config = id(new PhabricatorAuthProviderConfigQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->withIDs(array($id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$config) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = $this->buildHeaderView($config);
|
||||||
|
$properties = $this->buildPropertiesView($config);
|
||||||
|
$curtain = $this->buildCurtain($config);
|
||||||
|
|
||||||
|
$timeline = $this->buildTransactionTimeline(
|
||||||
|
$config,
|
||||||
|
new PhabricatorAuthProviderConfigTransactionQuery());
|
||||||
|
$timeline->setShouldTerminate(true);
|
||||||
|
|
||||||
|
$view = id(new PHUITwoColumnView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setCurtain($curtain)
|
||||||
|
->addPropertySection(pht('Details'), $properties)
|
||||||
|
->setMainColumn($timeline);
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
|
->addTextCrumb($config->getObjectName())
|
||||||
|
->setBorder(true);
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle(pht('Auth Provider: %s', $config->getDisplayName()))
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->appendChild($view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildHeaderView(PhabricatorAuthProviderConfig $config) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$view = id(new PHUIHeaderView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setHeader($config->getDisplayName());
|
||||||
|
|
||||||
|
if ($config->getIsEnabled()) {
|
||||||
|
$view->setStatus('fa-check', 'bluegrey', pht('Enabled'));
|
||||||
|
} else {
|
||||||
|
$view->setStatus('fa-ban', 'red', pht('Disabled'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildCurtain(PhabricatorAuthProviderConfig $config) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$id = $config->getID();
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$config,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$curtain = $this->newCurtainView($config);
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Edit Auth Provider'))
|
||||||
|
->setIcon('fa-pencil')
|
||||||
|
->setHref($this->getApplicationURI("config/edit/{$id}/"))
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
|
if ($config->getIsEnabled()) {
|
||||||
|
$disable_uri = $this->getApplicationURI('config/disable/'.$id.'/');
|
||||||
|
$disable_icon = 'fa-ban';
|
||||||
|
$disable_text = pht('Disable Provider');
|
||||||
|
} else {
|
||||||
|
$disable_uri = $this->getApplicationURI('config/enable/'.$id.'/');
|
||||||
|
$disable_icon = 'fa-check';
|
||||||
|
$disable_text = pht('Enable Provider');
|
||||||
|
}
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName($disable_text)
|
||||||
|
->setIcon($disable_icon)
|
||||||
|
->setHref($disable_uri)
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
|
return $curtain;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPropertiesView(PhabricatorAuthProviderConfig $config) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$view = id(new PHUIPropertyListView())
|
||||||
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
$view->addProperty(
|
||||||
|
pht('Provider Type'),
|
||||||
|
$config->getProvider()->getProviderName());
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
}
|
|
@ -123,6 +123,7 @@ abstract class PhabricatorAuthFactor extends Phobject {
|
||||||
->setUserPHID($viewer->getPHID())
|
->setUserPHID($viewer->getPHID())
|
||||||
->setSessionPHID($viewer->getSession()->getPHID())
|
->setSessionPHID($viewer->getSession()->getPHID())
|
||||||
->setFactorPHID($config->getPHID())
|
->setFactorPHID($config->getPHID())
|
||||||
|
->setIsNewChallenge(true)
|
||||||
->setWorkflowKey($engine->getWorkflowKey());
|
->setWorkflowKey($engine->getWorkflowKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,8 +284,11 @@ abstract class PhabricatorAuthFactor extends Phobject {
|
||||||
|
|
||||||
$error = $result->getErrorMessage();
|
$error = $result->getErrorMessage();
|
||||||
|
|
||||||
$icon = id(new PHUIIconView())
|
$icon = $result->getIcon();
|
||||||
->setIcon('fa-clock-o', 'red');
|
if (!$icon) {
|
||||||
|
$icon = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-clock-o', 'red');
|
||||||
|
}
|
||||||
|
|
||||||
return id(new PHUIFormTimerControl())
|
return id(new PHUIFormTimerControl())
|
||||||
->setIcon($icon)
|
->setIcon($icon)
|
||||||
|
@ -295,8 +299,11 @@ abstract class PhabricatorAuthFactor extends Phobject {
|
||||||
private function newAnsweredControl(
|
private function newAnsweredControl(
|
||||||
PhabricatorAuthFactorResult $result) {
|
PhabricatorAuthFactorResult $result) {
|
||||||
|
|
||||||
$icon = id(new PHUIIconView())
|
$icon = $result->getIcon();
|
||||||
->setIcon('fa-check-circle-o', 'green');
|
if (!$icon) {
|
||||||
|
$icon = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-check-circle-o', 'green');
|
||||||
|
}
|
||||||
|
|
||||||
return id(new PHUIFormTimerControl())
|
return id(new PHUIFormTimerControl())
|
||||||
->setIcon($icon)
|
->setIcon($icon)
|
||||||
|
@ -309,8 +316,11 @@ abstract class PhabricatorAuthFactor extends Phobject {
|
||||||
|
|
||||||
$error = $result->getErrorMessage();
|
$error = $result->getErrorMessage();
|
||||||
|
|
||||||
$icon = id(new PHUIIconView())
|
$icon = $result->getIcon();
|
||||||
->setIcon('fa-times', 'red');
|
if (!$icon) {
|
||||||
|
$icon = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-times', 'red');
|
||||||
|
}
|
||||||
|
|
||||||
return id(new PHUIFormTimerControl())
|
return id(new PHUIFormTimerControl())
|
||||||
->setIcon($icon)
|
->setIcon($icon)
|
||||||
|
@ -323,8 +333,11 @@ abstract class PhabricatorAuthFactor extends Phobject {
|
||||||
|
|
||||||
$error = $result->getErrorMessage();
|
$error = $result->getErrorMessage();
|
||||||
|
|
||||||
$icon = id(new PHUIIconView())
|
$icon = $result->getIcon();
|
||||||
->setIcon('fa-commenting', 'green');
|
if (!$icon) {
|
||||||
|
$icon = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-commenting', 'green');
|
||||||
|
}
|
||||||
|
|
||||||
return id(new PHUIFormTimerControl())
|
return id(new PHUIFormTimerControl())
|
||||||
->setIcon($icon)
|
->setIcon($icon)
|
||||||
|
|
|
@ -10,6 +10,7 @@ final class PhabricatorAuthFactorResult
|
||||||
private $errorMessage;
|
private $errorMessage;
|
||||||
private $value;
|
private $value;
|
||||||
private $issuedChallenges = array();
|
private $issuedChallenges = array();
|
||||||
|
private $icon;
|
||||||
|
|
||||||
public function setAnsweredChallenge(PhabricatorAuthChallenge $challenge) {
|
public function setAnsweredChallenge(PhabricatorAuthChallenge $challenge) {
|
||||||
if (!$challenge->getIsAnsweredChallenge()) {
|
if (!$challenge->getIsAnsweredChallenge()) {
|
||||||
|
@ -92,4 +93,13 @@ final class PhabricatorAuthFactorResult
|
||||||
return $this->issuedChallenges;
|
return $this->issuedChallenges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setIcon(PHUIIconView $icon) {
|
||||||
|
$this->icon = $icon;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIcon() {
|
||||||
|
return $this->icon;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -612,7 +612,22 @@ final class PhabricatorDuoAuthFactor
|
||||||
return $this->newResult()
|
return $this->newResult()
|
||||||
->setAnsweredChallenge($challenge);
|
->setAnsweredChallenge($challenge);
|
||||||
case 'waiting':
|
case 'waiting':
|
||||||
// No result yet, we'll render a default state later on.
|
// If we didn't just issue this challenge, give the user a stronger
|
||||||
|
// hint that they need to follow the instructions.
|
||||||
|
if (!$challenge->getIsNewChallenge()) {
|
||||||
|
return $this->newResult()
|
||||||
|
->setIsContinue(true)
|
||||||
|
->setIcon(
|
||||||
|
id(new PHUIIconView())
|
||||||
|
->setIcon('fa-exclamation-triangle', 'yellow'))
|
||||||
|
->setErrorMessage(
|
||||||
|
pht(
|
||||||
|
'You must approve the challenge which was sent to your '.
|
||||||
|
'phone. Open the Duo application and confirm the challenge, '.
|
||||||
|
'then continue.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we'll construct a default message later on.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case 'deny':
|
case 'deny':
|
||||||
|
@ -666,8 +681,7 @@ final class PhabricatorDuoAuthFactor
|
||||||
public function getRequestHasChallengeResponse(
|
public function getRequestHasChallengeResponse(
|
||||||
PhabricatorAuthFactorConfig $config,
|
PhabricatorAuthFactorConfig $config,
|
||||||
AphrontRequest $request) {
|
AphrontRequest $request) {
|
||||||
$value = $this->getChallengeResponseFromRequest($config, $request);
|
return false;
|
||||||
return (bool)strlen($value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newResultFromChallengeResponse(
|
protected function newResultFromChallengeResponse(
|
||||||
|
@ -675,41 +689,7 @@ final class PhabricatorDuoAuthFactor
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
array $challenges) {
|
array $challenges) {
|
||||||
|
return $this->newResult();
|
||||||
$challenge = $this->getChallengeForCurrentContext(
|
|
||||||
$config,
|
|
||||||
$viewer,
|
|
||||||
$challenges);
|
|
||||||
|
|
||||||
$code = $this->getChallengeResponseFromRequest(
|
|
||||||
$config,
|
|
||||||
$request);
|
|
||||||
|
|
||||||
$result = $this->newResult()
|
|
||||||
->setValue($code);
|
|
||||||
|
|
||||||
if ($challenge->getIsAnsweredChallenge()) {
|
|
||||||
return $result->setAnsweredChallenge($challenge);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (phutil_hashes_are_identical($code, $challenge->getChallengeKey())) {
|
|
||||||
$ttl = PhabricatorTime::getNow() + phutil_units('15 minutes in seconds');
|
|
||||||
|
|
||||||
$challenge
|
|
||||||
->markChallengeAsAnswered($ttl);
|
|
||||||
|
|
||||||
return $result->setAnsweredChallenge($challenge);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen($code)) {
|
|
||||||
$error_message = pht('Invalid');
|
|
||||||
} else {
|
|
||||||
$error_message = pht('Required');
|
|
||||||
}
|
|
||||||
|
|
||||||
$result->setErrorMessage($error_message);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function newDuoFuture(PhabricatorAuthFactorProvider $provider) {
|
private function newDuoFuture(PhabricatorAuthFactorProvider $provider) {
|
||||||
|
|
|
@ -128,6 +128,7 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
|
||||||
->setLabel(pht('TOTP Code'))
|
->setLabel(pht('TOTP Code'))
|
||||||
->setName('totpcode')
|
->setName('totpcode')
|
||||||
->setValue($code)
|
->setValue($code)
|
||||||
|
->setAutofocus(true)
|
||||||
->setError($e_code));
|
->setError($e_code));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,26 @@ final class PhabricatorAuthProvidersGuidanceEngineExtension
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateGuidance(PhabricatorGuidanceContext $context) {
|
public function generateGuidance(PhabricatorGuidanceContext $context) {
|
||||||
|
$configs = id(new PhabricatorAuthProviderConfigQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withIsEnabled(true)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$allows_registration = false;
|
||||||
|
foreach ($configs as $config) {
|
||||||
|
$provider = $config->getProvider();
|
||||||
|
if ($provider->shouldAllowRegistration()) {
|
||||||
|
$allows_registration = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no provider allows registration, we don't need provide any warnings
|
||||||
|
// about registration being too open.
|
||||||
|
if (!$allows_registration) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
$domains_key = 'auth.email-domains';
|
$domains_key = 'auth.email-domains';
|
||||||
$domains_link = $this->renderConfigLink($domains_key);
|
$domains_link = $this->renderConfigLink($domains_key);
|
||||||
$domains_value = PhabricatorEnv::getEnvConfig($domains_key);
|
$domains_value = PhabricatorEnv::getEnvConfig($domains_key);
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
abstract class PhabricatorAuthLoginHandler
|
|
||||||
extends Phobject {
|
|
||||||
|
|
||||||
private $request;
|
|
||||||
private $delegatingController;
|
|
||||||
|
|
||||||
public function getAuthLoginHeaderContent() {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
final public function setDelegatingController(AphrontController $controller) {
|
|
||||||
$this->delegatingController = $controller;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
final public function getDelegatingController() {
|
|
||||||
return $this->delegatingController;
|
|
||||||
}
|
|
||||||
|
|
||||||
final public function setRequest(AphrontRequest $request) {
|
|
||||||
$this->request = $request;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
final public function getRequest() {
|
|
||||||
return $this->request;
|
|
||||||
}
|
|
||||||
|
|
||||||
final public static function getAllHandlers() {
|
|
||||||
return id(new PhutilClassMapQuery())
|
|
||||||
->setAncestorClass(__CLASS__)
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -311,6 +311,12 @@ abstract class PhabricatorAuthProvider extends Phobject {
|
||||||
return 'Generic';
|
return 'Generic';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newIconView() {
|
||||||
|
return id(new PHUIIconView())
|
||||||
|
->setSpriteSheet(PHUIIconView::SPRITE_LOGIN)
|
||||||
|
->setSpriteIcon($this->getLoginIcon());
|
||||||
|
}
|
||||||
|
|
||||||
public function isLoginFormAButton() {
|
public function isLoginFormAButton() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@ final class PhabricatorLDAPAuthProvider extends PhabricatorAuthProvider {
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel(pht('LDAP Username'))
|
->setLabel(pht('LDAP Username'))
|
||||||
->setName('ldap_username')
|
->setName('ldap_username')
|
||||||
|
->setAutofocus(true)
|
||||||
->setValue($v_user)
|
->setValue($v_user)
|
||||||
->setError($e_user))
|
->setError($e_user))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
|
|
|
@ -229,6 +229,7 @@ final class PhabricatorPasswordAuthProvider extends PhabricatorAuthProvider {
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel(pht('Username or Email'))
|
->setLabel(pht('Username or Email'))
|
||||||
->setName('username')
|
->setName('username')
|
||||||
|
->setAutofocus(true)
|
||||||
->setValue($v_user)
|
->setValue($v_user)
|
||||||
->setError($e_user))
|
->setError($e_user))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
|
|
|
@ -6,11 +6,7 @@ final class PhabricatorAuthProviderConfigQuery
|
||||||
private $ids;
|
private $ids;
|
||||||
private $phids;
|
private $phids;
|
||||||
private $providerClasses;
|
private $providerClasses;
|
||||||
|
private $isEnabled;
|
||||||
const STATUS_ALL = 'status:all';
|
|
||||||
const STATUS_ENABLED = 'status:enabled';
|
|
||||||
|
|
||||||
private $status = self::STATUS_ALL;
|
|
||||||
|
|
||||||
public function withPHIDs(array $phids) {
|
public function withPHIDs(array $phids) {
|
||||||
$this->phids = $phids;
|
$this->phids = $phids;
|
||||||
|
@ -22,40 +18,26 @@ final class PhabricatorAuthProviderConfigQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withStatus($status) {
|
|
||||||
$this->status = $status;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function withProviderClasses(array $classes) {
|
public function withProviderClasses(array $classes) {
|
||||||
$this->providerClasses = $classes;
|
$this->providerClasses = $classes;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getStatusOptions() {
|
public function withIsEnabled($is_enabled) {
|
||||||
return array(
|
$this->isEnabled = $is_enabled;
|
||||||
self::STATUS_ALL => pht('All Providers'),
|
return $this;
|
||||||
self::STATUS_ENABLED => pht('Enabled Providers'),
|
}
|
||||||
);
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhabricatorAuthProviderConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new PhabricatorAuthProviderConfig();
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
$conn_r = $table->establishConnection('r');
|
|
||||||
|
|
||||||
$data = queryfx_all(
|
|
||||||
$conn_r,
|
|
||||||
'SELECT * FROM %T %Q %Q %Q',
|
|
||||||
$table->getTableName(),
|
|
||||||
$this->buildWhereClause($conn_r),
|
|
||||||
$this->buildOrderClause($conn_r),
|
|
||||||
$this->buildLimitClause($conn_r));
|
|
||||||
|
|
||||||
return $table->loadAllFromArray($data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$where = array();
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
if ($this->ids !== null) {
|
if ($this->ids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
|
@ -78,22 +60,27 @@ final class PhabricatorAuthProviderConfigQuery
|
||||||
$this->providerClasses);
|
$this->providerClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
$status = $this->status;
|
if ($this->isEnabled !== null) {
|
||||||
switch ($status) {
|
$where[] = qsprintf(
|
||||||
case self::STATUS_ALL:
|
$conn,
|
||||||
break;
|
'isEnabled = %d',
|
||||||
case self::STATUS_ENABLED:
|
(int)$this->isEnabled);
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn,
|
|
||||||
'isEnabled = 1');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception(pht("Unknown status '%s'!", $status));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn);
|
return $where;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->formatWhereClause($conn, $where);
|
protected function willFilterPage(array $configs) {
|
||||||
|
|
||||||
|
foreach ($configs as $key => $config) {
|
||||||
|
$provider = $config->getProvider();
|
||||||
|
if (!$provider) {
|
||||||
|
unset($configs[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $configs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryApplicationClass() {
|
public function getQueryApplicationClass() {
|
||||||
|
|
|
@ -168,35 +168,4 @@ final class PhabricatorExternalAccountQuery
|
||||||
return 'PhabricatorPeopleApplication';
|
return 'PhabricatorPeopleApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to find an external account and if none exists creates a new
|
|
||||||
* external account with a shiny new ID and PHID.
|
|
||||||
*
|
|
||||||
* NOTE: This function assumes the first item in various query parameters is
|
|
||||||
* the correct value to use in creating a new external account.
|
|
||||||
*/
|
|
||||||
public function loadOneOrCreate() {
|
|
||||||
$account = $this->executeOne();
|
|
||||||
if (!$account) {
|
|
||||||
$account = new PhabricatorExternalAccount();
|
|
||||||
if ($this->accountIDs) {
|
|
||||||
$account->setAccountID(reset($this->accountIDs));
|
|
||||||
}
|
|
||||||
if ($this->accountTypes) {
|
|
||||||
$account->setAccountType(reset($this->accountTypes));
|
|
||||||
}
|
|
||||||
if ($this->accountDomains) {
|
|
||||||
$account->setAccountDomain(reset($this->accountDomains));
|
|
||||||
}
|
|
||||||
if ($this->accountSecrets) {
|
|
||||||
$account->setAccountSecret(reset($this->accountSecrets));
|
|
||||||
}
|
|
||||||
if ($this->userPHIDs) {
|
|
||||||
$account->setUserPHID(reset($this->userPHIDs));
|
|
||||||
}
|
|
||||||
$account->save();
|
|
||||||
}
|
|
||||||
return $account;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ final class PhabricatorAuthChallenge
|
||||||
protected $properties = array();
|
protected $properties = array();
|
||||||
|
|
||||||
private $responseToken;
|
private $responseToken;
|
||||||
|
private $isNewChallenge;
|
||||||
|
|
||||||
const HTTPKEY = '__hisec.challenges__';
|
const HTTPKEY = '__hisec.challenges__';
|
||||||
const TOKEN_DIGEST_KEY = 'auth.challenge.token';
|
const TOKEN_DIGEST_KEY = 'auth.challenge.token';
|
||||||
|
@ -241,6 +242,15 @@ final class PhabricatorAuthChallenge
|
||||||
return $this->properties[$key];
|
return $this->properties[$key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setIsNewChallenge($is_new_challenge) {
|
||||||
|
$this->isNewChallenge = $is_new_challenge;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsNewChallenge() {
|
||||||
|
return $this->isNewChallenge;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class PhabricatorAuthPasswordTransaction
|
||||||
return PhabricatorAuthPasswordPHIDType::TYPECONST;
|
return PhabricatorAuthPasswordPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'PhabricatorAuthPasswordTransactionType';
|
return 'PhabricatorAuthPasswordTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,27 @@ final class PhabricatorAuthProviderConfig
|
||||||
return $this->provider;
|
return $this->provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
return '/auth/config/view/'.$this->getID().'/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getObjectName() {
|
||||||
|
return pht('Auth Provider %d', $this->getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayName() {
|
||||||
|
return $this->getProvider()->getProviderName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSortVector() {
|
||||||
|
return id(new PhutilSortVector())
|
||||||
|
->addString($this->getDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newIconView() {
|
||||||
|
return $this->getProvider()->newIconView();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,6 @@ final class PhabricatorAuthProviderConfigTransaction
|
||||||
return PhabricatorAuthAuthProviderPHIDType::TYPECONST;
|
return PhabricatorAuthAuthProviderPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getIcon() {
|
public function getIcon() {
|
||||||
$old = $this->getOldValue();
|
$old = $this->getOldValue();
|
||||||
$new = $this->getNewValue();
|
$new = $this->getNewValue();
|
||||||
|
|
|
@ -15,10 +15,6 @@ final class PhabricatorAuthSSHKeyTransaction
|
||||||
return PhabricatorAuthSSHKeyPHIDType::TYPECONST;
|
return PhabricatorAuthSSHKeyPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
$author_phid = $this->getAuthorPHID();
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,24 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
||||||
$issue->addPhabricatorConfig($key);
|
$issue->addPhabricatorConfig($key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (PhabricatorEnv::getEnvConfig('feed.http-hooks')) {
|
||||||
|
$this->newIssue('config.deprecated.feed.http-hooks')
|
||||||
|
->setShortName(pht('Feed Hooks Deprecated'))
|
||||||
|
->setName(pht('Migrate From "feed.http-hooks" to Webhooks'))
|
||||||
|
->addPhabricatorConfig('feed.http-hooks')
|
||||||
|
->setMessage(
|
||||||
|
pht(
|
||||||
|
'The "feed.http-hooks" option is deprecated in favor of '.
|
||||||
|
'Webhooks. This option will be removed in a future version '.
|
||||||
|
'of Phabricator.'.
|
||||||
|
"\n\n".
|
||||||
|
'You can configure Webhooks in Herald.'.
|
||||||
|
"\n\n".
|
||||||
|
'To resolve this issue, remove all URIs from "feed.http-hooks".'));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -182,6 +182,25 @@ EODOC
|
||||||
$mailers_description = $this->deformat(pht(<<<EODOC
|
$mailers_description = $this->deformat(pht(<<<EODOC
|
||||||
Define one or more mail transmission services. For help with configuring
|
Define one or more mail transmission services. For help with configuring
|
||||||
mailers, see **[[ %s | %s ]]** in the documentation.
|
mailers, see **[[ %s | %s ]]** in the documentation.
|
||||||
|
EODOC
|
||||||
|
,
|
||||||
|
PhabricatorEnv::getDoclink('Configuring Outbound Email'),
|
||||||
|
pht('Configuring Outbound Email')));
|
||||||
|
|
||||||
|
$default_description = $this->deformat(pht(<<<EODOC
|
||||||
|
Default address used as a "From" or "To" email address when an address is
|
||||||
|
required but no meaningful address is available.
|
||||||
|
|
||||||
|
If you configure inbound mail, you generally do not need to set this:
|
||||||
|
Phabricator will automatically generate and use a suitable mailbox on the
|
||||||
|
inbound mail domain.
|
||||||
|
|
||||||
|
Otherwise, this option should be configured to point at a valid mailbox which
|
||||||
|
discards all mail sent to it. If you point it at an invalid mailbox, mail sent
|
||||||
|
by Phabricator and some mail sent by users will bounce. If you point it at a
|
||||||
|
real user mailbox, that user will get a lot of mail they don't want.
|
||||||
|
|
||||||
|
For further guidance, see **[[ %s | %s ]]** in the documentation.
|
||||||
EODOC
|
EODOC
|
||||||
,
|
,
|
||||||
PhabricatorEnv::getDoclink('Configuring Outbound Email'),
|
PhabricatorEnv::getDoclink('Configuring Outbound Email'),
|
||||||
|
@ -192,7 +211,9 @@ EODOC
|
||||||
->setHidden(true)
|
->setHidden(true)
|
||||||
->setDescription($mailers_description),
|
->setDescription($mailers_description),
|
||||||
$this->newOption('metamta.default-address', 'string', null)
|
$this->newOption('metamta.default-address', 'string', null)
|
||||||
->setDescription(pht('Default "From" address.')),
|
->setLocked(true)
|
||||||
|
->setSummary(pht('Default address used when generating mail.'))
|
||||||
|
->setDescription($default_description),
|
||||||
$this->newOption(
|
$this->newOption(
|
||||||
'metamta.one-mail-per-recipient',
|
'metamta.one-mail-per-recipient',
|
||||||
'bool',
|
'bool',
|
||||||
|
|
|
@ -13,10 +13,6 @@ final class PhabricatorConfigTransaction
|
||||||
return PhabricatorConfigConfigPHIDType::TYPECONST;
|
return PhabricatorConfigConfigPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
$author_phid = $this->getAuthorPHID();
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ final class DifferentialDiffCreateController extends DifferentialController {
|
||||||
$arcanist_link,
|
$arcanist_link,
|
||||||
),
|
),
|
||||||
pht(
|
pht(
|
||||||
'You can also paste a diff below, or upload a file '.
|
'You can also paste a diff above, or upload a file '.
|
||||||
'containing a diff (for example, from %s, %s or %s).',
|
'containing a diff (for example, from %s, %s or %s).',
|
||||||
phutil_tag('tt', array(), 'svn diff'),
|
phutil_tag('tt', array(), 'svn diff'),
|
||||||
phutil_tag('tt', array(), 'git diff'),
|
phutil_tag('tt', array(), 'git diff'),
|
||||||
|
|
|
@ -566,11 +566,8 @@ final class DiffusionBrowseController extends DiffusionController {
|
||||||
$name = idx($spec, 'name', $auto);
|
$name = idx($spec, 'name', $auto);
|
||||||
$item->addIcon('fa-code', $name);
|
$item->addIcon('fa-code', $name);
|
||||||
|
|
||||||
if ($package->getAuditingEnabled()) {
|
$rule = $package->newAuditingRule();
|
||||||
$item->addIcon('fa-check', pht('Auditing Enabled'));
|
$item->addIcon($rule->getIconIcon(), $rule->getDisplayName());
|
||||||
} else {
|
|
||||||
$item->addIcon('fa-ban', pht('No Auditing'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($package->isArchived()) {
|
if ($package->isArchived()) {
|
||||||
$item->setDisabled(true);
|
$item->setDisabled(true);
|
||||||
|
|
|
@ -202,6 +202,7 @@ final class DiffusionCommitQuery
|
||||||
$table = $this->newResultObject();
|
$table = $this->newResultObject();
|
||||||
$conn = $table->establishConnection('r');
|
$conn = $table->establishConnection('r');
|
||||||
|
|
||||||
|
$empty_exception = null;
|
||||||
$subqueries = array();
|
$subqueries = array();
|
||||||
if ($this->responsiblePHIDs) {
|
if ($this->responsiblePHIDs) {
|
||||||
$base_authors = $this->authorPHIDs;
|
$base_authors = $this->authorPHIDs;
|
||||||
|
@ -222,21 +223,33 @@ final class DiffusionCommitQuery
|
||||||
|
|
||||||
$this->authorPHIDs = $all_authors;
|
$this->authorPHIDs = $all_authors;
|
||||||
$this->auditorPHIDs = $base_auditors;
|
$this->auditorPHIDs = $base_auditors;
|
||||||
$subqueries[] = $this->buildStandardPageQuery(
|
try {
|
||||||
$conn,
|
$subqueries[] = $this->buildStandardPageQuery(
|
||||||
$table->getTableName());
|
$conn,
|
||||||
|
$table->getTableName());
|
||||||
|
} catch (PhabricatorEmptyQueryException $ex) {
|
||||||
|
$empty_exception = $ex;
|
||||||
|
}
|
||||||
|
|
||||||
$this->authorPHIDs = $base_authors;
|
$this->authorPHIDs = $base_authors;
|
||||||
$this->auditorPHIDs = $all_auditors;
|
$this->auditorPHIDs = $all_auditors;
|
||||||
$subqueries[] = $this->buildStandardPageQuery(
|
try {
|
||||||
$conn,
|
$subqueries[] = $this->buildStandardPageQuery(
|
||||||
$table->getTableName());
|
$conn,
|
||||||
|
$table->getTableName());
|
||||||
|
} catch (PhabricatorEmptyQueryException $ex) {
|
||||||
|
$empty_exception = $ex;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$subqueries[] = $this->buildStandardPageQuery(
|
$subqueries[] = $this->buildStandardPageQuery(
|
||||||
$conn,
|
$conn,
|
||||||
$table->getTableName());
|
$table->getTableName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$subqueries) {
|
||||||
|
throw $empty_exception;
|
||||||
|
}
|
||||||
|
|
||||||
if (count($subqueries) > 1) {
|
if (count($subqueries) > 1) {
|
||||||
$unions = null;
|
$unions = null;
|
||||||
foreach ($subqueries as $subquery) {
|
foreach ($subqueries as $subquery) {
|
||||||
|
@ -642,10 +655,19 @@ final class DiffusionCommitQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->authorPHIDs !== null) {
|
if ($this->authorPHIDs !== null) {
|
||||||
|
$author_phids = $this->authorPHIDs;
|
||||||
|
if ($author_phids) {
|
||||||
|
$author_phids = $this->selectPossibleAuthors($author_phids);
|
||||||
|
if (!$author_phids) {
|
||||||
|
throw new PhabricatorEmptyQueryException(
|
||||||
|
pht('Author PHIDs contain no possible authors.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn,
|
$conn,
|
||||||
'commit.authorPHID IN (%Ls)',
|
'commit.authorPHID IN (%Ls)',
|
||||||
$this->authorPHIDs);
|
$author_phids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->epochMin !== null) {
|
if ($this->epochMin !== null) {
|
||||||
|
@ -934,5 +956,20 @@ final class DiffusionCommitQuery
|
||||||
) + $parent;
|
) + $parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function selectPossibleAuthors(array $phids) {
|
||||||
|
// See PHI1057. Select PHIDs which might possibly be commit authors from
|
||||||
|
// a larger list of PHIDs. This primarily filters out packages and projects
|
||||||
|
// from "Responsible Users: ..." queries. Our goal in performing this
|
||||||
|
// filtering is to improve the performance of the final query.
|
||||||
|
|
||||||
|
foreach ($phids as $key => $phid) {
|
||||||
|
if (phid_get_type($phid) !== PhabricatorPeopleUserPHIDType::TYPECONST) {
|
||||||
|
unset($phids[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $phids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,4 @@ final class DivinerLiveBookTransaction
|
||||||
return DivinerBookPHIDType::TYPECONST;
|
return DivinerBookPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,22 +20,22 @@ final class PhabricatorFeedConfigOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOptions() {
|
public function getOptions() {
|
||||||
|
$hooks_help = $this->deformat(pht(<<<EODOC
|
||||||
|
IMPORTANT: Feed hooks are deprecated and have been replaced by Webhooks.
|
||||||
|
|
||||||
|
You can configure Webhooks in Herald. This configuration option will be removed
|
||||||
|
in a future version of Phabricator.
|
||||||
|
|
||||||
|
(This legacy option may be configured with a list of URIs; feed stories will
|
||||||
|
send to these URIs.)
|
||||||
|
EODOC
|
||||||
|
));
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
$this->newOption('feed.http-hooks', 'list<string>', array())
|
$this->newOption('feed.http-hooks', 'list<string>', array())
|
||||||
->setLocked(true)
|
->setLocked(true)
|
||||||
->setSummary(pht('POST notifications of feed events.'))
|
->setSummary(pht('Deprecated.'))
|
||||||
->setDescription(
|
->setDescription($hooks_help),
|
||||||
pht(
|
|
||||||
"If you set this to a list of HTTP URIs, when a feed story is ".
|
|
||||||
"published a task will be created for each URI that posts the ".
|
|
||||||
"story data to the URI. Daemons automagically retry failures 100 ".
|
|
||||||
"times, waiting `\$fail_count * 60s` between each subsequent ".
|
|
||||||
"failure. Be sure to keep the daemon console (`%s`) open ".
|
|
||||||
"while developing and testing your end points. You may need to".
|
|
||||||
"restart your daemons to start sending HTTP requests.\n\n".
|
|
||||||
"NOTE: URIs are not validated, the URI must return HTTP status ".
|
|
||||||
"200 within 30 seconds, and no permission checks are performed.",
|
|
||||||
'/daemon/')),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,11 @@ final class FeedPublisherHTTPWorker extends FeedPushWorker {
|
||||||
'epoch' => $data->getEpoch(),
|
'epoch' => $data->getEpoch(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// NOTE: We're explicitly using "http_build_query()" here because the
|
||||||
|
// "storyData" parameter may be a nested object with arbitrary nested
|
||||||
|
// sub-objects.
|
||||||
|
$post_data = http_build_query($post_data, '', '&');
|
||||||
|
|
||||||
id(new HTTPSFuture($uri, $post_data))
|
id(new HTTPSFuture($uri, $post_data))
|
||||||
->setMethod('POST')
|
->setMethod('POST')
|
||||||
->setTimeout(30)
|
->setTimeout(30)
|
||||||
|
|
|
@ -76,6 +76,7 @@ final class FundBacker extends FundDAO
|
||||||
public function getCapabilities() {
|
public function getCapabilities() {
|
||||||
return array(
|
return array(
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +92,8 @@ final class FundBacker extends FundDAO
|
||||||
return $initiative->getPolicy($capability);
|
return $initiative->getPolicy($capability);
|
||||||
}
|
}
|
||||||
return PhabricatorPolicies::POLICY_NOONE;
|
return PhabricatorPolicies::POLICY_NOONE;
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
return PhabricatorPolicies::POLICY_NOONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class FundBackerTransaction
|
||||||
return FundBackerPHIDType::TYPECONST;
|
return FundBackerPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'FundBackerTransactionType';
|
return 'FundBackerTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,9 @@ final class HeraldCommentAction extends HeraldAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
$xaction = $object->getApplicationTransactionTemplate();
|
$xaction = $object->getApplicationTransactionTemplate();
|
||||||
try {
|
|
||||||
$comment = $xaction->getApplicationTransactionCommentObject();
|
$comment = $xaction->getApplicationTransactionCommentObject();
|
||||||
if (!$comment) {
|
if (!$comment) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (PhutilMethodNotImplementedException $ex) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class HeraldWebhookTransaction
|
||||||
return HeraldWebhookPHIDType::TYPECONST;
|
return HeraldWebhookPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'HeraldWebhookTransactionType';
|
return 'HeraldWebhookTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -364,16 +364,6 @@ final class LegalpadDocumentSignController extends LegalpadController {
|
||||||
if ($email_obj) {
|
if ($email_obj) {
|
||||||
return $this->signInResponse();
|
return $this->signInResponse();
|
||||||
}
|
}
|
||||||
$external_account = id(new PhabricatorExternalAccountQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withAccountTypes(array('email'))
|
|
||||||
->withAccountDomains(array($email->getDomainName()))
|
|
||||||
->withAccountIDs(array($email->getAddress()))
|
|
||||||
->loadOneOrCreate();
|
|
||||||
if ($external_account->getUserPHID()) {
|
|
||||||
return $this->signInResponse();
|
|
||||||
}
|
|
||||||
$signer_phid = $external_account->getPHID();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -226,7 +226,7 @@ final class LegalpadDocumentSignatureSearchEngine
|
||||||
$handles[$document->getPHID()]->renderLink(),
|
$handles[$document->getPHID()]->renderLink(),
|
||||||
$signer_phid
|
$signer_phid
|
||||||
? $handles[$signer_phid]->renderLink()
|
? $handles[$signer_phid]->renderLink()
|
||||||
: null,
|
: phutil_tag('em', array(), pht('None')),
|
||||||
$name,
|
$name,
|
||||||
phutil_tag(
|
phutil_tag(
|
||||||
'a',
|
'a',
|
||||||
|
|
|
@ -27,4 +27,8 @@ final class PhabricatorMetaMTAMailListController
|
||||||
return $nav;
|
return $nav;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function buildApplicationMenu() {
|
||||||
|
return $this->buildSideNav()->getMenu();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,4 @@ final class PhabricatorMetaMTAApplicationEmailTransaction
|
||||||
return PhabricatorMetaMTAApplicationEmailPHIDType::TYPECONST;
|
return PhabricatorMetaMTAApplicationEmailPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,6 @@ final class PhabricatorOAuthServerTransaction
|
||||||
return PhabricatorOAuthServerClientPHIDType::TYPECONST;
|
return PhabricatorOAuthServerClientPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
$author_phid = $this->getAuthorPHID();
|
$author_phid = $this->getAuthorPHID();
|
||||||
$old = $this->getOldValue();
|
$old = $this->getOldValue();
|
||||||
|
|
117
src/applications/owners/constants/PhabricatorOwnersAuditRule.php
Normal file
117
src/applications/owners/constants/PhabricatorOwnersAuditRule.php
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorOwnersAuditRule
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
const AUDITING_NONE = 'none';
|
||||||
|
const AUDITING_NO_OWNER = 'audit';
|
||||||
|
const AUDITING_UNREVIEWED = 'unreviewed';
|
||||||
|
const AUDITING_NO_OWNER_AND_UNREVIEWED = 'uninvolved-unreviewed';
|
||||||
|
const AUDITING_ALL = 'all';
|
||||||
|
|
||||||
|
private $key;
|
||||||
|
private $spec;
|
||||||
|
|
||||||
|
public static function newFromState($key) {
|
||||||
|
$specs = self::newSpecifications();
|
||||||
|
$spec = idx($specs, $key, array());
|
||||||
|
|
||||||
|
$rule = new self();
|
||||||
|
$rule->key = $key;
|
||||||
|
$rule->spec = $spec;
|
||||||
|
|
||||||
|
return $rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKey() {
|
||||||
|
return $this->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayName() {
|
||||||
|
return idx($this->spec, 'name', $this->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIconIcon() {
|
||||||
|
return idx($this->spec, 'icon.icon');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function newSelectControlMap() {
|
||||||
|
$specs = self::newSpecifications();
|
||||||
|
return ipull($specs, 'name');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getStorageValueFromAPIValue($value) {
|
||||||
|
$specs = self::newSpecifications();
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($specs as $key => $spec) {
|
||||||
|
$deprecated = idx($spec, 'deprecated', array());
|
||||||
|
if (isset($deprecated[$value])) {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getModernValueMap() {
|
||||||
|
$specs = self::newSpecifications();
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($specs as $key => $spec) {
|
||||||
|
$map[$key] = pht('"%s"', $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDeprecatedValueMap() {
|
||||||
|
$specs = self::newSpecifications();
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($specs as $key => $spec) {
|
||||||
|
$deprecated_map = idx($spec, 'deprecated', array());
|
||||||
|
foreach ($deprecated_map as $deprecated_key => $label) {
|
||||||
|
$map[$deprecated_key] = $label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function newSpecifications() {
|
||||||
|
return array(
|
||||||
|
self::AUDITING_NONE => array(
|
||||||
|
'name' => pht('No Auditing'),
|
||||||
|
'icon.icon' => 'fa-ban',
|
||||||
|
'deprecated' => array(
|
||||||
|
'' => pht('"" (empty string)'),
|
||||||
|
'0' => '"0"',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
self::AUDITING_UNREVIEWED => array(
|
||||||
|
'name' => pht('Audit Unreviewed Commits'),
|
||||||
|
'icon.icon' => 'fa-check',
|
||||||
|
),
|
||||||
|
self::AUDITING_NO_OWNER => array(
|
||||||
|
'name' => pht('Audit Commits With No Owner Involvement'),
|
||||||
|
'icon.icon' => 'fa-check',
|
||||||
|
'deprecated' => array(
|
||||||
|
'1' => '"1"',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
self::AUDITING_NO_OWNER_AND_UNREVIEWED => array(
|
||||||
|
'name' => pht(
|
||||||
|
'Audit Unreviewed Commits and Commits With No Owner Involvement'),
|
||||||
|
'icon.icon' => 'fa-check',
|
||||||
|
),
|
||||||
|
self::AUDITING_ALL => array(
|
||||||
|
'name' => pht('Audit All Commits'),
|
||||||
|
'icon.icon' => 'fa-check',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -194,12 +194,8 @@ final class PhabricatorOwnersDetailController
|
||||||
$name = idx($spec, 'name', $auto);
|
$name = idx($spec, 'name', $auto);
|
||||||
$view->addProperty(pht('Auto Review'), $name);
|
$view->addProperty(pht('Auto Review'), $name);
|
||||||
|
|
||||||
if ($package->getAuditingEnabled()) {
|
$rule = $package->newAuditingRule();
|
||||||
$auditing = pht('Enabled');
|
$view->addProperty(pht('Auditing'), $rule->getDisplayName());
|
||||||
} else {
|
|
||||||
$auditing = pht('Disabled');
|
|
||||||
}
|
|
||||||
$view->addProperty(pht('Auditing'), $auditing);
|
|
||||||
|
|
||||||
$ignored = $package->getIgnoredPathAttributes();
|
$ignored = $package->getIgnoredPathAttributes();
|
||||||
$ignored = array_keys($ignored);
|
$ignored = array_keys($ignored);
|
||||||
|
|
|
@ -140,12 +140,8 @@ EOTEXT
|
||||||
->setTransactionType(
|
->setTransactionType(
|
||||||
PhabricatorOwnersPackageAuditingTransaction::TRANSACTIONTYPE)
|
PhabricatorOwnersPackageAuditingTransaction::TRANSACTIONTYPE)
|
||||||
->setIsCopyable(true)
|
->setIsCopyable(true)
|
||||||
->setValue($object->getAuditingEnabled())
|
->setValue($object->getAuditingState())
|
||||||
->setOptions(
|
->setOptions(PhabricatorOwnersAuditRule::newSelectControlMap()),
|
||||||
array(
|
|
||||||
'' => pht('Disabled'),
|
|
||||||
'1' => pht('Enabled'),
|
|
||||||
)),
|
|
||||||
id(new PhabricatorRemarkupEditField())
|
id(new PhabricatorRemarkupEditField())
|
||||||
->setKey('description')
|
->setKey('description')
|
||||||
->setLabel(pht('Description'))
|
->setLabel(pht('Description'))
|
||||||
|
|
|
@ -13,7 +13,6 @@ final class PhabricatorOwnersPackage
|
||||||
PhabricatorNgramsInterface {
|
PhabricatorNgramsInterface {
|
||||||
|
|
||||||
protected $name;
|
protected $name;
|
||||||
protected $auditingEnabled;
|
|
||||||
protected $autoReview;
|
protected $autoReview;
|
||||||
protected $description;
|
protected $description;
|
||||||
protected $status;
|
protected $status;
|
||||||
|
@ -21,6 +20,7 @@ final class PhabricatorOwnersPackage
|
||||||
protected $editPolicy;
|
protected $editPolicy;
|
||||||
protected $dominion;
|
protected $dominion;
|
||||||
protected $properties = array();
|
protected $properties = array();
|
||||||
|
protected $auditingState;
|
||||||
|
|
||||||
private $paths = self::ATTACHABLE;
|
private $paths = self::ATTACHABLE;
|
||||||
private $owners = self::ATTACHABLE;
|
private $owners = self::ATTACHABLE;
|
||||||
|
@ -55,7 +55,7 @@ final class PhabricatorOwnersPackage
|
||||||
PhabricatorOwnersDefaultEditCapability::CAPABILITY);
|
PhabricatorOwnersDefaultEditCapability::CAPABILITY);
|
||||||
|
|
||||||
return id(new PhabricatorOwnersPackage())
|
return id(new PhabricatorOwnersPackage())
|
||||||
->setAuditingEnabled(0)
|
->setAuditingState(PhabricatorOwnersAuditRule::AUDITING_NONE)
|
||||||
->setAutoReview(self::AUTOREVIEW_NONE)
|
->setAutoReview(self::AUTOREVIEW_NONE)
|
||||||
->setDominion(self::DOMINION_STRONG)
|
->setDominion(self::DOMINION_STRONG)
|
||||||
->setViewPolicy($view_policy)
|
->setViewPolicy($view_policy)
|
||||||
|
@ -126,7 +126,7 @@ final class PhabricatorOwnersPackage
|
||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'name' => 'sort',
|
'name' => 'sort',
|
||||||
'description' => 'text',
|
'description' => 'text',
|
||||||
'auditingEnabled' => 'bool',
|
'auditingState' => 'text32',
|
||||||
'status' => 'text32',
|
'status' => 'text32',
|
||||||
'autoReview' => 'text32',
|
'autoReview' => 'text32',
|
||||||
'dominion' => 'text32',
|
'dominion' => 'text32',
|
||||||
|
@ -564,6 +564,10 @@ final class PhabricatorOwnersPackage
|
||||||
return '/owners/package/'.$this->getID().'/';
|
return '/owners/package/'.$this->getID().'/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newAuditingRule() {
|
||||||
|
return PhabricatorOwnersAuditRule::newFromState($this->getAuditingState());
|
||||||
|
}
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
@ -720,17 +724,11 @@ final class PhabricatorOwnersPackage
|
||||||
'label' => $review_label,
|
'label' => $review_label,
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($this->getAuditingEnabled()) {
|
$audit_rule = $this->newAuditingRule();
|
||||||
$audit_value = 'audit';
|
|
||||||
$audit_label = pht('Auditing Enabled');
|
|
||||||
} else {
|
|
||||||
$audit_value = 'none';
|
|
||||||
$audit_label = pht('No Auditing');
|
|
||||||
}
|
|
||||||
|
|
||||||
$audit = array(
|
$audit = array(
|
||||||
'value' => $audit_value,
|
'value' => $audit_rule->getKey(),
|
||||||
'label' => $audit_label,
|
'label' => $audit_rule->getDisplayName(),
|
||||||
);
|
);
|
||||||
|
|
||||||
$dominion_value = $this->getDominion();
|
$dominion_value = $this->getDominion();
|
||||||
|
|
|
@ -15,8 +15,4 @@ final class PhabricatorOwnersPackageTransaction
|
||||||
return 'PhabricatorOwnersPackageTransactionType';
|
return 'PhabricatorOwnersPackageTransactionType';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,27 +6,62 @@ final class PhabricatorOwnersPackageAuditingTransaction
|
||||||
const TRANSACTIONTYPE = 'owners.auditing';
|
const TRANSACTIONTYPE = 'owners.auditing';
|
||||||
|
|
||||||
public function generateOldValue($object) {
|
public function generateOldValue($object) {
|
||||||
return (int)$object->getAuditingEnabled();
|
return $object->getAuditingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateNewValue($object, $value) {
|
public function generateNewValue($object, $value) {
|
||||||
return (int)$value;
|
return PhabricatorOwnersAuditRule::getStorageValueFromAPIValue($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyInternalEffects($object, $value) {
|
public function applyInternalEffects($object, $value) {
|
||||||
$object->setAuditingEnabled($value);
|
$object->setAuditingState($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
if ($this->getNewValue()) {
|
$old_value = $this->getOldValue();
|
||||||
return pht(
|
$new_value = $this->getNewValue();
|
||||||
'%s enabled auditing for this package.',
|
|
||||||
$this->renderAuthor());
|
$old_rule = PhabricatorOwnersAuditRule::newFromState($old_value);
|
||||||
} else {
|
$new_rule = PhabricatorOwnersAuditRule::newFromState($new_value);
|
||||||
return pht(
|
|
||||||
'%s disabled auditing for this package.',
|
return pht(
|
||||||
$this->renderAuthor());
|
'%s changed the audit rule for this package from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderValue($old_rule->getDisplayName()),
|
||||||
|
$this->renderValue($new_rule->getDisplayName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
// See PHI1047. This transaction type accepted some weird stuff. Continue
|
||||||
|
// supporting it for now, but move toward sensible consistency.
|
||||||
|
|
||||||
|
$modern_options = PhabricatorOwnersAuditRule::getModernValueMap();
|
||||||
|
$deprecated_options = PhabricatorOwnersAuditRule::getDeprecatedValueMap();
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$new_value = $xaction->getNewValue();
|
||||||
|
|
||||||
|
if (isset($modern_options[$new_value])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($deprecated_options[$new_value])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Package auditing value "%s" is not supported. Supported options '.
|
||||||
|
'are: %s. Deprecated options are: %s.',
|
||||||
|
$new_value,
|
||||||
|
implode(', ', $modern_options),
|
||||||
|
implode(', ', $deprecated_options)),
|
||||||
|
$xaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class PassphraseCredentialTransaction
|
||||||
return PassphraseCredentialPHIDType::TYPECONST;
|
return PassphraseCredentialPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'PassphraseCredentialTransactionType';
|
return 'PassphraseCredentialTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,8 @@ final class PhabricatorPeopleApplication extends PhabricatorApplication {
|
||||||
'send/'
|
'send/'
|
||||||
=> 'PhabricatorPeopleInviteSendController',
|
=> 'PhabricatorPeopleInviteSendController',
|
||||||
),
|
),
|
||||||
'approve/(?P<id>[1-9]\d*)/' => 'PhabricatorPeopleApproveController',
|
'approve/(?P<id>[1-9]\d*)/(?:via/(?P<via>[^/]+)/)?'
|
||||||
|
=> 'PhabricatorPeopleApproveController',
|
||||||
'(?P<via>disapprove)/(?P<id>[1-9]\d*)/'
|
'(?P<via>disapprove)/(?P<id>[1-9]\d*)/'
|
||||||
=> 'PhabricatorPeopleDisableController',
|
=> 'PhabricatorPeopleDisableController',
|
||||||
'(?P<via>disable)/(?P<id>[1-9]\d*)/'
|
'(?P<via>disable)/(?P<id>[1-9]\d*)/'
|
||||||
|
|
|
@ -14,7 +14,15 @@ final class PhabricatorPeopleApproveController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
$done_uri = $this->getApplicationURI('query/approval/');
|
$via = $request->getURIData('via');
|
||||||
|
switch ($via) {
|
||||||
|
case 'profile':
|
||||||
|
$done_uri = urisprintf('/people/manage/%d/', $user->getID());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$done_uri = $this->getApplicationURI('query/approval/');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ($user->getIsApproved()) {
|
if ($user->getIsApproved()) {
|
||||||
return $this->newDialog()
|
return $this->newDialog()
|
||||||
|
|
|
@ -70,40 +70,53 @@ abstract class PhabricatorPeopleProfileController
|
||||||
$profile_icon = PhabricatorPeopleIconSet::getIconIcon($profile->getIcon());
|
$profile_icon = PhabricatorPeopleIconSet::getIconIcon($profile->getIcon());
|
||||||
$profile_title = $profile->getDisplayTitle();
|
$profile_title = $profile->getDisplayTitle();
|
||||||
|
|
||||||
$roles = array();
|
|
||||||
|
$tag = id(new PHUITagView())
|
||||||
|
->setType(PHUITagView::TYPE_SHADE);
|
||||||
|
|
||||||
|
$tags = array();
|
||||||
if ($user->getIsAdmin()) {
|
if ($user->getIsAdmin()) {
|
||||||
$roles[] = pht('Administrator');
|
$tags[] = id(clone $tag)
|
||||||
}
|
->setName(pht('Administrator'))
|
||||||
if ($user->getIsDisabled()) {
|
->setColor('blue');
|
||||||
$roles[] = pht('Disabled');
|
|
||||||
}
|
|
||||||
if (!$user->getIsApproved()) {
|
|
||||||
$roles[] = pht('Not Approved');
|
|
||||||
}
|
|
||||||
if ($user->getIsSystemAgent()) {
|
|
||||||
$roles[] = pht('Bot');
|
|
||||||
}
|
|
||||||
if ($user->getIsMailingList()) {
|
|
||||||
$roles[] = pht('Mailing List');
|
|
||||||
}
|
|
||||||
if (!$user->getIsEmailVerified()) {
|
|
||||||
$roles[] = pht('Email Not Verified');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$tag = null;
|
// "Disabled" gets a stronger status tag below.
|
||||||
if ($roles) {
|
|
||||||
$tag = id(new PHUITagView())
|
if (!$user->getIsApproved()) {
|
||||||
->setName(implode(', ', $roles))
|
$tags[] = id(clone $tag)
|
||||||
->addClass('project-view-header-tag')
|
->setName('Not Approved')
|
||||||
->setType(PHUITagView::TYPE_SHADE);
|
->setColor('yellow');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->getIsSystemAgent()) {
|
||||||
|
$tags[] = id(clone $tag)
|
||||||
|
->setName(pht('Bot'))
|
||||||
|
->setColor('orange');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->getIsMailingList()) {
|
||||||
|
$tags[] = id(clone $tag)
|
||||||
|
->setName(pht('Mailing List'))
|
||||||
|
->setColor('orange');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$user->getIsEmailVerified()) {
|
||||||
|
$tags[] = id(clone $tag)
|
||||||
|
->setName(pht('Email Not Verified'))
|
||||||
|
->setColor('violet');
|
||||||
}
|
}
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader(array($user->getFullName(), $tag))
|
->setHeader($user->getFullName())
|
||||||
->setImage($picture)
|
->setImage($picture)
|
||||||
->setProfileHeader(true)
|
->setProfileHeader(true)
|
||||||
->addClass('people-profile-header');
|
->addClass('people-profile-header');
|
||||||
|
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
$header->addTag($tag);
|
||||||
|
}
|
||||||
|
|
||||||
require_celerity_resource('project-view-css');
|
require_celerity_resource('project-view-css');
|
||||||
|
|
||||||
if ($user->getIsDisabled()) {
|
if ($user->getIsDisabled()) {
|
||||||
|
|
|
@ -92,6 +92,8 @@ final class PhabricatorPeopleProfileManageController
|
||||||
PeopleDisableUsersCapability::CAPABILITY);
|
PeopleDisableUsersCapability::CAPABILITY);
|
||||||
$can_disable = ($has_disable && !$is_self);
|
$can_disable = ($has_disable && !$is_self);
|
||||||
|
|
||||||
|
$id = $user->getID();
|
||||||
|
|
||||||
$welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine())
|
$welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine())
|
||||||
->setSender($viewer)
|
->setSender($viewer)
|
||||||
->setRecipient($user);
|
->setRecipient($user);
|
||||||
|
@ -103,7 +105,7 @@ final class PhabricatorPeopleProfileManageController
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setIcon('fa-pencil')
|
->setIcon('fa-pencil')
|
||||||
->setName(pht('Edit Profile'))
|
->setName(pht('Edit Profile'))
|
||||||
->setHref($this->getApplicationURI('editprofile/'.$user->getID().'/'))
|
->setHref($this->getApplicationURI('editprofile/'.$id.'/'))
|
||||||
->setDisabled(!$can_edit)
|
->setDisabled(!$can_edit)
|
||||||
->setWorkflow(!$can_edit));
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
|
@ -111,7 +113,7 @@ final class PhabricatorPeopleProfileManageController
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setIcon('fa-picture-o')
|
->setIcon('fa-picture-o')
|
||||||
->setName(pht('Edit Profile Picture'))
|
->setName(pht('Edit Profile Picture'))
|
||||||
->setHref($this->getApplicationURI('picture/'.$user->getID().'/'))
|
->setHref($this->getApplicationURI('picture/'.$id.'/'))
|
||||||
->setDisabled(!$can_edit)
|
->setDisabled(!$can_edit)
|
||||||
->setWorkflow(!$can_edit));
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
|
@ -137,7 +139,7 @@ final class PhabricatorPeopleProfileManageController
|
||||||
->setName($empower_name)
|
->setName($empower_name)
|
||||||
->setDisabled(!$can_admin)
|
->setDisabled(!$can_admin)
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setHref($this->getApplicationURI('empower/'.$user->getID().'/')));
|
->setHref($this->getApplicationURI('empower/'.$id.'/')));
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
|
@ -145,7 +147,7 @@ final class PhabricatorPeopleProfileManageController
|
||||||
->setName(pht('Change Username'))
|
->setName(pht('Change Username'))
|
||||||
->setDisabled(!$is_admin)
|
->setDisabled(!$is_admin)
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setHref($this->getApplicationURI('rename/'.$user->getID().'/')));
|
->setHref($this->getApplicationURI('rename/'.$id.'/')));
|
||||||
|
|
||||||
if ($user->getIsDisabled()) {
|
if ($user->getIsDisabled()) {
|
||||||
$disable_icon = 'fa-check-circle-o';
|
$disable_icon = 'fa-check-circle-o';
|
||||||
|
@ -161,19 +163,34 @@ final class PhabricatorPeopleProfileManageController
|
||||||
->setName(pht('Send Welcome Email'))
|
->setName(pht('Send Welcome Email'))
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setDisabled(!$can_welcome)
|
->setDisabled(!$can_welcome)
|
||||||
->setHref($this->getApplicationURI('welcome/'.$user->getID().'/')));
|
->setHref($this->getApplicationURI('welcome/'.$id.'/')));
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setType(PhabricatorActionView::TYPE_DIVIDER));
|
->setType(PhabricatorActionView::TYPE_DIVIDER));
|
||||||
|
|
||||||
|
if (!$user->getIsApproved()) {
|
||||||
|
$approve_action = id(new PhabricatorActionView())
|
||||||
|
->setIcon('fa-thumbs-up')
|
||||||
|
->setName(pht('Approve User'))
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setDisabled(!$is_admin)
|
||||||
|
->setHref("/people/approve/{$id}/via/profile/");
|
||||||
|
|
||||||
|
if ($is_admin) {
|
||||||
|
$approve_action->setColor(PhabricatorActionView::GREEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
$curtain->addAction($approve_action);
|
||||||
|
}
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setIcon($disable_icon)
|
->setIcon($disable_icon)
|
||||||
->setName($disable_name)
|
->setName($disable_name)
|
||||||
->setDisabled(!$can_disable)
|
->setDisabled(!$can_disable)
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setHref($this->getApplicationURI('disable/'.$user->getID().'/')));
|
->setHref($this->getApplicationURI('disable/'.$id.'/')));
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
|
@ -181,7 +198,7 @@ final class PhabricatorPeopleProfileManageController
|
||||||
->setName(pht('Delete User'))
|
->setName(pht('Delete User'))
|
||||||
->setDisabled(!$can_admin)
|
->setDisabled(!$can_admin)
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setHref($this->getApplicationURI('delete/'.$user->getID().'/')));
|
->setHref($this->getApplicationURI('delete/'.$id.'/')));
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPeopleUsernameMailEngine
|
||||||
|
extends PhabricatorPeopleMailEngine {
|
||||||
|
|
||||||
|
private $oldUsername;
|
||||||
|
private $newUsername;
|
||||||
|
|
||||||
|
public function setNewUsername($new_username) {
|
||||||
|
$this->newUsername = $new_username;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNewUsername() {
|
||||||
|
return $this->newUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOldUsername($old_username) {
|
||||||
|
$this->oldUsername = $old_username;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOldUsername() {
|
||||||
|
return $this->oldUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateMail() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newMail() {
|
||||||
|
$sender = $this->getSender();
|
||||||
|
$recipient = $this->getRecipient();
|
||||||
|
|
||||||
|
$sender_username = $sender->getUsername();
|
||||||
|
$sender_realname = $sender->getRealName();
|
||||||
|
|
||||||
|
$old_username = $this->getOldUsername();
|
||||||
|
$new_username = $this->getNewUsername();
|
||||||
|
|
||||||
|
$body = sprintf(
|
||||||
|
"%s\n\n %s\n %s\n",
|
||||||
|
pht(
|
||||||
|
'%s (%s) has changed your Phabricator username.',
|
||||||
|
$sender_username,
|
||||||
|
$sender_realname),
|
||||||
|
pht(
|
||||||
|
'Old Username: %s',
|
||||||
|
$old_username),
|
||||||
|
pht(
|
||||||
|
'New Username: %s',
|
||||||
|
$new_username));
|
||||||
|
|
||||||
|
return id(new PhabricatorMetaMTAMail())
|
||||||
|
->addTos(array($recipient->getPHID()))
|
||||||
|
->setSubject(pht('[Phabricator] Username Changed'))
|
||||||
|
->setBody($body);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -555,55 +555,6 @@ final class PhabricatorUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendUsernameChangeEmail(
|
|
||||||
PhabricatorUser $admin,
|
|
||||||
$old_username) {
|
|
||||||
|
|
||||||
$admin_username = $admin->getUserName();
|
|
||||||
$admin_realname = $admin->getRealName();
|
|
||||||
$new_username = $this->getUserName();
|
|
||||||
|
|
||||||
$password_instructions = null;
|
|
||||||
if (PhabricatorPasswordAuthProvider::getPasswordProvider()) {
|
|
||||||
$engine = new PhabricatorAuthSessionEngine();
|
|
||||||
$uri = $engine->getOneTimeLoginURI(
|
|
||||||
$this,
|
|
||||||
null,
|
|
||||||
PhabricatorAuthSessionEngine::ONETIME_USERNAME);
|
|
||||||
$password_instructions = sprintf(
|
|
||||||
"%s\n\n %s\n\n%s\n",
|
|
||||||
pht(
|
|
||||||
"If you use a password to login, you'll need to reset it ".
|
|
||||||
"before you can login again. You can reset your password by ".
|
|
||||||
"following this link:"),
|
|
||||||
$uri,
|
|
||||||
pht(
|
|
||||||
"And, of course, you'll need to use your new username to login ".
|
|
||||||
"from now on. If you use OAuth to login, nothing should change."));
|
|
||||||
}
|
|
||||||
|
|
||||||
$body = sprintf(
|
|
||||||
"%s\n\n %s\n %s\n\n%s",
|
|
||||||
pht(
|
|
||||||
'%s (%s) has changed your Phabricator username.',
|
|
||||||
$admin_username,
|
|
||||||
$admin_realname),
|
|
||||||
pht(
|
|
||||||
'Old Username: %s',
|
|
||||||
$old_username),
|
|
||||||
pht(
|
|
||||||
'New Username: %s',
|
|
||||||
$new_username),
|
|
||||||
$password_instructions);
|
|
||||||
|
|
||||||
$mail = id(new PhabricatorMetaMTAMail())
|
|
||||||
->addTos(array($this->getPHID()))
|
|
||||||
->setForceDelivery(true)
|
|
||||||
->setSubject(pht('[Phabricator] Username Changed'))
|
|
||||||
->setBody($body)
|
|
||||||
->saveAndSend();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function describeValidUsername() {
|
public static function describeValidUsername() {
|
||||||
return pht(
|
return pht(
|
||||||
'Usernames must contain only numbers, letters, period, underscore and '.
|
'Usernames must contain only numbers, letters, period, underscore and '.
|
||||||
|
@ -1180,9 +1131,10 @@ final class PhabricatorUser
|
||||||
$this->openTransaction();
|
$this->openTransaction();
|
||||||
$this->delete();
|
$this->delete();
|
||||||
|
|
||||||
$externals = id(new PhabricatorExternalAccount())->loadAllWhere(
|
$externals = id(new PhabricatorExternalAccountQuery())
|
||||||
'userPHID = %s',
|
->setViewer($engine->getViewer())
|
||||||
$this->getPHID());
|
->withUserPHIDs(array($this->getPHID()))
|
||||||
|
->execute();
|
||||||
foreach ($externals as $external) {
|
foreach ($externals as $external) {
|
||||||
$external->delete();
|
$external->delete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class PhabricatorUserTransaction
|
||||||
return PhabricatorPeopleUserPHIDType::TYPECONST;
|
return PhabricatorPeopleUserPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'PhabricatorUserTransactionType';
|
return 'PhabricatorUserTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,18 +18,27 @@ final class PhabricatorUserUsernameTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyExternalEffects($object, $value) {
|
public function applyExternalEffects($object, $value) {
|
||||||
|
$actor = $this->getActor();
|
||||||
$user = $object;
|
$user = $object;
|
||||||
|
|
||||||
|
$old_username = $this->getOldValue();
|
||||||
|
$new_username = $this->getNewValue();
|
||||||
|
|
||||||
$this->newUserLog(PhabricatorUserLog::ACTION_CHANGE_USERNAME)
|
$this->newUserLog(PhabricatorUserLog::ACTION_CHANGE_USERNAME)
|
||||||
->setOldValue($this->getOldValue())
|
->setOldValue($old_username)
|
||||||
->setNewValue($value)
|
->setNewValue($new_username)
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
// The SSH key cache currently includes usernames, so dirty it. See T12554
|
// The SSH key cache currently includes usernames, so dirty it. See T12554
|
||||||
// for discussion.
|
// for discussion.
|
||||||
PhabricatorAuthSSHKeyQuery::deleteSSHKeyCache();
|
PhabricatorAuthSSHKeyQuery::deleteSSHKeyCache();
|
||||||
|
|
||||||
$user->sendUsernameChangeEmail($this->getActor(), $this->getOldValue());
|
id(new PhabricatorPeopleUsernameMailEngine())
|
||||||
|
->setSender($actor)
|
||||||
|
->setRecipient($object)
|
||||||
|
->setOldUsername($old_username)
|
||||||
|
->setNewUsername($new_username)
|
||||||
|
->sendMail();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
|
@ -40,6 +49,15 @@ final class PhabricatorUserUsernameTransaction
|
||||||
$this->renderNewValue());
|
$this->renderNewValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTitleForFeed() {
|
||||||
|
return pht(
|
||||||
|
'%s renamed %s from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderObject(),
|
||||||
|
$this->renderOldValue(),
|
||||||
|
$this->renderNewValue());
|
||||||
|
}
|
||||||
|
|
||||||
public function validateTransactions($object, array $xactions) {
|
public function validateTransactions($object, array $xactions) {
|
||||||
$actor = $this->getActor();
|
$actor = $this->getActor();
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
|
|
@ -15,10 +15,6 @@ final class PhameBlogTransaction
|
||||||
return PhabricatorPhameBlogPHIDType::TYPECONST;
|
return PhabricatorPhameBlogPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'PhameBlogTransactionType';
|
return 'PhameBlogTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,6 @@ final class PhluxTransaction extends PhabricatorApplicationTransaction {
|
||||||
return PhluxVariablePHIDType::TYPECONST;
|
return PhluxVariablePHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
$author_phid = $this->getAuthorPHID();
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ final class PhortunePaymentMethodCreateController
|
||||||
$provider = $providers[$provider_id];
|
$provider = $providers[$provider_id];
|
||||||
|
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
$display_exception = null;
|
||||||
if ($request->isFormPost() && $request->getBool('isProviderForm')) {
|
if ($request->isFormPost() && $request->getBool('isProviderForm')) {
|
||||||
$method = id(new PhortunePaymentMethod())
|
$method = id(new PhortunePaymentMethod())
|
||||||
->setAccountPHID($account->getPHID())
|
->setAccountPHID($account->getPHID())
|
||||||
|
@ -107,14 +108,23 @@ final class PhortunePaymentMethodCreateController
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$errors) {
|
if (!$errors) {
|
||||||
$errors = $provider->createPaymentMethodFromRequest(
|
try {
|
||||||
$request,
|
$provider->createPaymentMethodFromRequest(
|
||||||
$method,
|
$request,
|
||||||
$client_token);
|
$method,
|
||||||
|
$client_token);
|
||||||
|
} catch (PhortuneDisplayException $exception) {
|
||||||
|
$display_exception = $exception;
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$errors = array(
|
||||||
|
pht('There was an error adding this payment method:'),
|
||||||
|
$ex->getMessage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$errors) {
|
if (!$errors && !$display_exception) {
|
||||||
$method->save();
|
$method->save();
|
||||||
|
|
||||||
// If we added this method on a cart flow, return to the cart to
|
// If we added this method on a cart flow, return to the cart to
|
||||||
|
@ -133,13 +143,17 @@ final class PhortunePaymentMethodCreateController
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
||||||
} else {
|
} else {
|
||||||
$dialog = id(new AphrontDialogView())
|
if ($display_exception) {
|
||||||
->setUser($viewer)
|
$dialog_body = $display_exception->getView();
|
||||||
->setTitle(pht('Error Adding Payment Method'))
|
} else {
|
||||||
->appendChild(id(new PHUIInfoView())->setErrors($errors))
|
$dialog_body = id(new PHUIInfoView())
|
||||||
->addCancelButton($request->getRequestURI());
|
->setErrors($errors);
|
||||||
|
}
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Error Adding Payment Method'))
|
||||||
|
->appendChild($dialog_body)
|
||||||
|
->addCancelButton($request->getRequestURI());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortuneDisplayException
|
||||||
|
extends Exception {
|
||||||
|
|
||||||
|
public function setView($view) {
|
||||||
|
$this->view = $view;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getView() {
|
||||||
|
return $this->view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -233,8 +233,6 @@ final class PhortuneStripePaymentProvider extends PhortunePaymentProvider {
|
||||||
array $token) {
|
array $token) {
|
||||||
$this->loadStripeAPILibraries();
|
$this->loadStripeAPILibraries();
|
||||||
|
|
||||||
$errors = array();
|
|
||||||
|
|
||||||
$secret_key = $this->getSecretKey();
|
$secret_key = $this->getSecretKey();
|
||||||
$stripe_token = $token['stripeCardToken'];
|
$stripe_token = $token['stripeCardToken'];
|
||||||
|
|
||||||
|
@ -253,7 +251,15 @@ final class PhortuneStripePaymentProvider extends PhortunePaymentProvider {
|
||||||
// the card more than once. We create one Customer for each card;
|
// the card more than once. We create one Customer for each card;
|
||||||
// they do not map to PhortuneAccounts because we allow an account to
|
// they do not map to PhortuneAccounts because we allow an account to
|
||||||
// have more than one active card.
|
// have more than one active card.
|
||||||
$customer = Stripe_Customer::create($params, $secret_key);
|
try {
|
||||||
|
$customer = Stripe_Customer::create($params, $secret_key);
|
||||||
|
} catch (Stripe_CardError $ex) {
|
||||||
|
$display_exception = $this->newDisplayExceptionFromCardError($ex);
|
||||||
|
if ($display_exception) {
|
||||||
|
throw $display_exception;
|
||||||
|
}
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
|
||||||
$card = $info->card;
|
$card = $info->card;
|
||||||
|
|
||||||
|
@ -267,8 +273,6 @@ final class PhortuneStripePaymentProvider extends PhortunePaymentProvider {
|
||||||
'stripe.customerID' => $customer->id,
|
'stripe.customerID' => $customer->id,
|
||||||
'stripe.cardToken' => $stripe_token,
|
'stripe.cardToken' => $stripe_token,
|
||||||
));
|
));
|
||||||
|
|
||||||
return $errors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderCreatePaymentMethodForm(
|
public function renderCreatePaymentMethodForm(
|
||||||
|
@ -383,4 +387,84 @@ final class PhortuneStripePaymentProvider extends PhortunePaymentProvider {
|
||||||
require_once $root.'/externals/stripe-php/lib/Stripe.php';
|
require_once $root.'/externals/stripe-php/lib/Stripe.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function newDisplayExceptionFromCardError(Stripe_CardError $ex) {
|
||||||
|
$body = $ex->getJSONBody();
|
||||||
|
if (!$body) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$map = idx($body, 'error');
|
||||||
|
if (!$map) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$view = array();
|
||||||
|
|
||||||
|
$message = idx($map, 'message');
|
||||||
|
|
||||||
|
$view[] = id(new PHUIInfoView())
|
||||||
|
->setErrors(array($message));
|
||||||
|
|
||||||
|
$view[] = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'mlt mlb',
|
||||||
|
),
|
||||||
|
pht('Additional details about this error:'));
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
pht('Error Code'),
|
||||||
|
idx($map, 'code'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
pht('Error Type'),
|
||||||
|
idx($map, 'type'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$param = idx($map, 'param');
|
||||||
|
if (strlen($param)) {
|
||||||
|
$rows[] = array(
|
||||||
|
pht('Error Param'),
|
||||||
|
$param,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$decline_code = idx($map, 'decline_code');
|
||||||
|
if (strlen($decline_code)) {
|
||||||
|
$rows[] = array(
|
||||||
|
pht('Decline Code'),
|
||||||
|
$decline_code,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$doc_url = idx($map, 'doc_url');
|
||||||
|
if ($doc_url) {
|
||||||
|
$rows[] = array(
|
||||||
|
pht('Learn More'),
|
||||||
|
phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => $doc_url,
|
||||||
|
'target' => '_blank',
|
||||||
|
),
|
||||||
|
$doc_url),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$view[] = id(new AphrontTableView($rows))
|
||||||
|
->setColumnClasses(
|
||||||
|
array(
|
||||||
|
'header',
|
||||||
|
'wide',
|
||||||
|
));
|
||||||
|
|
||||||
|
return id(new PhortuneDisplayException(get_class($ex)))
|
||||||
|
->setView($view);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class PhortuneAccountTransaction
|
||||||
return PhortuneAccountPHIDType::TYPECONST;
|
return PhortuneAccountPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'PhortuneAccountTransactionType';
|
return 'PhortuneAccountTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,6 @@ final class PhortuneCartTransaction
|
||||||
return PhortuneCartPHIDType::TYPECONST;
|
return PhortuneCartPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function shouldHideForMail(array $xactions) {
|
public function shouldHideForMail(array $xactions) {
|
||||||
switch ($this->getTransactionType()) {
|
switch ($this->getTransactionType()) {
|
||||||
case self::TYPE_CREATED:
|
case self::TYPE_CREATED:
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class PhortuneMerchantTransaction
|
||||||
return PhortuneMerchantPHIDType::TYPECONST;
|
return PhortuneMerchantPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'PhortuneMerchantTransactionType';
|
return 'PhortuneMerchantTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,6 @@ final class PhortunePaymentProviderConfigTransaction
|
||||||
return PhortunePaymentProviderPHIDType::TYPECONST;
|
return PhortunePaymentProviderPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
$author_phid = $this->getAuthorPHID();
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
|
||||||
|
|
|
@ -175,9 +175,10 @@ final class PhabricatorPolicyFilter extends Phobject {
|
||||||
if (!in_array($capability, $object_capabilities)) {
|
if (!in_array($capability, $object_capabilities)) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
pht(
|
pht(
|
||||||
"Testing for capability '%s' on an object which does ".
|
'Testing for capability "%s" on an object ("%s") which does '.
|
||||||
"not have that capability!",
|
'not support that capability.',
|
||||||
$capability));
|
$capability,
|
||||||
|
get_class($object)));
|
||||||
}
|
}
|
||||||
|
|
||||||
$policy = $this->getObjectPolicy($object, $capability);
|
$policy = $this->getObjectPolicy($object, $capability);
|
||||||
|
|
|
@ -19,10 +19,6 @@ final class PhabricatorProjectTransaction
|
||||||
return PhabricatorProjectProjectPHIDType::TYPECONST;
|
return PhabricatorProjectProjectPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'PhabricatorProjectTransactionType';
|
return 'PhabricatorProjectTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class PhabricatorRepositoryTransaction
|
||||||
return PhabricatorRepositoryRepositoryPHIDType::TYPECONST;
|
return PhabricatorRepositoryRepositoryPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'PhabricatorRepositoryTransactionType';
|
return 'PhabricatorRepositoryTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,28 +132,91 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
||||||
$author_phid,
|
$author_phid,
|
||||||
$revision) {
|
$revision) {
|
||||||
|
|
||||||
// Don't trigger an audit if auditing isn't enabled for the package.
|
$audit_uninvolved = false;
|
||||||
if (!$package->getAuditingEnabled()) {
|
$audit_unreviewed = false;
|
||||||
return false;
|
|
||||||
|
$rule = $package->newAuditingRule();
|
||||||
|
switch ($rule->getKey()) {
|
||||||
|
case PhabricatorOwnersAuditRule::AUDITING_NONE:
|
||||||
|
return false;
|
||||||
|
case PhabricatorOwnersAuditRule::AUDITING_ALL:
|
||||||
|
return true;
|
||||||
|
case PhabricatorOwnersAuditRule::AUDITING_NO_OWNER:
|
||||||
|
$audit_uninvolved = true;
|
||||||
|
break;
|
||||||
|
case PhabricatorOwnersAuditRule::AUDITING_UNREVIEWED:
|
||||||
|
$audit_unreviewed = true;
|
||||||
|
break;
|
||||||
|
case PhabricatorOwnersAuditRule::AUDITING_NO_OWNER_AND_UNREVIEWED:
|
||||||
|
$audit_uninvolved = true;
|
||||||
|
$audit_unreviewed = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger an audit if we don't recognize the commit's author.
|
// If auditing is configured to trigger on unreviewed changes, check if
|
||||||
if (!$author_phid) {
|
// the revision was "Accepted" when it landed. If not, trigger an audit.
|
||||||
return true;
|
if ($audit_unreviewed) {
|
||||||
|
$commit_unreviewed = true;
|
||||||
|
if ($revision) {
|
||||||
|
$was_accepted = DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED;
|
||||||
|
if ($revision->isPublished()) {
|
||||||
|
if ($revision->getProperty($was_accepted)) {
|
||||||
|
$commit_unreviewed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($commit_unreviewed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If auditing is configured to trigger on changes with no involved owner,
|
||||||
|
// check for an owner. If we don't find one, trigger an audit.
|
||||||
|
if ($audit_uninvolved) {
|
||||||
|
$commit_uninvolved = $this->isOwnerInvolved(
|
||||||
|
$commit,
|
||||||
|
$package,
|
||||||
|
$author_phid,
|
||||||
|
$revision);
|
||||||
|
if ($commit_uninvolved) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't find any reason to trigger an audit for this commit.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isOwnerInvolved(
|
||||||
|
PhabricatorRepositoryCommit $commit,
|
||||||
|
PhabricatorOwnersPackage $package,
|
||||||
|
$author_phid,
|
||||||
|
$revision) {
|
||||||
|
|
||||||
$owner_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(
|
$owner_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(
|
||||||
array(
|
array(
|
||||||
$package->getID(),
|
$package->getID(),
|
||||||
));
|
));
|
||||||
$owner_phids = array_fuse($owner_phids);
|
$owner_phids = array_fuse($owner_phids);
|
||||||
|
|
||||||
// Don't trigger an audit if the author is a package owner.
|
// For the purposes of deciding whether the owners were involved in the
|
||||||
if (isset($owner_phids[$author_phid])) {
|
// revision or not, consider a review by the package itself to count as
|
||||||
return false;
|
// involvement. This can happen when human reviewers force-accept on
|
||||||
|
// behalf of packages they don't own but have authority over.
|
||||||
|
$owner_phids[$package->getPHID()] = $package->getPHID();
|
||||||
|
|
||||||
|
// If the commit author is identifiable and a package owner, they're
|
||||||
|
// involved.
|
||||||
|
if ($author_phid) {
|
||||||
|
if (isset($owner_phids[$author_phid])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger an audit of there is no corresponding revision.
|
// Otherwise, we need to find an owner as a reviewer.
|
||||||
|
|
||||||
|
// If we don't have a revision, this is hopeless: no owners are involved.
|
||||||
if (!$revision) {
|
if (!$revision) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -168,26 +231,25 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
||||||
foreach ($revision->getReviewers() as $reviewer) {
|
foreach ($revision->getReviewers() as $reviewer) {
|
||||||
$reviewer_phid = $reviewer->getReviewerPHID();
|
$reviewer_phid = $reviewer->getReviewerPHID();
|
||||||
|
|
||||||
// If this reviewer isn't a package owner, just ignore them.
|
// If this reviewer isn't a package owner or the package itself,
|
||||||
|
// just ignore them.
|
||||||
if (empty($owner_phids[$reviewer_phid])) {
|
if (empty($owner_phids[$reviewer_phid])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this reviewer accepted the revision and owns the package, we're
|
// If this reviewer accepted the revision and owns the package (or is
|
||||||
// all clear and do not need to trigger an audit.
|
// the package), we've found an involved owner.
|
||||||
if (isset($accepted_statuses[$reviewer->getReviewerStatus()])) {
|
if (isset($accepted_statuses[$reviewer->getReviewerStatus()])) {
|
||||||
$found_accept = true;
|
$found_accept = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't trigger an audit if a package owner already reviewed the
|
|
||||||
// revision.
|
|
||||||
if ($found_accept) {
|
if ($found_accept) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,12 +70,8 @@ final class PhabricatorFulltextIndexEngineExtension
|
||||||
private function getCommentVersion($object) {
|
private function getCommentVersion($object) {
|
||||||
$xaction = $object->getApplicationTransactionTemplate();
|
$xaction = $object->getApplicationTransactionTemplate();
|
||||||
|
|
||||||
try {
|
$comment = $xaction->getApplicationTransactionCommentObject();
|
||||||
$comment = $xaction->getApplicationTransactionCommentObject();
|
if (!$comment) {
|
||||||
if (!$comment) {
|
|
||||||
return 'none';
|
|
||||||
}
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
return 'none';
|
return 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,4 @@ final class PhabricatorProfileMenuItemConfigurationTransaction
|
||||||
return PhabricatorProfileMenuItemPHIDType::TYPECONST;
|
return PhabricatorProfileMenuItemPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,13 +41,6 @@ final class PhabricatorExternalAccountsSettingsPanel
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setNoDataString(pht('You have no linked accounts.'));
|
->setNoDataString(pht('You have no linked accounts.'));
|
||||||
|
|
||||||
$login_accounts = 0;
|
|
||||||
foreach ($accounts as $account) {
|
|
||||||
if ($account->isUsableForLogin()) {
|
|
||||||
$login_accounts++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$item = new PHUIObjectItemView();
|
$item = new PHUIObjectItemView();
|
||||||
|
|
||||||
|
@ -72,8 +65,6 @@ final class PhabricatorExternalAccountsSettingsPanel
|
||||||
'account provider).'));
|
'account provider).'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$can_unlink = $can_unlink && (!$can_login || ($login_accounts > 1));
|
|
||||||
|
|
||||||
$can_refresh = $provider && $provider->shouldAllowAccountRefresh();
|
$can_refresh = $provider && $provider->shouldAllowAccountRefresh();
|
||||||
if ($can_refresh) {
|
if ($can_refresh) {
|
||||||
$item->addAction(
|
$item->addAction(
|
||||||
|
@ -105,26 +96,39 @@ final class PhabricatorExternalAccountsSettingsPanel
|
||||||
|
|
||||||
$accounts = mpull($accounts, null, 'getProviderKey');
|
$accounts = mpull($accounts, null, 'getProviderKey');
|
||||||
|
|
||||||
$providers = PhabricatorAuthProvider::getAllEnabledProviders();
|
$configs = id(new PhabricatorAuthProviderConfigQuery())
|
||||||
$providers = msort($providers, 'getProviderName');
|
->setViewer($viewer)
|
||||||
foreach ($providers as $key => $provider) {
|
->withIsEnabled(true)
|
||||||
if (isset($accounts[$key])) {
|
->execute();
|
||||||
continue;
|
$configs = msort($configs, 'getSortVector');
|
||||||
}
|
|
||||||
|
foreach ($configs as $config) {
|
||||||
|
$provider = $config->getProvider();
|
||||||
|
|
||||||
if (!$provider->shouldAllowAccountLink()) {
|
if (!$provider->shouldAllowAccountLink()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't show the user providers they already have linked.
|
||||||
|
$provider_key = $config->getProvider()->getProviderKey();
|
||||||
|
if (isset($accounts[$provider_key])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$link_uri = '/auth/link/'.$provider->getProviderKey().'/';
|
$link_uri = '/auth/link/'.$provider->getProviderKey().'/';
|
||||||
|
|
||||||
$item = id(new PHUIObjectItemView())
|
$link_button = id(new PHUIButtonView())
|
||||||
->setHeader($provider->getProviderName())
|
->setTag('a')
|
||||||
|
->setIcon('fa-link')
|
||||||
->setHref($link_uri)
|
->setHref($link_uri)
|
||||||
->addAction(
|
->setColor(PHUIButtonView::GREY)
|
||||||
id(new PHUIListItemView())
|
->setText(pht('Link External Account'));
|
||||||
->setIcon('fa-link')
|
|
||||||
->setHref($link_uri));
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setHeader($config->getDisplayName())
|
||||||
|
->setHref($link_uri)
|
||||||
|
->setImageIcon($config->newIconView())
|
||||||
|
->setSideColumn($link_button);
|
||||||
|
|
||||||
$linkable->addItem($item);
|
$linkable->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class PhabricatorUserPreferencesTransaction
|
||||||
return 'user';
|
return 'user';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getApplicationTransactionType() {
|
public function getApplicationTransactionType() {
|
||||||
return PhabricatorUserPreferencesPHIDType::TYPECONST;
|
return PhabricatorUserPreferencesPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,19 @@ final class PhabricatorSlowvoteVoteController
|
||||||
$method = $poll->getMethod();
|
$method = $poll->getMethod();
|
||||||
$is_plurality = ($method == PhabricatorSlowvotePoll::METHOD_PLURALITY);
|
$is_plurality = ($method == PhabricatorSlowvotePoll::METHOD_PLURALITY);
|
||||||
|
|
||||||
|
if (!$votes) {
|
||||||
|
if ($is_plurality) {
|
||||||
|
$message = pht('You must vote for something.');
|
||||||
|
} else {
|
||||||
|
$message = pht('You must vote for at least one option.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Stand For Something'))
|
||||||
|
->appendParagraph($message)
|
||||||
|
->addCancelButton($poll->getURI());
|
||||||
|
}
|
||||||
|
|
||||||
if ($is_plurality && count($votes) > 1) {
|
if ($is_plurality && count($votes) > 1) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
pht('In this poll, you may only vote for one option.'));
|
pht('In this poll, you may only vote for one option.'));
|
||||||
|
@ -52,23 +65,39 @@ final class PhabricatorSlowvoteVoteController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($old_votes as $old_vote) {
|
$poll->openTransaction();
|
||||||
if (!idx($votes, $old_vote->getOptionID(), false)) {
|
$poll->beginReadLocking();
|
||||||
|
|
||||||
|
$poll->reload();
|
||||||
|
|
||||||
|
$old_votes = id(new PhabricatorSlowvoteChoice())->loadAllWhere(
|
||||||
|
'pollID = %d AND authorPHID = %s',
|
||||||
|
$poll->getID(),
|
||||||
|
$viewer->getPHID());
|
||||||
|
$old_votes = mpull($old_votes, null, 'getOptionID');
|
||||||
|
|
||||||
|
foreach ($old_votes as $old_vote) {
|
||||||
|
if (idx($votes, $old_vote->getOptionID())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$old_vote->delete();
|
$old_vote->delete();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($votes as $vote) {
|
foreach ($votes as $vote) {
|
||||||
if (idx($old_votes, $vote, false)) {
|
if (idx($old_votes, $vote)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
id(new PhabricatorSlowvoteChoice())
|
||||||
|
->setAuthorPHID($viewer->getPHID())
|
||||||
|
->setPollID($poll->getID())
|
||||||
|
->setOptionID($vote)
|
||||||
|
->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
id(new PhabricatorSlowvoteChoice())
|
$poll->endReadLocking();
|
||||||
->setAuthorPHID($viewer->getPHID())
|
$poll->saveTransaction();
|
||||||
->setPollID($poll->getID())
|
|
||||||
->setOptionID($vote)
|
|
||||||
->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())
|
return id(new AphrontRedirectResponse())
|
||||||
->setURI($poll->getURI());
|
->setURI($poll->getURI());
|
||||||
|
|
|
@ -11,10 +11,6 @@ final class PhabricatorSpacesNamespaceTransaction
|
||||||
return PhabricatorSpacesNamespacePHIDType::TYPECONST;
|
return PhabricatorSpacesNamespacePHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseTransactionClass() {
|
public function getBaseTransactionClass() {
|
||||||
return 'PhabricatorSpacesNamespaceTransactionType';
|
return 'PhabricatorSpacesNamespaceTransactionType';
|
||||||
}
|
}
|
||||||
|
|
|
@ -360,12 +360,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($template) {
|
if ($template) {
|
||||||
try {
|
$comment = $template->getApplicationTransactionCommentObject();
|
||||||
$comment = $template->getApplicationTransactionCommentObject();
|
|
||||||
} catch (PhutilMethodNotImplementedException $ex) {
|
|
||||||
$comment = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($comment) {
|
if ($comment) {
|
||||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||||
}
|
}
|
||||||
|
@ -1120,6 +1115,16 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$transaction_open = true;
|
$transaction_open = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can technically test any object for CAN_INTERACT, but we can
|
||||||
|
// run into some issues in doing so (for example, in project unit tests).
|
||||||
|
// For now, only test for CAN_INTERACT if the object is explicitly a
|
||||||
|
// lockable object.
|
||||||
|
|
||||||
|
$was_locked = false;
|
||||||
|
if ($object instanceof PhabricatorEditEngineLockableInterface) {
|
||||||
|
$was_locked = !PhabricatorPolicyFilter::canInteract($actor, $object);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($xactions as $xaction) {
|
foreach ($xactions as $xaction) {
|
||||||
$this->applyInternalEffects($object, $xaction);
|
$this->applyInternalEffects($object, $xaction);
|
||||||
}
|
}
|
||||||
|
@ -1137,6 +1142,10 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($xactions as $xaction) {
|
foreach ($xactions as $xaction) {
|
||||||
|
if ($was_locked) {
|
||||||
|
$xaction->setIsLockOverrideTransaction(true);
|
||||||
|
}
|
||||||
|
|
||||||
$xaction->setObjectPHID($object->getPHID());
|
$xaction->setObjectPHID($object->getPHID());
|
||||||
if ($xaction->getComment()) {
|
if ($xaction->getComment()) {
|
||||||
$xaction->setPHID($xaction->generatePHID());
|
$xaction->setPHID($xaction->generatePHID());
|
||||||
|
|
|
@ -23,12 +23,7 @@ final class PhabricatorCommentEditEngineExtension
|
||||||
PhabricatorApplicationTransactionInterface $object) {
|
PhabricatorApplicationTransactionInterface $object) {
|
||||||
|
|
||||||
$xaction = $object->getApplicationTransactionTemplate();
|
$xaction = $object->getApplicationTransactionTemplate();
|
||||||
|
$comment = $xaction->getApplicationTransactionCommentObject();
|
||||||
try {
|
|
||||||
$comment = $xaction->getApplicationTransactionCommentObject();
|
|
||||||
} catch (PhutilMethodNotImplementedException $ex) {
|
|
||||||
$comment = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (bool)$comment;
|
return (bool)$comment;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ abstract class PhabricatorApplicationTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
public function getApplicationTransactionCommentObject() {
|
||||||
throw new PhutilMethodNotImplementedException();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMetadataValue($key, $default = null) {
|
public function getMetadataValue($key, $default = null) {
|
||||||
|
@ -169,6 +169,14 @@ abstract class PhabricatorApplicationTransaction
|
||||||
return (bool)$this->getMetadataValue('core.mfa', false);
|
return (bool)$this->getMetadataValue('core.mfa', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setIsLockOverrideTransaction($override) {
|
||||||
|
return $this->setMetadataValue('core.lock-override', $override);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsLockOverrideTransaction() {
|
||||||
|
return (bool)$this->getMetadataValue('core.lock-override', false);
|
||||||
|
}
|
||||||
|
|
||||||
public function attachComment(
|
public function attachComment(
|
||||||
PhabricatorApplicationTransactionComment $comment) {
|
PhabricatorApplicationTransactionComment $comment) {
|
||||||
$this->comment = $comment;
|
$this->comment = $comment;
|
||||||
|
@ -1529,6 +1537,12 @@ abstract class PhabricatorApplicationTransaction
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't group lock override and non-override transactions together.
|
||||||
|
$is_override = $this->getIsLockOverrideTransaction();
|
||||||
|
if ($is_override != $xaction->getIsLockOverrideTransaction()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1731,12 +1745,7 @@ abstract class PhabricatorApplicationTransaction
|
||||||
PhabricatorDestructionEngine $engine) {
|
PhabricatorDestructionEngine $engine) {
|
||||||
|
|
||||||
$this->openTransaction();
|
$this->openTransaction();
|
||||||
$comment_template = null;
|
$comment_template = $this->getApplicationTransactionCommentObject();
|
||||||
try {
|
|
||||||
$comment_template = $this->getApplicationTransactionCommentObject();
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
// Continue; no comments for these transactions.
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($comment_template) {
|
if ($comment_template) {
|
||||||
$comments = $comment_template->loadAllWhere(
|
$comments = $comment_template->loadAllWhere(
|
||||||
|
|
|
@ -23,10 +23,6 @@ final class PhabricatorEditEngineConfigurationTransaction
|
||||||
return PhabricatorEditEngineConfigurationPHIDType::TYPECONST;
|
return PhabricatorEditEngineConfigurationPHIDType::TYPECONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationTransactionCommentObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
$author_phid = $this->getAuthorPHID();
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
|
||||||
|
|
|
@ -416,7 +416,8 @@ class PhabricatorApplicationTransactionView extends AphrontView {
|
||||||
->setColor($xaction->getColor())
|
->setColor($xaction->getColor())
|
||||||
->setHideCommentOptions($this->getHideCommentOptions())
|
->setHideCommentOptions($this->getHideCommentOptions())
|
||||||
->setIsSilent($xaction->getIsSilentTransaction())
|
->setIsSilent($xaction->getIsSilentTransaction())
|
||||||
->setIsMFA($xaction->getIsMFATransaction());
|
->setIsMFA($xaction->getIsMFATransaction())
|
||||||
|
->setIsLockOverride($xaction->getIsLockOverrideTransaction());
|
||||||
|
|
||||||
list($token, $token_removed) = $xaction->getToken();
|
list($token, $token_removed) = $xaction->getToken();
|
||||||
if ($token) {
|
if ($token) {
|
||||||
|
|
|
@ -47,18 +47,31 @@ not. For more information on using daemons, see
|
||||||
@{article:Managing Daemons with phd}.
|
@{article:Managing Daemons with phd}.
|
||||||
|
|
||||||
|
|
||||||
Basics
|
Outbound "From" and "To" Addresses
|
||||||
======
|
==================================
|
||||||
|
|
||||||
Before configuring outbound mail, you should first set up
|
When Phabricator sends outbound mail, it must select some "From" address to
|
||||||
`metamta.default-address` in Configuration. This determines where mail is sent
|
send mail from, since mailers require this.
|
||||||
"From" by default.
|
|
||||||
|
|
||||||
If your domain is `example.org`, set this to something
|
When mail only has "CC" recipients, Phabricator generates a dummy "To" address,
|
||||||
like `noreply@example.org`.
|
since some mailers require this and some users write mail rules that depend
|
||||||
|
on whether they appear in the "To" or "CC" line.
|
||||||
|
|
||||||
Ideally, this should be a valid, deliverable address that doesn't bounce if
|
In both cases, the address should ideally correspond to a valid, deliverable
|
||||||
users accidentally send mail to it.
|
mailbox that accepts the mail and then simply discards it. If the address is
|
||||||
|
not valid, some outbound mail will bounce, and users will receive bounces when
|
||||||
|
they "Reply All" even if the other recipients for the message are valid. In
|
||||||
|
contrast, if the address is a real user address, that user will receive a lot
|
||||||
|
of mail they probably don't want.
|
||||||
|
|
||||||
|
If you plan to configure //inbound// mail later, you usually don't need to do
|
||||||
|
anything. Phabricator will automatically create a `noreply@` mailbox which
|
||||||
|
works the right way (accepts and discards all mail it receives) and
|
||||||
|
automatically use it when generating addresses.
|
||||||
|
|
||||||
|
If you don't plan to configure inbound mail, you may need to configure an
|
||||||
|
address for Phabricator to use. You can do this by setting
|
||||||
|
`metamta.default-address`.
|
||||||
|
|
||||||
|
|
||||||
Configuring Mailers
|
Configuring Mailers
|
||||||
|
|
|
@ -3,17 +3,28 @@
|
||||||
|
|
||||||
Using Diviner, a documentation generator.
|
Using Diviner, a documentation generator.
|
||||||
|
|
||||||
= Overview =
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
NOTE: Diviner is new and not yet generally useful.
|
Diviner is an application for creating technical documentation.
|
||||||
|
|
||||||
= Generating Documentation =
|
This article is maintained in a text file in the Phabricator repository and
|
||||||
|
generated into the display document you are currently reading using Diviner.
|
||||||
|
|
||||||
|
Beyond generating articles, Diviner can also analyze source code and generate
|
||||||
|
documentation about classes, methods, and other primitives.
|
||||||
|
|
||||||
|
|
||||||
|
Generating Documentation
|
||||||
|
========================
|
||||||
|
|
||||||
To generate documentation, run:
|
To generate documentation, run:
|
||||||
|
|
||||||
phabricator/ $ ./bin/diviner generate --book <book>
|
phabricator/ $ ./bin/diviner generate --book <book>
|
||||||
|
|
||||||
= .book Files =
|
|
||||||
|
Diviner ".book" Files
|
||||||
|
=====================
|
||||||
|
|
||||||
Diviner documentation books are configured using JSON `.book` files, which
|
Diviner documentation books are configured using JSON `.book` files, which
|
||||||
look like this:
|
look like this:
|
||||||
|
|
|
@ -114,16 +114,23 @@ Auditing
|
||||||
========
|
========
|
||||||
|
|
||||||
You can automatically trigger audits on unreviewed code by configuring
|
You can automatically trigger audits on unreviewed code by configuring
|
||||||
**Auditing**. The available settings are:
|
**Auditing**. The available settings allow you to select behavior based on
|
||||||
|
these conditions:
|
||||||
|
|
||||||
- **Disabled**: Do not trigger audits.
|
- **No Owner Involvement**: Triggers an audit when the commit author is not
|
||||||
- **Enabled**: Trigger audits.
|
a package owner, and no package owner reviewed an associated revision in
|
||||||
|
Differential.
|
||||||
|
- **Unreviewed Commits**: Triggers an audit when a commit has no associated
|
||||||
|
revision in Differential, or the associated revision in Differential landed
|
||||||
|
without being "Accepted".
|
||||||
|
|
||||||
When enabled, audits are triggered for commits which:
|
For example, the **Audit Commits With No Owner Involvement** option triggers
|
||||||
|
audits for commits which:
|
||||||
|
|
||||||
- affect code owned by the package;
|
- affect code owned by the package;
|
||||||
- were not authored by a package owner; and
|
- were not authored by a package owner; and
|
||||||
- were not accepted by a package owner.
|
- were not accepted (in Differential) by a package owner or the package
|
||||||
|
itself.
|
||||||
|
|
||||||
Audits do not trigger if the package has been archived.
|
Audits do not trigger if the package has been archived.
|
||||||
|
|
||||||
|
|
|
@ -432,7 +432,7 @@ abstract class PhabricatorStorageManagementWorkflow
|
||||||
case 'key':
|
case 'key':
|
||||||
if (($phase == 'drop_keys') && $adjust['exists']) {
|
if (($phase == 'drop_keys') && $adjust['exists']) {
|
||||||
if ($adjust['name'] == 'PRIMARY') {
|
if ($adjust['name'] == 'PRIMARY') {
|
||||||
$key_name = 'PRIMARY KEY';
|
$key_name = qsprintf($conn, 'PRIMARY KEY');
|
||||||
} else {
|
} else {
|
||||||
$key_name = qsprintf($conn, 'KEY %T', $adjust['name']);
|
$key_name = qsprintf($conn, 'KEY %T', $adjust['name']);
|
||||||
}
|
}
|
||||||
|
|
92
src/infrastructure/util/PhabricatorMetronome.php
Normal file
92
src/infrastructure/util/PhabricatorMetronome.php
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tick at a given frequency with a specifiable offset.
|
||||||
|
*
|
||||||
|
* One use case for this is to flatten out load spikes caused by periodic
|
||||||
|
* service calls. Give each host a metronome that ticks at the same frequency,
|
||||||
|
* but with different offsets. Then, have hosts make service calls only after
|
||||||
|
* their metronome ticks. This spreads service calls out evenly more quickly
|
||||||
|
* and more predictably than adding random jitter.
|
||||||
|
*/
|
||||||
|
final class PhabricatorMetronome
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $offset = 0;
|
||||||
|
private $frequency;
|
||||||
|
|
||||||
|
public function setOffset($offset) {
|
||||||
|
if (!is_int($offset)) {
|
||||||
|
throw new Exception(pht('Metronome offset must be an integer.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($offset < 0) {
|
||||||
|
throw new Exception(pht('Metronome offset must be 0 or more.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're not requiring that the offset be smaller than the frequency. If
|
||||||
|
// the offset is larger, we'll just clamp it to the frequency before we
|
||||||
|
// use it. This allows the offset to be configured before the frequency
|
||||||
|
// is configured, which is useful for using a hostname as an offset seed.
|
||||||
|
|
||||||
|
$this->offset = $offset;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFrequency($frequency) {
|
||||||
|
if (!is_int($frequency)) {
|
||||||
|
throw new Exception(pht('Metronome frequency must be an integer.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($frequency < 1) {
|
||||||
|
throw new Exception(pht('Metronome frequency must be 1 or more.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->frequency = $frequency;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOffsetFromSeed($seed) {
|
||||||
|
$offset = PhabricatorHash::digestToRange($seed, 0, PHP_INT_MAX);
|
||||||
|
return $this->setOffset($offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFrequency() {
|
||||||
|
if ($this->frequency === null) {
|
||||||
|
throw new PhutilInvalidStateException('setFrequency');
|
||||||
|
}
|
||||||
|
return $this->frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOffset() {
|
||||||
|
$frequency = $this->getFrequency();
|
||||||
|
return ($this->offset % $frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNextTickAfter($epoch) {
|
||||||
|
$frequency = $this->getFrequency();
|
||||||
|
$offset = $this->getOffset();
|
||||||
|
|
||||||
|
$remainder = ($epoch % $frequency);
|
||||||
|
|
||||||
|
if ($remainder < $offset) {
|
||||||
|
return ($epoch - $remainder) + $offset;
|
||||||
|
} else {
|
||||||
|
return ($epoch - $remainder) + $frequency + $offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function didTickBetween($min, $max) {
|
||||||
|
if ($max < $min) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Maximum tick window must not be smaller than minimum tick window.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$next = $this->getNextTickAfter($min);
|
||||||
|
return ($next <= $max);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue