1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-15 10:00:55 +01:00

(stable) Promote 2017 Week 26

This commit is contained in:
epriestley 2017-06-30 17:15:52 -07:00
commit 5306fbfa7a
71 changed files with 1095 additions and 542 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 411 B

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View file

@ -18,6 +18,7 @@ AllowTcpForwarding no
PrintMotd no
PrintLastLog no
PasswordAuthentication no
ChallengeResponseAuthentication no
AuthorizedKeysFile none
PidFile /var/run/sshd-phabricator.pid

View file

@ -1488,8 +1488,8 @@ phutil_register_library_map(array(
'ManiphestHovercardEngineExtension' => 'applications/maniphest/engineextension/ManiphestHovercardEngineExtension.php',
'ManiphestInfoConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php',
'ManiphestNameIndex' => 'applications/maniphest/storage/ManiphestNameIndex.php',
'ManiphestPointsConfigOptionType' => 'applications/maniphest/config/ManiphestPointsConfigOptionType.php',
'ManiphestPriorityConfigOptionType' => 'applications/maniphest/config/ManiphestPriorityConfigOptionType.php',
'ManiphestPointsConfigType' => 'applications/maniphest/config/ManiphestPointsConfigType.php',
'ManiphestPrioritiesConfigType' => 'applications/maniphest/config/ManiphestPrioritiesConfigType.php',
'ManiphestPriorityEmailCommand' => 'applications/maniphest/command/ManiphestPriorityEmailCommand.php',
'ManiphestPrioritySearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestPrioritySearchConduitAPIMethod.php',
'ManiphestProjectNameFulltextEngineExtension' => 'applications/maniphest/engineextension/ManiphestProjectNameFulltextEngineExtension.php',
@ -1500,11 +1500,11 @@ phutil_register_library_map(array(
'ManiphestReportController' => 'applications/maniphest/controller/ManiphestReportController.php',
'ManiphestSchemaSpec' => 'applications/maniphest/storage/ManiphestSchemaSpec.php',
'ManiphestSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestSearchConduitAPIMethod.php',
'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php',
'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php',
'ManiphestStatusSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php',
'ManiphestStatusesConfigType' => 'applications/maniphest/config/ManiphestStatusesConfigType.php',
'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php',
'ManiphestSubtypesConfigOptionsType' => 'applications/maniphest/config/ManiphestSubtypesConfigOptionsType.php',
'ManiphestSubtypesConfigType' => 'applications/maniphest/config/ManiphestSubtypesConfigType.php',
'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php',
'ManiphestTaskAssignHeraldAction' => 'applications/maniphest/herald/ManiphestTaskAssignHeraldAction.php',
'ManiphestTaskAssignOtherHeraldAction' => 'applications/maniphest/herald/ManiphestTaskAssignOtherHeraldAction.php',
@ -2153,6 +2153,7 @@ phutil_register_library_map(array(
'PhabricatorBoardLayoutEngine' => 'applications/project/engine/PhabricatorBoardLayoutEngine.php',
'PhabricatorBoardRenderingEngine' => 'applications/project/engine/PhabricatorBoardRenderingEngine.php',
'PhabricatorBoardResponseEngine' => 'applications/project/engine/PhabricatorBoardResponseEngine.php',
'PhabricatorBoolConfigType' => 'applications/config/type/PhabricatorBoolConfigType.php',
'PhabricatorBoolEditField' => 'applications/transactions/editfield/PhabricatorBoolEditField.php',
'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php',
'PhabricatorBuiltinDraftEngine' => 'applications/transactions/draft/PhabricatorBuiltinDraftEngine.php',
@ -2328,14 +2329,15 @@ phutil_register_library_map(array(
'PhabricatorChatLogEvent' => 'applications/chatlog/storage/PhabricatorChatLogEvent.php',
'PhabricatorChatLogQuery' => 'applications/chatlog/query/PhabricatorChatLogQuery.php',
'PhabricatorChunkedFileStorageEngine' => 'applications/files/engine/PhabricatorChunkedFileStorageEngine.php',
'PhabricatorClassConfigType' => 'applications/config/type/PhabricatorClassConfigType.php',
'PhabricatorClusterConfigOptions' => 'applications/config/option/PhabricatorClusterConfigOptions.php',
'PhabricatorClusterDatabasesConfigOptionType' => 'infrastructure/cluster/config/PhabricatorClusterDatabasesConfigOptionType.php',
'PhabricatorClusterDatabasesConfigType' => 'infrastructure/cluster/config/PhabricatorClusterDatabasesConfigType.php',
'PhabricatorClusterException' => 'infrastructure/cluster/exception/PhabricatorClusterException.php',
'PhabricatorClusterExceptionHandler' => 'infrastructure/cluster/exception/PhabricatorClusterExceptionHandler.php',
'PhabricatorClusterImpossibleWriteException' => 'infrastructure/cluster/exception/PhabricatorClusterImpossibleWriteException.php',
'PhabricatorClusterImproperWriteException' => 'infrastructure/cluster/exception/PhabricatorClusterImproperWriteException.php',
'PhabricatorClusterNoHostForRoleException' => 'infrastructure/cluster/exception/PhabricatorClusterNoHostForRoleException.php',
'PhabricatorClusterSearchConfigOptionType' => 'infrastructure/cluster/config/PhabricatorClusterSearchConfigOptionType.php',
'PhabricatorClusterSearchConfigType' => 'infrastructure/cluster/config/PhabricatorClusterSearchConfigType.php',
'PhabricatorClusterServiceHealthRecord' => 'infrastructure/cluster/PhabricatorClusterServiceHealthRecord.php',
'PhabricatorClusterStrandedException' => 'infrastructure/cluster/exception/PhabricatorClusterStrandedException.php',
'PhabricatorColumnProxyInterface' => 'applications/project/interface/PhabricatorColumnProxyInterface.php',
@ -2448,6 +2450,7 @@ phutil_register_library_map(array(
'PhabricatorConfigTableSchema' => 'applications/config/schema/PhabricatorConfigTableSchema.php',
'PhabricatorConfigTransaction' => 'applications/config/storage/PhabricatorConfigTransaction.php',
'PhabricatorConfigTransactionQuery' => 'applications/config/query/PhabricatorConfigTransactionQuery.php',
'PhabricatorConfigType' => 'applications/config/type/PhabricatorConfigType.php',
'PhabricatorConfigValidationException' => 'applications/config/exception/PhabricatorConfigValidationException.php',
'PhabricatorConfigVersionController' => 'applications/config/controller/PhabricatorConfigVersionController.php',
'PhabricatorConpherenceApplication' => 'applications/conpherence/application/PhabricatorConpherenceApplication.php',
@ -2754,6 +2757,7 @@ phutil_register_library_map(array(
'PhabricatorEmojiRemarkupRule' => 'applications/macro/markup/PhabricatorEmojiRemarkupRule.php',
'PhabricatorEmojiTranslation' => 'infrastructure/internationalization/translation/PhabricatorEmojiTranslation.php',
'PhabricatorEmptyQueryException' => 'infrastructure/query/PhabricatorEmptyQueryException.php',
'PhabricatorEnumConfigType' => 'applications/config/type/PhabricatorEnumConfigType.php',
'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php',
'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php',
'PhabricatorEpochEditField' => 'applications/transactions/editfield/PhabricatorEpochEditField.php',
@ -2997,6 +3001,7 @@ phutil_register_library_map(array(
'PhabricatorInlineCommentPreviewController' => 'infrastructure/diff/PhabricatorInlineCommentPreviewController.php',
'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php',
'PhabricatorInstructionsEditField' => 'applications/transactions/editfield/PhabricatorInstructionsEditField.php',
'PhabricatorIntConfigType' => 'applications/config/type/PhabricatorIntConfigType.php',
'PhabricatorInternalSetting' => 'applications/settings/setting/PhabricatorInternalSetting.php',
'PhabricatorInternationalizationManagementExtractWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php',
'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php',
@ -3005,6 +3010,7 @@ phutil_register_library_map(array(
'PhabricatorIteratedMD5PasswordHasherTestCase' => 'infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php',
'PhabricatorIteratorFileUploadSource' => 'applications/files/uploadsource/PhabricatorIteratorFileUploadSource.php',
'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php',
'PhabricatorJSONConfigType' => 'applications/config/type/PhabricatorJSONConfigType.php',
'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php',
'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php',
'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php',
@ -3193,7 +3199,7 @@ phutil_register_library_map(array(
'PhabricatorNotificationQuery' => 'applications/notification/query/PhabricatorNotificationQuery.php',
'PhabricatorNotificationSearchEngine' => 'applications/notification/query/PhabricatorNotificationSearchEngine.php',
'PhabricatorNotificationServerRef' => 'applications/notification/client/PhabricatorNotificationServerRef.php',
'PhabricatorNotificationServersConfigOptionType' => 'applications/notification/config/PhabricatorNotificationServersConfigOptionType.php',
'PhabricatorNotificationServersConfigType' => 'applications/notification/config/PhabricatorNotificationServersConfigType.php',
'PhabricatorNotificationStatusView' => 'applications/notification/view/PhabricatorNotificationStatusView.php',
'PhabricatorNotificationTestController' => 'applications/notification/controller/PhabricatorNotificationTestController.php',
'PhabricatorNotificationTestFeedStory' => 'applications/notification/feed/PhabricatorNotificationTestFeedStory.php',
@ -3608,7 +3614,7 @@ phutil_register_library_map(array(
'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php',
'PhabricatorProjectCardView' => 'applications/project/view/PhabricatorProjectCardView.php',
'PhabricatorProjectColorTransaction' => 'applications/project/xaction/PhabricatorProjectColorTransaction.php',
'PhabricatorProjectColorsConfigOptionType' => 'applications/project/config/PhabricatorProjectColorsConfigOptionType.php',
'PhabricatorProjectColorsConfigType' => 'applications/project/config/PhabricatorProjectColorsConfigType.php',
'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php',
'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php',
'PhabricatorProjectColumnEditController' => 'applications/project/controller/PhabricatorProjectColumnEditController.php',
@ -3646,7 +3652,7 @@ phutil_register_library_map(array(
'PhabricatorProjectHovercardEngineExtension' => 'applications/project/engineextension/PhabricatorProjectHovercardEngineExtension.php',
'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php',
'PhabricatorProjectIconTransaction' => 'applications/project/xaction/PhabricatorProjectIconTransaction.php',
'PhabricatorProjectIconsConfigOptionType' => 'applications/project/config/PhabricatorProjectIconsConfigOptionType.php',
'PhabricatorProjectIconsConfigType' => 'applications/project/config/PhabricatorProjectIconsConfigType.php',
'PhabricatorProjectImageTransaction' => 'applications/project/xaction/PhabricatorProjectImageTransaction.php',
'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php',
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
@ -3743,6 +3749,7 @@ phutil_register_library_map(array(
'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php',
'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php',
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php',
'PhabricatorRegexListConfigType' => 'applications/config/type/PhabricatorRegexListConfigType.php',
'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php',
'PhabricatorReleephApplication' => 'applications/releeph/application/PhabricatorReleephApplication.php',
'PhabricatorReleephApplicationConfigOptions' => 'applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php',
@ -3937,6 +3944,7 @@ phutil_register_library_map(array(
'PhabricatorSelectSetting' => 'applications/settings/setting/PhabricatorSelectSetting.php',
'PhabricatorSendGridConfigOptions' => 'applications/config/option/PhabricatorSendGridConfigOptions.php',
'PhabricatorSessionsSettingsPanel' => 'applications/settings/panel/PhabricatorSessionsSettingsPanel.php',
'PhabricatorSetConfigType' => 'applications/config/type/PhabricatorSetConfigType.php',
'PhabricatorSetting' => 'applications/settings/setting/PhabricatorSetting.php',
'PhabricatorSettingsAccountPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsAccountPanelGroup.php',
'PhabricatorSettingsAddEmailAction' => 'applications/settings/action/PhabricatorSettingsAddEmailAction.php',
@ -4067,6 +4075,8 @@ phutil_register_library_map(array(
'PhabricatorStoragePatch' => 'infrastructure/storage/management/PhabricatorStoragePatch.php',
'PhabricatorStorageSchemaSpec' => 'infrastructure/storage/schema/PhabricatorStorageSchemaSpec.php',
'PhabricatorStorageSetupCheck' => 'applications/config/check/PhabricatorStorageSetupCheck.php',
'PhabricatorStringConfigType' => 'applications/config/type/PhabricatorStringConfigType.php',
'PhabricatorStringListConfigType' => 'applications/config/type/PhabricatorStringListConfigType.php',
'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php',
'PhabricatorStringSetting' => 'applications/settings/setting/PhabricatorStringSetting.php',
'PhabricatorSubmitEditField' => 'applications/transactions/editfield/PhabricatorSubmitEditField.php',
@ -4127,7 +4137,9 @@ phutil_register_library_map(array(
'PhabricatorTestStorageEngine' => 'applications/files/engine/PhabricatorTestStorageEngine.php',
'PhabricatorTestWorker' => 'infrastructure/daemon/workers/__tests__/PhabricatorTestWorker.php',
'PhabricatorTextAreaEditField' => 'applications/transactions/editfield/PhabricatorTextAreaEditField.php',
'PhabricatorTextConfigType' => 'applications/config/type/PhabricatorTextConfigType.php',
'PhabricatorTextEditField' => 'applications/transactions/editfield/PhabricatorTextEditField.php',
'PhabricatorTextListConfigType' => 'applications/config/type/PhabricatorTextListConfigType.php',
'PhabricatorTime' => 'infrastructure/time/PhabricatorTime.php',
'PhabricatorTimeFormatSetting' => 'applications/settings/setting/PhabricatorTimeFormatSetting.php',
'PhabricatorTimeGuard' => 'infrastructure/time/PhabricatorTimeGuard.php',
@ -4252,6 +4264,7 @@ phutil_register_library_map(array(
'PhabricatorWebContentSource' => 'infrastructure/contentsource/PhabricatorWebContentSource.php',
'PhabricatorWebServerSetupCheck' => 'applications/config/check/PhabricatorWebServerSetupCheck.php',
'PhabricatorWeekStartDaySetting' => 'applications/settings/setting/PhabricatorWeekStartDaySetting.php',
'PhabricatorWildConfigType' => 'applications/config/type/PhabricatorWildConfigType.php',
'PhabricatorWordPressAuthProvider' => 'applications/auth/provider/PhabricatorWordPressAuthProvider.php',
'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php',
'PhabricatorWorkerActiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php',
@ -6590,8 +6603,8 @@ phutil_register_library_map(array(
'ManiphestHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
'ManiphestInfoConduitAPIMethod' => 'ManiphestConduitAPIMethod',
'ManiphestNameIndex' => 'ManiphestDAO',
'ManiphestPointsConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'ManiphestPriorityConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'ManiphestPointsConfigType' => 'PhabricatorJSONConfigType',
'ManiphestPrioritiesConfigType' => 'PhabricatorJSONConfigType',
'ManiphestPriorityEmailCommand' => 'ManiphestEmailCommand',
'ManiphestPrioritySearchConduitAPIMethod' => 'ManiphestConduitAPIMethod',
'ManiphestProjectNameFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
@ -6602,11 +6615,11 @@ phutil_register_library_map(array(
'ManiphestReportController' => 'ManiphestController',
'ManiphestSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'ManiphestSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'ManiphestStatusEmailCommand' => 'ManiphestEmailCommand',
'ManiphestStatusSearchConduitAPIMethod' => 'ManiphestConduitAPIMethod',
'ManiphestStatusesConfigType' => 'PhabricatorJSONConfigType',
'ManiphestSubpriorityController' => 'ManiphestController',
'ManiphestSubtypesConfigOptionsType' => 'PhabricatorConfigJSONOptionType',
'ManiphestSubtypesConfigType' => 'PhabricatorJSONConfigType',
'ManiphestTask' => array(
'ManiphestDAO',
'PhabricatorSubscribableInterface',
@ -7348,6 +7361,7 @@ phutil_register_library_map(array(
'PhabricatorBoardLayoutEngine' => 'Phobject',
'PhabricatorBoardRenderingEngine' => 'Phobject',
'PhabricatorBoardResponseEngine' => 'Phobject',
'PhabricatorBoolConfigType' => 'PhabricatorTextConfigType',
'PhabricatorBoolEditField' => 'PhabricatorEditField',
'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation',
'PhabricatorBuiltinDraftEngine' => 'PhabricatorDraftEngine',
@ -7565,14 +7579,15 @@ phutil_register_library_map(array(
),
'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorChunkedFileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorClassConfigType' => 'PhabricatorTextConfigType',
'PhabricatorClusterConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorClusterDatabasesConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'PhabricatorClusterDatabasesConfigType' => 'PhabricatorJSONConfigType',
'PhabricatorClusterException' => 'Exception',
'PhabricatorClusterExceptionHandler' => 'PhabricatorRequestExceptionHandler',
'PhabricatorClusterImpossibleWriteException' => 'PhabricatorClusterException',
'PhabricatorClusterImproperWriteException' => 'PhabricatorClusterException',
'PhabricatorClusterNoHostForRoleException' => 'Exception',
'PhabricatorClusterSearchConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'PhabricatorClusterSearchConfigType' => 'PhabricatorJSONConfigType',
'PhabricatorClusterServiceHealthRecord' => 'Phobject',
'PhabricatorClusterStrandedException' => 'PhabricatorClusterException',
'PhabricatorColumnsEditField' => 'PhabricatorPHIDListEditField',
@ -7697,6 +7712,7 @@ phutil_register_library_map(array(
'PhabricatorConfigTableSchema' => 'PhabricatorConfigStorageSchema',
'PhabricatorConfigTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorConfigType' => 'Phobject',
'PhabricatorConfigValidationException' => 'Exception',
'PhabricatorConfigVersionController' => 'PhabricatorConfigController',
'PhabricatorConpherenceApplication' => 'PhabricatorApplication',
@ -8040,6 +8056,7 @@ phutil_register_library_map(array(
'PhabricatorEmojiRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorEmojiTranslation' => 'PhutilTranslation',
'PhabricatorEmptyQueryException' => 'Exception',
'PhabricatorEnumConfigType' => 'PhabricatorTextConfigType',
'PhabricatorEnv' => 'Phobject',
'PhabricatorEnvTestCase' => 'PhabricatorTestCase',
'PhabricatorEpochEditField' => 'PhabricatorEditField',
@ -8324,6 +8341,7 @@ phutil_register_library_map(array(
'PhabricatorInlineCommentPreviewController' => 'PhabricatorController',
'PhabricatorInlineSummaryView' => 'AphrontView',
'PhabricatorInstructionsEditField' => 'PhabricatorEditField',
'PhabricatorIntConfigType' => 'PhabricatorTextConfigType',
'PhabricatorInternalSetting' => 'PhabricatorSetting',
'PhabricatorInternationalizationManagementExtractWorkflow' => 'PhabricatorInternationalizationManagementWorkflow',
'PhabricatorInternationalizationManagementWorkflow' => 'PhabricatorManagementWorkflow',
@ -8332,6 +8350,7 @@ phutil_register_library_map(array(
'PhabricatorIteratedMD5PasswordHasherTestCase' => 'PhabricatorTestCase',
'PhabricatorIteratorFileUploadSource' => 'PhabricatorFileUploadSource',
'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider',
'PhabricatorJSONConfigType' => 'PhabricatorTextConfigType',
'PhabricatorJavelinLinter' => 'ArcanistLinter',
'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorJumpNavHandler' => 'Phobject',
@ -8533,7 +8552,7 @@ phutil_register_library_map(array(
'PhabricatorNotificationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorNotificationSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorNotificationServerRef' => 'Phobject',
'PhabricatorNotificationServersConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'PhabricatorNotificationServersConfigType' => 'PhabricatorJSONConfigType',
'PhabricatorNotificationStatusView' => 'AphrontTagView',
'PhabricatorNotificationTestController' => 'PhabricatorNotificationController',
'PhabricatorNotificationTestFeedStory' => 'PhabricatorFeedStory',
@ -9046,7 +9065,7 @@ phutil_register_library_map(array(
'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectCardView' => 'AphrontTagView',
'PhabricatorProjectColorTransaction' => 'PhabricatorProjectTransactionType',
'PhabricatorProjectColorsConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'PhabricatorProjectColorsConfigType' => 'PhabricatorJSONConfigType',
'PhabricatorProjectColumn' => array(
'PhabricatorProjectDAO',
'PhabricatorApplicationTransactionInterface',
@ -9097,7 +9116,7 @@ phutil_register_library_map(array(
'PhabricatorProjectHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
'PhabricatorProjectIconSet' => 'PhabricatorIconSet',
'PhabricatorProjectIconTransaction' => 'PhabricatorProjectTransactionType',
'PhabricatorProjectIconsConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'PhabricatorProjectIconsConfigType' => 'PhabricatorJSONConfigType',
'PhabricatorProjectImageTransaction' => 'PhabricatorProjectTransactionType',
'PhabricatorProjectListController' => 'PhabricatorProjectController',
'PhabricatorProjectListView' => 'AphrontView',
@ -9199,6 +9218,7 @@ phutil_register_library_map(array(
'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorRedirectController' => 'PhabricatorController',
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
'PhabricatorRegexListConfigType' => 'PhabricatorTextListConfigType',
'PhabricatorRegistrationProfile' => 'Phobject',
'PhabricatorReleephApplication' => 'PhabricatorApplication',
'PhabricatorReleephApplicationConfigOptions' => 'PhabricatorApplicationConfigOptions',
@ -9453,6 +9473,7 @@ phutil_register_library_map(array(
'PhabricatorSelectSetting' => 'PhabricatorSetting',
'PhabricatorSendGridConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorSessionsSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorSetConfigType' => 'PhabricatorTextConfigType',
'PhabricatorSetting' => 'Phobject',
'PhabricatorSettingsAccountPanelGroup' => 'PhabricatorSettingsPanelGroup',
'PhabricatorSettingsAddEmailAction' => 'PhabricatorSystemAction',
@ -9600,6 +9621,8 @@ phutil_register_library_map(array(
'PhabricatorStoragePatch' => 'Phobject',
'PhabricatorStorageSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorStringConfigType' => 'PhabricatorTextConfigType',
'PhabricatorStringListConfigType' => 'PhabricatorTextListConfigType',
'PhabricatorStringListEditField' => 'PhabricatorEditField',
'PhabricatorStringSetting' => 'PhabricatorSetting',
'PhabricatorSubmitEditField' => 'PhabricatorEditField',
@ -9659,7 +9682,9 @@ phutil_register_library_map(array(
'PhabricatorTestStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorTestWorker' => 'PhabricatorWorker',
'PhabricatorTextAreaEditField' => 'PhabricatorEditField',
'PhabricatorTextConfigType' => 'PhabricatorConfigType',
'PhabricatorTextEditField' => 'PhabricatorEditField',
'PhabricatorTextListConfigType' => 'PhabricatorTextConfigType',
'PhabricatorTime' => 'Phobject',
'PhabricatorTimeFormatSetting' => 'PhabricatorSelectSetting',
'PhabricatorTimeGuard' => 'Phobject',
@ -9817,6 +9842,7 @@ phutil_register_library_map(array(
'PhabricatorWebContentSource' => 'PhabricatorContentSource',
'PhabricatorWebServerSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorWeekStartDaySetting' => 'PhabricatorSelectSetting',
'PhabricatorWildConfigType' => 'PhabricatorJSONConfigType',
'PhabricatorWordPressAuthProvider' => 'PhabricatorOAuth2AuthProvider',
'PhabricatorWorker' => 'Phobject',
'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask',

View file

@ -274,6 +274,56 @@ final class PhabricatorConfigEditController
PhabricatorConfigOption $option,
AphrontRequest $request) {
$type = $option->newOptionType();
if ($type) {
$is_set = $type->isValuePresentInRequest($option, $request);
if ($is_set) {
$value = $type->readValueFromRequest($option, $request);
$errors = array();
try {
$canonical_value = $type->newValueFromRequestValue(
$option,
$value);
$type->validateStoredValue($option, $canonical_value);
$xaction = $type->newTransaction($option, $canonical_value);
} catch (PhabricatorConfigValidationException $ex) {
$errors[] = $ex->getMessage();
$xaction = null;
} catch (Exception $ex) {
// NOTE: Some older validators throw bare exceptions. Purely in good
// taste, it would be nice to convert these at some point.
$errors[] = $ex->getMessage();
$xaction = null;
}
return array(
$errors ? pht('Invalid') : null,
$errors,
$value,
$xaction,
);
} else {
$delete_xaction = id(new PhabricatorConfigTransaction())
->setTransactionType(PhabricatorConfigTransaction::TYPE_EDIT)
->setNewValue(
array(
'deleted' => true,
'value' => null,
));
return array(
null,
array(),
null,
$delete_xaction,
);
}
}
// TODO: If we missed on the new `PhabricatorConfigType` map, fall back
// to the old semi-modular, semi-hacky way of doing things.
$xaction = new PhabricatorConfigTransaction();
$xaction->setTransactionType(PhabricatorConfigTransaction::TYPE_EDIT);
@ -284,92 +334,10 @@ final class PhabricatorConfigEditController
$info = $option->getCustomObject()->readRequest($option, $request);
list($e_value, $errors, $set_value, $value) = $info;
} else {
$value = $request->getStr('value');
if (!strlen($value)) {
$value = null;
$xaction->setNewValue(
array(
'deleted' => true,
'value' => null,
));
return array($e_value, $errors, $value, $xaction);
}
$type = $option->getType();
$set_value = null;
switch ($type) {
case 'int':
if (preg_match('/^-?[0-9]+$/', trim($value))) {
$set_value = (int)$value;
} else {
$e_value = pht('Invalid');
$errors[] = pht('Value must be an integer.');
}
break;
case 'string':
case 'enum':
$set_value = (string)$value;
break;
case 'list<string>':
case 'list<regex>':
$set_value = phutil_split_lines(
$request->getStr('value'),
$retain_endings = false);
foreach ($set_value as $key => $v) {
if (!strlen($v)) {
unset($set_value[$key]);
}
}
$set_value = array_values($set_value);
break;
case 'set':
$set_value = array_fill_keys($request->getStrList('value'), true);
break;
case 'bool':
switch ($value) {
case 'true':
$set_value = true;
break;
case 'false':
$set_value = false;
break;
default:
$e_value = pht('Invalid');
$errors[] = pht('Value must be boolean, "true" or "false".');
break;
}
break;
case 'class':
if (!class_exists($value)) {
$e_value = pht('Invalid');
$errors[] = pht('Class does not exist.');
} else {
$base = $option->getBaseClass();
if (!is_subclass_of($value, $base)) {
$e_value = pht('Invalid');
$errors[] = pht('Class is not of valid type.');
} else {
$set_value = $value;
}
}
break;
default:
$json = json_decode($value, true);
if ($json === null && strtolower($value) != 'null') {
$e_value = pht('Invalid');
$errors[] = pht(
'The given value must be valid JSON. This means, among '.
'other things, that you must wrap strings in double-quotes.');
} else {
$set_value = $json;
}
break;
}
throw new Exception(
pht(
'Unknown configuration option type "%s".',
$option->getType()));
}
if (!$errors) {
@ -390,30 +358,22 @@ final class PhabricatorConfigEditController
PhabricatorConfigEntry $entry,
$value) {
$type = $option->newOptionType();
if ($type) {
return $type->newDisplayValue($option, $value);
}
if ($option->isCustomType()) {
return $option->getCustomObject()->getDisplayValue(
$option,
$entry,
$value);
} else {
$type = $option->getType();
switch ($type) {
case 'int':
case 'string':
case 'enum':
case 'class':
return $value;
case 'bool':
return $value ? 'true' : 'false';
case 'list<string>':
case 'list<regex>':
return implode("\n", nonempty($value, array()));
case 'set':
return implode("\n", nonempty(array_keys($value), array()));
default:
return PhabricatorConfigJSON::prettyPrintJSON($value);
}
}
throw new Exception(
pht(
'Unknown configuration option type "%s".',
$option->getType()));
}
private function renderControls(
@ -421,75 +381,24 @@ final class PhabricatorConfigEditController
$display_value,
$e_value) {
$type = $option->newOptionType();
if ($type) {
return $type->newControls(
$option,
$display_value,
$e_value);
}
if ($option->isCustomType()) {
$controls = $option->getCustomObject()->renderControls(
$option,
$display_value,
$e_value);
} else {
$type = $option->getType();
switch ($type) {
case 'int':
case 'string':
$control = id(new AphrontFormTextControl());
break;
case 'bool':
$control = id(new AphrontFormSelectControl())
->setOptions(
array(
'' => pht('(Use Default)'),
'true' => idx($option->getBoolOptions(), 0),
'false' => idx($option->getBoolOptions(), 1),
));
break;
case 'enum':
$options = array_mergev(
array(
array('' => pht('(Use Default)')),
$option->getEnumOptions(),
));
$control = id(new AphrontFormSelectControl())
->setOptions($options);
break;
case 'class':
$symbols = id(new PhutilSymbolLoader())
->setType('class')
->setAncestorClass($option->getBaseClass())
->setConcreteOnly(true)
->selectSymbolsWithoutLoading();
$names = ipull($symbols, 'name', 'name');
asort($names);
$names = array(
'' => pht('(Use Default)'),
) + $names;
$control = id(new AphrontFormSelectControl())
->setOptions($names);
break;
case 'list<string>':
case 'list<regex>':
$control = id(new AphrontFormTextAreaControl())
->setCaption(pht('Separate values with newlines.'));
break;
case 'set':
$control = id(new AphrontFormTextAreaControl())
->setCaption(pht('Separate values with newlines or commas.'));
break;
default:
$control = id(new AphrontFormTextAreaControl())
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
->setCustomClass('PhabricatorMonospaced')
->setCaption(pht('Enter value in JSON.'));
break;
}
$control
->setLabel(pht('Database Value'))
->setError($e_value)
->setValue($display_value)
->setName('value');
$controls = array($control);
throw new Exception(
pht(
'Unknown configuration option type "%s".',
$option->getType()));
}
return $controls;

View file

@ -59,84 +59,37 @@ final class PhabricatorConfigManagementSetWorkflow
$option = $options[$key];
$type = $option->getType();
switch ($type) {
case 'string':
case 'class':
case 'enum':
$value = (string)$value;
break;
case 'int':
if (!ctype_digit($value)) {
throw new PhutilArgumentUsageException(
pht(
"Config key '%s' is of type '%s'. Specify an integer.",
$key,
$type));
}
$value = (int)$value;
break;
case 'bool':
if ($value == 'true') {
$value = true;
} else if ($value == 'false') {
$value = false;
} else {
throw new PhutilArgumentUsageException(
pht(
"Config key '%s' is of type '%s'. Specify '%s' or '%s'.",
$key,
$type,
'true',
'false'));
}
break;
default:
$value = json_decode($value, true);
if (!is_array($value)) {
switch ($type) {
case 'set':
$command = csprintf(
'./bin/config set %R %s',
$key,
'{"value1": true, "value2": true}');
$message = sprintf(
"%s\n\n %s\n",
pht(
'Config key "%s" is of type "%s". Specify it in JSON. '.
'For example:',
$key,
$type),
$command);
break;
default:
if (preg_match('/^list</', $type)) {
$command = csprintf(
'./bin/config set %R %s',
$key,
'["a", "b", "c"]');
$message = sprintf(
"%s\n\n %s\n",
pht(
'Config key "%s" is of type "%s". Specify it in JSON. '.
'For example:',
$key,
$type),
$command);
} else {
$type = $option->newOptionType();
if ($type) {
try {
$value = $type->newValueFromCommandLineValue(
$option,
$value);
$type->validateStoredValue($option, $value);
} catch (PhabricatorConfigValidationException $ex) {
throw new PhutilArgumentUsageException($ex->getMessage());
}
} else {
// NOTE: For now, this handles both "wild" values and custom types.
$type = $option->getType();
switch ($type) {
default:
$value = json_decode($value, true);
if (!is_array($value)) {
switch ($type) {
default:
$message = pht(
'Config key "%s" is of type "%s". Specify it in JSON.',
$key,
$type);
}
break;
break;
}
throw new PhutilArgumentUsageException($message);
}
throw new PhutilArgumentUsageException($message);
}
break;
break;
}
}
$use_database = $args->getArg('database');
if ($option->getLocked() && $use_database) {
throw new PhutilArgumentUsageException(

View file

@ -20,133 +20,34 @@ abstract class PhabricatorApplicationConfigOptions extends Phobject {
return;
}
$type = $option->newOptionType();
if ($type) {
try {
$type->validateStoredValue($option, $value);
$this->didValidateOption($option, $value);
} catch (PhabricatorConfigValidationException $ex) {
throw $ex;
} catch (Exception $ex) {
// If custom validators threw exceptions other than validation
// exceptions, convert them to validation exceptions so we repair the
// configuration and raise an error.
throw new PhabricatorConfigValidationException($ex->getMessage());
}
return;
}
if ($option->isCustomType()) {
try {
return $option->getCustomObject()->validateOption($option, $value);
} catch (Exception $ex) {
// If custom validators threw exceptions, convert them to configuation
// validation exceptions so we repair the configuration and raise
// an error.
throw new PhabricatorConfigValidationException($ex->getMessage());
}
}
switch ($option->getType()) {
case 'bool':
if ($value !== true &&
$value !== false) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' is of type bool, but value is not true or false.",
$option->getKey()));
}
break;
case 'int':
if (!is_int($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' is of type int, but value is not an integer.",
$option->getKey()));
}
break;
case 'string':
if (!is_string($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' is of type string, but value is not a string.",
$option->getKey()));
}
break;
case 'class':
$symbols = id(new PhutilSymbolLoader())
->setType('class')
->setAncestorClass($option->getBaseClass())
->setConcreteOnly(true)
->selectSymbolsWithoutLoading();
$names = ipull($symbols, 'name', 'name');
if (empty($names[$value])) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' value must name a class extending '%s'.",
$option->getKey(),
$option->getBaseClass()));
}
break;
case 'set':
$valid = true;
if (!is_array($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a set, but value is not an array.",
$option->getKey()));
}
foreach ($value as $v) {
if ($v !== true) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a set, but array contains values other ".
"than 'true'.",
$option->getKey()));
}
}
break;
case 'list<regex>':
$valid = true;
if (!is_array($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of regular expressions, but value ".
"is not an array.",
$option->getKey()));
}
if ($value && array_keys($value) != range(0, count($value) - 1)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of regular expressions, but the ".
"value is a map with unnatural keys.",
$option->getKey()));
}
foreach ($value as $v) {
$ok = @preg_match($v, '');
if ($ok === false) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of regular expressions, but the ".
"value '%s' is not a valid regular expression.",
$option->getKey(),
$v));
}
}
break;
case 'list<string>':
$valid = true;
if (!is_array($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of strings, but value is not ".
"an array.",
$option->getKey()));
}
if ($value && array_keys($value) != range(0, count($value) - 1)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of strings, but the value is a ".
"map with unnatural keys.",
$option->getKey()));
}
foreach ($value as $v) {
if (!is_string($v)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of strings, but it contains one ".
"or more non-strings.",
$option->getKey()));
}
}
break;
case 'wild':
default:
break;
} else {
throw new Exception(
pht(
'Unknown configuration option type "%s".',
$option->getType()));
}
$this->didValidateOption($option, $value);

View file

@ -20,7 +20,7 @@ final class PhabricatorClusterConfigOptions
}
public function getOptions() {
$databases_type = 'custom:PhabricatorClusterDatabasesConfigOptionType';
$databases_type = 'cluster.databases';
$databases_help = $this->deformat(pht(<<<EOTEXT
WARNING: This is a prototype option and the description below is currently pure
fantasy.
@ -38,7 +38,7 @@ EOTEXT
$intro_href = PhabricatorEnv::getDoclink('Clustering Introduction');
$intro_name = pht('Clustering Introduction');
$search_type = 'custom:PhabricatorClusterSearchConfigOptionType';
$search_type = 'cluster.search';
$search_help = $this->deformat(pht(<<<EOTEXT
Define one or more fulltext storage services. Here you can configure which
hosts will handle fulltext search queries and indexing. For help with

View file

@ -175,6 +175,12 @@ final class PhabricatorConfigOption
return $this->type;
}
public function newOptionType() {
$type_key = $this->getType();
$type_map = PhabricatorConfigType::getAllTypes();
return idx($type_map, $type_key);
}
public function isCustomType() {
return !strncmp($this->getType(), 'custom:', 7);
}

View file

@ -297,9 +297,9 @@ EODOC
$this->newOption('metamta.user-address-format', 'enum', 'full')
->setEnumOptions(
array(
'short' => 'short',
'real' => 'real',
'full' => 'full',
'short' => pht('Short'),
'real' => pht('Real'),
'full' => pht('Full'),
))
->setSummary(pht('Control how Phabricator renders user names in mail.'))
->setDescription($address_description)

View file

@ -20,7 +20,7 @@ final class PhabricatorNotificationConfigOptions
}
public function getOptions() {
$servers_type = 'custom:PhabricatorNotificationServersConfigOptionType';
$servers_type = 'cluster.notifications';
$servers_help = $this->deformat(pht(<<<EOTEXT
Provide a list of notification servers to enable real-time notifications.

View file

@ -21,12 +21,12 @@ final class PhabricatorUIConfigOptions
public function getOptions() {
$options = array(
'blindigo' => 'blindigo',
'red' => 'red',
'blue' => 'blue',
'green' => 'green',
'indigo' => 'indigo',
'dark' => 'dark',
'blindigo' => pht('Blindigo'),
'red' => pht('Red'),
'blue' => pht('Blue'),
'green' => pht('Green'),
'indigo' => pht('Indigo'),
'dark' => pht('Dark'),
);
$example = <<<EOJSON

View file

@ -0,0 +1,62 @@
<?php
final class PhabricatorBoolConfigType
extends PhabricatorTextConfigType {
const TYPEKEY = 'bool';
protected function newCanonicalValue(
PhabricatorConfigOption $option,
$value) {
if (!preg_match('/^(true|false)\z/', $value)) {
throw $this->newException(
pht(
'Value for option "%s" of type "%s" must be either '.
'"true" or "false".',
$option->getKey(),
$this->getTypeKey()));
}
return ($value === 'true');
}
public function newDisplayValue(
PhabricatorConfigOption $option,
$value) {
if ($value) {
return 'true';
} else {
return 'false';
}
}
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
if (!is_bool($value)) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the configured value is not '.
'a boolean.',
$option->getKey(),
$this->getTypeKey()));
}
}
protected function newControl(PhabricatorConfigOption $option) {
$bool_map = $option->getBoolOptions();
$map = array(
'' => pht('(Use Default)'),
) + array(
'true' => idx($bool_map, 0),
'false' => idx($bool_map, 1),
);
return id(new AphrontFormSelectControl())
->setOptions($map);
}
}

View file

@ -0,0 +1,76 @@
<?php
final class PhabricatorClassConfigType
extends PhabricatorTextConfigType {
const TYPEKEY = 'class';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
if (!is_string($value)) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the configured value is not '.
'a string.',
$option->getKey(),
$this->getTypeKey()));
}
$base = $option->getBaseClass();
$map = $this->getClassOptions($option);
try {
$ok = class_exists($value);
} catch (Exception $ex) {
$ok = false;
}
if (!$ok) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the configured value is not the '.
'name of a known class. Valid selections are: %s.',
$option->getKey(),
$this->getTypeKey(),
implode(', ', array_keys($map))));
}
if (!isset($map[$value])) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the current value ("%s") is not '.
'a known, concrete subclass of base class "%s". Valid selections '.
'are: %s.',
$option->getKey(),
$this->getTypeKey(),
$value,
$base,
implode(', ', array_keys($map))));
}
}
protected function newControl(PhabricatorConfigOption $option) {
$map = array(
'' => pht('(Use Default)'),
) + $this->getClassOptions($option);
return id(new AphrontFormSelectControl())
->setOptions($map);
}
private function getClassOptions(PhabricatorConfigOption $option) {
$symbols = id(new PhutilSymbolLoader())
->setType('class')
->setAncestorClass($option->getBaseClass())
->setConcreteOnly(true)
->selectSymbolsWithoutLoading();
$map = ipull($symbols, 'name', 'name');
asort($map);
return $map;
}
}

View file

@ -0,0 +1,111 @@
<?php
abstract class PhabricatorConfigType extends Phobject {
final public function getTypeKey() {
return $this->getPhobjectClassConstant('TYPEKEY');
}
final public static function getAllTypes() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getTypeKey')
->execute();
}
public function isValuePresentInRequest(
PhabricatorConfigOption $option,
AphrontRequest $request) {
$http_type = $this->newHTTPParameterType();
return $http_type->getExists($request, 'value');
}
public function readValueFromRequest(
PhabricatorConfigOption $option,
AphrontRequest $request) {
$http_type = $this->newHTTPParameterType();
return $http_type->getValue($request, 'value');
}
abstract protected function newHTTPParameterType();
public function newTransaction(
PhabricatorConfigOption $option,
$value) {
$xaction_value = $this->newTransactionValue($option, $value);
return id(new PhabricatorConfigTransaction())
->setTransactionType(PhabricatorConfigTransaction::TYPE_EDIT)
->setNewValue(
array(
'deleted' => false,
'value' => $xaction_value,
));
}
protected function newTransactionValue(
PhabricatorConfigOption $option,
$value) {
return $value;
}
public function newDisplayValue(
PhabricatorConfigOption $option,
$value) {
return $value;
}
public function newControls(
PhabricatorConfigOption $option,
$value,
$error) {
$control = $this->newControl($option)
->setError($error)
->setLabel(pht('Database Value'))
->setName('value');
$value = $this->newControlValue($option, $value);
$control->setValue($value);
return array(
$control,
);
}
abstract protected function newControl(PhabricatorConfigOption $option);
protected function newControlValue(
PhabricatorConfigOption $option,
$value) {
return $value;
}
protected function newException($message) {
return new PhabricatorConfigValidationException($message);
}
public function newValueFromRequestValue(
PhabricatorConfigOption $option,
$value) {
return $this->newCanonicalValue($option, $value);
}
public function newValueFromCommandLineValue(
PhabricatorConfigOption $option,
$value) {
return $this->newCanonicalValue($option, $value);
}
protected function newCanonicalValue(
PhabricatorConfigOption $option,
$value) {
return $value;
}
abstract public function validateStoredValue(
PhabricatorConfigOption $option,
$value);
}

View file

@ -0,0 +1,43 @@
<?php
final class PhabricatorEnumConfigType
extends PhabricatorTextConfigType {
const TYPEKEY = 'enum';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
if (!is_string($value)) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the configured value is not '.
'a string.',
$option->getKey(),
$this->getTypeKey()));
}
$map = $option->getEnumOptions();
if (!isset($map[$value])) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the current value ("%s") is not '.
'among the set of valid values: %s.',
$option->getKey(),
$this->getTypeKey(),
$value,
implode(', ', array_keys($map))));
}
}
protected function newControl(PhabricatorConfigOption $option) {
$map = array(
'' => pht('(Use Default)'),
) + $option->getEnumOptions();
return id(new AphrontFormSelectControl())
->setOptions($map);
}
}

View file

@ -0,0 +1,36 @@
<?php
final class PhabricatorIntConfigType
extends PhabricatorTextConfigType {
const TYPEKEY = 'int';
protected function newCanonicalValue(
PhabricatorConfigOption $option,
$value) {
if (!preg_match('/^-?[0-9]+\z/', $value)) {
throw $this->newException(
pht(
'Value for option "%s" must be an integer.',
$option->getKey()));
}
return (int)$value;
}
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
if (!is_int($value)) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the configured value is not '.
'an integer.',
$option->getKey(),
$this->getTypeKey()));
}
}
}

View file

@ -0,0 +1,38 @@
<?php
abstract class PhabricatorJSONConfigType
extends PhabricatorTextConfigType {
protected function newCanonicalValue(
PhabricatorConfigOption $option,
$value) {
try {
$value = phutil_json_decode($value);
} catch (Exception $ex) {
throw $this->newException(
pht(
'Value for option "%s" (of type "%s") must be specified in JSON, '.
'but input could not be decoded: %s',
$option->getKey(),
$this->getTypeKey(),
$ex->getMessage()));
}
return $value;
}
protected function newControl(PhabricatorConfigOption $option) {
return id(new AphrontFormTextAreaControl())
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
->setCustomClass('PhabricatorMonospaced')
->setCaption(pht('Enter value in JSON.'));
}
public function newDisplayValue(
PhabricatorConfigOption $option,
$value) {
return PhabricatorConfigJSON::prettyPrintJSON($value);
}
}

View file

@ -0,0 +1,24 @@
<?php
final class PhabricatorRegexListConfigType
extends PhabricatorTextListConfigType {
const TYPEKEY = 'list<regex>';
protected function validateStoredItem(
PhabricatorConfigOption $option,
$value) {
$ok = @preg_match($value, '');
if ($ok === false) {
throw $this->newException(
pht(
'Option "%s" is of type "%s" and must be set to a list of valid '.
'regular expressions, but "%s" is not a valid regular expression.',
$option->getKey(),
$this->getTypeKey(),
$value));
}
}
}

View file

@ -0,0 +1,92 @@
<?php
final class PhabricatorSetConfigType
extends PhabricatorTextConfigType {
const TYPEKEY = 'set';
protected function newControl(PhabricatorConfigOption $option) {
return id(new AphrontFormTextAreaControl())
->setCaption(pht('Separate values with newlines or commas.'));
}
protected function newCanonicalValue(
PhabricatorConfigOption $option,
$value) {
$value = preg_split('/[\n,]+/', $value);
foreach ($value as $k => $v) {
if (!strlen($v)) {
unset($value[$k]);
}
$value[$k] = trim($v);
}
return array_fill_keys($value, true);
}
public function newValueFromCommandLineValue(
PhabricatorConfigOption $option,
$value) {
try {
$value = phutil_json_decode($value);
} catch (Exception $ex) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the value you provided is not a '.
'valid JSON list: when providing a set from the command line, '.
'specify it as a list of values in JSON. You may need to quote the '.
'value for your shell (for example: \'["a", "b", ...]\').',
$option->getKey(),
$this->getTypeKey()));
}
if ($value) {
if (array_keys($value) !== range(0, count($value) - 1)) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", and should be specified on the '.
'command line as a JSON list of values. You may need to quote '.
'the value for your shell (for example: \'["a", "b", ...]\').',
$option->getKey(),
$this->getTypeKey()));
}
}
return array_fill_keys($value, true);
}
public function newDisplayValue(
PhabricatorConfigOption $option,
$value) {
return implode("\n", array_keys($value));
}
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
if (!is_array($value)) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the configured value is not '.
'a list.',
$option->getKey(),
$this->getTypeKey()));
}
foreach ($value as $k => $v) {
if ($v !== true) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the value at index "%s" of the '.
'list is not "true".',
$option->getKey(),
$this->getTypeKey(),
$k));
}
}
}
}

View file

@ -0,0 +1,22 @@
<?php
final class PhabricatorStringConfigType
extends PhabricatorTextConfigType {
const TYPEKEY = 'string';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
if (!is_string($value)) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the configured value is not '.
'a string.',
$option->getKey(),
$this->getTypeKey()));
}
}
}

View file

@ -0,0 +1,8 @@
<?php
final class PhabricatorStringListConfigType
extends PhabricatorTextListConfigType {
const TYPEKEY = 'list<string>';
}

View file

@ -0,0 +1,27 @@
<?php
abstract class PhabricatorTextConfigType
extends PhabricatorConfigType {
public function isValuePresentInRequest(
PhabricatorConfigOption $option,
AphrontRequest $request) {
$value = parent::readValueFromRequest($option, $request);
return (bool)strlen($value);
}
protected function newCanonicalValue(
PhabricatorConfigOption $option,
$value) {
return (string)$value;
}
protected function newHTTPParameterType() {
return new AphrontStringHTTPParameterType();
}
protected function newControl(PhabricatorConfigOption $option) {
return new AphrontFormTextControl();
}
}

View file

@ -0,0 +1,98 @@
<?php
abstract class PhabricatorTextListConfigType
extends PhabricatorTextConfigType {
protected function newControl(PhabricatorConfigOption $option) {
return id(new AphrontFormTextAreaControl())
->setCaption(pht('Separate values with newlines.'));
}
protected function newCanonicalValue(
PhabricatorConfigOption $option,
$value) {
$value = phutil_split_lines($value, $retain_endings = false);
foreach ($value as $k => $v) {
if (!strlen($v)) {
unset($value[$k]);
}
}
return array_values($value);
}
public function newValueFromCommandLineValue(
PhabricatorConfigOption $option,
$value) {
try {
$value = phutil_json_decode($value);
} catch (Exception $ex) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the value you provided is not a '.
'valid JSON list. When setting a list option from the command '.
'line, specify the value in JSON. You may need to quote the '.
'value for your shell (for example: \'["a", "b", ...]\').',
$option->getKey(),
$this->getTypeKey()));
}
return $value;
}
public function newDisplayValue(
PhabricatorConfigOption $option,
$value) {
return implode("\n", $value);
}
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
if (!is_array($value)) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the configured value is not '.
'a list.',
$option->getKey(),
$this->getTypeKey()));
}
$expect_key = 0;
foreach ($value as $k => $v) {
if (!is_string($v)) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the item at index "%s" of the '.
'list is not a string.',
$option->getKey(),
$this->getTypeKey(),
$k));
}
// Make sure this is a list with keys "0, 1, 2, ...", not a map with
// arbitrary keys.
if ($k != $expect_key) {
throw $this->newException(
pht(
'Option "%s" is of type "%s", but the value is not a list: it '.
'is a map with unnatural or sparse keys.',
$option->getKey(),
$this->getTypeKey()));
}
$expect_key++;
$this->validateStoredItem($option, $v);
}
}
protected function validateStoredItem(
PhabricatorConfigOption $option,
$value) {
return;
}
}

