(stable) Promote 2017 Week 26
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 4.2 KiB |
BIN
resources/builtin/projects/v3/briefcase.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
resources/builtin/projects/v3/bug.png
Normal file
After Width: | Height: | Size: 8 KiB |
BIN
resources/builtin/projects/v3/calendar.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
resources/builtin/projects/v3/cloud.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
resources/builtin/projects/v3/creditcard.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
resources/builtin/projects/v3/database.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
resources/builtin/projects/v3/desktop.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
resources/builtin/projects/v3/experimental.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
resources/builtin/projects/v3/flag.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
resources/builtin/projects/v3/folder.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
resources/builtin/projects/v3/lock.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
resources/builtin/projects/v3/mail.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
resources/builtin/projects/v3/mobile.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
resources/builtin/projects/v3/organization.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
resources/builtin/projects/v3/people.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
resources/builtin/projects/v3/servers.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
resources/builtin/projects/v3/tag.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
resources/builtin/projects/v3/trash.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
resources/builtin/projects/v3/truck.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
resources/builtin/projects/v3/umbrella.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
|
@ -18,6 +18,7 @@ AllowTcpForwarding no
|
|||
PrintMotd no
|
||||
PrintLastLog no
|
||||
PasswordAuthentication no
|
||||
ChallengeResponseAuthentication no
|
||||
AuthorizedKeysFile none
|
||||
|
||||
PidFile /var/run/sshd-phabricator.pid
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
62
src/applications/config/type/PhabricatorBoolConfigType.php
Normal 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);
|
||||
}
|
||||
}
|
76
src/applications/config/type/PhabricatorClassConfigType.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
111
src/applications/config/type/PhabricatorConfigType.php
Normal 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);
|
||||
|
||||
}
|
43
src/applications/config/type/PhabricatorEnumConfigType.php
Normal 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);
|
||||
}
|
||||
|
||||
}
|
36
src/applications/config/type/PhabricatorIntConfigType.php
Normal 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()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
38
src/applications/config/type/PhabricatorJSONConfigType.php
Normal 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
92
src/applications/config/type/PhabricatorSetConfigType.php
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
22
src/applications/config/type/PhabricatorStringConfigType.php
Normal 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()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorStringListConfigType
|
||||
extends PhabricatorTextListConfigType {
|
||||
|
||||
const TYPEKEY = 'list<string>';
|
||||
|
||||
}
|
27
src/applications/config/type/PhabricatorTextConfigType.php
Normal 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
39
src/applications/config/type/PhabricatorWildConfigType.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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'),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -50,11 +50,4 @@ final class DifferentialTestPlanCommitMessageField
|
|||
);
|
||||
}
|
||||
|
||||
public function validateTransactions($object, array $xactions) {
|
||||
return $this->validateCommitMessageCorpusTransactions(
|
||||
$object,
|
||||
$xactions,
|
||||
pht('Test Plan'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ManiphestPointsConfigOptionType
|
||||
extends PhabricatorConfigJSONOptionType {
|
||||
|
||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
||||
ManiphestTaskPoints::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
final class ManiphestPointsConfigType
|
||||
extends PhabricatorJSONConfigType {
|
||||
|
||||
const TYPEKEY = 'maniphest.points';
|
||||
|
||||
public function validateStoredValue(
|
||||
PhabricatorConfigOption $option,
|
||||
$value) {
|
||||
ManiphestTaskPoints::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
final class ManiphestPrioritiesConfigType
|
||||
extends PhabricatorJSONConfigType {
|
||||
|
||||
const TYPEKEY = 'maniphest.priorities';
|
||||
|
||||
public function validateStoredValue(
|
||||
PhabricatorConfigOption $option,
|
||||
$value) {
|
||||
ManiphestTaskPriority::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ManiphestPriorityConfigOptionType
|
||||
extends PhabricatorConfigJSONOptionType {
|
||||
|
||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
||||
ManiphestTaskPriority::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ManiphestStatusConfigOptionType
|
||||
extends PhabricatorConfigJSONOptionType {
|
||||
|
||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
||||
ManiphestTaskStatus::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
final class ManiphestStatusesConfigType
|
||||
extends PhabricatorJSONConfigType {
|
||||
|
||||
const TYPEKEY = 'maniphest.statuses';
|
||||
|
||||
public function validateStoredValue(
|
||||
PhabricatorConfigOption $option,
|
||||
$value) {
|
||||
ManiphestTaskStatus::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ManiphestSubtypesConfigOptionsType
|
||||
extends PhabricatorConfigJSONOptionType {
|
||||
|
||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
||||
PhabricatorEditEngineSubtype::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
final class ManiphestSubtypesConfigType
|
||||
extends PhabricatorJSONConfigType {
|
||||
|
||||
const TYPEKEY = 'maniphest.subtypes';
|
||||
|
||||
public function validateStoredValue(
|
||||
PhabricatorConfigOption $option,
|
||||
$value) {
|
||||
PhabricatorEditEngineSubtype::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 '.
|
|
@ -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.'))
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectColorsConfigOptionType
|
||||
extends PhabricatorConfigJSONOptionType {
|
||||
|
||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
||||
PhabricatorProjectIconSet::validateColorConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectColorsConfigType
|
||||
extends PhabricatorJSONConfigType {
|
||||
|
||||
const TYPEKEY = 'project.colors';
|
||||
|
||||
public function validateStoredValue(
|
||||
PhabricatorConfigOption $option,
|
||||
$value) {
|
||||
PhabricatorProjectIconSet::validateColorConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectIconsConfigOptionType
|
||||
extends PhabricatorConfigJSONOptionType {
|
||||
|
||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
||||
PhabricatorProjectIconSet::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectIconsConfigType
|
||||
extends PhabricatorJSONConfigType {
|
||||
|
||||
const TYPEKEY = 'project.icons';
|
||||
|
||||
public function validateStoredValue(
|
||||
PhabricatorConfigOption $option,
|
||||
$value) {
|
||||
PhabricatorProjectIconSet::validateConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -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())
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 '.
|
|
@ -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) {
|
|
@ -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(
|
||||
|
|