1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-05 20:31:03 +01:00

(stable) Promote 2019 Week 31

This commit is contained in:
epriestley 2019-07-31 12:00:09 -07:00
commit 6f6ae61f00
128 changed files with 3071 additions and 1269 deletions

View file

@ -10,7 +10,7 @@ return array(
'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf',
'core.pkg.css' => 'af983028',
'core.pkg.js' => '5a792749',
'core.pkg.js' => '73a06a9f',
'differential.pkg.css' => '8d8360fb',
'differential.pkg.js' => '67e02996',
'diffusion.pkg.css' => '42c75c37',
@ -253,7 +253,7 @@ return array(
'rsrc/externals/javelin/lib/URI.js' => '2e255291',
'rsrc/externals/javelin/lib/Vector.js' => 'e9c80beb',
'rsrc/externals/javelin/lib/WebSocket.js' => 'fdc13e4e',
'rsrc/externals/javelin/lib/Workflow.js' => '445e21a8',
'rsrc/externals/javelin/lib/Workflow.js' => '945ff654',
'rsrc/externals/javelin/lib/__tests__/Cookie.js' => 'ca686f71',
'rsrc/externals/javelin/lib/__tests__/DOM.js' => '4566e249',
'rsrc/externals/javelin/lib/__tests__/JSON.js' => '710377ae',
@ -412,16 +412,16 @@ return array(
'rsrc/js/application/phortune/phortune-credit-card-form.js' => 'd12d214f',
'rsrc/js/application/policy/behavior-policy-control.js' => '0eaa33a9',
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '9347f172',
'rsrc/js/application/projects/WorkboardBoard.js' => 'c02a5497',
'rsrc/js/application/projects/WorkboardBoard.js' => 'b46d88c5',
'rsrc/js/application/projects/WorkboardCard.js' => '0392a5d8',
'rsrc/js/application/projects/WorkboardCardTemplate.js' => '2a61f8d4',
'rsrc/js/application/projects/WorkboardCardTemplate.js' => '84f82dad',
'rsrc/js/application/projects/WorkboardColumn.js' => 'c3d24e63',
'rsrc/js/application/projects/WorkboardController.js' => '42c7a5a7',
'rsrc/js/application/projects/WorkboardController.js' => 'b9d0c2f3',
'rsrc/js/application/projects/WorkboardDropEffect.js' => '8e0aa661',
'rsrc/js/application/projects/WorkboardHeader.js' => '111bfd2d',
'rsrc/js/application/projects/WorkboardHeaderTemplate.js' => 'ebe83a6b',
'rsrc/js/application/projects/WorkboardOrderTemplate.js' => '03e8891f',
'rsrc/js/application/projects/behavior-project-boards.js' => 'aad45445',
'rsrc/js/application/projects/behavior-project-boards.js' => '58cb6a88',
'rsrc/js/application/projects/behavior-project-create.js' => '34c53422',
'rsrc/js/application/projects/behavior-reorder-columns.js' => '8ac32fd9',
'rsrc/js/application/releeph/releeph-preview-branch.js' => '75184d68',
@ -667,7 +667,7 @@ return array(
'javelin-behavior-phuix-example' => 'c2c500a7',
'javelin-behavior-policy-control' => '0eaa33a9',
'javelin-behavior-policy-rule-editor' => '9347f172',
'javelin-behavior-project-boards' => 'aad45445',
'javelin-behavior-project-boards' => '58cb6a88',
'javelin-behavior-project-create' => '34c53422',
'javelin-behavior-quicksand-blacklist' => '5a6f6a06',
'javelin-behavior-read-only-warning' => 'b9109f8f',
@ -743,16 +743,16 @@ return array(
'javelin-view-renderer' => '9aae2b66',
'javelin-view-visitor' => '308f9fe4',
'javelin-websocket' => 'fdc13e4e',
'javelin-workboard-board' => 'c02a5497',
'javelin-workboard-board' => 'b46d88c5',
'javelin-workboard-card' => '0392a5d8',
'javelin-workboard-card-template' => '2a61f8d4',
'javelin-workboard-card-template' => '84f82dad',
'javelin-workboard-column' => 'c3d24e63',
'javelin-workboard-controller' => '42c7a5a7',
'javelin-workboard-controller' => 'b9d0c2f3',
'javelin-workboard-drop-effect' => '8e0aa661',
'javelin-workboard-header' => '111bfd2d',
'javelin-workboard-header-template' => 'ebe83a6b',
'javelin-workboard-order-template' => '03e8891f',
'javelin-workflow' => '445e21a8',
'javelin-workflow' => '945ff654',
'maniphest-report-css' => '3d53188b',
'maniphest-task-edit-css' => '272daa84',
'maniphest-task-summary-css' => '61d1667e',
@ -1133,9 +1133,6 @@ return array(
'javelin-stratcom',
'javelin-behavior',
),
'2a61f8d4' => array(
'javelin-install',
),
'2a8b62d9' => array(
'multirow-row-manager',
'javelin-install',
@ -1264,16 +1261,6 @@ return array(
'4234f572' => array(
'syntax-default-css',
),
'42c7a5a7' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
'javelin-workflow',
'phabricator-drag-and-drop-file-upload',
'javelin-workboard-board',
),
'4370900d' => array(
'javelin-install',
'javelin-util',
@ -1294,17 +1281,6 @@ return array(
'43bc9360' => array(
'javelin-install',
),
'445e21a8' => array(
'javelin-stratcom',
'javelin-request',
'javelin-dom',
'javelin-vector',
'javelin-install',
'javelin-util',
'javelin-mask',
'javelin-uri',
'javelin-routable',
),
'46116c01' => array(
'javelin-request',
'javelin-behavior',
@ -1423,6 +1399,16 @@ return array(
'javelin-vector',
'javelin-typeahead-static-source',
),
'58cb6a88' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
'javelin-workflow',
'javelin-workboard-controller',
'javelin-workboard-drop-effect',
),
'5902260c' => array(
'javelin-util',
'javelin-magical-init',
@ -1618,6 +1604,9 @@ return array(
'javelin-resource',
'javelin-routable',
),
'84f82dad' => array(
'javelin-install',
),
'87428eb2' => array(
'javelin-behavior',
'javelin-diffusion-locate-file-source',
@ -1709,6 +1698,17 @@ return array(
'javelin-typeahead-preloaded-source',
'javelin-util',
),
'945ff654' => array(
'javelin-stratcom',
'javelin-request',
'javelin-dom',
'javelin-vector',
'javelin-install',
'javelin-util',
'javelin-mask',
'javelin-uri',
'javelin-routable',
),
'94681e22' => array(
'javelin-magical-init',
'javelin-install',
@ -1840,16 +1840,6 @@ return array(
'javelin-dom',
'javelin-util',
),
'aad45445' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
'javelin-workflow',
'javelin-workboard-controller',
'javelin-workboard-drop-effect',
),
'ab85e184' => array(
'javelin-install',
'javelin-dom',
@ -1898,6 +1888,18 @@ return array(
'b347a301' => array(
'javelin-behavior',
),
'b46d88c5' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
'javelin-workboard-column',
'javelin-workboard-header-template',
'javelin-workboard-card-template',
'javelin-workboard-order-template',
),
'b49fd60c' => array(
'multirow-row-manager',
'trigger-rule',
@ -1940,20 +1942,18 @@ return array(
'javelin-uri',
'phabricator-notification',
),
'bde53589' => array(
'phui-inline-comment-view-css',
),
'c02a5497' => array(
'b9d0c2f3' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
'javelin-workboard-column',
'javelin-workboard-header-template',
'javelin-workboard-card-template',
'javelin-workboard-order-template',
'phabricator-drag-and-drop-file-upload',
'javelin-workboard-board',
),
'bde53589' => array(
'phui-inline-comment-view-css',
),
'c03f2fb4' => array(
'javelin-install',

View file

@ -0,0 +1,2 @@
RENAME TABLE {$NAMESPACE}_pastebin.edge
TO {$NAMESPACE}_paste.edge;

View file

@ -0,0 +1,2 @@
RENAME TABLE {$NAMESPACE}_pastebin.edgedata
TO {$NAMESPACE}_paste.edgedata;

View file

@ -0,0 +1,2 @@
RENAME TABLE {$NAMESPACE}_pastebin.pastebin_paste
TO {$NAMESPACE}_paste.paste;

View file

@ -0,0 +1,2 @@
RENAME TABLE {$NAMESPACE}_pastebin.pastebin_pastetransaction
TO {$NAMESPACE}_paste.paste_transaction;

View file

@ -0,0 +1,2 @@
RENAME TABLE {$NAMESPACE}_pastebin.pastebin_pastetransaction_comment
TO {$NAMESPACE}_paste.paste_transaction_comment;

View file

@ -2117,6 +2117,8 @@ phutil_register_library_map(array(
'PhabricatorActionListView' => 'view/layout/PhabricatorActionListView.php',
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
'PhabricatorActivitySettingsPanel' => 'applications/settings/panel/PhabricatorActivitySettingsPanel.php',
'PhabricatorAddEmailUserLogType' => 'applications/people/userlog/PhabricatorAddEmailUserLogType.php',
'PhabricatorAddMultifactorUserLogType' => 'applications/people/userlog/PhabricatorAddMultifactorUserLogType.php',
'PhabricatorAdministratorsPolicyRule' => 'applications/people/policyrule/PhabricatorAdministratorsPolicyRule.php',
'PhabricatorAjaxRequestExceptionHandler' => 'aphront/handler/PhabricatorAjaxRequestExceptionHandler.php',
'PhabricatorAlmanacApplication' => 'applications/almanac/application/PhabricatorAlmanacApplication.php',
@ -2265,6 +2267,9 @@ phutil_register_library_map(array(
'PhabricatorAuthDisableController' => 'applications/auth/controller/config/PhabricatorAuthDisableController.php',
'PhabricatorAuthDowngradeSessionController' => 'applications/auth/controller/PhabricatorAuthDowngradeSessionController.php',
'PhabricatorAuthEditController' => 'applications/auth/controller/config/PhabricatorAuthEditController.php',
'PhabricatorAuthEmailLoginAction' => 'applications/auth/action/PhabricatorAuthEmailLoginAction.php',
'PhabricatorAuthEmailLoginMessageType' => 'applications/auth/message/PhabricatorAuthEmailLoginMessageType.php',
'PhabricatorAuthEmailSetPasswordMessageType' => 'applications/auth/message/PhabricatorAuthEmailSetPasswordMessageType.php',
'PhabricatorAuthFactor' => 'applications/auth/factor/PhabricatorAuthFactor.php',
'PhabricatorAuthFactorConfig' => 'applications/auth/storage/PhabricatorAuthFactorConfig.php',
'PhabricatorAuthFactorConfigQuery' => 'applications/auth/query/PhabricatorAuthFactorConfigQuery.php',
@ -2426,7 +2431,10 @@ phutil_register_library_map(array(
'PhabricatorAuthTemporaryTokenTypeModule' => 'applications/auth/tokentype/PhabricatorAuthTemporaryTokenTypeModule.php',
'PhabricatorAuthTerminateSessionController' => 'applications/auth/controller/PhabricatorAuthTerminateSessionController.php',
'PhabricatorAuthTestSMSAction' => 'applications/auth/action/PhabricatorAuthTestSMSAction.php',
'PhabricatorAuthTryEmailLoginAction' => 'applications/auth/action/PhabricatorAuthTryEmailLoginAction.php',
'PhabricatorAuthTryFactorAction' => 'applications/auth/action/PhabricatorAuthTryFactorAction.php',
'PhabricatorAuthTryPasswordAction' => 'applications/auth/action/PhabricatorAuthTryPasswordAction.php',
'PhabricatorAuthTryPasswordWithoutCAPTCHAAction' => 'applications/auth/action/PhabricatorAuthTryPasswordWithoutCAPTCHAAction.php',
'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php',
'PhabricatorAuthValidateController' => 'applications/auth/controller/PhabricatorAuthValidateController.php',
'PhabricatorAuthWaitForApprovalMessageType' => 'applications/auth/message/PhabricatorAuthWaitForApprovalMessageType.php',
@ -2662,6 +2670,7 @@ phutil_register_library_map(array(
'PhabricatorCelerityApplication' => 'applications/celerity/application/PhabricatorCelerityApplication.php',
'PhabricatorCelerityTestCase' => '__tests__/PhabricatorCelerityTestCase.php',
'PhabricatorChangeParserTestCase' => 'applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php',
'PhabricatorChangePasswordUserLogType' => 'applications/people/userlog/PhabricatorChangePasswordUserLogType.php',
'PhabricatorChangesetCachePurger' => 'applications/cache/purger/PhabricatorChangesetCachePurger.php',
'PhabricatorChangesetResponse' => 'infrastructure/diff/PhabricatorChangesetResponse.php',
'PhabricatorChartAxis' => 'applications/fact/chart/PhabricatorChartAxis.php',
@ -2715,7 +2724,9 @@ phutil_register_library_map(array(
'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php',
'PhabricatorConduitApplication' => 'applications/conduit/application/PhabricatorConduitApplication.php',
'PhabricatorConduitCallManagementWorkflow' => 'applications/conduit/management/PhabricatorConduitCallManagementWorkflow.php',
'PhabricatorConduitCertificateFailureUserLogType' => 'applications/people/userlog/PhabricatorConduitCertificateFailureUserLogType.php',
'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/PhabricatorConduitCertificateToken.php',
'PhabricatorConduitCertificateUserLogType' => 'applications/people/userlog/PhabricatorConduitCertificateUserLogType.php',
'PhabricatorConduitConsoleController' => 'applications/conduit/controller/PhabricatorConduitConsoleController.php',
'PhabricatorConduitContentSource' => 'infrastructure/contentsource/PhabricatorConduitContentSource.php',
'PhabricatorConduitController' => 'applications/conduit/controller/PhabricatorConduitController.php',
@ -3205,6 +3216,7 @@ phutil_register_library_map(array(
'PhabricatorEmailFormatSetting' => 'applications/settings/setting/PhabricatorEmailFormatSetting.php',
'PhabricatorEmailFormatSettingsPanel' => 'applications/settings/panel/PhabricatorEmailFormatSettingsPanel.php',
'PhabricatorEmailLoginController' => 'applications/auth/controller/PhabricatorEmailLoginController.php',
'PhabricatorEmailLoginUserLogType' => 'applications/people/userlog/PhabricatorEmailLoginUserLogType.php',
'PhabricatorEmailNotificationsSetting' => 'applications/settings/setting/PhabricatorEmailNotificationsSetting.php',
'PhabricatorEmailPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php',
'PhabricatorEmailRePrefixSetting' => 'applications/settings/setting/PhabricatorEmailRePrefixSetting.php',
@ -3218,6 +3230,7 @@ phutil_register_library_map(array(
'PhabricatorEmojiRemarkupRule' => 'applications/macro/markup/PhabricatorEmojiRemarkupRule.php',
'PhabricatorEmojiTranslation' => 'infrastructure/internationalization/translation/PhabricatorEmojiTranslation.php',
'PhabricatorEmptyQueryException' => 'infrastructure/query/exception/PhabricatorEmptyQueryException.php',
'PhabricatorEnterHisecUserLogType' => 'applications/people/userlog/PhabricatorEnterHisecUserLogType.php',
'PhabricatorEnumConfigType' => 'applications/config/type/PhabricatorEnumConfigType.php',
'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php',
'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php',
@ -3230,6 +3243,7 @@ phutil_register_library_map(array(
'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php',
'PhabricatorExcelExportFormat' => 'infrastructure/export/format/PhabricatorExcelExportFormat.php',
'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php',
'PhabricatorExitHisecUserLogType' => 'applications/people/userlog/PhabricatorExitHisecUserLogType.php',
'PhabricatorExportEngine' => 'infrastructure/export/engine/PhabricatorExportEngine.php',
'PhabricatorExportEngineBulkJobType' => 'infrastructure/export/engine/PhabricatorExportEngineBulkJobType.php',
'PhabricatorExportEngineExtension' => 'infrastructure/export/engine/PhabricatorExportEngineExtension.php',
@ -3270,6 +3284,7 @@ phutil_register_library_map(array(
'PhabricatorFactObjectDimension' => 'applications/fact/storage/PhabricatorFactObjectDimension.php',
'PhabricatorFactRaw' => 'applications/fact/storage/PhabricatorFactRaw.php',
'PhabricatorFactUpdateIterator' => 'applications/fact/extract/PhabricatorFactUpdateIterator.php',
'PhabricatorFailHisecUserLogType' => 'applications/people/userlog/PhabricatorFailHisecUserLogType.php',
'PhabricatorFaviconRef' => 'applications/files/favicon/PhabricatorFaviconRef.php',
'PhabricatorFaviconRefQuery' => 'applications/files/favicon/PhabricatorFaviconRefQuery.php',
'PhabricatorFavoritesApplication' => 'applications/favorites/application/PhabricatorFavoritesApplication.php',
@ -3404,6 +3419,7 @@ phutil_register_library_map(array(
'PhabricatorFlaggableInterface' => 'applications/flag/interface/PhabricatorFlaggableInterface.php',
'PhabricatorFlagsApplication' => 'applications/flag/application/PhabricatorFlagsApplication.php',
'PhabricatorFlagsUIEventListener' => 'applications/flag/events/PhabricatorFlagsUIEventListener.php',
'PhabricatorFullLoginUserLogType' => 'applications/people/userlog/PhabricatorFullLoginUserLogType.php',
'PhabricatorFulltextEngine' => 'applications/search/index/PhabricatorFulltextEngine.php',
'PhabricatorFulltextEngineExtension' => 'applications/search/index/PhabricatorFulltextEngineExtension.php',
'PhabricatorFulltextEngineExtensionModule' => 'applications/search/index/PhabricatorFulltextEngineExtensionModule.php',
@ -3542,7 +3558,10 @@ phutil_register_library_map(array(
'PhabricatorLockLogManagementWorkflow' => 'applications/daemon/management/PhabricatorLockLogManagementWorkflow.php',
'PhabricatorLockManagementWorkflow' => 'applications/daemon/management/PhabricatorLockManagementWorkflow.php',
'PhabricatorLogTriggerAction' => 'infrastructure/daemon/workers/action/PhabricatorLogTriggerAction.php',
'PhabricatorLoginFailureUserLogType' => 'applications/people/userlog/PhabricatorLoginFailureUserLogType.php',
'PhabricatorLoginUserLogType' => 'applications/people/userlog/PhabricatorLoginUserLogType.php',
'PhabricatorLogoutController' => 'applications/auth/controller/PhabricatorLogoutController.php',
'PhabricatorLogoutUserLogType' => 'applications/people/userlog/PhabricatorLogoutUserLogType.php',
'PhabricatorLunarPhasePolicyRule' => 'applications/policy/rule/PhabricatorLunarPhasePolicyRule.php',
'PhabricatorMacroApplication' => 'applications/macro/application/PhabricatorMacroApplication.php',
'PhabricatorMacroAudioBehaviorTransaction' => 'applications/macro/xaction/PhabricatorMacroAudioBehaviorTransaction.php',
@ -3951,6 +3970,7 @@ phutil_register_library_map(array(
'PhabricatorPackagesVersionViewController' => 'applications/packages/controller/PhabricatorPackagesVersionViewController.php',
'PhabricatorPackagesView' => 'applications/packages/view/PhabricatorPackagesView.php',
'PhabricatorPagerUIExample' => 'applications/uiexample/examples/PhabricatorPagerUIExample.php',
'PhabricatorPartialLoginUserLogType' => 'applications/people/userlog/PhabricatorPartialLoginUserLogType.php',
'PhabricatorPassphraseApplication' => 'applications/passphrase/application/PhabricatorPassphraseApplication.php',
'PhabricatorPasswordAuthProvider' => 'applications/auth/provider/PhabricatorPasswordAuthProvider.php',
'PhabricatorPasswordDestructionEngineExtension' => 'applications/auth/extension/PhabricatorPasswordDestructionEngineExtension.php',
@ -4001,6 +4021,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleDeleteController' => 'applications/people/controller/PhabricatorPeopleDeleteController.php',
'PhabricatorPeopleDetailsProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleDetailsProfileMenuItem.php',
'PhabricatorPeopleDisableController' => 'applications/people/controller/PhabricatorPeopleDisableController.php',
'PhabricatorPeopleEmailLoginMailEngine' => 'applications/people/mail/PhabricatorPeopleEmailLoginMailEngine.php',
'PhabricatorPeopleEmpowerController' => 'applications/people/controller/PhabricatorPeopleEmpowerController.php',
'PhabricatorPeopleExternalPHIDType' => 'applications/people/phid/PhabricatorPeopleExternalPHIDType.php',
'PhabricatorPeopleIconSet' => 'applications/people/icon/PhabricatorPeopleIconSet.php',
@ -4010,6 +4031,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleListController' => 'applications/people/controller/PhabricatorPeopleListController.php',
'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php',
'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php',
'PhabricatorPeopleLogViewController' => 'applications/people/controller/PhabricatorPeopleLogViewController.php',
'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php',
'PhabricatorPeopleMailEngine' => 'applications/people/mail/PhabricatorPeopleMailEngine.php',
'PhabricatorPeopleMailEngineException' => 'applications/people/mail/PhabricatorPeopleMailEngineException.php',
@ -4138,6 +4160,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php',
'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php',
'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php',
'PhabricatorPrimaryEmailUserLogType' => 'applications/people/userlog/PhabricatorPrimaryEmailUserLogType.php',
'PhabricatorProfileMenuEditEngine' => 'applications/search/editor/PhabricatorProfileMenuEditEngine.php',
'PhabricatorProfileMenuEditor' => 'applications/search/editor/PhabricatorProfileMenuEditor.php',
'PhabricatorProfileMenuEngine' => 'applications/search/engine/PhabricatorProfileMenuEngine.php',
@ -4158,9 +4181,12 @@ phutil_register_library_map(array(
'PhabricatorProjectArchiveController' => 'applications/project/controller/PhabricatorProjectArchiveController.php',
'PhabricatorProjectBoardBackgroundController' => 'applications/project/controller/PhabricatorProjectBoardBackgroundController.php',
'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php',
'PhabricatorProjectBoardDefaultController' => 'applications/project/controller/PhabricatorProjectBoardDefaultController.php',
'PhabricatorProjectBoardDisableController' => 'applications/project/controller/PhabricatorProjectBoardDisableController.php',
'PhabricatorProjectBoardFilterController' => 'applications/project/controller/PhabricatorProjectBoardFilterController.php',
'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php',
'PhabricatorProjectBoardManageController' => 'applications/project/controller/PhabricatorProjectBoardManageController.php',
'PhabricatorProjectBoardReloadController' => 'applications/project/controller/PhabricatorProjectBoardReloadController.php',
'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php',
'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php',
'PhabricatorProjectBuiltinsExample' => 'applications/uiexample/examples/PhabricatorProjectBuiltinsExample.php',
@ -4170,6 +4196,8 @@ phutil_register_library_map(array(
'PhabricatorProjectColorsConfigType' => 'applications/project/config/PhabricatorProjectColorsConfigType.php',
'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php',
'PhabricatorProjectColumnAuthorOrder' => 'applications/project/order/PhabricatorProjectColumnAuthorOrder.php',
'PhabricatorProjectColumnBulkEditController' => 'applications/project/controller/PhabricatorProjectColumnBulkEditController.php',
'PhabricatorProjectColumnBulkMoveController' => 'applications/project/controller/PhabricatorProjectColumnBulkMoveController.php',
'PhabricatorProjectColumnCreatedOrder' => 'applications/project/order/PhabricatorProjectColumnCreatedOrder.php',
'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php',
'PhabricatorProjectColumnEditController' => 'applications/project/controller/PhabricatorProjectColumnEditController.php',
@ -4196,6 +4224,7 @@ phutil_register_library_map(array(
'PhabricatorProjectColumnTransactionQuery' => 'applications/project/query/PhabricatorProjectColumnTransactionQuery.php',
'PhabricatorProjectColumnTransactionType' => 'applications/project/xaction/column/PhabricatorProjectColumnTransactionType.php',
'PhabricatorProjectColumnTriggerTransaction' => 'applications/project/xaction/column/PhabricatorProjectColumnTriggerTransaction.php',
'PhabricatorProjectColumnViewQueryController' => 'applications/project/controller/PhabricatorProjectColumnViewQueryController.php',
'PhabricatorProjectConfigOptions' => 'applications/project/config/PhabricatorProjectConfigOptions.php',
'PhabricatorProjectConfiguredCustomField' => 'applications/project/customfield/PhabricatorProjectConfiguredCustomField.php',
'PhabricatorProjectController' => 'applications/project/controller/PhabricatorProjectController.php',
@ -4207,7 +4236,6 @@ phutil_register_library_map(array(
'PhabricatorProjectCustomFieldStringIndex' => 'applications/project/storage/PhabricatorProjectCustomFieldStringIndex.php',
'PhabricatorProjectDAO' => 'applications/project/storage/PhabricatorProjectDAO.php',
'PhabricatorProjectDatasource' => 'applications/project/typeahead/PhabricatorProjectDatasource.php',
'PhabricatorProjectDefaultController' => 'applications/project/controller/PhabricatorProjectDefaultController.php',
'PhabricatorProjectDescriptionField' => 'applications/project/customfield/PhabricatorProjectDescriptionField.php',
'PhabricatorProjectDetailsProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectDetailsProfileMenuItem.php',
'PhabricatorProjectDropEffect' => 'applications/project/icon/PhabricatorProjectDropEffect.php',
@ -4356,6 +4384,7 @@ phutil_register_library_map(array(
'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php',
'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php',
'PhabricatorRateLimitRequestExceptionHandler' => 'aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php',
'PhabricatorReassignEmailUserLogType' => 'applications/people/userlog/PhabricatorReassignEmailUserLogType.php',
'PhabricatorRebuildIndexesWorker' => 'applications/search/worker/PhabricatorRebuildIndexesWorker.php',
'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php',
'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php',
@ -4374,6 +4403,8 @@ phutil_register_library_map(array(
'PhabricatorRemarkupFigletBlockInterpreter' => 'infrastructure/markup/interpreter/PhabricatorRemarkupFigletBlockInterpreter.php',
'PhabricatorRemarkupHyperlinkEngineExtension' => 'applications/remarkup/engineextension/PhabricatorRemarkupHyperlinkEngineExtension.php',
'PhabricatorRemarkupUIExample' => 'applications/uiexample/examples/PhabricatorRemarkupUIExample.php',
'PhabricatorRemoveEmailUserLogType' => 'applications/people/userlog/PhabricatorRemoveEmailUserLogType.php',
'PhabricatorRemoveMultifactorUserLogType' => 'applications/people/userlog/PhabricatorRemoveMultifactorUserLogType.php',
'PhabricatorRepositoriesSetupCheck' => 'applications/config/check/PhabricatorRepositoriesSetupCheck.php',
'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php',
'PhabricatorRepositoryActivateTransaction' => 'applications/repository/xaction/PhabricatorRepositoryActivateTransaction.php',
@ -4512,6 +4543,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryVCSTransaction' => 'applications/repository/xaction/PhabricatorRepositoryVCSTransaction.php',
'PhabricatorRepositoryWorkingCopyVersion' => 'applications/repository/storage/PhabricatorRepositoryWorkingCopyVersion.php',
'PhabricatorRequestExceptionHandler' => 'aphront/handler/PhabricatorRequestExceptionHandler.php',
'PhabricatorResetPasswordUserLogType' => 'applications/people/userlog/PhabricatorResetPasswordUserLogType.php',
'PhabricatorResourceSite' => 'aphront/site/PhabricatorResourceSite.php',
'PhabricatorRobotsController' => 'applications/system/controller/PhabricatorRobotsController.php',
'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php',
@ -4618,6 +4650,7 @@ phutil_register_library_map(array(
'PhabricatorShiftChartFunction' => 'applications/fact/chart/PhabricatorShiftChartFunction.php',
'PhabricatorShortSite' => 'aphront/site/PhabricatorShortSite.php',
'PhabricatorShowFiletreeSetting' => 'applications/settings/setting/PhabricatorShowFiletreeSetting.php',
'PhabricatorSignDocumentsUserLogType' => 'applications/people/userlog/PhabricatorSignDocumentsUserLogType.php',
'PhabricatorSimpleEditType' => 'applications/transactions/edittype/PhabricatorSimpleEditType.php',
'PhabricatorSinChartFunction' => 'applications/fact/chart/PhabricatorSinChartFunction.php',
'PhabricatorSite' => 'aphront/site/PhabricatorSite.php',
@ -4908,6 +4941,8 @@ phutil_register_library_map(array(
'PhabricatorUserFulltextEngine' => 'applications/people/search/PhabricatorUserFulltextEngine.php',
'PhabricatorUserIconField' => 'applications/people/customfield/PhabricatorUserIconField.php',
'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php',
'PhabricatorUserLogType' => 'applications/people/userlog/PhabricatorUserLogType.php',
'PhabricatorUserLogTypeDatasource' => 'applications/people/typeahead/PhabricatorUserLogTypeDatasource.php',
'PhabricatorUserLogView' => 'applications/people/view/PhabricatorUserLogView.php',
'PhabricatorUserMessageCountCacheType' => 'applications/people/cache/PhabricatorUserMessageCountCacheType.php',
'PhabricatorUserNotificationCountCacheType' => 'applications/people/cache/PhabricatorUserNotificationCountCacheType.php',
@ -4938,6 +4973,7 @@ phutil_register_library_map(array(
'PhabricatorUsersPolicyRule' => 'applications/people/policyrule/PhabricatorUsersPolicyRule.php',
'PhabricatorUsersSearchField' => 'applications/people/searchfield/PhabricatorUsersSearchField.php',
'PhabricatorVCSResponse' => 'applications/repository/response/PhabricatorVCSResponse.php',
'PhabricatorVerifyEmailUserLogType' => 'applications/people/userlog/PhabricatorVerifyEmailUserLogType.php',
'PhabricatorVersionedDraft' => 'applications/draft/storage/PhabricatorVersionedDraft.php',
'PhabricatorVeryWowEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorVeryWowEnglishTranslation.php',
'PhabricatorVideoDocumentEngine' => 'applications/files/document/PhabricatorVideoDocumentEngine.php',
@ -4949,6 +4985,7 @@ phutil_register_library_map(array(
'PhabricatorWeekStartDaySetting' => 'applications/settings/setting/PhabricatorWeekStartDaySetting.php',
'PhabricatorWildConfigType' => 'applications/config/type/PhabricatorWildConfigType.php',
'PhabricatorWordPressAuthProvider' => 'applications/auth/provider/PhabricatorWordPressAuthProvider.php',
'PhabricatorWorkboardViewState' => 'applications/project/state/PhabricatorWorkboardViewState.php',
'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php',
'PhabricatorWorkerActiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php',
'PhabricatorWorkerActiveTaskQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerActiveTaskQuery.php',
@ -5017,6 +5054,7 @@ phutil_register_library_map(array(
'PhabricatorXHProfSampleQuery' => 'applications/xhprof/query/PhabricatorXHProfSampleQuery.php',
'PhabricatorXHProfSampleSearchEngine' => 'applications/xhprof/query/PhabricatorXHProfSampleSearchEngine.php',
'PhabricatorYoutubeRemarkupRule' => 'infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php',
'PhabricatorZipSetupCheck' => 'applications/config/check/PhabricatorZipSetupCheck.php',
'Phame404Response' => 'applications/phame/site/Phame404Response.php',
'PhameBlog' => 'applications/phame/storage/PhameBlog.php',
'PhameBlog404Controller' => 'applications/phame/controller/blog/PhameBlog404Controller.php',
@ -5576,6 +5614,7 @@ phutil_register_library_map(array(
'SlowvoteEmbedView' => 'applications/slowvote/view/SlowvoteEmbedView.php',
'SlowvoteInfoConduitAPIMethod' => 'applications/slowvote/conduit/SlowvoteInfoConduitAPIMethod.php',
'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php',
'SlowvoteSearchConduitAPIMethod' => 'applications/slowvote/conduit/SlowvoteSearchConduitAPIMethod.php',
'SubscriptionListDialogBuilder' => 'applications/subscriptions/view/SubscriptionListDialogBuilder.php',
'SubscriptionListStringBuilder' => 'applications/subscriptions/view/SubscriptionListStringBuilder.php',
'TokenConduitAPIMethod' => 'applications/tokens/conduit/TokenConduitAPIMethod.php',
@ -8037,6 +8076,8 @@ phutil_register_library_map(array(
'PhabricatorActionListView' => 'AphrontTagView',
'PhabricatorActionView' => 'AphrontView',
'PhabricatorActivitySettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorAddEmailUserLogType' => 'PhabricatorUserLogType',
'PhabricatorAddMultifactorUserLogType' => 'PhabricatorUserLogType',
'PhabricatorAdministratorsPolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorAjaxRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
'PhabricatorAlmanacApplication' => 'PhabricatorApplication',
@ -8212,6 +8253,9 @@ phutil_register_library_map(array(
'PhabricatorAuthDisableController' => 'PhabricatorAuthProviderConfigController',
'PhabricatorAuthDowngradeSessionController' => 'PhabricatorAuthController',
'PhabricatorAuthEditController' => 'PhabricatorAuthProviderConfigController',
'PhabricatorAuthEmailLoginAction' => 'PhabricatorSystemAction',
'PhabricatorAuthEmailLoginMessageType' => 'PhabricatorAuthMessageType',
'PhabricatorAuthEmailSetPasswordMessageType' => 'PhabricatorAuthMessageType',
'PhabricatorAuthFactor' => 'Phobject',
'PhabricatorAuthFactorConfig' => array(
'PhabricatorAuthDAO',
@ -8410,7 +8454,10 @@ phutil_register_library_map(array(
'PhabricatorAuthTemporaryTokenTypeModule' => 'PhabricatorConfigModule',
'PhabricatorAuthTerminateSessionController' => 'PhabricatorAuthController',
'PhabricatorAuthTestSMSAction' => 'PhabricatorSystemAction',
'PhabricatorAuthTryEmailLoginAction' => 'PhabricatorSystemAction',
'PhabricatorAuthTryFactorAction' => 'PhabricatorSystemAction',
'PhabricatorAuthTryPasswordAction' => 'PhabricatorSystemAction',
'PhabricatorAuthTryPasswordWithoutCAPTCHAAction' => 'PhabricatorSystemAction',
'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController',
'PhabricatorAuthValidateController' => 'PhabricatorAuthController',
'PhabricatorAuthWaitForApprovalMessageType' => 'PhabricatorAuthMessageType',
@ -8696,6 +8743,7 @@ phutil_register_library_map(array(
'PhabricatorCelerityApplication' => 'PhabricatorApplication',
'PhabricatorCelerityTestCase' => 'PhabricatorTestCase',
'PhabricatorChangeParserTestCase' => 'PhabricatorWorkingCopyTestCase',
'PhabricatorChangePasswordUserLogType' => 'PhabricatorUserLogType',
'PhabricatorChangesetCachePurger' => 'PhabricatorCachePurger',
'PhabricatorChangesetResponse' => 'AphrontProxyResponse',
'PhabricatorChartAxis' => 'Phobject',
@ -8754,7 +8802,9 @@ phutil_register_library_map(array(
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
'PhabricatorConduitApplication' => 'PhabricatorApplication',
'PhabricatorConduitCallManagementWorkflow' => 'PhabricatorConduitManagementWorkflow',
'PhabricatorConduitCertificateFailureUserLogType' => 'PhabricatorUserLogType',
'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
'PhabricatorConduitCertificateUserLogType' => 'PhabricatorUserLogType',
'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
'PhabricatorConduitContentSource' => 'PhabricatorContentSource',
'PhabricatorConduitController' => 'PhabricatorController',
@ -9296,6 +9346,7 @@ phutil_register_library_map(array(
'PhabricatorEmailFormatSetting' => 'PhabricatorSelectSetting',
'PhabricatorEmailFormatSettingsPanel' => 'PhabricatorEditEngineSettingsPanel',
'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
'PhabricatorEmailLoginUserLogType' => 'PhabricatorUserLogType',
'PhabricatorEmailNotificationsSetting' => 'PhabricatorSelectSetting',
'PhabricatorEmailPreferencesSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorEmailRePrefixSetting' => 'PhabricatorSelectSetting',
@ -9309,6 +9360,7 @@ phutil_register_library_map(array(
'PhabricatorEmojiRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorEmojiTranslation' => 'PhutilTranslation',
'PhabricatorEmptyQueryException' => 'Exception',
'PhabricatorEnterHisecUserLogType' => 'PhabricatorUserLogType',
'PhabricatorEnumConfigType' => 'PhabricatorTextConfigType',
'PhabricatorEnv' => 'Phobject',
'PhabricatorEnvTestCase' => 'PhabricatorTestCase',
@ -9321,6 +9373,7 @@ phutil_register_library_map(array(
'PhabricatorExampleEventListener' => 'PhabricatorEventListener',
'PhabricatorExcelExportFormat' => 'PhabricatorExportFormat',
'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource',
'PhabricatorExitHisecUserLogType' => 'PhabricatorUserLogType',
'PhabricatorExportEngine' => 'Phobject',
'PhabricatorExportEngineBulkJobType' => 'PhabricatorWorkerSingleBulkJobType',
'PhabricatorExportEngineExtension' => 'Phobject',
@ -9366,6 +9419,7 @@ phutil_register_library_map(array(
'PhabricatorFactObjectDimension' => 'PhabricatorFactDimension',
'PhabricatorFactRaw' => 'PhabricatorFactDAO',
'PhabricatorFactUpdateIterator' => 'PhutilBufferedIterator',
'PhabricatorFailHisecUserLogType' => 'PhabricatorUserLogType',
'PhabricatorFaviconRef' => 'Phobject',
'PhabricatorFaviconRefQuery' => 'Phobject',
'PhabricatorFavoritesApplication' => 'PhabricatorApplication',
@ -9537,6 +9591,7 @@ phutil_register_library_map(array(
'PhabricatorFlaggableInterface' => 'PhabricatorPHIDInterface',
'PhabricatorFlagsApplication' => 'PhabricatorApplication',
'PhabricatorFlagsUIEventListener' => 'PhabricatorEventListener',
'PhabricatorFullLoginUserLogType' => 'PhabricatorUserLogType',
'PhabricatorFulltextEngine' => 'Phobject',
'PhabricatorFulltextEngineExtension' => 'Phobject',
'PhabricatorFulltextEngineExtensionModule' => 'PhabricatorConfigModule',
@ -9682,7 +9737,10 @@ phutil_register_library_map(array(
'PhabricatorLockLogManagementWorkflow' => 'PhabricatorLockManagementWorkflow',
'PhabricatorLockManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorLogTriggerAction' => 'PhabricatorTriggerAction',
'PhabricatorLoginFailureUserLogType' => 'PhabricatorUserLogType',
'PhabricatorLoginUserLogType' => 'PhabricatorUserLogType',
'PhabricatorLogoutController' => 'PhabricatorAuthController',
'PhabricatorLogoutUserLogType' => 'PhabricatorUserLogType',
'PhabricatorLunarPhasePolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorMacroApplication' => 'PhabricatorApplication',
'PhabricatorMacroAudioBehaviorTransaction' => 'PhabricatorMacroTransactionType',
@ -10162,6 +10220,7 @@ phutil_register_library_map(array(
'PhabricatorPackagesVersionViewController' => 'PhabricatorPackagesVersionController',
'PhabricatorPackagesView' => 'AphrontView',
'PhabricatorPagerUIExample' => 'PhabricatorUIExample',
'PhabricatorPartialLoginUserLogType' => 'PhabricatorUserLogType',
'PhabricatorPassphraseApplication' => 'PhabricatorApplication',
'PhabricatorPasswordAuthProvider' => 'PhabricatorAuthProvider',
'PhabricatorPasswordDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
@ -10224,6 +10283,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleDeleteController' => 'PhabricatorPeopleController',
'PhabricatorPeopleDetailsProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorPeopleDisableController' => 'PhabricatorPeopleController',
'PhabricatorPeopleEmailLoginMailEngine' => 'PhabricatorPeopleMailEngine',
'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController',
'PhabricatorPeopleExternalPHIDType' => 'PhabricatorPHIDType',
'PhabricatorPeopleIconSet' => 'PhabricatorIconSet',
@ -10233,6 +10293,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorPeopleLogViewController' => 'PhabricatorPeopleController',
'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController',
'PhabricatorPeopleMailEngine' => 'Phobject',
'PhabricatorPeopleMailEngineException' => 'Exception',
@ -10381,6 +10442,7 @@ phutil_register_library_map(array(
),
'PhabricatorPolicyType' => 'PhabricatorPolicyConstants',
'PhabricatorPonderApplication' => 'PhabricatorApplication',
'PhabricatorPrimaryEmailUserLogType' => 'PhabricatorUserLogType',
'PhabricatorProfileMenuEditEngine' => 'PhabricatorEditEngine',
'PhabricatorProfileMenuEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorProfileMenuEngine' => 'Phobject',
@ -10421,9 +10483,12 @@ phutil_register_library_map(array(
'PhabricatorProjectArchiveController' => 'PhabricatorProjectController',
'PhabricatorProjectBoardBackgroundController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardController' => 'PhabricatorProjectController',
'PhabricatorProjectBoardDefaultController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardDisableController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardFilterController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardManageController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardReloadController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBuiltinsExample' => 'PhabricatorUIExample',
@ -10440,6 +10505,8 @@ phutil_register_library_map(array(
'PhabricatorConduitResultInterface',
),
'PhabricatorProjectColumnAuthorOrder' => 'PhabricatorProjectColumnOrder',
'PhabricatorProjectColumnBulkEditController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectColumnBulkMoveController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectColumnCreatedOrder' => 'PhabricatorProjectColumnOrder',
'PhabricatorProjectColumnDetailController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectColumnEditController' => 'PhabricatorProjectBoardController',
@ -10469,6 +10536,7 @@ phutil_register_library_map(array(
'PhabricatorProjectColumnTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorProjectColumnTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorProjectColumnTriggerTransaction' => 'PhabricatorProjectColumnTransactionType',
'PhabricatorProjectColumnViewQueryController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorProjectConfiguredCustomField' => array(
'PhabricatorProjectStandardCustomField',
@ -10483,7 +10551,6 @@ phutil_register_library_map(array(
'PhabricatorProjectCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage',
'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
'PhabricatorProjectDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorProjectDefaultController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectDescriptionField' => 'PhabricatorProjectStandardCustomField',
'PhabricatorProjectDetailsProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorProjectDropEffect' => 'Phobject',
@ -10643,6 +10710,7 @@ phutil_register_library_map(array(
'Iterator',
),
'PhabricatorRateLimitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
'PhabricatorReassignEmailUserLogType' => 'PhabricatorUserLogType',
'PhabricatorRebuildIndexesWorker' => 'PhabricatorWorker',
'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorRedirectController' => 'PhabricatorController',
@ -10661,6 +10729,8 @@ phutil_register_library_map(array(
'PhabricatorRemarkupFigletBlockInterpreter' => 'PhutilRemarkupBlockInterpreter',
'PhabricatorRemarkupHyperlinkEngineExtension' => 'PhutilRemarkupHyperlinkEngineExtension',
'PhabricatorRemarkupUIExample' => 'PhabricatorUIExample',
'PhabricatorRemoveEmailUserLogType' => 'PhabricatorUserLogType',
'PhabricatorRemoveMultifactorUserLogType' => 'PhabricatorUserLogType',
'PhabricatorRepositoriesSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorRepository' => array(
'PhabricatorRepositoryDAO',
@ -10868,6 +10938,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryVCSTransaction' => 'PhabricatorRepositoryTransactionType',
'PhabricatorRepositoryWorkingCopyVersion' => 'PhabricatorRepositoryDAO',
'PhabricatorRequestExceptionHandler' => 'AphrontRequestExceptionHandler',
'PhabricatorResetPasswordUserLogType' => 'PhabricatorUserLogType',
'PhabricatorResourceSite' => 'PhabricatorSite',
'PhabricatorRobotsController' => 'PhabricatorController',
'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine',
@ -10976,6 +11047,7 @@ phutil_register_library_map(array(
'PhabricatorShiftChartFunction' => 'PhabricatorChartFunction',
'PhabricatorShortSite' => 'PhabricatorSite',
'PhabricatorShowFiletreeSetting' => 'PhabricatorSelectSetting',
'PhabricatorSignDocumentsUserLogType' => 'PhabricatorUserLogType',
'PhabricatorSimpleEditType' => 'PhabricatorEditType',
'PhabricatorSinChartFunction' => 'PhabricatorChartFunction',
'PhabricatorSite' => 'AphrontSite',
@ -11004,6 +11076,7 @@ phutil_register_library_map(array(
'PhabricatorProjectInterface',
'PhabricatorDestructibleInterface',
'PhabricatorSpacesInterface',
'PhabricatorConduitResultInterface',
),
'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController',
'PhabricatorSlowvotePollPHIDType' => 'PhabricatorPHIDType',
@ -11310,6 +11383,8 @@ phutil_register_library_map(array(
'PhabricatorUserDAO',
'PhabricatorPolicyInterface',
),
'PhabricatorUserLogType' => 'Phobject',
'PhabricatorUserLogTypeDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorUserLogView' => 'AphrontView',
'PhabricatorUserMessageCountCacheType' => 'PhabricatorUserCacheType',
'PhabricatorUserNotificationCountCacheType' => 'PhabricatorUserCacheType',
@ -11345,6 +11420,7 @@ phutil_register_library_map(array(
'PhabricatorUsersPolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorUsersSearchField' => 'PhabricatorSearchTokenizerField',
'PhabricatorVCSResponse' => 'AphrontResponse',
'PhabricatorVerifyEmailUserLogType' => 'PhabricatorUserLogType',
'PhabricatorVersionedDraft' => 'PhabricatorDraftDAO',
'PhabricatorVeryWowEnglishTranslation' => 'PhutilTranslation',
'PhabricatorVideoDocumentEngine' => 'PhabricatorDocumentEngine',
@ -11356,6 +11432,7 @@ phutil_register_library_map(array(
'PhabricatorWeekStartDaySetting' => 'PhabricatorSelectSetting',
'PhabricatorWildConfigType' => 'PhabricatorJSONConfigType',
'PhabricatorWordPressAuthProvider' => 'PhabricatorOAuth2AuthProvider',
'PhabricatorWorkboardViewState' => 'Phobject',
'PhabricatorWorker' => 'Phobject',
'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask',
'PhabricatorWorkerActiveTaskQuery' => 'PhabricatorWorkerTaskQuery',
@ -11437,6 +11514,7 @@ phutil_register_library_map(array(
'PhabricatorXHProfSampleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorXHProfSampleSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorYoutubeRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorZipSetupCheck' => 'PhabricatorSetupCheck',
'Phame404Response' => 'AphrontHTMLResponse',
'PhameBlog' => array(
'PhameDAO',
@ -12145,6 +12223,7 @@ phutil_register_library_map(array(
'SlowvoteEmbedView' => 'AphrontView',
'SlowvoteInfoConduitAPIMethod' => 'SlowvoteConduitAPIMethod',
'SlowvoteRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'SlowvoteSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'SubscriptionListDialogBuilder' => 'Phobject',
'SubscriptionListStringBuilder' => 'Phobject',
'TokenConduitAPIMethod' => 'ConduitAPIMethod',

View file

@ -5,10 +5,6 @@ final class PhabricatorAuthChangePasswordAction
const TYPECONST = 'auth.password';
public function getActionConstant() {
return self::TYPECONST;
}
public function getScoreThreshold() {
return 20 / phutil_units('1 hour in seconds');
}

View file

@ -0,0 +1,17 @@
<?php
final class PhabricatorAuthEmailLoginAction extends PhabricatorSystemAction {
const TYPECONST = 'mail.login';
public function getScoreThreshold() {
return 3 / phutil_units('1 hour in seconds');
}
public function getLimitExplanation() {
return pht(
'Too many account recovery email links have been sent to this account '.
'in a short period of time.');
}
}

View file

@ -4,10 +4,6 @@ final class PhabricatorAuthNewFactorAction extends PhabricatorSystemAction {
const TYPECONST = 'auth.factor.new';
public function getActionConstant() {
return self::TYPECONST;
}
public function getScoreThreshold() {
return 60 / phutil_units('1 hour in seconds');
}

View file

@ -4,10 +4,6 @@ final class PhabricatorAuthTestSMSAction extends PhabricatorSystemAction {
const TYPECONST = 'auth.sms.test';
public function getActionConstant() {
return self::TYPECONST;
}
public function getScoreThreshold() {
return 60 / phutil_units('1 hour in seconds');
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorAuthTryEmailLoginAction
extends PhabricatorSystemAction {
const TYPECONST = 'mail.try-login';
public function getScoreThreshold() {
return 20 / phutil_units('1 hour in seconds');
}
public function getLimitExplanation() {
return pht(
'You have made too many account recovery requests in a short period '.
'of time.');
}
}

View file

@ -4,10 +4,6 @@ final class PhabricatorAuthTryFactorAction extends PhabricatorSystemAction {
const TYPECONST = 'auth.factor';
public function getActionConstant() {
return self::TYPECONST;
}
public function getScoreThreshold() {
return 10 / phutil_units('1 hour in seconds');
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorAuthTryPasswordAction
extends PhabricatorSystemAction {
const TYPECONST = 'auth.password';
public function getScoreThreshold() {
return 100 / phutil_units('1 hour in seconds');
}
public function getLimitExplanation() {
return pht(
'Your remote address has made too many login attempts in a short '.
'period of time.');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorAuthTryPasswordWithoutCAPTCHAAction
extends PhabricatorSystemAction {
const TYPECONST = 'auth.password-without-captcha';
public function getScoreThreshold() {
return 10 / phutil_units('1 hour in seconds');
}
}

View file

@ -108,7 +108,7 @@ final class PhabricatorAuthApplication extends PhabricatorApplication {
'PhabricatorAuthMessageListController',
$this->getEditRoutePattern('edit/') =>
'PhabricatorAuthMessageEditController',
'(?P<id>[1-9]\d*)/' =>
'(?P<id>[^/]+)/' =>
'PhabricatorAuthMessageViewController',
),

View file

@ -53,6 +53,14 @@ final class PhabricatorEmailLoginController
// it expensive to fish for valid email addresses while giving the user
// a better error if they goof their email.
$action_actor = PhabricatorSystemActionEngine::newActorFromRequest(
$request);
PhabricatorSystemActionEngine::willTakeAction(
array($action_actor),
new PhabricatorAuthTryEmailLoginAction(),
1);
$target_email = id(new PhabricatorUserEmail())->loadOneWhere(
'address = %s',
$v_email);
@ -94,29 +102,40 @@ final class PhabricatorEmailLoginController
}
if (!$errors) {
$body = $this->newAccountLoginMailBody(
$target_user,
$is_logged_in);
$target_address = new PhutilEmailAddress($target_email->getAddress());
$user_log = PhabricatorUserLog::initializeNewLog(
$viewer,
$target_user->getPHID(),
PhabricatorEmailLoginUserLogType::LOGTYPE);
$mail_engine = id(new PhabricatorPeopleEmailLoginMailEngine())
->setSender($viewer)
->setRecipient($target_user)
->setRecipientAddress($target_address)
->setActivityLog($user_log);
try {
$mail_engine->validateMail();
} catch (PhabricatorPeopleMailEngineException $ex) {
return $this->newDialog()
->setTitle($ex->getTitle())
->appendParagraph($ex->getBody())
->addCancelButton('/auth/start/', pht('Done'));
}
$mail_engine->sendMail();
if ($is_logged_in) {
$subject = pht('[Phabricator] Account Password Link');
$instructions = pht(
'An email has been sent containing a link you can use to set '.
'a password for your account.');
} else {
$subject = pht('[Phabricator] Account Login Link');
$instructions = pht(
'An email has been sent containing a link you can use to log '.
'in to your account.');
}
$mail = id(new PhabricatorMetaMTAMail())
->setSubject($subject)
->setForceDelivery(true)
->addRawTos(array($target_email->getAddress()))
->setBody($body)
->saveAndSend();
return $this->newDialog()
->setTitle(pht('Check Your Email'))
->setShortTitle(pht('Email Sent'))
@ -182,55 +201,6 @@ final class PhabricatorEmailLoginController
->addSubmitButton(pht('Send Email'));
}
private function newAccountLoginMailBody(
PhabricatorUser $user,
$is_logged_in) {
$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_logged_in) {
$body = pht(
'You can use this link to set a password on your account:'.
"\n\n %s\n",
$uri);
} else 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();
}

View file

@ -79,6 +79,7 @@ final class PhabricatorAuthEditController
}
$errors = array();
$validation_exception = null;
$v_login = $config->getShouldAllowLogin();
$v_registration = $config->getShouldAllowRegistration();
@ -153,12 +154,16 @@ final class PhabricatorAuthEditController
$editor = id(new PhabricatorAuthProviderConfigEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->applyTransactions($config, $xactions);
->setContinueOnNoEffect(true);
$next_uri = $config->getURI();
try {
$editor->applyTransactions($config, $xactions);
$next_uri = $config->getURI();
return id(new AphrontRedirectResponse())->setURI($next_uri);
return id(new AphrontRedirectResponse())->setURI($next_uri);
} catch (Exception $ex) {
$validation_exception = $ex;
}
}
} else {
$properties = $provider->readFormValuesFromProvider();
@ -325,12 +330,35 @@ final class PhabricatorAuthEditController
$provider->extendEditForm($request, $form, $properties, $issues);
$locked_config_key = 'auth.lock-config';
$is_locked = PhabricatorEnv::getEnvConfig($locked_config_key);
$locked_warning = null;
if ($is_locked && !$validation_exception) {
$message = pht(
'Authentication provider configuration is locked, and can not be '.
'changed without being unlocked. See the configuration setting %s '.
'for details.',
phutil_tag(
'a',
array(
'href' => '/config/edit/'.$locked_config_key,
),
$locked_config_key));
$locked_warning = id(new PHUIInfoView())
->setViewer($viewer)
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors(array($message));
}
$form
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri)
->setDisabled($is_locked)
->setValue($button));
$help = $provider->getConfigurationHelp();
if ($help) {
$form->appendChild(id(new PHUIFormDividerControl()));
@ -346,12 +374,16 @@ final class PhabricatorAuthEditController
$form_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Provider'))
->setFormErrors($errors)
->setValidationException($validation_exception)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$locked_warning,
$form_box,
$footer,
));

View file

@ -78,12 +78,14 @@ final class PhabricatorAuthListController
->setGuidanceContext($guidance_context)
->newInfoView();
$is_disabled = (!$can_manage || $is_locked);
$button = id(new PHUIButtonView())
->setTag('a')
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
->setHref($this->getApplicationURI('config/new/'))
->setIcon('fa-plus')
->setDisabled(!$can_manage || $is_locked)
->setDisabled($is_disabled)
->setWorkflow($is_disabled)
->setHref($this->getApplicationURI('config/new/'))
->setText(pht('Add Provider'));
$list->setFlush(true);

View file

@ -9,6 +9,27 @@ final class PhabricatorAuthNewController
$viewer = $this->getViewer();
$cancel_uri = $this->getApplicationURI();
$locked_config_key = 'auth.lock-config';
$is_locked = PhabricatorEnv::getEnvConfig($locked_config_key);
if ($is_locked) {
$message = pht(
'Authentication provider configuration is locked, and can not be '.
'changed without being unlocked. See the configuration setting %s '.
'for details.',
phutil_tag(
'a',
array(
'href' => '/config/edit/'.$locked_config_key,
),
$locked_config_key));
return $this->newDialog()
->setUser($viewer)
->setTitle(pht('Authentication Config Locked'))
->appendChild($message)
->addCancelButton($cancel_uri);
}
$providers = PhabricatorAuthProvider::getAllBaseProviders();

View file

@ -114,6 +114,86 @@ final class PhabricatorAuthProviderViewController
pht('Provider Type'),
$config->getProvider()->getProviderName());
$status = $this->buildStatus($config);
$view->addProperty(pht('Status'), $status);
return $view;
}
private function buildStatus(PhabricatorAuthProviderConfig $config) {
$viewer = $this->getViewer();
$view = id(new PHUIStatusListView())
->setViewer($viewer);
$icon_enabled = PHUIStatusItemView::ICON_ACCEPT;
$icon_disabled = PHUIStatusItemView::ICON_REJECT;
$icon_map = array(
true => $icon_enabled,
false => $icon_disabled,
);
$color_map = array(
true => 'green',
false => 'red',
);
$provider = $config->getProvider();
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(
$icon_map[$config->getIsEnabled()],
$color_map[$config->getIsEnabled()])
->setTarget(pht('Provider Enabled')));
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(
$icon_map[$config->getShouldAllowLogin()],
$color_map[$config->getShouldAllowLogin()])
->setTarget(pht('Allow Logins')));
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(
$icon_map[$config->getShouldAllowRegistration()],
$color_map[$config->getShouldAllowRegistration()])
->setTarget(pht('Allow Registration')));
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(
$icon_map[$config->getShouldAllowLink()],
$color_map[$config->getShouldAllowLink()])
->setTarget(pht('Allow Account Linking')));
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(
$icon_map[$config->getShouldAllowUnlink()],
$color_map[$config->getShouldAllowUnlink()])
->setTarget(pht('Allow Account Unlinking')));
if ($provider->shouldAllowEmailTrustConfiguration()) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(
$icon_map[$config->getShouldTrustEmails()],
$color_map[$config->getShouldTrustEmails()])
->setTarget(pht('Trust Email Addresses')));
}
if ($provider->supportsAutoLogin()) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(
$icon_map[$config->getShouldAutoLogin()],
$color_map[$config->getShouldAutoLogin()])
->setTarget(pht('Allow Auto Login')));
}
return $view;
}
}

View file

@ -19,11 +19,14 @@ final class PhabricatorAuthMessageListController
$list = new PHUIObjectItemListView();
foreach ($types as $type) {
$message = idx($messages, $type->getMessageTypeKey());
if ($message) {
$href = $message->getURI();
$name = $message->getMessageTypeDisplayName();
} else {
$href = '/auth/message/edit/?messageKey='.$type->getMessageTypeKey();
$href = urisprintf(
'/auth/message/%s/',
$type->getMessageTypeKey());
$name = $type->getDisplayName();
}

View file

@ -9,26 +9,61 @@ final class PhabricatorAuthMessageViewController
$this->requireApplicationCapability(
AuthManageProvidersCapability::CAPABILITY);
$message = id(new PhabricatorAuthMessageQuery())
->setViewer($viewer)
->withIDs(array($request->getURIData('id')))
->executeOne();
if (!$message) {
return new Aphront404Response();
// The "id" in the URI may either be an actual storage record ID (if a
// message has already been created) or a message type key (for a message
// type which does not have a record yet).
// This flow allows messages which have not been set yet to have a detail
// page (so users can get detailed information about the message and see
// any default value).
$id = $request->getURIData('id');
if (ctype_digit($id)) {
$message = id(new PhabricatorAuthMessageQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$message) {
return new Aphront404Response();
}
} else {
$types = PhabricatorAuthMessageType::getAllMessageTypes();
if (!isset($types[$id])) {
return new Aphront404Response();
}
// If this message type already has a storage record, redirect to the
// canonical page for the record.
$message = id(new PhabricatorAuthMessageQuery())
->setViewer($viewer)
->withMessageKeys(array($id))
->executeOne();
if ($message) {
$message_uri = $message->getURI();
return id(new AphrontRedirectResponse())->setURI($message_uri);
}
// Otherwise, create an empty placeholder message object with the
// appropriate message type.
$message = PhabricatorAuthMessage::initializeNewMessage($types[$id]);
}
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($message->getObjectName())
->addTextCrumb($message->getMessageType()->getDisplayName())
->setBorder(true);
$header = $this->buildHeaderView($message);
$properties = $this->buildPropertiesView($message);
$curtain = $this->buildCurtain($message);
$timeline = $this->buildTransactionTimeline(
$message,
new PhabricatorAuthMessageTransactionQuery());
$timeline->setShouldTerminate(true);
if ($message->getID()) {
$timeline = $this->buildTransactionTimeline(
$message,
new PhabricatorAuthMessageTransactionQuery());
$timeline->setShouldTerminate(true);
} else {
$timeline = null;
}
$view = id(new PHUITwoColumnView())
->setHeader($header)
@ -62,19 +97,36 @@ final class PhabricatorAuthMessageViewController
private function buildPropertiesView(PhabricatorAuthMessage $message) {
$viewer = $this->getViewer();
$message_type = $message->getMessageType();
$view = id(new PHUIPropertyListView())
->setViewer($viewer);
$view->addProperty(
pht('Description'),
$message->getMessageType()->getShortDescription());
$full_description = $message_type->getFullDescription();
if (strlen($full_description)) {
$view->addTextContent(new PHUIRemarkupView($viewer, $full_description));
} else {
$short_description = $message_type->getShortDescription();
$view->addProperty(pht('Description'), $short_description);
}
$view->addSectionHeader(
pht('Message Preview'),
PHUIPropertyListView::ICON_SUMMARY);
$message_text = $message->getMessageText();
if (strlen($message_text)) {
$view->addSectionHeader(
pht('Message Preview'),
PHUIPropertyListView::ICON_SUMMARY);
$view->addTextContent(
new PHUIRemarkupView($viewer, $message->getMessageText()));
$view->addTextContent(new PHUIRemarkupView($viewer, $message_text));
}
$default_text = $message_type->getDefaultMessageText();
if (strlen($default_text)) {
$view->addSectionHeader(
pht('Default Message'),
PHUIPropertyListView::ICON_SUMMARY);
$view->addTextContent(new PHUIRemarkupView($viewer, $default_text));
}
return $view;
}
@ -88,13 +140,27 @@ final class PhabricatorAuthMessageViewController
$message,
PhabricatorPolicyCapability::CAN_EDIT);
if ($id) {
$edit_uri = urisprintf('message/edit/%s/', $id);
$edit_name = pht('Edit Message');
} else {
$edit_uri = urisprintf('message/edit/');
$params = array(
'messageKey' => $message->getMessageKey(),
);
$edit_uri = new PhutilURI($edit_uri, $params);
$edit_name = pht('Customize Message');
}
$edit_uri = $this->getApplicationURI($edit_uri);
$curtain = $this->newCurtainView($message);
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Message'))
->setName($edit_name)
->setIcon('fa-pencil')
->setHref($this->getApplicationURI("message/edit/{$id}/"))
->setHref($edit_uri)
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));

View file

@ -125,4 +125,25 @@ final class PhabricatorAuthProviderConfigEditor
return parent::mergeTransactions($u, $v);
}
protected function validateAllTransactions(
PhabricatorLiskDAO $object,
array $xactions) {
$errors = parent::validateAllTransactions($object, $xactions);
$locked_config_key = 'auth.lock-config';
$is_locked = PhabricatorEnv::getEnvConfig($locked_config_key);
if ($is_locked) {
$errors[] = new PhabricatorApplicationTransactionValidationError(
null,
pht('Config Locked'),
pht('Authentication provider configuration is locked, and can not be '.
'changed without being unlocked.'),
null);
}
return $errors;
}
}

View file

@ -294,8 +294,8 @@ final class PhabricatorAuthSessionEngine extends Phobject {
null,
$identity_phid,
($partial
? PhabricatorUserLog::ACTION_LOGIN_PARTIAL
: PhabricatorUserLog::ACTION_LOGIN));
? PhabricatorPartialLoginUserLogType::LOGTYPE
: PhabricatorLoginUserLogType::LOGTYPE));
$log->setDetails(
array(
@ -366,7 +366,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$log = PhabricatorUserLog::initializeNewLog(
$user,
$user->getPHID(),
PhabricatorUserLog::ACTION_LOGOUT);
PhabricatorLogoutUserLogType::LOGTYPE);
$log->save();
$extensions = PhabricatorAuthSessionEngineExtension::getAllExtensions();
@ -688,13 +688,13 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$log = PhabricatorUserLog::initializeNewLog(
$viewer,
$viewer->getPHID(),
PhabricatorUserLog::ACTION_ENTER_HISEC);
PhabricatorEnterHisecUserLogType::LOGTYPE);
$log->save();
} else {
$log = PhabricatorUserLog::initializeNewLog(
$viewer,
$viewer->getPHID(),
PhabricatorUserLog::ACTION_FAIL_HISEC);
PhabricatorFailHisecUserLogType::LOGTYPE);
$log->save();
}
}
@ -831,7 +831,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$log = PhabricatorUserLog::initializeNewLog(
$viewer,
$viewer->getPHID(),
PhabricatorUserLog::ACTION_EXIT_HISEC);
PhabricatorExitHisecUserLogType::LOGTYPE);
$log->save();
}
@ -872,7 +872,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$log = PhabricatorUserLog::initializeNewLog(
$viewer,
$viewer->getPHID(),
PhabricatorUserLog::ACTION_LOGIN_FULL);
PhabricatorFullLoginUserLogType::LOGTYPE);
$log->save();
unset($unguarded);
}
@ -917,7 +917,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$log = PhabricatorUserLog::initializeNewLog(
$viewer,
$viewer->getPHID(),
PhabricatorUserLog::ACTION_LOGIN_LEGALPAD);
PhabricatorSignDocumentsUserLogType::LOGTYPE);
$log->save();
}
unset($unguarded);

View file

@ -0,0 +1,41 @@
<?php
final class PhabricatorAuthEmailLoginMessageType
extends PhabricatorAuthMessageType {
const MESSAGEKEY = 'mail.login';
public function getDisplayName() {
return pht('Mail Body: Email Login');
}
public function getShortDescription() {
return pht(
'Guidance in the message body when users request an email link '.
'to access their account.');
}
public function getFullDescription() {
return pht(
'Guidance included in the mail message body when users request an '.
'email link to access their account.'.
"\n\n".
'For installs with password authentication enabled, users access this '.
'workflow by using the "Forgot your password?" link on the login '.
'screen.'.
"\n\n".
'For installs without password authentication enabled, users access '.
'this workflow by using the "Send a login link to your email address." '.
'link on the login screen. This workflow allows users to recover '.
'access to their account if there is an issue with an external '.
'login service.');
}
public function getDefaultMessageText() {
return pht(
'You (or someone pretending to be you) recently requested an account '.
'recovery link be sent to this email address. If you did not make '.
'this request, you can ignore this message.');
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorAuthEmailSetPasswordMessageType
extends PhabricatorAuthMessageType {
const MESSAGEKEY = 'mail.set-password';
public function getDisplayName() {
return pht('Mail Body: Set Password');
}
public function getShortDescription() {
return pht(
'Guidance in the message body when users set a password on an account '.
'which did not previously have a password.');
}
}

View file

@ -28,5 +28,14 @@ abstract class PhabricatorAuthMessageType
}
abstract public function getDisplayName();
abstract public function getShortDescription();
public function getFullDescription() {
return null;
}
public function getDefaultMessageText() {
return null;
}
}

View file

@ -6,7 +6,7 @@ final class PhabricatorAuthWelcomeMailMessageType
const MESSAGEKEY = 'mail.welcome';
public function getDisplayName() {
return pht('Welcome Email Body');
return pht('Mail Body: Welcome');
}
public function getShortDescription() {

View file

@ -255,48 +255,29 @@ final class PhabricatorPasswordAuthProvider extends PhabricatorAuthProvider {
$viewer = $request->getUser();
$content_source = PhabricatorContentSource::newFromRequest($request);
$captcha_limit = 5;
$hard_limit = 32;
$limit_window = phutil_units('15 minutes in seconds');
$rate_actor = PhabricatorSystemActionEngine::newActorFromRequest($request);
$failed_attempts = PhabricatorUserLog::loadRecentEventsFromThisIP(
PhabricatorUserLog::ACTION_LOGIN_FAILURE,
$limit_window);
PhabricatorSystemActionEngine::willTakeAction(
array($rate_actor),
new PhabricatorAuthTryPasswordAction(),
1);
// If the same remote address has submitted several failed login attempts
// recently, require they provide a CAPTCHA response for new attempts.
$require_captcha = false;
$captcha_valid = false;
if (AphrontFormRecaptchaControl::isRecaptchaEnabled()) {
if (count($failed_attempts) > $captcha_limit) {
try {
PhabricatorSystemActionEngine::willTakeAction(
array($rate_actor),
new PhabricatorAuthTryPasswordWithoutCAPTCHAAction(),
1);
} catch (PhabricatorSystemActionRateLimitException $ex) {
$require_captcha = true;
$captcha_valid = AphrontFormRecaptchaControl::processCaptcha($request);
}
}
// If the user has submitted quite a few failed login attempts recently,
// give them a hard limit.
if (count($failed_attempts) > $hard_limit) {
$guidance = array();
$guidance[] = pht(
'Your remote address has failed too many login attempts recently. '.
'Wait a few minutes before trying again.');
$guidance[] = pht(
'If you are unable to log in to your account, you can '.
'[[ /login/email | send a reset link to your email address ]].');
$guidance = implode("\n\n", $guidance);
$dialog = $controller->newDialog()
->setTitle(pht('Too Many Login Attempts'))
->appendChild(new PHUIRemarkupView($viewer, $guidance))
->addCancelButton('/auth/start/', pht('Wait Patiently'));
return array(null, $dialog);
}
$response = null;
$account = null;
$log_user = null;
@ -337,7 +318,7 @@ final class PhabricatorPasswordAuthProvider extends PhabricatorAuthProvider {
$log = PhabricatorUserLog::initializeNewLog(
null,
$log_user ? $log_user->getPHID() : null,
PhabricatorUserLog::ACTION_LOGIN_FAILURE);
PhabricatorLoginFailureUserLogType::LOGTYPE);
$log->save();
}

View file

@ -45,7 +45,7 @@ final class PhabricatorAuthMessage
}
public function getURI() {
return urisprintf('/auth/message/%s', $this->getID());
return urisprintf('/auth/message/%s/', $this->getID());
}
public function attachMessageType(PhabricatorAuthMessageType $type) {
@ -75,12 +75,16 @@ final class PhabricatorAuthMessage
$message_key) {
$message = self::loadMessage($viewer, $message_key);
if (!$message) {
return null;
if ($message) {
$message_text = $message->getMessageText();
if (strlen($message_text)) {
return $message_text;
}
}
return $message->getMessageText();
$message_type = PhabricatorAuthMessageType::newFromKey($message_key);
return $message_type->getDefaultMessageText();
}

View file

@ -14,15 +14,8 @@ final class PhabricatorAuthProviderConfigTransaction
const PROPERTY_KEY = 'auth:property';
private $provider;
public function setProvider(PhabricatorAuthProvider $provider) {
$this->provider = $provider;
return $this;
}
public function getProvider() {
return $this->provider;
return $this->getObject()->getProvider();
}
public function getApplicationName() {

View file

@ -41,7 +41,7 @@ final class ConduitGetCertificateConduitAPIMethod extends ConduitAPIMethod {
protected function execute(ConduitAPIRequest $request) {
$failed_attempts = PhabricatorUserLog::loadRecentEventsFromThisIP(
PhabricatorUserLog::ACTION_CONDUIT_CERTIFICATE_FAILURE,
PhabricatorConduitCertificateFailureUserLogType::LOGTYPE,
60 * 5);
if (count($failed_attempts) > 5) {
@ -61,7 +61,7 @@ final class ConduitGetCertificateConduitAPIMethod extends ConduitAPIMethod {
$log = PhabricatorUserLog::initializeNewLog(
$request->getUser(),
$info->getUserPHID(),
PhabricatorUserLog::ACTION_CONDUIT_CERTIFICATE)
PhabricatorConduitCertificateUserLogType::LOGTYPE)
->save();
}
@ -85,7 +85,7 @@ final class ConduitGetCertificateConduitAPIMethod extends ConduitAPIMethod {
$log = PhabricatorUserLog::initializeNewLog(
$request->getUser(),
$info ? $info->getUserPHID() : '-',
PhabricatorUserLog::ACTION_CONDUIT_CERTIFICATE_FAILURE)
PhabricatorConduitCertificateFailureUserLogType::LOGTYPE)
->save();
}

View file

@ -0,0 +1,29 @@
<?php
final class PhabricatorZipSetupCheck extends PhabricatorSetupCheck {
public function getDefaultGroup() {
return self::GROUP_OTHER;
}
protected function executeChecks() {
if (!extension_loaded('zip')) {
$message = pht(
'The PHP "zip" extension is not installed. This extension is '.
'required by certain data export operations, including exporting '.
'data to Excel.'.
"\n\n".
'To clear this setup issue, install the extension and restart your '.
'webserver.'.
"\n\n".
'You may safely ignore this issue if you do not plan to export '.
'data in Zip archives or Excel spreadsheets, or intend to install '.
'the extension later.');
$this->newIssue('extension.zip')
->setName(pht('Missing "zip" Extension'))
->setMessage($message)
->addPHPExtension('zip');
}
}
}

View file

@ -22,7 +22,7 @@ final class PhabricatorDaemonManagementStatusWorkflow
'instance ("%s").',
$instance));
} else {
$this->writeInfo(
$this->logInfo(
pht('NO DAEMONS'),
pht('There are no running daemon processes.'));
}

View file

@ -7,17 +7,6 @@ abstract class DiffusionQueryConduitAPIMethod
return true;
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodStatusDescription() {
return pht(
'See T2784 - migrating Diffusion working copy calls to conduit methods. '.
'Until that task is completed (and possibly after) these methods are '.
'unstable.');
}
private $diffusionRequest;
private $repository;

View file

@ -5,10 +5,6 @@ final class PhabricatorFilesOutboundRequestAction
const TYPECONST = 'files.outbound';
public function getActionConstant() {
return self::TYPECONST;
}
public function getScoreThreshold() {
return 60 / phutil_units('1 hour in seconds');
}

View file

@ -6,6 +6,7 @@ final class PhabricatorFlagQuery
const GROUP_COLOR = 'color';
const GROUP_NONE = 'none';
private $ids;
private $ownerPHIDs;
private $types;
private $objectPHIDs;
@ -15,6 +16,11 @@ final class PhabricatorFlagQuery
private $needHandles;
private $needObjects;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withOwnerPHIDs(array $owner_phids) {
$this->ownerPHIDs = $owner_phids;
return $this;
@ -126,6 +132,13 @@ final class PhabricatorFlagQuery
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
$where = array();
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'flag.id IN (%Ld)',
$this->ids);
}
if ($this->ownerPHIDs) {
$where[] = qsprintf(
$conn,

View file

@ -24,26 +24,27 @@ final class HarbormasterBuildableActionController
$issuable = array();
foreach ($buildable->getBuilds() as $build) {
$builds = $buildable->getBuilds();
foreach ($builds as $key => $build) {
switch ($action) {
case HarbormasterBuildCommand::COMMAND_RESTART:
if ($build->canRestartBuild()) {
$issuable[] = $build;
$issuable[$key] = $build;
}
break;
case HarbormasterBuildCommand::COMMAND_PAUSE:
if ($build->canPauseBuild()) {
$issuable[] = $build;
$issuable[$key] = $build;
}
break;
case HarbormasterBuildCommand::COMMAND_RESUME:
if ($build->canResumeBuild()) {
$issuable[] = $build;
$issuable[$key] = $build;
}
break;
case HarbormasterBuildCommand::COMMAND_ABORT:
if ($build->canAbortBuild()) {
$issuable[] = $build;
$issuable[$key] = $build;
}
break;
default:
@ -59,6 +60,14 @@ final class HarbormasterBuildableActionController
}
}
$building = false;
foreach ($issuable as $key => $build) {
if ($build->isBuilding()) {
$building = true;
break;
}
}
$return_uri = '/'.$buildable->getMonogram();
if ($request->isDialogFormPost() && $issuable) {
$editor = id(new HarbormasterBuildableTransactionEditor())
@ -89,34 +98,137 @@ final class HarbormasterBuildableActionController
return id(new AphrontRedirectResponse())->setURI($return_uri);
}
$width = AphrontDialogView::WIDTH_DEFAULT;
switch ($action) {
case HarbormasterBuildCommand::COMMAND_RESTART:
// See T13348. The "Restart Builds" action may restart only a subset
// of builds, so show the user a preview of which builds will actually
// restart.
$body = array();
if ($issuable) {
$title = pht('Really restart builds?');
if ($restricted) {
$body = pht(
'You only have permission to restart some builds. Progress '.
'on builds you have permission to restart will be discarded '.
'and they will restart. Side effects of these builds will '.
'occur again. Really restart all builds?');
} else {
$body = pht(
'Progress on all builds will be discarded, and all builds will '.
'restart. Side effects of the builds will occur again. Really '.
'restart all builds?');
}
$title = pht('Restart Builds');
$submit = pht('Restart Builds');
} else {
$title = pht('Unable to Restart Builds');
}
if ($builds) {
$width = AphrontDialogView::WIDTH_FORM;
$body[] = pht('Builds for this buildable:');
$rows = array();
foreach ($builds as $key => $build) {
if (isset($issuable[$key])) {
$icon = id(new PHUIIconView())
->setIcon('fa-repeat green');
$build_note = pht('Will Restart');
} else {
$icon = null;
try {
$build->assertCanRestartBuild();
} catch (HarbormasterRestartException $ex) {
$icon = id(new PHUIIconView())
->setIcon('fa-times red');
$build_note = pht(
'%s: %s',
phutil_tag('strong', array(), pht('Not Restartable')),
$ex->getTitle());
}
if (!$icon) {
try {
$build->assertCanIssueCommand($viewer, $action);
} catch (PhabricatorPolicyException $ex) {
$icon = id(new PHUIIconView())
->setIcon('fa-lock red');
$build_note = pht(
'%s: %s',
phutil_tag('strong', array(), pht('Not Restartable')),
pht('You do not have permission to restart this build.'));
}
}
if (!$icon) {
$icon = id(new PHUIIconView())
->setIcon('fa-times red');
$build_note = pht('Will Not Restart');
}
}
$build_name = phutil_tag(
'a',
array(
'href' => $build->getURI(),
'target' => '_blank',
),
pht('%s %s', $build->getObjectName(), $build->getName()));
$rows[] = array(
$icon,
$build_name,
$build_note,
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
null,
pht('Build'),
pht('Action'),
))
->setColumnClasses(
array(
null,
'pri',
'wide',
));
$table = phutil_tag(
'div',
array(
'class' => 'mlt mlb',
),
$table);
$body[] = $table;
}
if ($issuable) {
$warnings = array();
if ($restricted) {
$body = pht('You do not have permission to restart any builds.');
$warnings[] = pht(
'You only have permission to restart some builds.');
}
if ($building) {
$warnings[] = pht(
'Progress on running builds will be discarded.');
}
$warnings[] = pht(
'When a build is restarted, side effects associated with '.
'the build may occur again.');
$body[] = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors($warnings);
$body[] = pht('Really restart builds?');
} else {
if ($restricted) {
$body[] = pht('You do not have permission to restart any builds.');
} else {
$body = pht('No builds can be restarted.');
$body[] = pht('No builds can be restarted.');
}
}
break;
case HarbormasterBuildCommand::COMMAND_PAUSE:
if ($issuable) {
@ -193,6 +305,7 @@ final class HarbormasterBuildableActionController
$dialog = id(new AphrontDialogView())
->setUser($viewer)
->setWidth($width)
->setTitle($title)
->appendChild($body)
->addCancelButton($return_uri);

View file

@ -128,7 +128,7 @@ final class HarbormasterBuildableViewController
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-repeat')
->setName(pht('Restart All Builds'))
->setName(pht('Restart Builds'))
->setHref($this->getApplicationURI($restart_uri))
->setWorkflow(true)
->setDisabled(!$can_restart || !$can_edit));
@ -136,7 +136,7 @@ final class HarbormasterBuildableViewController
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-pause')
->setName(pht('Pause All Builds'))
->setName(pht('Pause Builds'))
->setHref($this->getApplicationURI($pause_uri))
->setWorkflow(true)
->setDisabled(!$can_pause || !$can_edit));
@ -144,7 +144,7 @@ final class HarbormasterBuildableViewController
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-play')
->setName(pht('Resume All Builds'))
->setName(pht('Resume Builds'))
->setHref($this->getApplicationURI($resume_uri))
->setWorkflow(true)
->setDisabled(!$can_resume || !$can_edit));
@ -152,7 +152,7 @@ final class HarbormasterBuildableViewController
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-exclamation-triangle')
->setName(pht('Abort All Builds'))
->setName(pht('Abort Builds'))
->setHref($this->getApplicationURI($abort_uri))
->setWorkflow(true)
->setDisabled(!$can_abort || !$can_edit));

View file

@ -434,7 +434,7 @@ EODOCS
$engine = id(new PhabricatorBoardResponseEngine())
->setViewer($viewer)
->setBoardPHID($board_phid)
->setObjectPHID($object_phid)
->setUpdatePHIDs(array($object_phid))
->setVisiblePHIDs($visible_phids);
if ($ordering) {

View file

@ -3,6 +3,7 @@
final class ManiphestTransactionEditor
extends PhabricatorApplicationTransactionEditor {
private $oldProjectPHIDs;
private $moreValidationErrors = array();
public function getEditorApplicationClass() {
@ -378,6 +379,11 @@ final class ManiphestTransactionEditor
}
}
$send_notifications = PhabricatorNotificationClient::isEnabled();
if ($send_notifications) {
$this->oldProjectPHIDs = $this->loadProjectPHIDs($object);
}
return $results;
}
@ -859,4 +865,69 @@ final class ManiphestTransactionEditor
return array_values($phid_list);
}
protected function didApplyTransactions($object, array $xactions) {
$send_notifications = PhabricatorNotificationClient::isEnabled();
if ($send_notifications) {
$old_phids = $this->oldProjectPHIDs;
$new_phids = $this->loadProjectPHIDs($object);
// We want to emit update notifications for all old and new tagged
// projects, and all parents of those projects. For example, if an
// edit removes project "A > B" from a task, the "A" workboard should
// receive an update event.
$project_phids = array_fuse($old_phids) + array_fuse($new_phids);
$project_phids = array_keys($project_phids);
$projects = id(new PhabricatorProjectQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs($project_phids)
->execute();
$notify_projects = array();
foreach ($projects as $project) {
$notify_projects[$project->getPHID()] = $project;
foreach ($project->getAncestorProjects() as $ancestor) {
$notify_projects[$ancestor->getPHID()] = $ancestor;
}
}
foreach ($notify_projects as $key => $project) {
if (!$project->getHasWorkboard()) {
unset($notify_projects[$key]);
}
}
$notify_phids = array_keys($notify_projects);
if ($notify_phids) {
$data = array(
'type' => 'workboards',
'subscribers' => $notify_phids,
);
PhabricatorNotificationClient::tryToPostMessage($data);
}
}
return $xactions;
}
private function loadProjectPHIDs(ManiphestTask $task) {
if (!$task->getPHID()) {
return array();
}
$edge_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(array($task->getPHID()))
->withEdgeTypes(
array(
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
));
$edge_query->execute();
return $edge_query->getDestinationPHIDs();
}
}

View file

@ -2,9 +2,7 @@
final class PhabricatorMetaMTAErrorMailAction extends PhabricatorSystemAction {
public function getActionConstant() {
return 'email.error';
}
const TYPECONST = 'email.error';
public function getScoreThreshold() {
return 6 / phutil_units('1 hour in seconds');

View file

@ -37,4 +37,8 @@ final class PhabricatorNotificationClient extends Phobject {
}
}
public static function isEnabled() {
return (bool)PhabricatorNotificationServerRef::getEnabledAdminServers();
}
}

View file

@ -15,12 +15,11 @@ final class PhabricatorOAuthClientViewController
}
$header = $this->buildHeaderView($client);
$actions = $this->buildActionView($client);
$properties = $this->buildPropertyListView($client);
$properties->setActionList($actions);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($client->getName());
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($client->getName())
->setBorder(true);
$timeline = $this->buildTransactionTimeline(
$client,
@ -28,19 +27,27 @@ final class PhabricatorOAuthClientViewController
$timeline->setShouldTerminate(true);
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->setHeaderText(pht('Details'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties);
$title = pht('OAuth Application: %s', $client->getName());
return $this->newPage()
->setCrumbs($crumbs)
->setTitle($title)
->appendChild(
$curtain = $this->buildCurtain($client);
$columns = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(
array(
$box,
$timeline,
));
return $this->newPage()
->setCrumbs($crumbs)
->setTitle($title)
->appendChild($columns);
}
private function buildHeaderView(PhabricatorOAuthServerClient $client) {
@ -60,8 +67,9 @@ final class PhabricatorOAuthClientViewController
return $header;
}
private function buildActionView(PhabricatorOAuthServerClient $client) {
private function buildCurtain(PhabricatorOAuthServerClient $client) {
$viewer = $this->getViewer();
$actions = array();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
@ -70,24 +78,19 @@ final class PhabricatorOAuthClientViewController
$id = $client->getID();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$actions[] = id(new PhabricatorActionView())
->setName(pht('Edit Application'))
->setIcon('fa-pencil')
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit)
->setHref($client->getEditURI());
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Application'))
->setIcon('fa-pencil')
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit)
->setHref($client->getEditURI()));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Show Application Secret'))
->setIcon('fa-eye')
->setHref($this->getApplicationURI("client/secret/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(true));
$actions[] = id(new PhabricatorActionView())
->setName(pht('Show Application Secret'))
->setIcon('fa-eye')
->setHref($this->getApplicationURI("client/secret/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(true);
$is_disabled = $client->getIsDisabled();
if ($is_disabled) {
@ -100,22 +103,26 @@ final class PhabricatorOAuthClientViewController
$disable_uri = $this->getApplicationURI("client/disable/{$id}/");
$view->addAction(
id(new PhabricatorActionView())
->setName($disable_text)
->setIcon($disable_icon)
->setWorkflow(true)
->setDisabled(!$can_edit)
->setHref($disable_uri));
$actions[] = id(new PhabricatorActionView())
->setName($disable_text)
->setIcon($disable_icon)
->setWorkflow(true)
->setDisabled(!$can_edit)
->setHref($disable_uri);
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Generate Test Token'))
->setIcon('fa-plus')
->setWorkflow(true)
->setHref($this->getApplicationURI("client/test/{$id}/")));
$actions[] = id(new PhabricatorActionView())
->setName(pht('Generate Test Token'))
->setIcon('fa-plus')
->setWorkflow(true)
->setHref($this->getApplicationURI("client/test/{$id}/"));
return $view;
$curtain = $this->newCurtainView($client);
foreach ($actions as $action) {
$curtain->addAction($action);
}
return $curtain;
}
private function buildPropertyListView(PhabricatorOAuthServerClient $client) {
@ -132,10 +139,6 @@ final class PhabricatorOAuthClientViewController
pht('Redirect URI'),
$client->getRedirectURI());
$view->addProperty(
pht('Created'),
phabricator_datetime($client->getDateCreated(), $viewer));
return $view;
}
}

View file

@ -32,7 +32,9 @@ final class PhabricatorOAuthServerClientPHIDType extends PhabricatorPHIDType {
foreach ($handles as $phid => $handle) {
$client = $objects[$phid];
$handle->setName($client->getName());
$handle
->setName($client->getName())
->setURI($client->getURI());
}
}

View file

@ -59,6 +59,12 @@ final class PhabricatorOAuthServerClient
PhabricatorOAuthServerClientPHIDType::TYPECONST);
}
public function getURI() {
return urisprintf(
'/oauthserver/client/view/%d/',
$this->getID());
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -3,7 +3,7 @@
abstract class PhabricatorPasteDAO extends PhabricatorLiskDAO {
public function getApplicationName() {
return 'pastebin';
return 'paste';
}
}

View file

@ -8,7 +8,7 @@ final class PhabricatorPasteTransaction
const MAILTAG_COMMENT = 'paste-comment';
public function getApplicationName() {
return 'pastebin';
return 'paste';
}
public function getApplicationTransactionType() {

View file

@ -44,6 +44,7 @@ final class PhabricatorPeopleApplication extends PhabricatorApplication {
$this->getQueryRoutePattern() => 'PhabricatorPeopleListController',
'logs/' => array(
$this->getQueryRoutePattern() => 'PhabricatorPeopleLogsController',
'(?P<id>\d+)/' => 'PhabricatorPeopleLogViewController',
),
'invite/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'

View file

@ -0,0 +1,92 @@
<?php
final class PhabricatorPeopleLogViewController
extends PhabricatorPeopleController {
public function shouldRequireAdmin() {
return false;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$id = $request->getURIData('id');
$log = id(new PhabricatorPeopleLogQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$log) {
return new Aphront404Response();
}
$logs_uri = $this->getApplicationURI('logs/');
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb(pht('Activity Logs'), $logs_uri)
->addTextCrumb($log->getObjectName())
->setBorder(true);
$header = $this->buildHeaderView($log);
$properties = $this->buildPropertiesView($log);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->addPropertySection(pht('Details'), $properties);
return $this->newPage()
->setCrumbs($crumbs)
->setTitle($log->getObjectName())
->appendChild($view);
}
private function buildHeaderView(PhabricatorUserLog $log) {
$viewer = $this->getViewer();
$view = id(new PHUIHeaderView())
->setViewer($viewer)
->setHeader($log->getObjectName());
return $view;
}
private function buildPropertiesView(PhabricatorUserLog $log) {
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setViewer($viewer);
$type_map = PhabricatorUserLogType::getAllLogTypes();
$type_map = mpull($type_map, 'getLogTypeName', 'getLogTypeKey');
$action = $log->getAction();
$type_name = idx($type_map, $action, $action);
$view->addProperty(pht('Event Type'), $type_name);
$view->addProperty(
pht('Event Date'),
phabricator_datetime($log->getDateCreated(), $viewer));
$actor_phid = $log->getActorPHID();
if ($actor_phid) {
$view->addProperty(
pht('Acting User'),
$viewer->renderHandle($actor_phid));
}
$user_phid = $log->getUserPHID();
if ($user_phid) {
$view->addProperty(
pht('Affected User'),
$viewer->renderHandle($user_phid));
}
$remote_address = $log->getRemoteAddressForViewer($viewer);
if ($remote_address !== null) {
$view->addProperty(pht('Remote Address'), $remote_address);
}
return $view;
}
}

View file

@ -252,15 +252,30 @@ final class PhabricatorPeopleProfileViewController
PhabricatorUser $user,
$viewer) {
$query = new PhabricatorFeedQuery();
$query->withFilterPHIDs(
array(
$user->getPHID(),
));
$query->setLimit(100);
$query->setViewer($viewer);
$query = id(new PhabricatorFeedQuery())
->setViewer($viewer)
->withFilterPHIDs(array($user->getPHID()))
->setLimit(100)
->setReturnPartialResultsOnOverheat(true);
$stories = $query->execute();
$overheated_view = null;
$is_overheated = $query->getIsOverheated();
if ($is_overheated) {
$overheated_message =
PhabricatorApplicationSearchController::newOverheatedError(
(bool)$stories);
$overheated_view = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setTitle(pht('Query Overheated'))
->setErrors(
array(
$overheated_message,
));
}
$builder = new PhabricatorFeedBuilder($stories);
$builder->setUser($viewer);
$builder->setShowHovercards(true);
@ -268,8 +283,10 @@ final class PhabricatorPeopleProfileViewController
'requires but just a single step.'));
$view = $builder->buildView();
return $view->render();
return array(
$overheated_view,
$view->render(),
);
}
}

View file

@ -74,18 +74,11 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
throw $ex;
}
$log = PhabricatorUserLog::initializeNewLog(
$this->requireActor(),
$user->getPHID(),
PhabricatorUserLog::ACTION_CREATE);
$log->setNewValue($email->getAddress());
$log->save();
if ($is_reassign) {
$log = PhabricatorUserLog::initializeNewLog(
$this->requireActor(),
$user->getPHID(),
PhabricatorUserLog::ACTION_EMAIL_REASSIGN);
PhabricatorReassignEmailUserLogType::LOGTYPE);
$log->setNewValue($email->getAddress());
$log->save();
}
@ -100,35 +93,6 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
}
/**
* @task edit
*/
public function updateUser(
PhabricatorUser $user,
PhabricatorUserEmail $email = null) {
if (!$user->getID()) {
throw new Exception(pht('User has not been created yet!'));
}
$user->openTransaction();
$user->save();
if ($email) {
$email->save();
}
$log = PhabricatorUserLog::initializeNewLog(
$this->requireActor(),
$user->getPHID(),
PhabricatorUserLog::ACTION_EDIT);
$log->save();
$user->saveTransaction();
return $this;
}
/* -( Editing Roles )------------------------------------------------------ */
/**
@ -151,18 +115,9 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
return $this;
}
$log = PhabricatorUserLog::initializeNewLog(
$actor,
$user->getPHID(),
PhabricatorUserLog::ACTION_SYSTEM_AGENT);
$log->setOldValue($user->getIsSystemAgent());
$log->setNewValue($system_agent);
$user->setIsSystemAgent((int)$system_agent);
$user->save();
$log->save();
$user->endWriteLocking();
$user->saveTransaction();
@ -189,18 +144,9 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
return $this;
}
$log = PhabricatorUserLog::initializeNewLog(
$actor,
$user->getPHID(),
PhabricatorUserLog::ACTION_MAILING_LIST);
$log->setOldValue($user->getIsMailingList());
$log->setNewValue($mailing_list);
$user->setIsMailingList((int)$mailing_list);
$user->save();
$log->save();
$user->endWriteLocking();
$user->saveTransaction();
@ -249,7 +195,7 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
$log = PhabricatorUserLog::initializeNewLog(
$actor,
$user->getPHID(),
PhabricatorUserLog::ACTION_EMAIL_ADD);
PhabricatorAddEmailUserLogType::LOGTYPE);
$log->setNewValue($email->getAddress());
$log->save();
@ -300,7 +246,7 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
$log = PhabricatorUserLog::initializeNewLog(
$actor,
$user->getPHID(),
PhabricatorUserLog::ACTION_EMAIL_REMOVE);
PhabricatorRemoveEmailUserLogType::LOGTYPE);
$log->setOldValue($email->getAddress());
$log->save();
@ -366,7 +312,7 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
$log = PhabricatorUserLog::initializeNewLog(
$actor,
$user->getPHID(),
PhabricatorUserLog::ACTION_EMAIL_PRIMARY);
PhabricatorPrimaryEmailUserLogType::LOGTYPE);
$log->setOldValue($old_primary ? $old_primary->getAddress() : null);
$log->setNewValue($email->getAddress());
@ -425,7 +371,7 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
$log = PhabricatorUserLog::initializeNewLog(
$actor,
$user->getPHID(),
PhabricatorUserLog::ACTION_EMAIL_VERIFY);
PhabricatorVerifyEmailUserLogType::LOGTYPE);
$log->setNewValue($email->getAddress());
$log->save();
}
@ -487,7 +433,7 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
$log = PhabricatorUserLog::initializeNewLog(
$actor,
$user->getPHID(),
PhabricatorUserLog::ACTION_EMAIL_REASSIGN);
PhabricatorReassignEmailUserLogType::LOGTYPE);
$log->setNewValue($email->getAddress());
$log->save();
}

View file

@ -0,0 +1,130 @@
<?php
final class PhabricatorPeopleEmailLoginMailEngine
extends PhabricatorPeopleMailEngine {
public function validateMail() {
$recipient = $this->getRecipient();
if ($recipient->getIsDisabled()) {
$this->throwValidationException(
pht('User is Disabled'),
pht(
'You can not send an email login link to this email address '.
'because the associated user account is disabled.'));
}
if (!$recipient->canEstablishWebSessions()) {
$this->throwValidationException(
pht('Not a Normal User'),
pht(
'You can not send an email login link to this email address '.
'because the associated user account is not a normal user account '.
'and can not log in to the web interface.'));
}
}
protected function newMail() {
$is_set_password = $this->isSetPasswordWorkflow();
if ($is_set_password) {
$subject = pht('[Phabricator] Account Password Link');
} else {
$subject = pht('[Phabricator] Account Login Link');
}
$recipient = $this->getRecipient();
PhabricatorSystemActionEngine::willTakeAction(
array($recipient->getPHID()),
new PhabricatorAuthEmailLoginAction(),
1);
$engine = new PhabricatorAuthSessionEngine();
$login_uri = $engine->getOneTimeLoginURI(
$recipient,
null,
PhabricatorAuthSessionEngine::ONETIME_RESET);
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
$have_passwords = $this->isPasswordAuthEnabled();
$body = array();
if ($is_set_password) {
$message_key = PhabricatorAuthEmailSetPasswordMessageType::MESSAGEKEY;
} else {
$message_key = PhabricatorAuthEmailLoginMessageType::MESSAGEKEY;
}
$message_body = PhabricatorAuthMessage::loadMessageText(
$recipient,
$message_key);
if (strlen($message_body)) {
$body[] = $this->newRemarkupText($message_body);
}
if ($have_passwords) {
if ($is_set_password) {
$body[] = pht(
'You can use this link to set a password on your account:'.
"\n\n %s\n",
$login_uri);
} else if ($is_serious) {
$body[] = pht(
"You can use this link to reset your Phabricator password:".
"\n\n %s\n",
$login_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",
$login_uri);
}
} else {
$body[] = pht(
"You can use this login link to regain access to your Phabricator ".
"account:".
"\n\n".
" %s\n",
$login_uri);
}
$body = implode("\n\n", $body);
return id(new PhabricatorMetaMTAMail())
->setSubject($subject)
->setBody($body);
}
private function isPasswordAuthEnabled() {
return (bool)PhabricatorPasswordAuthProvider::getPasswordProvider();
}
private function isSetPasswordWorkflow() {
$sender = $this->getSender();
$recipient = $this->getRecipient();
// Users can hit the "login with an email link" workflow while trying to
// set a password on an account which does not yet have a password. We
// require they verify that they own the email address and send them
// through the email login flow. In this case, the messaging is slightly
// different.
if ($sender->getPHID()) {
if ($sender->getPHID() === $recipient->getPHID()) {
return true;
}
}
return false;
}
}

View file

@ -5,6 +5,8 @@ abstract class PhabricatorPeopleMailEngine
private $sender;
private $recipient;
private $recipientAddress;
private $activityLog;
final public function setSender(PhabricatorUser $sender) {
$this->sender = $sender;
@ -30,6 +32,31 @@ abstract class PhabricatorPeopleMailEngine
return $this->recipient;
}
final public function setRecipientAddress(PhutilEmailAddress $address) {
$this->recipientAddress = $address;
return $this;
}
final public function getRecipientAddress() {
if (!$this->recipientAddress) {
throw new PhutilInvalidStateException('recipientAddress');
}
return $this->recipientAddress;
}
final public function hasRecipientAddress() {
return ($this->recipientAddress !== null);
}
final public function setActivityLog(PhabricatorUserLog $activity_log) {
$this->activityLog = $activity_log;
return $this;
}
final public function getActivityLog() {
return $this->activityLog;
}
final public function canSendMail() {
try {
$this->validateMail();
@ -43,6 +70,26 @@ abstract class PhabricatorPeopleMailEngine
$this->validateMail();
$mail = $this->newMail();
if ($this->hasRecipientAddress()) {
$recipient_address = $this->getRecipientAddress();
$mail->addRawTos(array($recipient_address->getAddress()));
} else {
$recipient = $this->getRecipient();
$mail->addTos(array($recipient->getPHID()));
}
$activity_log = $this->getActivityLog();
if ($activity_log) {
$activity_log->save();
$body = array();
$body[] = rtrim($mail->getBody(), "\n");
$body[] = pht('Activity Log ID: #%d', $activity_log->getID());
$body = implode("\n\n", $body)."\n";
$mail->setBody($body);
}
$mail
->setForceDelivery(true)
->save();
@ -53,7 +100,6 @@ abstract class PhabricatorPeopleMailEngine
abstract public function validateMail();
abstract protected function newMail();
final protected function throwValidationException($title, $body) {
throw new PhabricatorPeopleMailEngineException($title, $body);
}
@ -66,7 +112,10 @@ abstract class PhabricatorPeopleMailEngine
->setConfig('uri.base', PhabricatorEnv::getProductionURI('/'))
->setMode(PhutilRemarkupEngine::MODE_TEXT);
return $engine->markupText($text);
$rendered_text = $engine->markupText($text);
$rendered_text = rtrim($rendered_text, "\n");
return $rendered_text;
}
}

View file

@ -30,7 +30,6 @@ final class PhabricatorPeopleUsernameMailEngine
protected function newMail() {
$sender = $this->getSender();
$recipient = $this->getRecipient();
$sender_username = $sender->getUsername();
$sender_realname = $sender->getRealName();
@ -52,7 +51,6 @@ final class PhabricatorPeopleUsernameMailEngine
$new_username));
return id(new PhabricatorMetaMTAMail())
->addTos(array($recipient->getPHID()))
->setSubject(pht('[Phabricator] Username Changed'))
->setBody($body);
}

View file

@ -104,7 +104,6 @@ final class PhabricatorPeopleWelcomeMailEngine
$message = implode("\n\n", $message);
return id(new PhabricatorMetaMTAMail())
->addTos(array($recipient->getPHID()))
->setSubject(pht('[Phabricator] Welcome to Phabricator'))
->setBody($message);
}

View file

@ -3,6 +3,7 @@
final class PhabricatorPeopleLogQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $actorPHIDs;
private $userPHIDs;
private $relatedPHIDs;
@ -12,6 +13,11 @@ final class PhabricatorPeopleLogQuery
private $dateCreatedMin;
private $dateCreatedMax;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withActorPHIDs(array $actor_phids) {
$this->actorPHIDs = $actor_phids;
return $this;
@ -59,6 +65,13 @@ final class PhabricatorPeopleLogQuery
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'id IN (%Ld)',
$this->ids);
}
if ($this->actorPHIDs !== null) {
$where[] = qsprintf(
$conn,

View file

@ -64,6 +64,9 @@ final class PhabricatorPeopleLogSearchEngine
}
protected function buildCustomSearchFields() {
$types = PhabricatorUserLogType::getAllLogTypes();
$types = mpull($types, 'getLogTypeName', 'getLogTypeKey');
return array(
id(new PhabricatorUsersSearchField())
->setKey('userPHIDs')
@ -75,11 +78,11 @@ final class PhabricatorPeopleLogSearchEngine
->setAliases(array('actors', 'actor', 'actorPHID'))
->setLabel(pht('Actors'))
->setDescription(pht('Search for activity by specific users.')),
id(new PhabricatorSearchCheckboxesField())
id(new PhabricatorSearchDatasourceField())
->setKey('actions')
->setLabel(pht('Actions'))
->setDescription(pht('Search for particular types of activity.'))
->setOptions(PhabricatorUserLog::getActionTypeMap()),
->setDatasource(new PhabricatorUserLogTypeDatasource()),
id(new PhabricatorSearchTextField())
->setKey('ip')
->setLabel(pht('Filter IP'))
@ -194,7 +197,8 @@ final class PhabricatorPeopleLogSearchEngine
}
$handles = $viewer->loadHandles($phids);
$action_map = PhabricatorUserLog::getActionTypeMap();
$types = PhabricatorUserLogType::getAllLogTypes();
$types = mpull($types, 'getLogTypeName', 'getLogTypeKey');
$export = array();
foreach ($logs as $log) {
@ -214,7 +218,7 @@ final class PhabricatorPeopleLogSearchEngine
}
$action = $log->getAction();
$action_name = idx($action_map, $action, pht('Unknown ("%s")', $action));
$action_name = idx($types, $action, pht('Unknown ("%s")', $action));
$map = array(
'actorPHID' => $actor_phid,

View file

@ -3,43 +3,6 @@
final class PhabricatorUserLog extends PhabricatorUserDAO
implements PhabricatorPolicyInterface {
const ACTION_LOGIN = 'login';
const ACTION_LOGIN_PARTIAL = 'login-partial';
const ACTION_LOGIN_FULL = 'login-full';
const ACTION_LOGOUT = 'logout';
const ACTION_LOGIN_FAILURE = 'login-fail';
const ACTION_LOGIN_LEGALPAD = 'login-legalpad';
const ACTION_RESET_PASSWORD = 'reset-pass';
const ACTION_CREATE = 'create';
const ACTION_EDIT = 'edit';
const ACTION_ADMIN = 'admin';
const ACTION_SYSTEM_AGENT = 'system-agent';
const ACTION_MAILING_LIST = 'mailing-list';
const ACTION_DISABLE = 'disable';
const ACTION_APPROVE = 'approve';
const ACTION_DELETE = 'delete';
const ACTION_CONDUIT_CERTIFICATE = 'conduit-cert';
const ACTION_CONDUIT_CERTIFICATE_FAILURE = 'conduit-cert-fail';
const ACTION_EMAIL_PRIMARY = 'email-primary';
const ACTION_EMAIL_REMOVE = 'email-remove';
const ACTION_EMAIL_ADD = 'email-add';
const ACTION_EMAIL_VERIFY = 'email-verify';
const ACTION_EMAIL_REASSIGN = 'email-reassign';
const ACTION_CHANGE_PASSWORD = 'change-password';
const ACTION_CHANGE_USERNAME = 'change-username';
const ACTION_ENTER_HISEC = 'hisec-enter';
const ACTION_EXIT_HISEC = 'hisec-exit';
const ACTION_FAIL_HISEC = 'hisec-fail';
const ACTION_MULTI_ADD = 'multi-add';
const ACTION_MULTI_REMOVE = 'multi-remove';
protected $actorPHID;
protected $userPHID;
protected $action;
@ -49,44 +12,6 @@ final class PhabricatorUserLog extends PhabricatorUserDAO
protected $remoteAddr;
protected $session;
public static function getActionTypeMap() {
return array(
self::ACTION_LOGIN => pht('Login'),
self::ACTION_LOGIN_PARTIAL => pht('Login: Partial Login'),
self::ACTION_LOGIN_FULL => pht('Login: Upgrade to Full'),
self::ACTION_LOGIN_FAILURE => pht('Login: Failure'),
self::ACTION_LOGIN_LEGALPAD =>
pht('Login: Signed Required Legalpad Documents'),
self::ACTION_LOGOUT => pht('Logout'),
self::ACTION_RESET_PASSWORD => pht('Reset Password'),
self::ACTION_CREATE => pht('Create Account'),
self::ACTION_EDIT => pht('Edit Account'),
self::ACTION_ADMIN => pht('Add/Remove Administrator'),
self::ACTION_SYSTEM_AGENT => pht('Add/Remove System Agent'),
self::ACTION_MAILING_LIST => pht('Add/Remove Mailing List'),
self::ACTION_DISABLE => pht('Enable/Disable'),
self::ACTION_APPROVE => pht('Approve Registration'),
self::ACTION_DELETE => pht('Delete User'),
self::ACTION_CONDUIT_CERTIFICATE
=> pht('Conduit: Read Certificate'),
self::ACTION_CONDUIT_CERTIFICATE_FAILURE
=> pht('Conduit: Read Certificate Failure'),
self::ACTION_EMAIL_PRIMARY => pht('Email: Change Primary'),
self::ACTION_EMAIL_ADD => pht('Email: Add Address'),
self::ACTION_EMAIL_REMOVE => pht('Email: Remove Address'),
self::ACTION_EMAIL_VERIFY => pht('Email: Verify'),
self::ACTION_EMAIL_REASSIGN => pht('Email: Reassign'),
self::ACTION_CHANGE_PASSWORD => pht('Change Password'),
self::ACTION_CHANGE_USERNAME => pht('Change Username'),
self::ACTION_ENTER_HISEC => pht('Hisec: Enter'),
self::ACTION_EXIT_HISEC => pht('Hisec: Exit'),
self::ACTION_FAIL_HISEC => pht('Hisec: Failed Attempt'),
self::ACTION_MULTI_ADD => pht('Multi-Factor: Add Factor'),
self::ACTION_MULTI_REMOVE => pht('Multi-Factor: Remove Factor'),
);
}
public static function initializeNewLog(
PhabricatorUser $actor = null,
$object_phid = null,
@ -175,6 +100,43 @@ final class PhabricatorUserLog extends PhabricatorUserDAO
) + parent::getConfiguration();
}
public function getURI() {
return urisprintf('/people/logs/%s/', $this->getID());
}
public function getObjectName() {
return pht('Activity Log %d', $this->getID());
}
public function getRemoteAddressForViewer(PhabricatorUser $viewer) {
$viewer_phid = $viewer->getPHID();
$actor_phid = $this->getActorPHID();
$user_phid = $this->getUserPHID();
if (!$viewer_phid) {
$can_see_ip = false;
} else if ($viewer->getIsAdmin()) {
$can_see_ip = true;
} else if ($viewer_phid == $actor_phid) {
// You can see the address if you took the action.
$can_see_ip = true;
} else if (!$actor_phid && ($viewer_phid == $user_phid)) {
// You can see the address if it wasn't authenticated and applied
// to you (partial login).
$can_see_ip = true;
} else {
// You can't see the address when an administrator disables your
// account, since it's their address.
$can_see_ip = false;
}
if (!$can_see_ip) {
return null;
}
return $this->getRemoteAddr();
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -0,0 +1,43 @@
<?php
final class PhabricatorUserLogTypeDatasource
extends PhabricatorTypeaheadDatasource {
public function getBrowseTitle() {
return pht('Browse Log Types');
}
public function getPlaceholderText() {
return pht('Type a log type name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorPeopleApplication';
}
public function loadResults() {
$results = $this->buildResults();
return $this->filterResultsAgainstTokens($results);
}
protected function renderSpecialTokens(array $values) {
return $this->renderTokensFromResults($this->buildResults(), $values);
}
private function buildResults() {
$results = array();
$type_map = PhabricatorUserLogType::getAllLogTypes();
foreach ($type_map as $type_key => $type) {
$result = id(new PhabricatorTypeaheadResult())
->setPHID($type_key)
->setName($type->getLogTypeName());
$results[$type_key] = $result;
}
return $results;
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorAddEmailUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'email-add';
public function getLogTypeName() {
return pht('Email: Add Address');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorAddMultifactorUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'multi-add';
public function getLogTypeName() {
return pht('Multi-Factor: Add Factor');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorChangePasswordUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'change-password';
public function getLogTypeName() {
return pht('Change Password');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorConduitCertificateFailureUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'conduit-cert-fail';
public function getLogTypeName() {
return pht('Conduit: Read Certificate Failure');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorConduitCertificateUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'conduit-cert';
public function getLogTypeName() {
return pht('Conduit: Read Certificate');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorEmailLoginUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'email-login';
public function getLogTypeName() {
return pht('Email: Recovery Link');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorEnterHisecUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'hisec-enter';
public function getLogTypeName() {
return pht('Hisec: Enter');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorExitHisecUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'hisec-exit';
public function getLogTypeName() {
return pht('Hisec: Exit');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorFailHisecUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'hisec-fail';
public function getLogTypeName() {
return pht('Hisec: Failed Attempt');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorFullLoginUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'login-full';
public function getLogTypeName() {
return pht('Login: Upgrade to Full');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorLoginFailureUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'login-fail';
public function getLogTypeName() {
return pht('Login: Failure');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorLoginUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'login';
public function getLogTypeName() {
return pht('Login');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorLogoutUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'logout';
public function getLogTypeName() {
return pht('Logout');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorPartialLoginUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'login-partial';
public function getLogTypeName() {
return pht('Login: Partial Login');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorPrimaryEmailUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'email-primary';
public function getLogTypeName() {
return pht('Email: Change Primary');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorReassignEmailUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'email-reassign';
public function getLogTypeName() {
return pht('Email: Reassign');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorRemoveEmailUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'email-remove';
public function getLogTypeName() {
return pht('Email: Remove Address');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorRemoveMultifactorUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'multi-remove';
public function getLogTypeName() {
return pht('Multi-Factor: Remove Factor');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorResetPasswordUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'reset-pass';
public function getLogTypeName() {
return pht('Reset Password');
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorSignDocumentsUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'login-legalpad';
public function getLogTypeName() {
return pht('Login: Signed Required Legalpad Documents');
}
}

View file

@ -0,0 +1,19 @@
<?php
abstract class PhabricatorUserLogType
extends Phobject {
final public function getLogTypeKey() {
return $this->getPhobjectClassConstant('LOGTYPE', 32);
}
abstract public function getLogTypeName();
final public static function getAllLogTypes() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getLogTypeKey')
->execute();
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorVerifyEmailUserLogType
extends PhabricatorUserLogType {
const LOGTYPE = 'email-verify';
public function getLogTypeName() {
return pht('Email: Verify Address');
}
}

View file

@ -27,7 +27,9 @@ final class PhabricatorUserLogView extends AphrontView {
}
$handles = $viewer->loadHandles($phids);
$action_map = PhabricatorUserLog::getActionTypeMap();
$types = PhabricatorUserLogType::getAllLogTypes();
$types = mpull($types, 'getLogTypeName', 'getLogTypeKey');
$base_uri = $this->searchBaseURI;
$viewer_phid = $viewer->getPHID();
@ -39,37 +41,20 @@ final class PhabricatorUserLogView extends AphrontView {
$actor_phid = $log->getActorPHID();
$user_phid = $log->getUserPHID();
if ($viewer->getIsAdmin()) {
$can_see_ip = true;
} else if ($viewer_phid == $actor_phid) {
// You can see the address if you took the action.
$can_see_ip = true;
} else if (!$actor_phid && ($viewer_phid == $user_phid)) {
// You can see the address if it wasn't authenticated and applied
// to you (partial login).
$can_see_ip = true;
} else {
// You can't see the address when an administrator disables your
// account, since it's their address.
$can_see_ip = false;
}
if ($can_see_ip) {
$ip = $log->getRemoteAddr();
$remote_address = $log->getRemoteAddressForViewer($viewer);
if ($remote_address !== null) {
if ($base_uri) {
$ip = phutil_tag(
$remote_address = phutil_tag(
'a',
array(
'href' => $base_uri.'?ip='.$ip.'#R',
'href' => $base_uri.'?ip='.$remote_address.'#R',
),
$ip);
$remote_address);
}
} else {
$ip = null;
}
$action = $log->getAction();
$action_name = idx($action_map, $action, $action);
$action_name = idx($types, $action, $action);
if ($actor_phid) {
$actor_name = $handles[$actor_phid]->renderLink();
@ -83,37 +68,47 @@ final class PhabricatorUserLogView extends AphrontView {
$user_name = null;
}
$action_link = phutil_tag(
'a',
array(
'href' => $log->getURI(),
),
$action_name);
$rows[] = array(
phabricator_date($log->getDateCreated(), $viewer),
phabricator_time($log->getDateCreated(), $viewer),
$action_name,
$log->getID(),
$action_link,
$actor_name,
$user_name,
$ip,
$remote_address,
$session,
phabricator_date($log->getDateCreated(), $viewer),
phabricator_time($log->getDateCreated(), $viewer),
);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
pht('Date'),
pht('Time'),
pht('ID'),
pht('Action'),
pht('Actor'),
pht('User'),
pht('IP'),
pht('Session'),
pht('Date'),
pht('Time'),
));
$table->setColumnClasses(
array(
'',
'right',
'wide',
'',
'',
'',
'n',
'',
'right',
));
return $table;

View file

@ -19,10 +19,6 @@ final class PhabricatorUserApproveTransaction
public function applyExternalEffects($object, $value) {
$user = $object;
$this->newUserLog(PhabricatorUserLog::ACTION_APPROVE)
->setOldValue((bool)$user->getIsApproved())
->setNewValue((bool)$value)
->save();
$actor = $this->getActor();
$title = pht(

View file

@ -17,13 +17,6 @@ final class PhabricatorUserDisableTransaction
$object->setIsDisabled((int)$value);
}
public function applyExternalEffects($object, $value) {
$this->newUserLog(PhabricatorUserLog::ACTION_DISABLE)
->setOldValue((bool)$object->getIsDisabled())
->setNewValue((bool)$value)
->save();
}
public function getTitle() {
$new = $this->getNewValue();
if ($new) {

View file

@ -17,15 +17,6 @@ final class PhabricatorUserEmpowerTransaction
$object->setIsAdmin((int)$value);
}
public function applyExternalEffects($object, $value) {
$user = $object;
$this->newUserLog(PhabricatorUserLog::ACTION_ADMIN)
->setOldValue($this->getOldValue())
->setNewValue($value)
->save();
}
public function validateTransactions($object, array $xactions) {
$user = $object;
$actor = $this->getActor();

View file

@ -1,13 +1,4 @@
<?php
abstract class PhabricatorUserTransactionType
extends PhabricatorModularTransactionType {
protected function newUserLog($action) {
return PhabricatorUserLog::initializeNewLog(
$this->getActor(),
$this->getObject()->getPHID(),
$action);
}
}
extends PhabricatorModularTransactionType {}

View file

@ -24,11 +24,6 @@ final class PhabricatorUserUsernameTransaction
$old_username = $this->getOldValue();
$new_username = $this->getNewValue();
$this->newUserLog(PhabricatorUserLog::ACTION_CHANGE_USERNAME)
->setOldValue($old_username)
->setNewValue($new_username)
->save();
// The SSH key cache currently includes usernames, so dirty it. See T12554
// for discussion.
PhabricatorAuthSSHKeyQuery::deleteSSHKeyCache();

View file

@ -93,10 +93,6 @@ abstract class PhameLiveController extends PhameController {
->needHeaderImage(true)
->withIDs(array($post_id));
if ($blog) {
$post_query->withBlogPHIDs(array($blog->getPHID()));
}
// Only show published posts on external domains.
if ($is_external) {
$post_query->withVisibility(
@ -123,10 +119,15 @@ abstract class PhameLiveController extends PhameController {
$this->post = $post;
// If we have a post, canonicalize the URI to the post's current slug and
// redirect the user if it isn't correct.
// redirect the user if it isn't correct. Likewise, canonicalize the URI
// if the blog ID is wrong. See T13353.
if ($post) {
$slug = $request->getURIData('slug');
if ($post->getSlug() != $slug) {
$wrong_slug = ($post->getSlug() !== $slug);
$wrong_blog = ($post->getBlog()->getID() !== $blog->getID());
if ($wrong_slug || $wrong_blog) {
if ($is_live) {
if ($is_external) {
$uri = $post->getExternalLiveURI();

View file

@ -103,7 +103,7 @@ final class PholioMockImagesView extends AphrontView {
'width' => $x,
'height' => $y,
'title' => $image->getName(),
'descriptionMarkup' => $description,
'descriptionMarkup' => hsprintf('%s', $description),
'isObsolete' => (bool)$image->getIsObsolete(),
'isImage' => $file->isViewableImage(),
'isViewable' => $file->isViewableInBrowser(),

View file

@ -5,10 +5,6 @@ final class PhortuneAddPaymentMethodAction
const TYPECONST = 'phortune.payment-method.add';
public function getActionConstant() {
return self::TYPECONST;
}
public function getScoreThreshold() {
return 60 / phutil_units('1 hour in seconds');
}

View file

@ -66,7 +66,6 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
'subprojects/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectSubprojectsController',
'board/(?P<id>[1-9]\d*)/'.
'(?P<filter>filter/)?'.
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorProjectBoardViewController',
'move/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectMoveController',
@ -80,6 +79,12 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
=> 'PhabricatorProjectColumnHideController',
'column/(?:(?P<id>\d+)/)?'
=> 'PhabricatorProjectColumnDetailController',
'viewquery/(?P<columnID>\d+)/'
=> 'PhabricatorProjectColumnViewQueryController',
'bulk/(?P<columnID>\d+)/'
=> 'PhabricatorProjectColumnBulkEditController',
'bulkmove/(?P<columnID>\d+)/(?P<mode>project|column)/'
=> 'PhabricatorProjectColumnBulkMoveController',
'import/'
=> 'PhabricatorProjectBoardImportController',
'reorder/'
@ -90,6 +95,12 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
=> 'PhabricatorProjectBoardManageController',
'background/'
=> 'PhabricatorProjectBoardBackgroundController',
'default/(?P<target>[^/]+)/'
=> 'PhabricatorProjectBoardDefaultController',
'filter/(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorProjectBoardFilterController',
'reload/'
=> 'PhabricatorProjectBoardReloadController',
),
'column/' => array(
'remove/(?P<id>\d+)/' =>
@ -112,8 +123,6 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
=> 'PhabricatorProjectSilenceController',
'warning/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectSubprojectWarningController',
'default/(?P<projectID>[1-9]\d*)/(?P<target>[^/]+)/'
=> 'PhabricatorProjectDefaultController',
),
'/tag/' => array(
'(?P<slug>[^/]+)/' => 'PhabricatorProjectViewController',

View file

@ -1,4 +1,36 @@
<?php
abstract class PhabricatorProjectBoardController
extends PhabricatorProjectController {}
extends PhabricatorProjectController {
private $viewState;
final protected function getViewState() {
if ($this->viewState === null) {
$this->viewState = $this->newViewState();
}
return $this->viewState;
}
private function newViewState() {
$project = $this->getProject();
$request = $this->getRequest();
return id(new PhabricatorWorkboardViewState())
->setProject($project)
->readFromRequest($request);
}
final protected function newWorkboardDialog() {
$dialog = $this->newDialog();
$state = $this->getViewState();
foreach ($state->getQueryParameters() as $key => $value) {
$dialog->addHiddenInput($key, $value);
}
return $dialog;
}
}

View file

@ -1,25 +1,20 @@
<?php
final class PhabricatorProjectDefaultController
final class PhabricatorProjectBoardDefaultController
extends PhabricatorProjectBoardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$project_id = $request->getURIData('projectID');
$project = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->withIDs(array($project_id))
->executeOne();
if (!$project) {
return new Aphront404Response();
$response = $this->loadProjectForEdit();
if ($response) {
return $response;
}
$this->setProject($project);
$project = $this->getProject();
$state = $this->getViewState();
$board_uri = $state->newWorkboardURI();
$remove_param = null;
$target = $request->getURIData('target');
switch ($target) {
@ -31,8 +26,10 @@ final class PhabricatorProjectDefaultController
'the board.');
$button = pht('Save Default Filter');
$xaction_value = $request->getStr('filter');
$xaction_value = $state->getQueryKey();
$xaction_type = PhabricatorProjectFilterTransaction::TRANSACTIONTYPE;
$remove_param = 'filter';
break;
case 'sort':
$title = pht('Set Board Default Order');
@ -42,8 +39,10 @@ final class PhabricatorProjectDefaultController
'the board.');
$button = pht('Save Default Order');
$xaction_value = $request->getStr('order');
$xaction_value = $state->getOrder();
$xaction_type = PhabricatorProjectSortTransaction::TRANSACTIONTYPE;
$remove_param = 'order';
break;
default:
return new Aphront404Response();
@ -51,12 +50,6 @@ final class PhabricatorProjectDefaultController
$id = $project->getID();
$view_uri = $this->getApplicationURI("board/{$id}/");
$view_uri = new PhutilURI($view_uri);
foreach ($request->getPassthroughRequestData() as $key => $value) {
$view_uri->replaceQueryParam($key, $value);
}
if ($request->isFormPost()) {
$xactions = array();
@ -71,20 +64,18 @@ final class PhabricatorProjectDefaultController
->setContinueOnMissingFields(true)
->applyTransactions($project, $xactions);
return id(new AphrontRedirectResponse())->setURI($view_uri);
// If the parameter we just modified is present in the query string,
// throw it away so the user is redirected back to the default view of
// the board, allowing them to see the new default behavior.
$board_uri->removeQueryParam($remove_param);
return id(new AphrontRedirectResponse())->setURI($board_uri);
}
$dialog = $this->newDialog()
return $this->newWorkboardDialog()
->setTitle($title)
->appendChild($body)
->setDisableWorkflowOnCancel(true)
->addCancelButton($view_uri)
->addCancelButton($board_uri)
->addSubmitButton($title);
foreach ($request->getPassthroughRequestData() as $key => $value) {
$dialog->addHiddenInput($key, $value);
}
return $dialog;
}
}

View file

@ -0,0 +1,56 @@
<?php
final class PhabricatorProjectBoardFilterController
extends PhabricatorProjectBoardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$response = $this->loadProject();
if ($response) {
return $response;
}
$project = $this->getProject();
$state = $this->getViewState();
$board_uri = $state->newWorkboardURI();
$search_engine = $state->getSearchEngine();
$is_submit = $request->isFormPost();
if ($is_submit) {
$saved_query = $search_engine->buildSavedQueryFromRequest($request);
$search_engine->saveQuery($saved_query);
} else {
$saved_query = $state->getSavedQuery();
if (!$saved_query) {
return new Aphront404Response();
}
}
$filter_form = id(new AphrontFormView())
->setUser($viewer);
$search_engine->buildSearchForm($filter_form, $saved_query);
$errors = $search_engine->getErrors();
if ($is_submit && !$errors) {
$query_key = $saved_query->getQueryKey();
$state->setQueryKey($query_key);
$board_uri = $state->newWorkboardURI();
return id(new AphrontRedirectResponse())->setURI($board_uri);
}
return $this->newWorkboardDialog()
->setWidth(AphrontDialogView::WIDTH_FULL)
->setTitle(pht('Advanced Filter'))
->appendChild($filter_form->buildLayoutView())
->setErrors($errors)
->addSubmitButton(pht('Apply Filter'))
->addCancelButton($board_uri);
}
}

View file

@ -0,0 +1,73 @@
<?php
final class PhabricatorProjectBoardReloadController
extends PhabricatorProjectBoardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$response = $this->loadProject();
if ($response) {
return $response;
}
$order = $request->getStr('order');
if (!strlen($order)) {
$order = PhabricatorProjectColumnNaturalOrder::ORDERKEY;
}
$ordering = PhabricatorProjectColumnOrder::getOrderByKey($order);
$ordering = id(clone $ordering)
->setViewer($viewer);
$project = $this->getProject();
$state = $this->getViewState();
$board_uri = $state->newWorkboardURI();
$layout_engine = $state->getLayoutEngine();
$board_phid = $project->getPHID();
$objects = $state->getObjects();
$objects = mpull($objects, null, 'getPHID');
try {
$client_state = $request->getStr('state');
$client_state = phutil_json_decode($client_state);
} catch (PhutilJSONParserException $ex) {
$client_state = array();
}
// Figure out which objects need to be updated: either the client has an
// out-of-date version of them (objects which have been edited); or they
// exist on the client but not on the server (objects which have been
// removed from the board); or they exist on the server but not on the
// client (objects which have been added to the board).
$update_objects = array();
foreach ($objects as $object_phid => $object) {
// TODO: For now, this is always hard-coded.
$object_version = 2;
$client_version = idx($client_state, $object_phid, 0);
if ($object_version > $client_version) {
$update_objects[$object_phid] = $object;
}
}
$update_phids = array_keys($update_objects);
$visible_phids = array_keys($client_state);
$engine = id(new PhabricatorBoardResponseEngine())
->setViewer($viewer)
->setBoardPHID($board_phid)
->setOrdering($ordering)
->setObjects($objects)
->setUpdatePHIDs($update_phids)
->setVisiblePHIDs($visible_phids);
return $engine->buildResponse();
}
}

View file

@ -3,14 +3,6 @@
final class PhabricatorProjectBoardViewController
extends PhabricatorProjectBoardController {
const BATCH_EDIT_ALL = 'all';
private $id;
private $slug;
private $queryKey;
private $sortKey;
private $showHidden;
public function shouldAllowPublic() {
return true;
}
@ -24,120 +16,25 @@ final class PhabricatorProjectBoardViewController
}
$project = $this->getProject();
$state = $this->getViewState();
$board_uri = $project->getWorkboardURI();
$this->readRequestState();
$board_uri = $this->getApplicationURI('board/'.$project->getID().'/');
$search_engine = id(new ManiphestTaskSearchEngine())
->setViewer($viewer)
->setBaseURI($board_uri)
->setIsBoardView(true);
if ($request->isFormPost()
&& !$request->getBool('initialize')
&& !$request->getStr('move')
&& !$request->getStr('queryColumnID')) {
$saved = $search_engine->buildSavedQueryFromRequest($request);
$search_engine->saveQuery($saved);
$filter_form = id(new AphrontFormView())
->setUser($viewer);
$search_engine->buildSearchForm($filter_form, $saved);
if ($search_engine->getErrors()) {
return $this->newDialog()
->setWidth(AphrontDialogView::WIDTH_FULL)
->setTitle(pht('Advanced Filter'))
->appendChild($filter_form->buildLayoutView())
->setErrors($search_engine->getErrors())
->setSubmitURI($board_uri)
->addSubmitButton(pht('Apply Filter'))
->addCancelButton($board_uri);
}
return id(new AphrontRedirectResponse())->setURI(
$this->getURIWithState(
$search_engine->getQueryResultsPageURI($saved->getQueryKey())));
$search_engine = $state->getSearchEngine();
$query_key = $state->getQueryKey();
$saved = $state->getSavedQuery();
if (!$saved) {
return new Aphront404Response();
}
$query_key = $this->getDefaultFilter($project);
$request_query = $request->getStr('filter');
if (strlen($request_query)) {
$query_key = $request_query;
}
$uri_query = $request->getURIData('queryKey');
if (strlen($uri_query)) {
$query_key = $uri_query;
}
$this->queryKey = $query_key;
$custom_query = null;
if ($search_engine->isBuiltinQuery($query_key)) {
$saved = $search_engine->buildSavedQueryFromBuiltin($query_key);
} else {
$saved = id(new PhabricatorSavedQueryQuery())
->setViewer($viewer)
->withQueryKeys(array($query_key))
->executeOne();
if (!$saved) {
return new Aphront404Response();
}
if ($saved->getID()) {
$custom_query = $saved;
} else {
$custom_query = null;
}
if ($request->getURIData('filter')) {
$filter_form = id(new AphrontFormView())
->setUser($viewer);
$search_engine->buildSearchForm($filter_form, $saved);
return $this->newDialog()
->setWidth(AphrontDialogView::WIDTH_FULL)
->setTitle(pht('Advanced Filter'))
->appendChild($filter_form->buildLayoutView())
->setSubmitURI($board_uri)
->addSubmitButton(pht('Apply Filter'))
->addCancelButton($board_uri);
}
$task_query = $search_engine->buildQueryFromSavedQuery($saved);
$select_phids = array($project->getPHID());
if ($project->getHasSubprojects() || $project->getHasMilestones()) {
$descendants = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->withAncestorProjectPHIDs($select_phids)
->execute();
foreach ($descendants as $descendant) {
$select_phids[] = $descendant->getPHID();
}
}
$tasks = $task_query
->withEdgeLogicPHIDs(
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
PhabricatorQueryConstraint::OPERATOR_ANCESTOR,
array($select_phids))
->setOrder(ManiphestTaskQuery::ORDER_PRIORITY)
->setViewer($viewer)
->execute();
$tasks = mpull($tasks, null, 'getPHID');
$layout_engine = $state->getLayoutEngine();
$board_phid = $project->getPHID();
// Regardless of display order, pass tasks to the layout engine in ID order
// so layout is consistent.
$board_tasks = msort($tasks, 'getID');
$layout_engine = id(new PhabricatorBoardLayoutEngine())
->setViewer($viewer)
->setBoardPHIDs(array($board_phid))
->setObjectPHIDs(array_keys($board_tasks))
->setFetchAllBoards(true)
->executeLayout();
$columns = $layout_engine->getColumns($board_phid);
if (!$columns || !$project->getHasWorkboard()) {
$has_normal_columns = false;
@ -190,307 +87,13 @@ final class PhabricatorProjectBoardViewController
->appendChild($content);
}
// If the user wants to turn a particular column into a query, build an
// apropriate filter and redirect them to the query results page.
$query_column_id = $request->getInt('queryColumnID');
if ($query_column_id) {
$column_id_map = mpull($columns, null, 'getID');
$query_column = idx($column_id_map, $query_column_id);
if (!$query_column) {
return new Aphront404Response();
}
// Create a saved query to combine the active filter on the workboard
// with the column filter. If the user currently has constraints on the
// board, we want to add a new column or project constraint, not
// completely replace the constraints.
$saved_query = $saved->newCopy();
if ($query_column->getProxyPHID()) {
$project_phids = $saved_query->getParameter('projectPHIDs');
if (!$project_phids) {
$project_phids = array();
}
$project_phids[] = $query_column->getProxyPHID();
$saved_query->setParameter('projectPHIDs', $project_phids);
} else {
$saved_query->setParameter(
'columnPHIDs',
array($query_column->getPHID()));
}
$search_engine = id(new ManiphestTaskSearchEngine())
->setViewer($viewer);
$search_engine->saveQuery($saved_query);
$query_key = $saved_query->getQueryKey();
$query_uri = new PhutilURI("/maniphest/query/{$query_key}/#R");
return id(new AphrontRedirectResponse())
->setURI($query_uri);
}
$tasks = $state->getObjects();
$task_can_edit_map = id(new PhabricatorPolicyFilter())
->setViewer($viewer)
->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))
->apply($tasks);
// If this is a batch edit, select the editable tasks in the chosen column
// and ship the user into the batch editor.
$batch_edit = $request->getStr('batch');
if ($batch_edit) {
if ($batch_edit !== self::BATCH_EDIT_ALL) {
$column_id_map = mpull($columns, null, 'getID');
$batch_column = idx($column_id_map, $batch_edit);
if (!$batch_column) {
return new Aphront404Response();
}
$batch_task_phids = $layout_engine->getColumnObjectPHIDs(
$board_phid,
$batch_column->getPHID());
foreach ($batch_task_phids as $key => $batch_task_phid) {
if (empty($task_can_edit_map[$batch_task_phid])) {
unset($batch_task_phids[$key]);
}
}
$batch_tasks = array_select_keys($tasks, $batch_task_phids);
} else {
$batch_tasks = $task_can_edit_map;
}
if (!$batch_tasks) {
$cancel_uri = $this->getURIWithState($board_uri);
return $this->newDialog()
->setTitle(pht('No Editable Tasks'))
->appendParagraph(
pht(
'The selected column contains no visible tasks which you '.
'have permission to edit.'))
->addCancelButton($board_uri);
}
// Create a saved query to hold the working set. This allows us to get
// around URI length limitations with a long "?ids=..." query string.
// For details, see T10268.
$search_engine = id(new ManiphestTaskSearchEngine())
->setViewer($viewer);
$saved_query = $search_engine->newSavedQuery();
$saved_query->setParameter('ids', mpull($batch_tasks, 'getID'));
$search_engine->saveQuery($saved_query);
$query_key = $saved_query->getQueryKey();
$bulk_uri = new PhutilURI("/maniphest/bulk/query/{$query_key}/");
$bulk_uri->replaceQueryParam('board', $this->id);
return id(new AphrontRedirectResponse())
->setURI($bulk_uri);
}
$move_id = $request->getStr('move');
if (strlen($move_id)) {
$column_id_map = mpull($columns, null, 'getID');
$move_column = idx($column_id_map, $move_id);
if (!$move_column) {
return new Aphront404Response();
}
$move_task_phids = $layout_engine->getColumnObjectPHIDs(
$board_phid,
$move_column->getPHID());
foreach ($move_task_phids as $key => $move_task_phid) {
if (empty($task_can_edit_map[$move_task_phid])) {
unset($move_task_phids[$key]);
}
}
$move_tasks = array_select_keys($tasks, $move_task_phids);
$cancel_uri = $this->getURIWithState($board_uri);
if (!$move_tasks) {
return $this->newDialog()
->setTitle(pht('No Movable Tasks'))
->appendParagraph(
pht(
'The selected column contains no visible tasks which you '.
'have permission to move.'))
->addCancelButton($cancel_uri);
}
$move_project_phid = $project->getPHID();
$move_column_phid = null;
$move_project = null;
$move_column = null;
$columns = null;
$errors = array();
if ($request->isFormOrHiSecPost()) {
$move_project_phid = head($request->getArr('moveProjectPHID'));
if (!$move_project_phid) {
$move_project_phid = $request->getStr('moveProjectPHID');
}
if (!$move_project_phid) {
if ($request->getBool('hasProject')) {
$errors[] = pht('Choose a project to move tasks to.');
}
} else {
$target_project = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->withPHIDs(array($move_project_phid))
->executeOne();
if (!$target_project) {
$errors[] = pht('You must choose a valid project.');
} else if (!$project->getHasWorkboard()) {
$errors[] = pht(
'You must choose a project with a workboard.');
} else {
$move_project = $target_project;
}
}
if ($move_project) {
$move_engine = id(new PhabricatorBoardLayoutEngine())
->setViewer($viewer)
->setBoardPHIDs(array($move_project->getPHID()))
->setFetchAllBoards(true)
->executeLayout();
$columns = $move_engine->getColumns($move_project->getPHID());
$columns = mpull($columns, null, 'getPHID');
foreach ($columns as $key => $column) {
if ($column->isHidden()) {
unset($columns[$key]);
}
}
$move_column_phid = $request->getStr('moveColumnPHID');
if (!$move_column_phid) {
if ($request->getBool('hasColumn')) {
$errors[] = pht('Choose a column to move tasks to.');
}
} else {
if (empty($columns[$move_column_phid])) {
$errors[] = pht(
'Choose a valid column on the target workboard to move '.
'tasks to.');
} else if ($columns[$move_column_phid]->getID() == $move_id) {
$errors[] = pht(
'You can not move tasks from a column to itself.');
} else {
$move_column = $columns[$move_column_phid];
}
}
}
}
if ($move_column && $move_project) {
foreach ($move_tasks as $move_task) {
$xactions = array();
// If we're switching projects, get out of the old project first
// and move to the new project.
if ($move_project->getID() != $project->getID()) {
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue(
'edge:type',
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)
->setNewValue(
array(
'-' => array(
$project->getPHID() => $project->getPHID(),
),
'+' => array(
$move_project->getPHID() => $move_project->getPHID(),
),
));
}
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COLUMNS)
->setNewValue(
array(
array(
'columnPHID' => $move_column->getPHID(),
),
));
$editor = id(new ManiphestTransactionEditor())
->setActor($viewer)
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setCancelURI($cancel_uri);
$editor->applyTransactions($move_task, $xactions);
}
return id(new AphrontRedirectResponse())
->setURI($cancel_uri);
}
if ($move_project) {
$column_form = id(new AphrontFormView())
->setViewer($viewer)
->appendControl(
id(new AphrontFormSelectControl())
->setName('moveColumnPHID')
->setLabel(pht('Move to Column'))
->setValue($move_column_phid)
->setOptions(mpull($columns, 'getDisplayName', 'getPHID')));
return $this->newDialog()
->setTitle(pht('Move Tasks'))
->setWidth(AphrontDialogView::WIDTH_FORM)
->setErrors($errors)
->addHiddenInput('move', $move_id)
->addHiddenInput('moveProjectPHID', $move_project->getPHID())
->addHiddenInput('hasColumn', true)
->addHiddenInput('hasProject', true)
->appendParagraph(
pht(
'Choose a column on the %s workboard to move tasks to:',
$viewer->renderHandle($move_project->getPHID())))
->appendForm($column_form)
->addSubmitButton(pht('Move Tasks'))
->addCancelButton($cancel_uri);
}
if ($move_project_phid) {
$move_project_phid_value = array($move_project_phid);
} else {
$move_project_phid_value = array();
}
$project_form = id(new AphrontFormView())
->setViewer($viewer)
->appendControl(
id(new AphrontFormTokenizerControl())
->setName('moveProjectPHID')
->setLimit(1)
->setLabel(pht('Move to Project'))
->setValue($move_project_phid_value)
->setDatasource(new PhabricatorProjectDatasource()));
return $this->newDialog()
->setTitle(pht('Move Tasks'))
->setWidth(AphrontDialogView::WIDTH_FORM)
->setErrors($errors)
->addHiddenInput('move', $move_id)
->addHiddenInput('hasProject', true)
->appendForm($project_form)
->addSubmitButton(pht('Continue'))
->addCancelButton($cancel_uri);
}
$board_id = celerity_generate_unique_node_id();
$board = id(new PHUIWorkboardView())
@ -506,7 +109,7 @@ final class PhabricatorProjectBoardViewController
$column_phids = array();
$visible_phids = array();
foreach ($columns as $column) {
if (!$this->showHidden) {
if (!$state->getShowHidden()) {
if ($column->isHidden()) {
continue;
}
@ -534,11 +137,13 @@ final class PhabricatorProjectBoardViewController
}
}
$container_phids = $state->getBoardContainerPHIDs();
$rendering_engine = id(new PhabricatorBoardRenderingEngine())
->setViewer($viewer)
->setObjects(array_select_keys($tasks, $visible_phids))
->setEditMap($task_can_edit_map)
->setExcludedProjectPHIDs($select_phids);
->setExcludedProjectPHIDs($container_phids);
$templates = array();
$all_tasks = array();
@ -651,7 +256,7 @@ final class PhabricatorProjectBoardViewController
);
}
$order_key = $this->sortKey;
$order_key = $state->getOrder();
$ordering_map = PhabricatorProjectColumnOrder::getEnabledOrders();
$ordering = id(clone $ordering_map[$order_key])
@ -681,11 +286,12 @@ final class PhabricatorProjectBoardViewController
'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'),
'uploadURI' => '/file/dropupload/',
'coverURI' => $this->getApplicationURI('cover/'),
'reloadURI' => phutil_string_cast($state->newWorkboardURI('reload/')),
'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(),
'pointsEnabled' => ManiphestTaskPoints::getIsEnabled(),
'boardPHID' => $project->getPHID(),
'order' => $this->sortKey,
'order' => $state->getOrder(),
'orders' => $order_maps,
'headers' => $headers,
'headerKeys' => $header_keys,
@ -703,7 +309,7 @@ final class PhabricatorProjectBoardViewController
$sort_menu = $this->buildSortMenu(
$viewer,
$project,
$this->sortKey,
$state->getOrder(),
$ordering_map);
$filter_menu = $this->buildFilterMenu(
@ -713,7 +319,7 @@ final class PhabricatorProjectBoardViewController
$search_engine,
$query_key);
$manage_menu = $this->buildManageMenu($project, $this->showHidden);
$manage_menu = $this->buildManageMenu($project, $state->getShowHidden());
$header_link = phutil_tag(
'a',
@ -777,55 +383,14 @@ final class PhabricatorProjectBoardViewController
return $page;
}
private function readRequestState() {
$request = $this->getRequest();
$project = $this->getProject();
$this->showHidden = $request->getBool('hidden');
$this->id = $project->getID();
$sort_key = $this->getDefaultSort($project);
$request_sort = $request->getStr('order');
if ($this->isValidSort($request_sort)) {
$sort_key = $request_sort;
}
$this->sortKey = $sort_key;
}
private function getDefaultSort(PhabricatorProject $project) {
$default_sort = $project->getDefaultWorkboardSort();
if ($this->isValidSort($default_sort)) {
return $default_sort;
}
return PhabricatorProjectColumnNaturalOrder::ORDERKEY;
}
private function getDefaultFilter(PhabricatorProject $project) {
$default_filter = $project->getDefaultWorkboardFilter();
if (strlen($default_filter)) {
return $default_filter;
}
return 'open';
}
private function isValidSort($sort) {
$map = PhabricatorProjectColumnOrder::getEnabledOrders();
return isset($map[$sort]);
}
private function buildSortMenu(
PhabricatorUser $viewer,
PhabricatorProject $project,
$sort_key,
array $ordering_map) {
$base_uri = $this->getURIWithState();
$state = $this->getViewState();
$base_uri = $state->newWorkboardURI();
$items = array();
foreach ($ordering_map as $key => $ordering) {
@ -855,9 +420,7 @@ final class PhabricatorProjectBoardViewController
$id = $project->getID();
$save_uri = "default/{$id}/sort/";
$save_uri = $this->getApplicationURI($save_uri);
$save_uri = $this->getURIWithState($save_uri, $force = true);
$save_uri = $state->newWorkboardURI('default/sort/');
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
@ -900,6 +463,8 @@ final class PhabricatorProjectBoardViewController
PhabricatorApplicationSearchEngine $engine,
$query_key) {
$state = $this->getViewState();
$named = array(
'open' => pht('Open Tasks'),
'all' => pht('All Tasks'),
@ -931,24 +496,26 @@ final class PhabricatorProjectBoardViewController
->setName($name);
if ($is_custom) {
$uri = $this->getApplicationURI(
'board/'.$this->id.'/filter/query/'.$key.'/');
// When you're using a custom filter already and you select "Custom
// Filter", you get a dialog back to let you edit the filter. This is
// equivalent to selecting "Advanced Filter..." to configure a new
// filter.
$filter_uri = $state->newWorkboardURI('filter/');
$item->setWorkflow(true);
} else {
$uri = $engine->getQueryResultsPageURI($key);
$filter_uri = urisprintf('query/%s/', $key);
$filter_uri = $state->newWorkboardURI($filter_uri);
$filter_uri->removeQueryParam('filter');
}
$uri = $this->getURIWithState($uri)
->removeQueryParam('filter');
$item->setHref($uri);
$item->setHref($filter_uri);
$items[] = $item;
}
$id = $project->getID();
$filter_uri = $this->getApplicationURI("board/{$id}/filter/");
$filter_uri = $this->getURIWithState($filter_uri, $force = true);
$filter_uri = $state->newWorkboardURI('filter/');
$items[] = id(new PhabricatorActionView())
->setIcon('fa-cog')
@ -956,9 +523,7 @@ final class PhabricatorProjectBoardViewController
->setWorkflow(true)
->setName(pht('Advanced Filter...'));
$save_uri = "default/{$id}/filter/";
$save_uri = $this->getApplicationURI($save_uri);
$save_uri = $this->getURIWithState($save_uri, $force = true);
$save_uri = $state->newWorkboardURI('default/filter/');
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
@ -1000,6 +565,7 @@ final class PhabricatorProjectBoardViewController
$request = $this->getRequest();
$viewer = $request->getUser();
$state = $this->getViewState();
$id = $project->getID();
@ -1029,12 +595,12 @@ final class PhabricatorProjectBoardViewController
->setWorkflow(true);
if ($show_hidden) {
$hidden_uri = $this->getURIWithState()
$hidden_uri = $state->newWorkboardURI()
->removeQueryParam('hidden');
$hidden_icon = 'fa-eye-slash';
$hidden_text = pht('Hide Hidden Columns');
} else {
$hidden_uri = $this->getURIWithState()
$hidden_uri = $state->newWorkboardURI()
->replaceQueryParam('hidden', 'true');
$hidden_icon = 'fa-eye';
$hidden_text = pht('Show Hidden Columns');
@ -1062,13 +628,6 @@ final class PhabricatorProjectBoardViewController
->setName(pht('Manage Workboard'))
->setHref($manage_uri);
$batch_edit_uri = $request->getRequestURI();
$batch_edit_uri->replaceQueryParam('batch', self::BATCH_EDIT_ALL);
$can_batch_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
PhabricatorApplication::getByClass('PhabricatorManiphestApplication'),
ManiphestBulkEditCapability::CAPABILITY);
$manage_menu = id(new PhabricatorActionListView())
->setUser($viewer);
foreach ($manage_items as $item) {
@ -1114,6 +673,7 @@ final class PhabricatorProjectBoardViewController
$request = $this->getRequest();
$viewer = $request->getUser();
$state = $this->getViewState();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
@ -1151,36 +711,51 @@ final class PhabricatorProjectBoardViewController
$column_items[] = id(new PhabricatorActionView())
->setType(PhabricatorActionView::TYPE_DIVIDER);
$batch_edit_uri = $request->getRequestURI();
$batch_edit_uri->replaceQueryParam('batch', $column->getID());
$can_batch_edit = PhabricatorPolicyFilter::hasCapability(
$query_uri = urisprintf('viewquery/%d/', $column->getID());
$query_uri = $state->newWorkboardURI($query_uri);
$column_items[] = id(new PhabricatorActionView())
->setName(pht('View Tasks as Query'))
->setIcon('fa-search')
->setHref($query_uri);
$column_move_uri = urisprintf('bulkmove/%d/column/', $column->getID());
$column_move_uri = $state->newWorkboardURI($column_move_uri);
$column_items[] = id(new PhabricatorActionView())
->setIcon('fa-arrows-h')
->setName(pht('Move Tasks to Column...'))
->setHref($column_move_uri)
->setWorkflow(true);
$project_move_uri = urisprintf('bulkmove/%d/project/', $column->getID());
$project_move_uri = $state->newWorkboardURI($project_move_uri);
$column_items[] = id(new PhabricatorActionView())
->setIcon('fa-arrows')
->setName(pht('Move Tasks to Project...'))
->setHref($project_move_uri)
->setWorkflow(true);
$bulk_edit_uri = urisprintf('bulk/%d/', $column->getID());
$bulk_edit_uri = $state->newWorkboardURI($bulk_edit_uri);
$can_bulk_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
PhabricatorApplication::getByClass('PhabricatorManiphestApplication'),
ManiphestBulkEditCapability::CAPABILITY);
$column_items[] = id(new PhabricatorActionView())
->setIcon('fa-list-ul')
->setIcon('fa-pencil-square-o')
->setName(pht('Bulk Edit Tasks...'))
->setHref($batch_edit_uri)
->setDisabled(!$can_batch_edit);
$batch_move_uri = $request->getRequestURI();
$batch_move_uri->replaceQueryParam('move', $column->getID());
$column_items[] = id(new PhabricatorActionView())
->setIcon('fa-arrow-right')
->setName(pht('Move Tasks to Column...'))
->setHref($batch_move_uri)
->setWorkflow(true);
$query_uri = $request->getRequestURI();
$query_uri->replaceQueryParam('queryColumnID', $column->getID());
->setHref($bulk_edit_uri)
->setDisabled(!$can_bulk_edit);
$column_items[] = id(new PhabricatorActionView())
->setName(pht('View as Query'))
->setIcon('fa-search')
->setHref($query_uri);
->setType(PhabricatorActionView::TYPE_DIVIDER);
$edit_uri = 'board/'.$this->id.'/edit/'.$column->getID().'/';
$edit_uri = 'board/'.$project->getID().'/edit/'.$column->getID().'/';
$column_items[] = id(new PhabricatorActionView())
->setName(pht('Edit Column'))
->setIcon('fa-pencil')
@ -1189,9 +764,9 @@ final class PhabricatorProjectBoardViewController
->setWorkflow(true);
$can_hide = ($can_edit && !$column->isDefaultColumn());
$hide_uri = 'board/'.$this->id.'/hide/'.$column->getID().'/';
$hide_uri = $this->getApplicationURI($hide_uri);
$hide_uri = $this->getURIWithState($hide_uri);
$hide_uri = urisprintf('hide/%d/', $column->getID());
$hide_uri = $state->newWorkboardURI($hide_uri);
if (!$column->isHidden()) {
$column_items[] = id(new PhabricatorActionView())
@ -1297,56 +872,6 @@ final class PhabricatorProjectBoardViewController
return $trigger_button;
}
/**
* Add current state parameters (like order and the visibility of hidden
* columns) to a URI.
*
* This allows actions which toggle or adjust one piece of state to keep
* the rest of the board state persistent. If no URI is provided, this method
* starts with the request URI.
*
* @param string|null URI to add state parameters to.
* @param bool True to explicitly include all state.
* @return PhutilURI URI with state parameters.
*/
private function getURIWithState($base = null, $force = false) {
$project = $this->getProject();
if ($base === null) {
$base = $this->getRequest()->getPath();
}
$base = new PhutilURI($base);
if ($force || ($this->sortKey != $this->getDefaultSort($project))) {
if ($this->sortKey !== null) {
$base->replaceQueryParam('order', $this->sortKey);
} else {
$base->removeQueryParam('order');
}
} else {
$base->removeQueryParam('order');
}
if ($force || ($this->queryKey != $this->getDefaultFilter($project))) {
if ($this->queryKey !== null) {
$base->replaceQueryParam('filter', $this->queryKey);
} else {
$base->removeQueryParam('filter');
}
} else {
$base->removeQueryParam('filter');
}
if ($this->showHidden) {
$base->replaceQueryParam('hidden', 'true');
} else {
$base->removeQueryParam('hidden');
}
return $base;
}
private function buildInitializeContent(PhabricatorProject $project) {
$request = $this->getRequest();
$viewer = $this->getViewer();

View file

@ -0,0 +1,72 @@
<?php
final class PhabricatorProjectColumnBulkEditController
extends PhabricatorProjectBoardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$response = $this->loadProject();
if ($response) {
return $response;
}
$project = $this->getProject();
$state = $this->getViewState();
$board_uri = $state->newWorkboardURI();
$layout_engine = $state->getLayoutEngine();
$board_phid = $project->getPHID();
$columns = $layout_engine->getColumns($board_phid);
$columns = mpull($columns, null, 'getID');
$column_id = $request->getURIData('columnID');
$bulk_column = idx($columns, $column_id);
if (!$bulk_column) {
return new Aphront404Response();
}
$bulk_task_phids = $layout_engine->getColumnObjectPHIDs(
$board_phid,
$bulk_column->getPHID());
$tasks = $state->getObjects();
$bulk_tasks = array_select_keys($tasks, $bulk_task_phids);
$bulk_tasks = id(new PhabricatorPolicyFilter())
->setViewer($viewer)
->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))
->apply($bulk_tasks);
if (!$bulk_tasks) {
return $this->newDialog()
->setTitle(pht('No Editable Tasks'))
->appendParagraph(
pht(
'The selected column contains no visible tasks which you '.
'have permission to edit.'))
->addCancelButton($board_uri);
}
// Create a saved query to hold the working set. This allows us to get
// around URI length limitations with a long "?ids=..." query string.
// For details, see T10268.
$search_engine = id(new ManiphestTaskSearchEngine())
->setViewer($viewer);
$saved_query = $search_engine->newSavedQuery();
$saved_query->setParameter('ids', mpull($bulk_tasks, 'getID'));
$search_engine->saveQuery($saved_query);
$query_key = $saved_query->getQueryKey();
$bulk_uri = new PhutilURI("/maniphest/bulk/query/{$query_key}/");
$bulk_uri->replaceQueryParam('board', $project->getID());
return id(new AphrontRedirectResponse())
->setURI($bulk_uri);
}
}

View file

@ -0,0 +1,264 @@
<?php
final class PhabricatorProjectColumnBulkMoveController
extends PhabricatorProjectBoardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$response = $this->loadProject();
if ($response) {
return $response;
}
// See T13316. If we're operating in "column" mode, we're going to skip
// the prompt for a project and just have the user select a target column.
// In "project" mode, we prompt them for a project first.
$is_column_mode = ($request->getURIData('mode') === 'column');
$src_project = $this->getProject();
$state = $this->getViewState();
$board_uri = $state->newWorkboardURI();
$layout_engine = $state->getLayoutEngine();
$board_phid = $src_project->getPHID();
$columns = $layout_engine->getColumns($board_phid);
$columns = mpull($columns, null, 'getID');
$column_id = $request->getURIData('columnID');
$src_column = idx($columns, $column_id);
if (!$src_column) {
return new Aphront404Response();
}
$move_task_phids = $layout_engine->getColumnObjectPHIDs(
$board_phid,
$src_column->getPHID());
$tasks = $state->getObjects();
$move_tasks = array_select_keys($tasks, $move_task_phids);
$move_tasks = id(new PhabricatorPolicyFilter())
->setViewer($viewer)
->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))
->apply($move_tasks);
if (!$move_tasks) {
return $this->newDialog()
->setTitle(pht('No Movable Tasks'))
->appendParagraph(
pht(
'The selected column contains no visible tasks which you '.
'have permission to move.'))
->addCancelButton($board_uri);
}
$dst_project_phid = null;
$dst_project = null;
$has_project = false;
if ($is_column_mode) {
$has_project = true;
$dst_project_phid = $src_project->getPHID();
} else {
if ($request->isFormOrHiSecPost()) {
$has_project = $request->getStr('hasProject');
if ($has_project) {
// We may read this from a tokenizer input as an array, or from a
// hidden input as a string.
$dst_project_phid = head($request->getArr('dstProjectPHID'));
if (!$dst_project_phid) {
$dst_project_phid = $request->getStr('dstProjectPHID');
}
}
}
}
$errors = array();
$hidden = array();
if ($has_project) {
if (!$dst_project_phid) {
$errors[] = pht('Choose a project to move tasks to.');
} else {
$dst_project = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->withPHIDs(array($dst_project_phid))
->executeOne();
if (!$dst_project) {
$errors[] = pht('Choose a valid project to move tasks to.');
}
if (!$dst_project->getHasWorkboard()) {
$errors[] = pht('You must choose a project with a workboard.');
$dst_project = null;
}
}
}
if ($dst_project) {
$same_project = ($src_project->getID() === $dst_project->getID());
$layout_engine = id(new PhabricatorBoardLayoutEngine())
->setViewer($viewer)
->setBoardPHIDs(array($dst_project->getPHID()))
->setFetchAllBoards(true)
->executeLayout();
$dst_columns = $layout_engine->getColumns($dst_project->getPHID());
$dst_columns = mpull($columns, null, 'getPHID');
$has_column = false;
$dst_column = null;
// If we're performing a move on the same board, default the
// control value to the current column.
if ($same_project) {
$dst_column_phid = $src_column->getPHID();
} else {
$dst_column_phid = null;
}
if ($request->isFormOrHiSecPost()) {
$has_column = $request->getStr('hasColumn');
if ($has_column) {
$dst_column_phid = $request->getStr('dstColumnPHID');
}
}
if ($has_column) {
$dst_column = idx($dst_columns, $dst_column_phid);
if (!$dst_column) {
$errors[] = pht('Choose a column to move tasks to.');
} else {
if ($dst_column->isHidden()) {
$errors[] = pht('You can not move tasks to a hidden column.');
$dst_column = null;
} else if ($dst_column->getPHID() === $src_column->getPHID()) {
$errors[] = pht('You can not move tasks from a column to itself.');
$dst_column = null;
}
}
}
if ($dst_column) {
foreach ($move_tasks as $move_task) {
$xactions = array();
// If we're switching projects, get out of the old project first
// and move to the new project.
if (!$same_project) {
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue(
'edge:type',
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)
->setNewValue(
array(
'-' => array(
$src_project->getPHID() => $src_project->getPHID(),
),
'+' => array(
$dst_project->getPHID() => $dst_project->getPHID(),
),
));
}
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COLUMNS)
->setNewValue(
array(
array(
'columnPHID' => $dst_column->getPHID(),
),
));
$editor = id(new ManiphestTransactionEditor())
->setActor($viewer)
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setCancelURI($board_uri);
$editor->applyTransactions($move_task, $xactions);
}
// If we did a move on the same workboard, redirect and preserve the
// state parameters. If we moved to a different workboard, go there
// with clean default state.
if ($same_project) {
$done_uri = $board_uri;
} else {
$done_uri = $dst_project->getWorkboardURI();
}
return id(new AphrontRedirectResponse())->setURI($done_uri);
}
$title = pht('Move Tasks to Column');
$form = id(new AphrontFormView())
->setViewer($viewer);
// If we're moving between projects, add a reminder about which project
// you selected in the previous step.
if (!$is_column_mode) {
$form->appendControl(
id(new AphrontFormStaticControl())
->setLabel(pht('Project'))
->setValue($dst_project->getDisplayName()));
}
$form->appendControl(
id(new AphrontFormSelectControl())
->setName('dstColumnPHID')
->setLabel(pht('Move to Column'))
->setValue($dst_column_phid)
->setOptions(mpull($dst_columns, 'getDisplayName', 'getPHID')));
$submit = pht('Move Tasks');
$hidden['dstProjectPHID'] = $dst_project->getPHID();
$hidden['hasColumn'] = true;
$hidden['hasProject'] = true;
} else {
$title = pht('Move Tasks to Project');
if ($dst_project_phid) {
$dst_project_phid_value = array($dst_project_phid);
} else {
$dst_project_phid_value = array();
}
$form = id(new AphrontFormView())
->setViewer($viewer)
->appendControl(
id(new AphrontFormTokenizerControl())
->setName('dstProjectPHID')
->setLimit(1)
->setLabel(pht('Move to Project'))
->setValue($dst_project_phid_value)
->setDatasource(new PhabricatorProjectDatasource()));
$submit = pht('Continue');
$hidden['hasProject'] = true;
}
$dialog = $this->newWorkboardDialog()
->setWidth(AphrontDialogView::WIDTH_FORM)
->setTitle($title)
->setErrors($errors)
->appendForm($form)
->addSubmitButton($submit)
->addCancelButton($board_uri);
foreach ($hidden as $key => $value) {
$dialog->addHiddenInput($key, $value);
}
return $dialog;
}
}

Some files were not shown because too many files have changed in this diff Show more