View file

@ -0,0 +1,39 @@
<?php
final class PhabricatorWildConfigType
extends PhabricatorJSONConfigType {
const TYPEKEY = 'wild';
protected function newCanonicalValue(
PhabricatorConfigOption $option,
$value) {
$raw_value = $value;
// NOTE: We're significantly more liberal about canonicalizing "wild"
// values than "JSON" values because they're used to deal with some
// unusual edge cases, including situations where old config has been left
// in the database and we aren't sure what type it's supposed to be.
// Accept anything we can decode.
$value = json_decode($raw_value, true);
if ($value === null && $raw_value != 'null') {
throw $this->newException(
pht(
'Value for option "%s" (of type "%s") must be specified in JSON, '.
'but input could not be decoded. (Did you forget to quote a string?)',
$option->getKey(),
$this->getTypeKey()));
}
return $value;
}
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
return;
}
}

View file

@ -260,7 +260,10 @@ EOHELP
->setDescription(
pht('Format for inlined or attached patches.'))
->setEnumOptions(
array('unified' => 'unified', 'git' => 'git')),
array(
'unified' => pht('Unified'),
'git' => pht('Git'),
)),
);
}

View file

@ -50,11 +50,4 @@ final class DifferentialTestPlanCommitMessageField
);
}
public function validateTransactions($object, array $xactions) {
return $this->validateCommitMessageCorpusTransactions(
$object,
$xactions,
pht('Test Plan'));
}
}

View file

@ -55,7 +55,10 @@ final class DifferentialRevisionTestPlanTransaction
}
public function validateTransactions($object, array $xactions) {
$errors = array();
$errors = $this->validateCommitMessageCorpusTransactions(
$object,
$xactions,
pht('Test Plan'));
$is_required = PhabricatorEnv::getEnvConfig(
'differential.require-test-plan-field');

View file

@ -23,6 +23,22 @@ final class DiffusionRepositoryURIViewController
return new Aphront404Response();
}
// For display, reload the URI by loading it through the repository. This
// may adjust builtin URIs for repository configuration, so we may end up
// with a different view of builtin URIs than we'd see if we loaded them
// directly from the database. See T12884.
$repository_with_uris = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->needURIs(true)
->execute();
$repository_uris = $repository->getURIs();
$repository_uris = mpull($repository_uris, null, 'getID');
$uri = idx($repository_uris, $uri->getID());
if (!$uri) {
return new Aphront404Response();
}
$title = array(
pht('URI'),
$repository->getDisplayName(),

View file

@ -141,7 +141,7 @@ final class HarbormasterBuildViewController
if ($ended) {
$when[] = pht(
'Completed at %s',
phabricator_datetime($started, $viewer));
phabricator_datetime($ended, $viewer));
$duration = ($ended - $started);
if ($duration) {

View file

@ -1,10 +0,0 @@
<?php
final class ManiphestPointsConfigOptionType
extends PhabricatorConfigJSONOptionType {
public function validateOption(PhabricatorConfigOption $option, $value) {
ManiphestTaskPoints::validateConfiguration($value);
}
}

View file

@ -0,0 +1,14 @@
<?php
final class ManiphestPointsConfigType
extends PhabricatorJSONConfigType {
const TYPEKEY = 'maniphest.points';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
ManiphestTaskPoints::validateConfiguration($value);
}
}

View file

@ -0,0 +1,14 @@
<?php
final class ManiphestPrioritiesConfigType
extends PhabricatorJSONConfigType {
const TYPEKEY = 'maniphest.priorities';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
ManiphestTaskPriority::validateConfiguration($value);
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ManiphestPriorityConfigOptionType
extends PhabricatorConfigJSONOptionType {
public function validateOption(PhabricatorConfigOption $option, $value) {
ManiphestTaskPriority::validateConfiguration($value);
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ManiphestStatusConfigOptionType
extends PhabricatorConfigJSONOptionType {
public function validateOption(PhabricatorConfigOption $option, $value) {
ManiphestTaskStatus::validateConfiguration($value);
}
}

View file

@ -0,0 +1,14 @@
<?php
final class ManiphestStatusesConfigType
extends PhabricatorJSONConfigType {
const TYPEKEY = 'maniphest.statuses';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
ManiphestTaskStatus::validateConfiguration($value);
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ManiphestSubtypesConfigOptionsType
extends PhabricatorConfigJSONOptionType {
public function validateOption(PhabricatorConfigOption $option, $value) {
PhabricatorEditEngineSubtype::validateConfiguration($value);
}
}

View file

@ -0,0 +1,14 @@
<?php
final class ManiphestSubtypesConfigType
extends PhabricatorJSONConfigType {
const TYPEKEY = 'maniphest.subtypes';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
PhabricatorEditEngineSubtype::validateConfiguration($value);
}
}

View file

@ -20,47 +20,47 @@ final class PhabricatorManiphestConfigOptions
}
public function getOptions() {
$priority_type = 'custom:ManiphestPriorityConfigOptionType';
$priority_type = 'maniphest.priorities';
$priority_defaults = array(
100 => array(
'name' => pht('Unbreak Now!'),
'keywords' => array('unbreak'),
'short' => pht('Unbreak!'),
'color' => 'pink',
'keywords' => array('unbreak'),
),
90 => array(
'name' => pht('Needs Triage'),
'keywords' => array('triage'),
'short' => pht('Triage'),
'color' => 'violet',
'keywords' => array('triage'),
),
80 => array(
'name' => pht('High'),
'keywords' => array('high'),
'short' => pht('High'),
'color' => 'red',
'keywords' => array('high'),
),
50 => array(
'name' => pht('Normal'),
'keywords' => array('normal'),
'short' => pht('Normal'),
'color' => 'orange',
'keywords' => array('normal'),
),
25 => array(
'name' => pht('Low'),
'keywords' => array('low'),
'short' => pht('Low'),
'color' => 'yellow',
'keywords' => array('low'),
),
0 => array(
'name' => pht('Wishlist'),
'keywords' => array('wish', 'wishlist'),
'short' => pht('Wish'),
'color' => 'sky',
'keywords' => array('wish', 'wishlist'),
),
);
$status_type = 'custom:ManiphestStatusConfigOptionType';
$status_type = 'maniphest.statuses';
$status_defaults = array(
'open' => array(
'name' => pht('Open'),
@ -265,7 +265,7 @@ EOTEXT
);
$fields_json = id(new PhutilJSON())->encodeFormatted($fields_example);
$points_type = 'custom:ManiphestPointsConfigOptionType';
$points_type = 'maniphest.points';
$points_example_1 = array(
'enabled' => true,
@ -299,7 +299,7 @@ See the example below for a starting point.
EOTEXT
));
$subtype_type = 'custom:ManiphestSubtypesConfigOptionsType';
$subtype_type = 'maniphest.subtypes';
$subtype_default_key = PhabricatorEditEngineSubtype::SUBTYPE_DEFAULT;
$subtype_example = array(
array(
@ -349,6 +349,32 @@ EOTEXT
,
$subtype_default_key));
$priorities_description = $this->deformat(pht(<<<EOTEXT
Allows you to edit or override the default priorities available in Maniphest,
like "High", "Normal" and "Low". The configuration should contain a map of
numeric priority values (where larger numbers correspond to higher priorities)
to priority specifications (see defaults below for examples).
The keys you can define for a priority are:
- `name` //Required string.// Name of the priority.
- `keywords` //Required list<string>.// List of unique keywords which identify
this priority, like "high" or "low". Each priority must have at least one
keyword and two priorities may not share the same keyword.
- `short` //Optional string.// Alternate shorter name, used in UIs where
there is less space available.
- `color` //Optional string.// Color for this priority, like "red" or
"blue".
- `disabled` //Optional bool.// Set to true to prevent users from choosing
this priority when creating or editing tasks. Existing tasks will not be
affected, and can be batch edited to a different priority or left to
eventually die out.
You can choose the default priority for newly created tasks with
"maniphest.default-priority".
EOTEXT
));
return array(
$this->newOption('maniphest.custom-field-definitions', 'wild', array())
@ -367,30 +393,7 @@ EOTEXT
$priority_type,
$priority_defaults)
->setSummary(pht('Configure Maniphest priority names.'))
->setDescription(
pht(
'Allows you to edit or override the default priorities available '.
'in Maniphest, like "High", "Normal" and "Low". The configuration '.
'should contain a map of priority constants to priority '.
'specifications (see defaults below for examples).'.
"\n\n".
'The keys you can define for a priority are:'.
"\n\n".
' - `name` Name of the priority.'."\n".
' - `short` Alternate shorter name, used in UIs where there is '.
' not much space available.'."\n".
' - `color` A color for this priority, like "red" or "blue".'.
' - `keywords` An optional list of keywords which can '.
' be used to select this priority when using `!priority` '.
' commands in email.'."\n".
' - `disabled` Optional boolean to prevent users from choosing '.
' this priority when creating or editing tasks. Existing '.
' tasks will be unaffected, and can be batch edited to a '.
' different priority or left to eventually die out.'.
"\n\n".
'You can choose which priority is the default for newly created '.
'tasks with `%s`.',
'maniphest.default-priority')),
->setDescription($priorities_description),
$this->newOption('maniphest.statuses', $status_type, $status_defaults)
->setSummary(pht('Configure Maniphest task statuses.'))
->setDescription($status_description)

View file

@ -203,6 +203,7 @@ final class ManiphestTaskPriority extends ManiphestConstants {
$config));
}
$all_keywords = array();
foreach ($config as $key => $value) {
if (!ctype_digit((string)$key)) {
throw new Exception(
@ -223,9 +224,9 @@ final class ManiphestTaskPriority extends ManiphestConstants {
$value,
array(
'name' => 'string',
'keywords' => 'list<string>',
'short' => 'optional string',
'color' => 'optional string',
'keywords' => 'list<string>',
'disabled' => 'optional bool',
));
@ -242,6 +243,18 @@ final class ManiphestTaskPriority extends ManiphestConstants {
'low',
'critical'));
}
if (isset($all_keywords[$keyword])) {
throw new Exception(
pht(
'Two different task priorities ("%s" and "%s") have the same '.
'keyword ("%s"). Keywords must uniquely identify priorities.',
$value['name'],
$all_keywords[$keyword],
$keyword));
}
$all_keywords[$keyword] = $value['name'];
}
}
}

View file

@ -1,19 +1,17 @@
<?php
final class PhabricatorNotificationServersConfigOptionType
extends PhabricatorConfigJSONOptionType {
final class PhabricatorNotificationServersConfigType
extends PhabricatorJSONConfigType {
public function validateOption(PhabricatorConfigOption $option, $value) {
if (!is_array($value)) {
throw new Exception(
pht(
'Notification server configuration is not valid: value must be a '.
'list of servers'));
}
const TYPEKEY = 'cluster.notifications';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
foreach ($value as $index => $spec) {
if (!is_array($spec)) {
throw new Exception(
throw $this->newException(
pht(
'Notification server configuration is not valid: each entry in '.
'the list must be a dictionary describing a service, but '.
@ -38,7 +36,7 @@ final class PhabricatorNotificationServersConfigOptionType
'disabled' => 'optional bool',
));
} catch (Exception $ex) {
throw new Exception(
throw $this->newException(
pht(
'Notification server configuration has an invalid service '.
'specification (at index "%s"): %s.',
@ -64,7 +62,7 @@ final class PhabricatorNotificationServersConfigOptionType
}
break;
default:
throw new Exception(
throw $this->newException(
pht(
'Notification server configuration describes an invalid '.
'host ("%s", at index "%s") with an unrecognized type ("%s"). '.
@ -81,7 +79,7 @@ final class PhabricatorNotificationServersConfigOptionType
case 'https':
break;
default:
throw new Exception(
throw $this->newException(
pht(
'Notification server configuration describes an invalid '.
'host ("%s", at index "%s") with an invalid protocol ("%s"). '.
@ -95,7 +93,7 @@ final class PhabricatorNotificationServersConfigOptionType
$path = idx($spec, 'path');
if ($type == 'admin' && strlen($path)) {
throw new Exception(
throw $this->newException(
pht(
'Notification server configuration describes an invalid host '.
'("%s", at index "%s"). This is an "admin" service but it has a '.
@ -108,7 +106,7 @@ final class PhabricatorNotificationServersConfigOptionType
// mistakes.
$key = "{$host}:{$port}";
if (isset($map[$key])) {
throw new Exception(
throw $this->newException(
pht(
'Notification server configuration is invalid: it describes the '.
'same host and port ("%s") multiple times. Each host and port '.
@ -120,7 +118,7 @@ final class PhabricatorNotificationServersConfigOptionType
if ($value) {
if (!$has_admin) {
throw new Exception(
throw $this->newException(
pht(
'Notification server configuration is invalid: it does not '.
'specify any enabled servers with type "admin". Notifications '.
@ -128,7 +126,7 @@ final class PhabricatorNotificationServersConfigOptionType
}
if (!$has_client) {
throw new Exception(
throw $this->newException(
pht(
'Notification server configuration is invalid: it does not '.
'specify any enabled servers with type "client". Notifications '.

View file

@ -43,7 +43,7 @@ final class PhabricatorUserConfigOptions
$this->newOption('user.fields', $custom_field_type, $default)
->setCustomData(id(new PhabricatorUser())->getCustomFieldBaseClass())
->setDescription(pht('Select and reorder user profile fields.')),
$this->newOption('user.custom-field-definitions', 'map', array())
$this->newOption('user.custom-field-definitions', 'wild', array())
->setDescription(pht('Add new simple fields to user profiles.')),
$this->newOption('user.require-real-name', 'bool', true)
->setDescription(pht('Always require real name for user profiles.'))

View file

@ -1,10 +0,0 @@
<?php
final class PhabricatorProjectColorsConfigOptionType
extends PhabricatorConfigJSONOptionType {
public function validateOption(PhabricatorConfigOption $option, $value) {
PhabricatorProjectIconSet::validateColorConfiguration($value);
}
}

View file

@ -0,0 +1,14 @@
<?php
final class PhabricatorProjectColorsConfigType
extends PhabricatorJSONConfigType {
const TYPEKEY = 'project.colors';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
PhabricatorProjectIconSet::validateColorConfiguration($value);
}
}

View file

@ -21,7 +21,7 @@ final class PhabricatorProjectConfigOptions
public function getOptions() {
$default_icons = PhabricatorProjectIconSet::getDefaultConfiguration();
$icons_type = 'custom:PhabricatorProjectIconsConfigOptionType';
$icons_type = 'project.icons';
$icons_description = $this->deformat(pht(<<<EOTEXT
Allows you to change and customize the available project icons.
@ -48,7 +48,7 @@ EOTEXT
));
$default_colors = PhabricatorProjectIconSet::getDefaultColorMap();
$colors_type = 'custom:PhabricatorProjectColorsConfigOptionType';
$colors_type = 'project.colors';
$colors_description = $this->deformat(pht(<<<EOTEXT
Allows you to relabel project colors.

View file

@ -1,10 +0,0 @@
<?php
final class PhabricatorProjectIconsConfigOptionType
extends PhabricatorConfigJSONOptionType {
public function validateOption(PhabricatorConfigOption $option, $value) {
PhabricatorProjectIconSet::validateConfiguration($value);
}
}

View file

@ -0,0 +1,14 @@
<?php
final class PhabricatorProjectIconsConfigType
extends PhabricatorJSONConfigType {
const TYPEKEY = 'project.icons';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
PhabricatorProjectIconSet::validateConfiguration($value);
}
}

View file

@ -121,9 +121,39 @@ final class PhabricatorProjectEditPictureController
}
}
$builtins = array(
'projects/v3/bug.png',
'projects/v3/calendar.png',
'projects/v3/cloud.png',
'projects/v3/creditcard.png',
'projects/v3/database.png',
'projects/v3/desktop.png',
'projects/v3/experimental.png',
'projects/v3/flag.png',
'projects/v3/folder.png',
'projects/v3/lock.png',
'projects/v3/mail.png',
'projects/v3/mobile.png',
'projects/v3/organization.png',
'projects/v3/people.png',
'projects/v3/servers.png',
'projects/v3/tag.png',
'projects/v3/trash.png',
'projects/v3/truck.png',
'projects/v3/umbrella.png',
);
foreach ($builtins as $builtin) {
$file = PhabricatorFile::loadBuiltin($viewer, $builtin);
$images[$file->getPHID()] = array(
'uri' => $file->getBestURI(),
'tip' => pht('Builtin Image'),
);
}
$images[PhabricatorPHIDConstants::PHID_VOID] = array(
'uri' => $default_image->getBestURI(),
'tip' => pht('No Picture'),
'tip' => pht('Default Picture'),
);
require_celerity_resource('people-profile-css');
@ -200,7 +230,7 @@ final class PhabricatorProjectEditPictureController
$compose_button = javelin_tag(
'button',
array(
'class' => 'grey',
'class' => 'button-grey',
'id' => $launch_id,
'sigil' => 'icon-composer',
),
@ -227,7 +257,7 @@ final class PhabricatorProjectEditPictureController
$form->appendChild(
id(new AphrontFormMarkupControl())
->setLabel(pht('Quick Create'))
->setLabel(pht('Custom'))
->setValue($compose_form));
$upload_form = id(new AphrontFormView())

View file

@ -13,7 +13,7 @@ abstract class PhabricatorSearchManagementWorkflow
$config_value = PhabricatorEnv::getEnvConfig($config_key);
try {
PhabricatorClusterSearchConfigOptionType::validateValue($config_value);
PhabricatorClusterSearchConfigType::validateValue($config_value);
} catch (Exception $ex) {
throw new PhutilArgumentUsageException(
pht(

View file

@ -1,19 +1,17 @@
<?php
final class PhabricatorClusterDatabasesConfigOptionType
extends PhabricatorConfigJSONOptionType {
final class PhabricatorClusterDatabasesConfigType
extends PhabricatorJSONConfigType {
public function validateOption(PhabricatorConfigOption $option, $value) {
if (!is_array($value)) {
throw new Exception(
pht(
'Database cluster configuration is not valid: value must be a '.
'list of database hosts.'));
}
const TYPEKEY = 'cluster.databases';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
foreach ($value as $index => $spec) {
if (!is_array($spec)) {
throw new Exception(
throw $this->newException(
pht(
'Database cluster configuration is not valid: each entry in the '.
'list must be a dictionary describing a database host, but '.
@ -40,7 +38,7 @@ final class PhabricatorClusterDatabasesConfigOptionType
'persistent' => 'optional bool',
));
} catch (Exception $ex) {
throw new Exception(
throw $this->newException(
pht(
'Database cluster configuration has an invalid host '.
'specification (at index "%s"): %s.',
@ -57,7 +55,7 @@ final class PhabricatorClusterDatabasesConfigOptionType
case 'replica':
break;
default:
throw new Exception(
throw $this->newException(
pht(
'Database cluster configuration describes an invalid '.
'host ("%s", at index "%s") with an unrecognized role ("%s"). '.
@ -78,7 +76,7 @@ final class PhabricatorClusterDatabasesConfigOptionType
// mistakes.
$key = "{$host}:{$port}";
if (isset($map[$key])) {
throw new Exception(
throw $this->newException(
pht(
'Database cluster configuration is invalid: it describes the '.
'same host ("%s") multiple times. Each host should appear only '.

View file

@ -1,20 +1,17 @@
<?php
final class PhabricatorClusterSearchConfigOptionType
extends PhabricatorConfigJSONOptionType {
final class PhabricatorClusterSearchConfigType
extends PhabricatorJSONConfigType {
public function validateOption(PhabricatorConfigOption $option, $value) {
const TYPEKEY = 'cluster.search';
public function validateStoredValue(
PhabricatorConfigOption $option,
$value) {
self::validateValue($value);
}
public static function validateValue($value) {
if (!is_array($value)) {
throw new Exception(
pht(
'Search cluster configuration is not valid: value must be a '.
'list of search hosts.'));
}
$engines = PhabricatorSearchService::loadAllFulltextStorageEngines();
foreach ($value as $index => $spec) {

View file

@ -39,6 +39,9 @@ final class PhabricatorMainMenuSearchView extends AphrontView {
'name' => 'query',
'id' => $search_id,
'autocomplete' => 'off',
'autocorrect' => 'off',
'autocapitalize' => 'off',
'spellcheck' => 'false',
));
$target = javelin_tag(