mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-15 01:50:55 +01:00
(stable) Promote 2018 Week 5
This commit is contained in:
commit
4a338fd408
79 changed files with 2526 additions and 858 deletions
|
@ -1525,10 +1525,6 @@ phutil_register_library_map(array(
|
||||||
'ManiphestEditProjectsCapability' => 'applications/maniphest/capability/ManiphestEditProjectsCapability.php',
|
'ManiphestEditProjectsCapability' => 'applications/maniphest/capability/ManiphestEditProjectsCapability.php',
|
||||||
'ManiphestEditStatusCapability' => 'applications/maniphest/capability/ManiphestEditStatusCapability.php',
|
'ManiphestEditStatusCapability' => 'applications/maniphest/capability/ManiphestEditStatusCapability.php',
|
||||||
'ManiphestEmailCommand' => 'applications/maniphest/command/ManiphestEmailCommand.php',
|
'ManiphestEmailCommand' => 'applications/maniphest/command/ManiphestEmailCommand.php',
|
||||||
'ManiphestExcelDefaultFormat' => 'applications/maniphest/export/ManiphestExcelDefaultFormat.php',
|
|
||||||
'ManiphestExcelFormat' => 'applications/maniphest/export/ManiphestExcelFormat.php',
|
|
||||||
'ManiphestExcelFormatTestCase' => 'applications/maniphest/export/__tests__/ManiphestExcelFormatTestCase.php',
|
|
||||||
'ManiphestExportController' => 'applications/maniphest/controller/ManiphestExportController.php',
|
|
||||||
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php',
|
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php',
|
||||||
'ManiphestHovercardEngineExtension' => 'applications/maniphest/engineextension/ManiphestHovercardEngineExtension.php',
|
'ManiphestHovercardEngineExtension' => 'applications/maniphest/engineextension/ManiphestHovercardEngineExtension.php',
|
||||||
'ManiphestInfoConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php',
|
'ManiphestInfoConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php',
|
||||||
|
@ -2230,9 +2226,10 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php',
|
'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php',
|
||||||
'PhabricatorBulkEditGroup' => 'applications/transactions/bulk/PhabricatorBulkEditGroup.php',
|
'PhabricatorBulkEditGroup' => 'applications/transactions/bulk/PhabricatorBulkEditGroup.php',
|
||||||
'PhabricatorBulkEngine' => 'applications/transactions/bulk/PhabricatorBulkEngine.php',
|
'PhabricatorBulkEngine' => 'applications/transactions/bulk/PhabricatorBulkEngine.php',
|
||||||
|
'PhabricatorBulkManagementExportWorkflow' => 'applications/transactions/bulk/management/PhabricatorBulkManagementExportWorkflow.php',
|
||||||
'PhabricatorBulkManagementMakeSilentWorkflow' => 'applications/transactions/bulk/management/PhabricatorBulkManagementMakeSilentWorkflow.php',
|
'PhabricatorBulkManagementMakeSilentWorkflow' => 'applications/transactions/bulk/management/PhabricatorBulkManagementMakeSilentWorkflow.php',
|
||||||
'PhabricatorBulkManagementWorkflow' => 'applications/transactions/bulk/management/PhabricatorBulkManagementWorkflow.php',
|
'PhabricatorBulkManagementWorkflow' => 'applications/transactions/bulk/management/PhabricatorBulkManagementWorkflow.php',
|
||||||
'PhabricatorCSVExportFormat' => 'infrastructure/export/PhabricatorCSVExportFormat.php',
|
'PhabricatorCSVExportFormat' => 'infrastructure/export/format/PhabricatorCSVExportFormat.php',
|
||||||
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
|
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
|
||||||
'PhabricatorCacheEngine' => 'applications/system/engine/PhabricatorCacheEngine.php',
|
'PhabricatorCacheEngine' => 'applications/system/engine/PhabricatorCacheEngine.php',
|
||||||
'PhabricatorCacheEngineExtension' => 'applications/system/engine/PhabricatorCacheEngineExtension.php',
|
'PhabricatorCacheEngineExtension' => 'applications/system/engine/PhabricatorCacheEngineExtension.php',
|
||||||
|
@ -2583,6 +2580,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php',
|
'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php',
|
||||||
'PhabricatorCustomFieldEditField' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php',
|
'PhabricatorCustomFieldEditField' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php',
|
||||||
'PhabricatorCustomFieldEditType' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditType.php',
|
'PhabricatorCustomFieldEditType' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditType.php',
|
||||||
|
'PhabricatorCustomFieldExportEngineExtension' => 'infrastructure/export/engine/PhabricatorCustomFieldExportEngineExtension.php',
|
||||||
'PhabricatorCustomFieldFulltextEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldFulltextEngineExtension.php',
|
'PhabricatorCustomFieldFulltextEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldFulltextEngineExtension.php',
|
||||||
'PhabricatorCustomFieldHeraldAction' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldAction.php',
|
'PhabricatorCustomFieldHeraldAction' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldAction.php',
|
||||||
'PhabricatorCustomFieldHeraldActionGroup' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldActionGroup.php',
|
'PhabricatorCustomFieldHeraldActionGroup' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldActionGroup.php',
|
||||||
|
@ -2840,15 +2838,20 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php',
|
'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php',
|
||||||
'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php',
|
'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php',
|
||||||
'PhabricatorEpochEditField' => 'applications/transactions/editfield/PhabricatorEpochEditField.php',
|
'PhabricatorEpochEditField' => 'applications/transactions/editfield/PhabricatorEpochEditField.php',
|
||||||
'PhabricatorEpochExportField' => 'infrastructure/export/PhabricatorEpochExportField.php',
|
'PhabricatorEpochExportField' => 'infrastructure/export/field/PhabricatorEpochExportField.php',
|
||||||
'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php',
|
'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php',
|
||||||
'PhabricatorEventEngine' => 'infrastructure/events/PhabricatorEventEngine.php',
|
'PhabricatorEventEngine' => 'infrastructure/events/PhabricatorEventEngine.php',
|
||||||
'PhabricatorEventListener' => 'infrastructure/events/PhabricatorEventListener.php',
|
'PhabricatorEventListener' => 'infrastructure/events/PhabricatorEventListener.php',
|
||||||
'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php',
|
'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php',
|
||||||
'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php',
|
'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php',
|
||||||
|
'PhabricatorExcelExportFormat' => 'infrastructure/export/format/PhabricatorExcelExportFormat.php',
|
||||||
'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php',
|
'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php',
|
||||||
'PhabricatorExportField' => 'infrastructure/export/PhabricatorExportField.php',
|
'PhabricatorExportEngine' => 'infrastructure/export/engine/PhabricatorExportEngine.php',
|
||||||
'PhabricatorExportFormat' => 'infrastructure/export/PhabricatorExportFormat.php',
|
'PhabricatorExportEngineBulkJobType' => 'infrastructure/export/engine/PhabricatorExportEngineBulkJobType.php',
|
||||||
|
'PhabricatorExportEngineExtension' => 'infrastructure/export/engine/PhabricatorExportEngineExtension.php',
|
||||||
|
'PhabricatorExportField' => 'infrastructure/export/field/PhabricatorExportField.php',
|
||||||
|
'PhabricatorExportFormat' => 'infrastructure/export/format/PhabricatorExportFormat.php',
|
||||||
|
'PhabricatorExportFormatSetting' => 'infrastructure/export/engine/PhabricatorExportFormatSetting.php',
|
||||||
'PhabricatorExtendedPolicyInterface' => 'applications/policy/interface/PhabricatorExtendedPolicyInterface.php',
|
'PhabricatorExtendedPolicyInterface' => 'applications/policy/interface/PhabricatorExtendedPolicyInterface.php',
|
||||||
'PhabricatorExtendingPhabricatorConfigOptions' => 'applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php',
|
'PhabricatorExtendingPhabricatorConfigOptions' => 'applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php',
|
||||||
'PhabricatorExtensionsSetupCheck' => 'applications/config/check/PhabricatorExtensionsSetupCheck.php',
|
'PhabricatorExtensionsSetupCheck' => 'applications/config/check/PhabricatorExtensionsSetupCheck.php',
|
||||||
|
@ -3069,7 +3072,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorHomeProfileMenuItem' => 'applications/home/menuitem/PhabricatorHomeProfileMenuItem.php',
|
'PhabricatorHomeProfileMenuItem' => 'applications/home/menuitem/PhabricatorHomeProfileMenuItem.php',
|
||||||
'PhabricatorHovercardEngineExtension' => 'applications/search/engineextension/PhabricatorHovercardEngineExtension.php',
|
'PhabricatorHovercardEngineExtension' => 'applications/search/engineextension/PhabricatorHovercardEngineExtension.php',
|
||||||
'PhabricatorHovercardEngineExtensionModule' => 'applications/search/engineextension/PhabricatorHovercardEngineExtensionModule.php',
|
'PhabricatorHovercardEngineExtensionModule' => 'applications/search/engineextension/PhabricatorHovercardEngineExtensionModule.php',
|
||||||
'PhabricatorIDExportField' => 'infrastructure/export/PhabricatorIDExportField.php',
|
'PhabricatorIDExportField' => 'infrastructure/export/field/PhabricatorIDExportField.php',
|
||||||
'PhabricatorIDsSearchEngineExtension' => 'applications/search/engineextension/PhabricatorIDsSearchEngineExtension.php',
|
'PhabricatorIDsSearchEngineExtension' => 'applications/search/engineextension/PhabricatorIDsSearchEngineExtension.php',
|
||||||
'PhabricatorIDsSearchField' => 'applications/search/field/PhabricatorIDsSearchField.php',
|
'PhabricatorIDsSearchField' => 'applications/search/field/PhabricatorIDsSearchField.php',
|
||||||
'PhabricatorIconDatasource' => 'applications/files/typeahead/PhabricatorIconDatasource.php',
|
'PhabricatorIconDatasource' => 'applications/files/typeahead/PhabricatorIconDatasource.php',
|
||||||
|
@ -3093,7 +3096,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php',
|
'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php',
|
||||||
'PhabricatorInstructionsEditField' => 'applications/transactions/editfield/PhabricatorInstructionsEditField.php',
|
'PhabricatorInstructionsEditField' => 'applications/transactions/editfield/PhabricatorInstructionsEditField.php',
|
||||||
'PhabricatorIntConfigType' => 'applications/config/type/PhabricatorIntConfigType.php',
|
'PhabricatorIntConfigType' => 'applications/config/type/PhabricatorIntConfigType.php',
|
||||||
'PhabricatorIntExportField' => 'infrastructure/export/PhabricatorIntExportField.php',
|
'PhabricatorIntExportField' => 'infrastructure/export/field/PhabricatorIntExportField.php',
|
||||||
'PhabricatorInternalSetting' => 'applications/settings/setting/PhabricatorInternalSetting.php',
|
'PhabricatorInternalSetting' => 'applications/settings/setting/PhabricatorInternalSetting.php',
|
||||||
'PhabricatorInternationalizationManagementExtractWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php',
|
'PhabricatorInternationalizationManagementExtractWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php',
|
||||||
'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php',
|
'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php',
|
||||||
|
@ -3103,7 +3106,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorIteratorFileUploadSource' => 'applications/files/uploadsource/PhabricatorIteratorFileUploadSource.php',
|
'PhabricatorIteratorFileUploadSource' => 'applications/files/uploadsource/PhabricatorIteratorFileUploadSource.php',
|
||||||
'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php',
|
'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php',
|
||||||
'PhabricatorJSONConfigType' => 'applications/config/type/PhabricatorJSONConfigType.php',
|
'PhabricatorJSONConfigType' => 'applications/config/type/PhabricatorJSONConfigType.php',
|
||||||
'PhabricatorJSONExportFormat' => 'infrastructure/export/PhabricatorJSONExportFormat.php',
|
'PhabricatorJSONExportFormat' => 'infrastructure/export/format/PhabricatorJSONExportFormat.php',
|
||||||
'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php',
|
'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php',
|
||||||
'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php',
|
'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php',
|
||||||
'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php',
|
'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php',
|
||||||
|
@ -3126,9 +3129,11 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorLipsumManagementWorkflow' => 'applications/lipsum/management/PhabricatorLipsumManagementWorkflow.php',
|
'PhabricatorLipsumManagementWorkflow' => 'applications/lipsum/management/PhabricatorLipsumManagementWorkflow.php',
|
||||||
'PhabricatorLipsumMondrianArtist' => 'applications/lipsum/image/PhabricatorLipsumMondrianArtist.php',
|
'PhabricatorLipsumMondrianArtist' => 'applications/lipsum/image/PhabricatorLipsumMondrianArtist.php',
|
||||||
'PhabricatorLiskDAO' => 'infrastructure/storage/lisk/PhabricatorLiskDAO.php',
|
'PhabricatorLiskDAO' => 'infrastructure/storage/lisk/PhabricatorLiskDAO.php',
|
||||||
|
'PhabricatorLiskExportEngineExtension' => 'infrastructure/export/engine/PhabricatorLiskExportEngineExtension.php',
|
||||||
'PhabricatorLiskFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorLiskFulltextEngineExtension.php',
|
'PhabricatorLiskFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorLiskFulltextEngineExtension.php',
|
||||||
'PhabricatorLiskSearchEngineExtension' => 'applications/search/engineextension/PhabricatorLiskSearchEngineExtension.php',
|
'PhabricatorLiskSearchEngineExtension' => 'applications/search/engineextension/PhabricatorLiskSearchEngineExtension.php',
|
||||||
'PhabricatorLiskSerializer' => 'infrastructure/storage/lisk/PhabricatorLiskSerializer.php',
|
'PhabricatorLiskSerializer' => 'infrastructure/storage/lisk/PhabricatorLiskSerializer.php',
|
||||||
|
'PhabricatorListExportField' => 'infrastructure/export/field/PhabricatorListExportField.php',
|
||||||
'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php',
|
'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php',
|
||||||
'PhabricatorLocalTimeTestCase' => 'view/__tests__/PhabricatorLocalTimeTestCase.php',
|
'PhabricatorLocalTimeTestCase' => 'view/__tests__/PhabricatorLocalTimeTestCase.php',
|
||||||
'PhabricatorLocaleScopeGuard' => 'infrastructure/internationalization/scope/PhabricatorLocaleScopeGuard.php',
|
'PhabricatorLocaleScopeGuard' => 'infrastructure/internationalization/scope/PhabricatorLocaleScopeGuard.php',
|
||||||
|
@ -3423,10 +3428,11 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php',
|
'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php',
|
||||||
'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php',
|
'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php',
|
||||||
'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php',
|
'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php',
|
||||||
'PhabricatorPHIDExportField' => 'infrastructure/export/PhabricatorPHIDExportField.php',
|
'PhabricatorPHIDExportField' => 'infrastructure/export/field/PhabricatorPHIDExportField.php',
|
||||||
'PhabricatorPHIDInterface' => 'applications/phid/interface/PhabricatorPHIDInterface.php',
|
'PhabricatorPHIDInterface' => 'applications/phid/interface/PhabricatorPHIDInterface.php',
|
||||||
'PhabricatorPHIDListEditField' => 'applications/transactions/editfield/PhabricatorPHIDListEditField.php',
|
'PhabricatorPHIDListEditField' => 'applications/transactions/editfield/PhabricatorPHIDListEditField.php',
|
||||||
'PhabricatorPHIDListEditType' => 'applications/transactions/edittype/PhabricatorPHIDListEditType.php',
|
'PhabricatorPHIDListEditType' => 'applications/transactions/edittype/PhabricatorPHIDListEditType.php',
|
||||||
|
'PhabricatorPHIDListExportField' => 'infrastructure/export/field/PhabricatorPHIDListExportField.php',
|
||||||
'PhabricatorPHIDResolver' => 'applications/phid/resolver/PhabricatorPHIDResolver.php',
|
'PhabricatorPHIDResolver' => 'applications/phid/resolver/PhabricatorPHIDResolver.php',
|
||||||
'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php',
|
'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php',
|
||||||
'PhabricatorPHIDTypeTestCase' => 'applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php',
|
'PhabricatorPHIDTypeTestCase' => 'applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php',
|
||||||
|
@ -3835,6 +3841,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php',
|
'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php',
|
||||||
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
|
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
|
||||||
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
||||||
|
'PhabricatorProjectsExportEngineExtension' => 'infrastructure/export/engine/PhabricatorProjectsExportEngineExtension.php',
|
||||||
'PhabricatorProjectsFulltextEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsFulltextEngineExtension.php',
|
'PhabricatorProjectsFulltextEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsFulltextEngineExtension.php',
|
||||||
'PhabricatorProjectsMembersSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsMembersSearchEngineAttachment.php',
|
'PhabricatorProjectsMembersSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsMembersSearchEngineAttachment.php',
|
||||||
'PhabricatorProjectsMembershipIndexEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php',
|
'PhabricatorProjectsMembershipIndexEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php',
|
||||||
|
@ -4126,6 +4133,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSpacesController' => 'applications/spaces/controller/PhabricatorSpacesController.php',
|
'PhabricatorSpacesController' => 'applications/spaces/controller/PhabricatorSpacesController.php',
|
||||||
'PhabricatorSpacesDAO' => 'applications/spaces/storage/PhabricatorSpacesDAO.php',
|
'PhabricatorSpacesDAO' => 'applications/spaces/storage/PhabricatorSpacesDAO.php',
|
||||||
'PhabricatorSpacesEditController' => 'applications/spaces/controller/PhabricatorSpacesEditController.php',
|
'PhabricatorSpacesEditController' => 'applications/spaces/controller/PhabricatorSpacesEditController.php',
|
||||||
|
'PhabricatorSpacesExportEngineExtension' => 'infrastructure/export/engine/PhabricatorSpacesExportEngineExtension.php',
|
||||||
'PhabricatorSpacesInterface' => 'applications/spaces/interface/PhabricatorSpacesInterface.php',
|
'PhabricatorSpacesInterface' => 'applications/spaces/interface/PhabricatorSpacesInterface.php',
|
||||||
'PhabricatorSpacesListController' => 'applications/spaces/controller/PhabricatorSpacesListController.php',
|
'PhabricatorSpacesListController' => 'applications/spaces/controller/PhabricatorSpacesListController.php',
|
||||||
'PhabricatorSpacesNamespace' => 'applications/spaces/storage/PhabricatorSpacesNamespace.php',
|
'PhabricatorSpacesNamespace' => 'applications/spaces/storage/PhabricatorSpacesNamespace.php',
|
||||||
|
@ -4189,9 +4197,10 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorStorageSchemaSpec' => 'infrastructure/storage/schema/PhabricatorStorageSchemaSpec.php',
|
'PhabricatorStorageSchemaSpec' => 'infrastructure/storage/schema/PhabricatorStorageSchemaSpec.php',
|
||||||
'PhabricatorStorageSetupCheck' => 'applications/config/check/PhabricatorStorageSetupCheck.php',
|
'PhabricatorStorageSetupCheck' => 'applications/config/check/PhabricatorStorageSetupCheck.php',
|
||||||
'PhabricatorStringConfigType' => 'applications/config/type/PhabricatorStringConfigType.php',
|
'PhabricatorStringConfigType' => 'applications/config/type/PhabricatorStringConfigType.php',
|
||||||
'PhabricatorStringExportField' => 'infrastructure/export/PhabricatorStringExportField.php',
|
'PhabricatorStringExportField' => 'infrastructure/export/field/PhabricatorStringExportField.php',
|
||||||
'PhabricatorStringListConfigType' => 'applications/config/type/PhabricatorStringListConfigType.php',
|
'PhabricatorStringListConfigType' => 'applications/config/type/PhabricatorStringListConfigType.php',
|
||||||
'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php',
|
'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php',
|
||||||
|
'PhabricatorStringListExportField' => 'infrastructure/export/field/PhabricatorStringListExportField.php',
|
||||||
'PhabricatorStringSetting' => 'applications/settings/setting/PhabricatorStringSetting.php',
|
'PhabricatorStringSetting' => 'applications/settings/setting/PhabricatorStringSetting.php',
|
||||||
'PhabricatorSubmitEditField' => 'applications/transactions/editfield/PhabricatorSubmitEditField.php',
|
'PhabricatorSubmitEditField' => 'applications/transactions/editfield/PhabricatorSubmitEditField.php',
|
||||||
'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php',
|
'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php',
|
||||||
|
@ -4206,6 +4215,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSubscriptionsEditController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php',
|
'PhabricatorSubscriptionsEditController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php',
|
||||||
'PhabricatorSubscriptionsEditEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsEditEngineExtension.php',
|
'PhabricatorSubscriptionsEditEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsEditEngineExtension.php',
|
||||||
'PhabricatorSubscriptionsEditor' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php',
|
'PhabricatorSubscriptionsEditor' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php',
|
||||||
|
'PhabricatorSubscriptionsExportEngineExtension' => 'infrastructure/export/engine/PhabricatorSubscriptionsExportEngineExtension.php',
|
||||||
'PhabricatorSubscriptionsFulltextEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsFulltextEngineExtension.php',
|
'PhabricatorSubscriptionsFulltextEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsFulltextEngineExtension.php',
|
||||||
'PhabricatorSubscriptionsHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsHeraldAction.php',
|
'PhabricatorSubscriptionsHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsHeraldAction.php',
|
||||||
'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php',
|
'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php',
|
||||||
|
@ -4253,7 +4263,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorTextAreaEditField' => 'applications/transactions/editfield/PhabricatorTextAreaEditField.php',
|
'PhabricatorTextAreaEditField' => 'applications/transactions/editfield/PhabricatorTextAreaEditField.php',
|
||||||
'PhabricatorTextConfigType' => 'applications/config/type/PhabricatorTextConfigType.php',
|
'PhabricatorTextConfigType' => 'applications/config/type/PhabricatorTextConfigType.php',
|
||||||
'PhabricatorTextEditField' => 'applications/transactions/editfield/PhabricatorTextEditField.php',
|
'PhabricatorTextEditField' => 'applications/transactions/editfield/PhabricatorTextEditField.php',
|
||||||
'PhabricatorTextExportFormat' => 'infrastructure/export/PhabricatorTextExportFormat.php',
|
'PhabricatorTextExportFormat' => 'infrastructure/export/format/PhabricatorTextExportFormat.php',
|
||||||
'PhabricatorTextListConfigType' => 'applications/config/type/PhabricatorTextListConfigType.php',
|
'PhabricatorTextListConfigType' => 'applications/config/type/PhabricatorTextListConfigType.php',
|
||||||
'PhabricatorTime' => 'infrastructure/time/PhabricatorTime.php',
|
'PhabricatorTime' => 'infrastructure/time/PhabricatorTime.php',
|
||||||
'PhabricatorTimeFormatSetting' => 'applications/settings/setting/PhabricatorTimeFormatSetting.php',
|
'PhabricatorTimeFormatSetting' => 'applications/settings/setting/PhabricatorTimeFormatSetting.php',
|
||||||
|
@ -4318,6 +4328,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorUIExample' => 'applications/uiexample/examples/PhabricatorUIExample.php',
|
'PhabricatorUIExample' => 'applications/uiexample/examples/PhabricatorUIExample.php',
|
||||||
'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/PhabricatorUIExampleRenderController.php',
|
'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/PhabricatorUIExampleRenderController.php',
|
||||||
'PhabricatorUIExamplesApplication' => 'applications/uiexample/application/PhabricatorUIExamplesApplication.php',
|
'PhabricatorUIExamplesApplication' => 'applications/uiexample/application/PhabricatorUIExamplesApplication.php',
|
||||||
|
'PhabricatorURIExportField' => 'infrastructure/export/field/PhabricatorURIExportField.php',
|
||||||
'PhabricatorUSEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php',
|
'PhabricatorUSEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php',
|
||||||
'PhabricatorUnifiedDiffsSetting' => 'applications/settings/setting/PhabricatorUnifiedDiffsSetting.php',
|
'PhabricatorUnifiedDiffsSetting' => 'applications/settings/setting/PhabricatorUnifiedDiffsSetting.php',
|
||||||
'PhabricatorUnitTestContentSource' => 'infrastructure/contentsource/PhabricatorUnitTestContentSource.php',
|
'PhabricatorUnitTestContentSource' => 'infrastructure/contentsource/PhabricatorUnitTestContentSource.php',
|
||||||
|
@ -4411,6 +4422,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorWorkerManagementWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php',
|
'PhabricatorWorkerManagementWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php',
|
||||||
'PhabricatorWorkerPermanentFailureException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerPermanentFailureException.php',
|
'PhabricatorWorkerPermanentFailureException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerPermanentFailureException.php',
|
||||||
'PhabricatorWorkerSchemaSpec' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerSchemaSpec.php',
|
'PhabricatorWorkerSchemaSpec' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerSchemaSpec.php',
|
||||||
|
'PhabricatorWorkerSingleBulkJobType' => 'infrastructure/daemon/workers/bulk/PhabricatorWorkerSingleBulkJobType.php',
|
||||||
'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php',
|
'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php',
|
||||||
'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTaskData.php',
|
'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTaskData.php',
|
||||||
'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/PhabricatorWorkerTaskDetailController.php',
|
'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/PhabricatorWorkerTaskDetailController.php',
|
||||||
|
@ -6768,10 +6780,6 @@ phutil_register_library_map(array(
|
||||||
'ManiphestEditProjectsCapability' => 'PhabricatorPolicyCapability',
|
'ManiphestEditProjectsCapability' => 'PhabricatorPolicyCapability',
|
||||||
'ManiphestEditStatusCapability' => 'PhabricatorPolicyCapability',
|
'ManiphestEditStatusCapability' => 'PhabricatorPolicyCapability',
|
||||||
'ManiphestEmailCommand' => 'MetaMTAEmailTransactionCommand',
|
'ManiphestEmailCommand' => 'MetaMTAEmailTransactionCommand',
|
||||||
'ManiphestExcelDefaultFormat' => 'ManiphestExcelFormat',
|
|
||||||
'ManiphestExcelFormat' => 'Phobject',
|
|
||||||
'ManiphestExcelFormatTestCase' => 'PhabricatorTestCase',
|
|
||||||
'ManiphestExportController' => 'ManiphestController',
|
|
||||||
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||||
'ManiphestHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
'ManiphestHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
||||||
'ManiphestInfoConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
'ManiphestInfoConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||||
|
@ -7572,6 +7580,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBulkContentSource' => 'PhabricatorContentSource',
|
'PhabricatorBulkContentSource' => 'PhabricatorContentSource',
|
||||||
'PhabricatorBulkEditGroup' => 'Phobject',
|
'PhabricatorBulkEditGroup' => 'Phobject',
|
||||||
'PhabricatorBulkEngine' => 'Phobject',
|
'PhabricatorBulkEngine' => 'Phobject',
|
||||||
|
'PhabricatorBulkManagementExportWorkflow' => 'PhabricatorBulkManagementWorkflow',
|
||||||
'PhabricatorBulkManagementMakeSilentWorkflow' => 'PhabricatorBulkManagementWorkflow',
|
'PhabricatorBulkManagementMakeSilentWorkflow' => 'PhabricatorBulkManagementWorkflow',
|
||||||
'PhabricatorBulkManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorBulkManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorCSVExportFormat' => 'PhabricatorExportFormat',
|
'PhabricatorCSVExportFormat' => 'PhabricatorExportFormat',
|
||||||
|
@ -7991,6 +8000,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCustomFieldEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
'PhabricatorCustomFieldEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||||
'PhabricatorCustomFieldEditField' => 'PhabricatorEditField',
|
'PhabricatorCustomFieldEditField' => 'PhabricatorEditField',
|
||||||
'PhabricatorCustomFieldEditType' => 'PhabricatorEditType',
|
'PhabricatorCustomFieldEditType' => 'PhabricatorEditType',
|
||||||
|
'PhabricatorCustomFieldExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
||||||
'PhabricatorCustomFieldFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
'PhabricatorCustomFieldFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||||
'PhabricatorCustomFieldHeraldAction' => 'HeraldAction',
|
'PhabricatorCustomFieldHeraldAction' => 'HeraldAction',
|
||||||
'PhabricatorCustomFieldHeraldActionGroup' => 'HeraldActionGroup',
|
'PhabricatorCustomFieldHeraldActionGroup' => 'HeraldActionGroup',
|
||||||
|
@ -8279,9 +8289,14 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEventListener' => 'PhutilEventListener',
|
'PhabricatorEventListener' => 'PhutilEventListener',
|
||||||
'PhabricatorEventType' => 'PhutilEventType',
|
'PhabricatorEventType' => 'PhutilEventType',
|
||||||
'PhabricatorExampleEventListener' => 'PhabricatorEventListener',
|
'PhabricatorExampleEventListener' => 'PhabricatorEventListener',
|
||||||
|
'PhabricatorExcelExportFormat' => 'PhabricatorExportFormat',
|
||||||
'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource',
|
'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource',
|
||||||
|
'PhabricatorExportEngine' => 'Phobject',
|
||||||
|
'PhabricatorExportEngineBulkJobType' => 'PhabricatorWorkerSingleBulkJobType',
|
||||||
|
'PhabricatorExportEngineExtension' => 'Phobject',
|
||||||
'PhabricatorExportField' => 'Phobject',
|
'PhabricatorExportField' => 'Phobject',
|
||||||
'PhabricatorExportFormat' => 'Phobject',
|
'PhabricatorExportFormat' => 'Phobject',
|
||||||
|
'PhabricatorExportFormatSetting' => 'PhabricatorInternalSetting',
|
||||||
'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
'PhabricatorExtensionsSetupCheck' => 'PhabricatorSetupCheck',
|
'PhabricatorExtensionsSetupCheck' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorExternalAccount' => array(
|
'PhabricatorExternalAccount' => array(
|
||||||
|
@ -8599,9 +8614,11 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorLipsumMondrianArtist' => 'PhabricatorLipsumArtist',
|
'PhabricatorLipsumMondrianArtist' => 'PhabricatorLipsumArtist',
|
||||||
'PhabricatorLiskDAO' => 'LiskDAO',
|
'PhabricatorLiskDAO' => 'LiskDAO',
|
||||||
|
'PhabricatorLiskExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
||||||
'PhabricatorLiskFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
'PhabricatorLiskFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||||
'PhabricatorLiskSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
'PhabricatorLiskSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||||
'PhabricatorLiskSerializer' => 'Phobject',
|
'PhabricatorLiskSerializer' => 'Phobject',
|
||||||
|
'PhabricatorListExportField' => 'PhabricatorExportField',
|
||||||
'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
||||||
'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase',
|
'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorLocaleScopeGuard' => 'Phobject',
|
'PhabricatorLocaleScopeGuard' => 'Phobject',
|
||||||
|
@ -8939,6 +8956,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPHIDExportField' => 'PhabricatorExportField',
|
'PhabricatorPHIDExportField' => 'PhabricatorExportField',
|
||||||
'PhabricatorPHIDListEditField' => 'PhabricatorEditField',
|
'PhabricatorPHIDListEditField' => 'PhabricatorEditField',
|
||||||
'PhabricatorPHIDListEditType' => 'PhabricatorEditType',
|
'PhabricatorPHIDListEditType' => 'PhabricatorEditType',
|
||||||
|
'PhabricatorPHIDListExportField' => 'PhabricatorListExportField',
|
||||||
'PhabricatorPHIDResolver' => 'Phobject',
|
'PhabricatorPHIDResolver' => 'Phobject',
|
||||||
'PhabricatorPHIDType' => 'Phobject',
|
'PhabricatorPHIDType' => 'Phobject',
|
||||||
'PhabricatorPHIDTypeTestCase' => 'PhutilTestCase',
|
'PhabricatorPHIDTypeTestCase' => 'PhutilTestCase',
|
||||||
|
@ -9439,6 +9457,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension',
|
'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension',
|
||||||
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||||
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
||||||
|
'PhabricatorProjectsExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
||||||
'PhabricatorProjectsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
'PhabricatorProjectsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||||
'PhabricatorProjectsMembersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
'PhabricatorProjectsMembersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||||
'PhabricatorProjectsMembershipIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
|
'PhabricatorProjectsMembershipIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
|
||||||
|
@ -9806,6 +9825,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSpacesController' => 'PhabricatorController',
|
'PhabricatorSpacesController' => 'PhabricatorController',
|
||||||
'PhabricatorSpacesDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorSpacesDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorSpacesEditController' => 'PhabricatorSpacesController',
|
'PhabricatorSpacesEditController' => 'PhabricatorSpacesController',
|
||||||
|
'PhabricatorSpacesExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
||||||
'PhabricatorSpacesInterface' => 'PhabricatorPHIDInterface',
|
'PhabricatorSpacesInterface' => 'PhabricatorPHIDInterface',
|
||||||
'PhabricatorSpacesListController' => 'PhabricatorSpacesController',
|
'PhabricatorSpacesListController' => 'PhabricatorSpacesController',
|
||||||
'PhabricatorSpacesNamespace' => array(
|
'PhabricatorSpacesNamespace' => array(
|
||||||
|
@ -9879,6 +9899,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorStringExportField' => 'PhabricatorExportField',
|
'PhabricatorStringExportField' => 'PhabricatorExportField',
|
||||||
'PhabricatorStringListConfigType' => 'PhabricatorTextListConfigType',
|
'PhabricatorStringListConfigType' => 'PhabricatorTextListConfigType',
|
||||||
'PhabricatorStringListEditField' => 'PhabricatorEditField',
|
'PhabricatorStringListEditField' => 'PhabricatorEditField',
|
||||||
|
'PhabricatorStringListExportField' => 'PhabricatorListExportField',
|
||||||
'PhabricatorStringSetting' => 'PhabricatorSetting',
|
'PhabricatorStringSetting' => 'PhabricatorSetting',
|
||||||
'PhabricatorSubmitEditField' => 'PhabricatorEditField',
|
'PhabricatorSubmitEditField' => 'PhabricatorEditField',
|
||||||
'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType',
|
'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType',
|
||||||
|
@ -9892,6 +9913,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSubscriptionsEditController' => 'PhabricatorController',
|
'PhabricatorSubscriptionsEditController' => 'PhabricatorController',
|
||||||
'PhabricatorSubscriptionsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
'PhabricatorSubscriptionsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||||
'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor',
|
'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor',
|
||||||
|
'PhabricatorSubscriptionsExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
||||||
'PhabricatorSubscriptionsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
'PhabricatorSubscriptionsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||||
'PhabricatorSubscriptionsHeraldAction' => 'HeraldAction',
|
'PhabricatorSubscriptionsHeraldAction' => 'HeraldAction',
|
||||||
'PhabricatorSubscriptionsListController' => 'PhabricatorController',
|
'PhabricatorSubscriptionsListController' => 'PhabricatorController',
|
||||||
|
@ -10015,6 +10037,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorUIExample' => 'Phobject',
|
'PhabricatorUIExample' => 'Phobject',
|
||||||
'PhabricatorUIExampleRenderController' => 'PhabricatorController',
|
'PhabricatorUIExampleRenderController' => 'PhabricatorController',
|
||||||
'PhabricatorUIExamplesApplication' => 'PhabricatorApplication',
|
'PhabricatorUIExamplesApplication' => 'PhabricatorApplication',
|
||||||
|
'PhabricatorURIExportField' => 'PhabricatorExportField',
|
||||||
'PhabricatorUSEnglishTranslation' => 'PhutilTranslation',
|
'PhabricatorUSEnglishTranslation' => 'PhutilTranslation',
|
||||||
'PhabricatorUnifiedDiffsSetting' => 'PhabricatorSelectSetting',
|
'PhabricatorUnifiedDiffsSetting' => 'PhabricatorSelectSetting',
|
||||||
'PhabricatorUnitTestContentSource' => 'PhabricatorContentSource',
|
'PhabricatorUnitTestContentSource' => 'PhabricatorContentSource',
|
||||||
|
@ -10138,6 +10161,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorWorkerManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorWorkerManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorWorkerPermanentFailureException' => 'Exception',
|
'PhabricatorWorkerPermanentFailureException' => 'Exception',
|
||||||
'PhabricatorWorkerSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
'PhabricatorWorkerSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
|
'PhabricatorWorkerSingleBulkJobType' => 'PhabricatorWorkerBulkJobType',
|
||||||
'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO',
|
'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO',
|
||||||
'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO',
|
'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO',
|
||||||
'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController',
|
'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController',
|
||||||
|
|
|
@ -358,9 +358,17 @@ final class PhabricatorAuditEditor
|
||||||
array $changes,
|
array $changes,
|
||||||
PhutilMarkupEngine $engine) {
|
PhutilMarkupEngine $engine) {
|
||||||
|
|
||||||
// we are only really trying to find unmentionable phids here...
|
$actor = $this->getActor();
|
||||||
// don't bother with this outside initial commit (i.e. create)
|
$result = array();
|
||||||
// transaction
|
|
||||||
|
// Some interactions (like "Fixes Txxx" interacting with Maniphest) have
|
||||||
|
// already been processed, so we're only re-parsing them here to avoid
|
||||||
|
// generating an extra redundant mention. Other interactions are being
|
||||||
|
// processed for the first time.
|
||||||
|
|
||||||
|
// We're only recognizing magic in the commit message itself, not in
|
||||||
|
// audit comments.
|
||||||
|
|
||||||
$is_commit = false;
|
$is_commit = false;
|
||||||
foreach ($xactions as $xaction) {
|
foreach ($xactions as $xaction) {
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
|
@ -370,8 +378,6 @@ final class PhabricatorAuditEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "result" is always an array....
|
|
||||||
$result = array();
|
|
||||||
if (!$is_commit) {
|
if (!$is_commit) {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
@ -403,6 +409,46 @@ final class PhabricatorAuditEditor
|
||||||
->withNames($monograms)
|
->withNames($monograms)
|
||||||
->execute();
|
->execute();
|
||||||
$phid_map[] = mpull($objects, 'getPHID', 'getPHID');
|
$phid_map[] = mpull($objects, 'getPHID', 'getPHID');
|
||||||
|
|
||||||
|
|
||||||
|
$reverts_refs = id(new DifferentialCustomFieldRevertsParser())
|
||||||
|
->parseCorpus($huge_block);
|
||||||
|
$reverts = array_mergev(ipull($reverts_refs, 'monograms'));
|
||||||
|
if ($reverts) {
|
||||||
|
// Only allow commits to revert other commits in the same repository.
|
||||||
|
$reverted_commits = id(new DiffusionCommitQuery())
|
||||||
|
->setViewer($actor)
|
||||||
|
->withRepository($object->getRepository())
|
||||||
|
->withIdentifiers($reverts)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$reverted_revisions = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($actor)
|
||||||
|
->withNames($reverts)
|
||||||
|
->withTypes(
|
||||||
|
array(
|
||||||
|
DifferentialRevisionPHIDType::TYPECONST,
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$reverted_phids =
|
||||||
|
mpull($reverted_commits, 'getPHID', 'getPHID') +
|
||||||
|
mpull($reverted_revisions, 'getPHID', 'getPHID');
|
||||||
|
|
||||||
|
// NOTE: Skip any write attempts if a user cleverly implies a commit
|
||||||
|
// reverts itself, although this would be exceptionally clever in Git
|
||||||
|
// or Mercurial.
|
||||||
|
unset($reverted_phids[$object->getPHID()]);
|
||||||
|
|
||||||
|
$reverts_edge = DiffusionCommitRevertsCommitEdgeType::EDGECONST;
|
||||||
|
$result[] = id(new PhabricatorAuditTransaction())
|
||||||
|
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||||
|
->setMetadataValue('edge:type', $reverts_edge)
|
||||||
|
->setNewValue(array('+' => $reverted_phids));
|
||||||
|
|
||||||
|
$phid_map[] = $reverted_phids;
|
||||||
|
}
|
||||||
|
|
||||||
$phid_map = array_mergev($phid_map);
|
$phid_map = array_mergev($phid_map);
|
||||||
$this->setUnmentionablePHIDMap($phid_map);
|
$this->setUnmentionablePHIDMap($phid_map);
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,26 @@
|
||||||
final class ConduitPHIDParameterType
|
final class ConduitPHIDParameterType
|
||||||
extends ConduitParameterType {
|
extends ConduitParameterType {
|
||||||
|
|
||||||
|
private $isNullable;
|
||||||
|
|
||||||
|
public function setIsNullable($is_nullable) {
|
||||||
|
$this->isNullable = $is_nullable;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsNullable() {
|
||||||
|
return $this->isNullable;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getParameterValue(array $request, $key, $strict) {
|
protected function getParameterValue(array $request, $key, $strict) {
|
||||||
$value = parent::getParameterValue($request, $key, $strict);
|
$value = parent::getParameterValue($request, $key, $strict);
|
||||||
|
|
||||||
|
if ($this->getIsNullable()) {
|
||||||
|
if ($value === null) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_string($value)) {
|
if (!is_string($value)) {
|
||||||
$this->raiseValidationException(
|
$this->raiseValidationException(
|
||||||
$request,
|
$request,
|
||||||
|
@ -17,7 +34,11 @@ final class ConduitPHIDParameterType
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getParameterTypeName() {
|
protected function getParameterTypeName() {
|
||||||
return 'phid';
|
if ($this->getIsNullable()) {
|
||||||
|
return 'phid|null';
|
||||||
|
} else {
|
||||||
|
return 'phid';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getParameterFormatDescriptions() {
|
protected function getParameterFormatDescriptions() {
|
||||||
|
@ -27,9 +48,15 @@ final class ConduitPHIDParameterType
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getParameterExamples() {
|
protected function getParameterExamples() {
|
||||||
return array(
|
$examples = array(
|
||||||
'"PHID-WXYZ-1111222233334444"',
|
'"PHID-WXYZ-1111222233334444"',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($this->getIsNullable()) {
|
||||||
|
$examples[] = 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $examples;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,18 +71,10 @@ final class PhabricatorDaemonBulkJobViewController
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
$curtain = $this->newCurtainView($job);
|
$curtain = $this->newCurtainView($job);
|
||||||
|
|
||||||
if ($job->isConfirming()) {
|
foreach ($job->getCurtainActions($viewer) as $action) {
|
||||||
$continue_uri = $job->getMonitorURI();
|
$curtain->addAction($action);
|
||||||
} else {
|
|
||||||
$continue_uri = $job->getDoneURI();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$curtain->addAction(
|
|
||||||
id(new PhabricatorActionView())
|
|
||||||
->setHref($continue_uri)
|
|
||||||
->setIcon('fa-arrow-circle-o-right')
|
|
||||||
->setName(pht('Continue')));
|
|
||||||
|
|
||||||
return $curtain;
|
return $curtain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -919,7 +919,44 @@ final class DifferentialTransactionEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setUnmentionablePHIDMap(array_merge($task_phids, $rev_phids));
|
$revert_refs = id(new DifferentialCustomFieldRevertsParser())
|
||||||
|
->parseCorpus($content_block);
|
||||||
|
|
||||||
|
$revert_monograms = array();
|
||||||
|
foreach ($revert_refs as $match) {
|
||||||
|
foreach ($match['monograms'] as $monogram) {
|
||||||
|
$revert_monograms[] = $monogram;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($revert_monograms) {
|
||||||
|
$revert_objects = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($this->getActor())
|
||||||
|
->withNames($revert_monograms)
|
||||||
|
->withTypes(
|
||||||
|
array(
|
||||||
|
DifferentialRevisionPHIDType::TYPECONST,
|
||||||
|
PhabricatorRepositoryCommitPHIDType::TYPECONST,
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$revert_phids = mpull($revert_objects, 'getPHID', 'getPHID');
|
||||||
|
|
||||||
|
// Don't let an object revert itself, although other silly stuff like
|
||||||
|
// cycles of objects reverting each other is not prevented.
|
||||||
|
unset($revert_phids[$object->getPHID()]);
|
||||||
|
|
||||||
|
$revert_type = DiffusionCommitRevertsCommitEdgeType::EDGECONST;
|
||||||
|
$edges[$revert_type] = $revert_phids;
|
||||||
|
} else {
|
||||||
|
$revert_phids = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setUnmentionablePHIDMap(
|
||||||
|
array_merge(
|
||||||
|
$task_phids,
|
||||||
|
$rev_phids,
|
||||||
|
$revert_phids));
|
||||||
|
|
||||||
$result = array();
|
$result = array();
|
||||||
foreach ($edges as $type => $specs) {
|
foreach ($edges as $type => $specs) {
|
||||||
|
|
|
@ -121,7 +121,7 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
||||||
$this->getEditRoutePattern('edit/') =>
|
$this->getEditRoutePattern('edit/') =>
|
||||||
'DiffusionRepositoryEditController',
|
'DiffusionRepositoryEditController',
|
||||||
'pushlog/' => array(
|
'pushlog/' => array(
|
||||||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController',
|
$this->getQueryRoutePattern() => 'DiffusionPushLogListController',
|
||||||
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
|
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
|
||||||
),
|
),
|
||||||
'pulllog/' => array(
|
'pulllog/' => array(
|
||||||
|
|
|
@ -9,4 +9,9 @@ final class DiffusionPullLogListController
|
||||||
->buildResponse();
|
->buildResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function buildApplicationCrumbs() {
|
||||||
|
return parent::buildApplicationCrumbs()
|
||||||
|
->addTextCrumb(pht('Pull Logs'), $this->getApplicationURI('pulllog/'));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,9 @@ final class DiffusionPushLogListController
|
||||||
->buildResponse();
|
->buildResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function buildApplicationCrumbs() {
|
||||||
|
return parent::buildApplicationCrumbs()
|
||||||
|
->addTextCrumb(pht('Push Logs'), $this->getApplicationURI('pushlog/'));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ final class DiffusionCommitRevertedByCommitEdgeType
|
||||||
$add_edges) {
|
$add_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s added %s reverting commit(s): %s.',
|
'%s added %s reverting change(s): %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$add_count,
|
$add_count,
|
||||||
$add_edges);
|
$add_edges);
|
||||||
|
@ -31,7 +31,7 @@ final class DiffusionCommitRevertedByCommitEdgeType
|
||||||
$rem_edges) {
|
$rem_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s removed %s reverting commit(s): %s.',
|
'%s removed %s reverting change(s): %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$rem_count,
|
$rem_count,
|
||||||
$rem_edges);
|
$rem_edges);
|
||||||
|
@ -46,7 +46,7 @@ final class DiffusionCommitRevertedByCommitEdgeType
|
||||||
$rem_edges) {
|
$rem_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s edited reverting commit(s), added %s: %s; removed %s: %s.',
|
'%s edited reverting change(s), added %s: %s; removed %s: %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$add_count,
|
$add_count,
|
||||||
$add_edges,
|
$add_edges,
|
||||||
|
@ -61,7 +61,7 @@ final class DiffusionCommitRevertedByCommitEdgeType
|
||||||
$add_edges) {
|
$add_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s added %s reverting commit(s) for %s: %s.',
|
'%s added %s reverting change(s) for %s: %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$add_count,
|
$add_count,
|
||||||
$object,
|
$object,
|
||||||
|
@ -75,7 +75,7 @@ final class DiffusionCommitRevertedByCommitEdgeType
|
||||||
$rem_edges) {
|
$rem_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s removed %s reverting commit(s) for %s: %s.',
|
'%s removed %s reverting change(s) for %s: %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$rem_count,
|
$rem_count,
|
||||||
$object,
|
$object,
|
||||||
|
@ -92,7 +92,7 @@ final class DiffusionCommitRevertedByCommitEdgeType
|
||||||
$rem_edges) {
|
$rem_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s edited reverting commit(s) for %s, added %s: %s; removed %s: %s.',
|
'%s edited reverting change(s) for %s, added %s: %s; removed %s: %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$object,
|
$object,
|
||||||
$add_count,
|
$add_count,
|
||||||
|
|
|
@ -22,7 +22,7 @@ final class DiffusionCommitRevertsCommitEdgeType extends PhabricatorEdgeType {
|
||||||
$add_edges) {
|
$add_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s added %s reverted commit(s): %s.',
|
'%s added %s reverted change(s): %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$add_count,
|
$add_count,
|
||||||
$add_edges);
|
$add_edges);
|
||||||
|
@ -34,7 +34,7 @@ final class DiffusionCommitRevertsCommitEdgeType extends PhabricatorEdgeType {
|
||||||
$rem_edges) {
|
$rem_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s removed %s reverted commit(s): %s.',
|
'%s removed %s reverted change(s): %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$rem_count,
|
$rem_count,
|
||||||
$rem_edges);
|
$rem_edges);
|
||||||
|
@ -49,7 +49,7 @@ final class DiffusionCommitRevertsCommitEdgeType extends PhabricatorEdgeType {
|
||||||
$rem_edges) {
|
$rem_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s edited reverted commit(s), added %s: %s; removed %s: %s.',
|
'%s edited reverted change(s), added %s: %s; removed %s: %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$add_count,
|
$add_count,
|
||||||
$add_edges,
|
$add_edges,
|
||||||
|
@ -64,7 +64,7 @@ final class DiffusionCommitRevertsCommitEdgeType extends PhabricatorEdgeType {
|
||||||
$add_edges) {
|
$add_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s added %s reverted commit(s) for %s: %s.',
|
'%s added %s reverted change(s) for %s: %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$add_count,
|
$add_count,
|
||||||
$object,
|
$object,
|
||||||
|
@ -78,7 +78,7 @@ final class DiffusionCommitRevertsCommitEdgeType extends PhabricatorEdgeType {
|
||||||
$rem_edges) {
|
$rem_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s removed %s reverted commit(s) for %s: %s.',
|
'%s removed %s reverted change(s) for %s: %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$rem_count,
|
$rem_count,
|
||||||
$object,
|
$object,
|
||||||
|
@ -95,7 +95,7 @@ final class DiffusionCommitRevertsCommitEdgeType extends PhabricatorEdgeType {
|
||||||
$rem_edges) {
|
$rem_edges) {
|
||||||
|
|
||||||
return pht(
|
return pht(
|
||||||
'%s edited reverted commit(s) for %s, added %s: %s; removed %s: %s.',
|
'%s edited reverted change(s) for %s, added %s: %s; removed %s: %s.',
|
||||||
$actor,
|
$actor,
|
||||||
$object,
|
$object,
|
||||||
$add_count,
|
$add_count,
|
||||||
|
|
|
@ -135,13 +135,16 @@ final class HeraldCommitAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadAffectedPaths() {
|
public function loadAffectedPaths() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
if ($this->affectedPaths === null) {
|
if ($this->affectedPaths === null) {
|
||||||
$result = PhabricatorOwnerPathQuery::loadAffectedPaths(
|
$result = PhabricatorOwnerPathQuery::loadAffectedPaths(
|
||||||
$this->getRepository(),
|
$this->getRepository(),
|
||||||
$this->commit,
|
$this->commit,
|
||||||
PhabricatorUser::getOmnipotentUser());
|
$viewer);
|
||||||
$this->affectedPaths = $result;
|
$this->affectedPaths = $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->affectedPaths;
|
return $this->affectedPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,6 +175,8 @@ final class HeraldCommitAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadDifferentialRevision() {
|
public function loadDifferentialRevision() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
if ($this->affectedRevision === null) {
|
if ($this->affectedRevision === null) {
|
||||||
$this->affectedRevision = false;
|
$this->affectedRevision = false;
|
||||||
|
|
||||||
|
@ -189,7 +194,7 @@ final class HeraldCommitAdapter
|
||||||
|
|
||||||
$revision = id(new DifferentialRevisionQuery())
|
$revision = id(new DifferentialRevisionQuery())
|
||||||
->withIDs(array($revision_id))
|
->withIDs(array($revision_id))
|
||||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
->setViewer($viewer)
|
||||||
->needReviewers(true)
|
->needReviewers(true)
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if ($revision) {
|
if ($revision) {
|
||||||
|
@ -197,6 +202,7 @@ final class HeraldCommitAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->affectedRevision;
|
return $this->affectedRevision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +329,7 @@ final class HeraldCommitAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private function callConduit($method, array $params) {
|
private function callConduit($method, array $params) {
|
||||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
$drequest = DiffusionRequest::newFromDictionary(
|
$drequest = DiffusionRequest::newFromDictionary(
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -26,6 +26,12 @@ final class DiffusionPullLogSearchEngine
|
||||||
$query->withPullerPHIDs($map['pullerPHIDs']);
|
$query->withPullerPHIDs($map['pullerPHIDs']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($map['createdStart'] || $map['createdEnd']) {
|
||||||
|
$query->withEpochBetween(
|
||||||
|
$map['createdStart'],
|
||||||
|
$map['createdEnd']);
|
||||||
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,17 +50,19 @@ final class DiffusionPullLogSearchEngine
|
||||||
->setLabel(pht('Pullers'))
|
->setLabel(pht('Pullers'))
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht('Search for pull logs by specific users.')),
|
pht('Search for pull logs by specific users.')),
|
||||||
|
id(new PhabricatorSearchDateField())
|
||||||
|
->setLabel(pht('Created After'))
|
||||||
|
->setKey('createdStart'),
|
||||||
|
id(new PhabricatorSearchDateField())
|
||||||
|
->setLabel(pht('Created Before'))
|
||||||
|
->setKey('createdEnd'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newExportFields() {
|
protected function newExportFields() {
|
||||||
return array(
|
$viewer = $this->requireViewer();
|
||||||
id(new PhabricatorIDExportField())
|
|
||||||
->setKey('id')
|
$fields = array(
|
||||||
->setLabel(pht('ID')),
|
|
||||||
id(new PhabricatorPHIDExportField())
|
|
||||||
->setKey('phid')
|
|
||||||
->setLabel(pht('PHID')),
|
|
||||||
id(new PhabricatorPHIDExportField())
|
id(new PhabricatorPHIDExportField())
|
||||||
->setKey('repositoryPHID')
|
->setKey('repositoryPHID')
|
||||||
->setLabel(pht('Repository PHID')),
|
->setLabel(pht('Repository PHID')),
|
||||||
|
@ -80,9 +88,17 @@ final class DiffusionPullLogSearchEngine
|
||||||
->setKey('date')
|
->setKey('date')
|
||||||
->setLabel(pht('Date')),
|
->setLabel(pht('Date')),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($viewer->getIsAdmin()) {
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('remoteAddress')
|
||||||
|
->setLabel(pht('Remote Address'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newExport(array $events) {
|
protected function newExportData(array $events) {
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
$phids = array();
|
$phids = array();
|
||||||
|
@ -111,9 +127,7 @@ final class DiffusionPullLogSearchEngine
|
||||||
$puller_name = null;
|
$puller_name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$export[] = array(
|
$map = array(
|
||||||
'id' => $event->getID(),
|
|
||||||
'phid' => $event->getPHID(),
|
|
||||||
'repositoryPHID' => $repository_phid,
|
'repositoryPHID' => $repository_phid,
|
||||||
'repository' => $repository_name,
|
'repository' => $repository_name,
|
||||||
'pullerPHID' => $puller_phid,
|
'pullerPHID' => $puller_phid,
|
||||||
|
@ -123,6 +137,12 @@ final class DiffusionPullLogSearchEngine
|
||||||
'code' => $event->getResultCode(),
|
'code' => $event->getResultCode(),
|
||||||
'date' => $event->getEpoch(),
|
'date' => $event->getEpoch(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($viewer->getIsAdmin()) {
|
||||||
|
$map['remoteAddress'] = $event->getRemoteAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
$export[] = $map;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $export;
|
return $export;
|
||||||
|
|
|
@ -22,24 +22,10 @@ final class DiffusionPullLogListView extends AphrontView {
|
||||||
}
|
}
|
||||||
$handles = $viewer->loadHandles($handle_phids);
|
$handles = $viewer->loadHandles($handle_phids);
|
||||||
|
|
||||||
// Figure out which repositories are editable. We only let you see remote
|
// Only administrators can view remote addresses.
|
||||||
// IPs if you have edit capability on a repository.
|
$remotes_visible = $viewer->getIsAdmin();
|
||||||
$editable_repos = array();
|
|
||||||
if ($events) {
|
|
||||||
$editable_repos = id(new PhabricatorRepositoryQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->requireCapabilities(
|
|
||||||
array(
|
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT,
|
|
||||||
))
|
|
||||||
->withPHIDs(mpull($events, 'getRepositoryPHID'))
|
|
||||||
->execute();
|
|
||||||
$editable_repos = mpull($editable_repos, null, 'getPHID');
|
|
||||||
}
|
|
||||||
|
|
||||||
$rows = array();
|
$rows = array();
|
||||||
$any_host = false;
|
|
||||||
foreach ($events as $event) {
|
foreach ($events as $event) {
|
||||||
if ($event->getRepositoryPHID()) {
|
if ($event->getRepositoryPHID()) {
|
||||||
$repository = $event->getRepository();
|
$repository = $event->getRepository();
|
||||||
|
@ -47,13 +33,10 @@ final class DiffusionPullLogListView extends AphrontView {
|
||||||
$repository = null;
|
$repository = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reveal this if it's valid and the user can edit the repository. For
|
if ($remotes_visible) {
|
||||||
// invalid requests you currently have to go fishing in the database.
|
$remote_address = $event->getRemoteAddress();
|
||||||
$remote_address = '-';
|
} else {
|
||||||
if ($repository) {
|
$remote_address = null;
|
||||||
if (isset($editable_repos[$event->getRepositoryPHID()])) {
|
|
||||||
$remote_address = $event->getRemoteAddress();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$event_id = $event->getID();
|
$event_id = $event->getID();
|
||||||
|
@ -107,6 +90,13 @@ final class DiffusionPullLogListView extends AphrontView {
|
||||||
'',
|
'',
|
||||||
'n',
|
'n',
|
||||||
'right',
|
'right',
|
||||||
|
))
|
||||||
|
->setColumnVisibility(
|
||||||
|
array(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
$remotes_visible,
|
||||||
));
|
));
|
||||||
|
|
||||||
return $table;
|
return $table;
|
||||||
|
|
|
@ -25,31 +25,21 @@ final class DiffusionPushLogListView extends AphrontView {
|
||||||
|
|
||||||
$handles = $viewer->loadHandles($handle_phids);
|
$handles = $viewer->loadHandles($handle_phids);
|
||||||
|
|
||||||
// Figure out which repositories are editable. We only let you see remote
|
// Only administrators can view remote addresses.
|
||||||
// IPs if you have edit capability on a repository.
|
$remotes_visible = $viewer->getIsAdmin();
|
||||||
$editable_repos = array();
|
|
||||||
if ($logs) {
|
$flag_map = PhabricatorRepositoryPushLog::getFlagDisplayNames();
|
||||||
$editable_repos = id(new PhabricatorRepositoryQuery())
|
$reject_map = PhabricatorRepositoryPushLog::getRejectCodeDisplayNames();
|
||||||
->setViewer($viewer)
|
|
||||||
->requireCapabilities(
|
|
||||||
array(
|
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT,
|
|
||||||
))
|
|
||||||
->withPHIDs(mpull($logs, 'getRepositoryPHID'))
|
|
||||||
->execute();
|
|
||||||
$editable_repos = mpull($editable_repos, null, 'getPHID');
|
|
||||||
}
|
|
||||||
|
|
||||||
$rows = array();
|
$rows = array();
|
||||||
$any_host = false;
|
$any_host = false;
|
||||||
foreach ($logs as $log) {
|
foreach ($logs as $log) {
|
||||||
$repository = $log->getRepository();
|
$repository = $log->getRepository();
|
||||||
|
|
||||||
// Reveal this if it's valid and the user can edit the repository.
|
if ($remotes_visible) {
|
||||||
$remote_address = '-';
|
|
||||||
if (isset($editable_repos[$log->getRepositoryPHID()])) {
|
|
||||||
$remote_address = $log->getPushEvent()->getRemoteAddress();
|
$remote_address = $log->getPushEvent()->getRemoteAddress();
|
||||||
|
} else {
|
||||||
|
$remote_address = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$event_id = $log->getPushEvent()->getID();
|
$event_id = $log->getPushEvent()->getID();
|
||||||
|
@ -72,6 +62,23 @@ final class DiffusionPushLogListView extends AphrontView {
|
||||||
$device = null;
|
$device = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$flags = $log->getChangeFlags();
|
||||||
|
$flag_names = array();
|
||||||
|
foreach ($flag_map as $flag_key => $flag_name) {
|
||||||
|
if (($flags & $flag_key) === $flag_key) {
|
||||||
|
$flag_names[] = $flag_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$flag_names = phutil_implode_html(
|
||||||
|
phutil_tag('br'),
|
||||||
|
$flag_names);
|
||||||
|
|
||||||
|
$reject_code = $log->getPushEvent()->getRejectCode();
|
||||||
|
$reject_label = idx(
|
||||||
|
$reject_map,
|
||||||
|
$reject_code,
|
||||||
|
pht('Unknown ("%s")', $reject_code));
|
||||||
|
|
||||||
$rows[] = array(
|
$rows[] = array(
|
||||||
phutil_tag(
|
phutil_tag(
|
||||||
'a',
|
'a',
|
||||||
|
@ -98,10 +105,8 @@ final class DiffusionPushLogListView extends AphrontView {
|
||||||
'href' => $repository->getCommitURI($log->getRefNew()),
|
'href' => $repository->getCommitURI($log->getRefNew()),
|
||||||
),
|
),
|
||||||
$log->getRefNewShort()),
|
$log->getRefNewShort()),
|
||||||
|
$flag_names,
|
||||||
// TODO: Make these human-readable.
|
$reject_label,
|
||||||
$log->getChangeFlags(),
|
|
||||||
$log->getPushEvent()->getRejectCode(),
|
|
||||||
$viewer->formatShortDateTime($log->getEpoch()),
|
$viewer->formatShortDateTime($log->getEpoch()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -120,7 +125,7 @@ final class DiffusionPushLogListView extends AphrontView {
|
||||||
pht('Old'),
|
pht('Old'),
|
||||||
pht('New'),
|
pht('New'),
|
||||||
pht('Flags'),
|
pht('Flags'),
|
||||||
pht('Code'),
|
pht('Result'),
|
||||||
pht('Date'),
|
pht('Date'),
|
||||||
))
|
))
|
||||||
->setColumnClasses(
|
->setColumnClasses(
|
||||||
|
@ -135,6 +140,8 @@ final class DiffusionPushLogListView extends AphrontView {
|
||||||
'wide',
|
'wide',
|
||||||
'n',
|
'n',
|
||||||
'n',
|
'n',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
'right',
|
'right',
|
||||||
))
|
))
|
||||||
->setColumnVisibility(
|
->setColumnVisibility(
|
||||||
|
@ -142,7 +149,7 @@ final class DiffusionPushLogListView extends AphrontView {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
$remotes_visible,
|
||||||
true,
|
true,
|
||||||
$any_host,
|
$any_host,
|
||||||
));
|
));
|
||||||
|
|
|
@ -272,8 +272,12 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||||
$file->setByteSize($length);
|
$file->setByteSize($length);
|
||||||
|
|
||||||
// NOTE: Once we receive the first chunk, we'll detect its MIME type and
|
// NOTE: Once we receive the first chunk, we'll detect its MIME type and
|
||||||
// update the parent file. This matters for large media files like video.
|
// update the parent file if a MIME type hasn't been provided. This matters
|
||||||
$file->setMimeType('application/octet-stream');
|
// for large media files like video.
|
||||||
|
$mime_type = idx($params, 'mime-type');
|
||||||
|
if (!strlen($mime_type)) {
|
||||||
|
$file->setMimeType('application/octet-stream');
|
||||||
|
}
|
||||||
|
|
||||||
$chunked_hash = idx($params, 'chunkedHash');
|
$chunked_hash = idx($params, 'chunkedHash');
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ abstract class PhabricatorFileUploadSource
|
||||||
private $name;
|
private $name;
|
||||||
private $relativeTTL;
|
private $relativeTTL;
|
||||||
private $viewPolicy;
|
private $viewPolicy;
|
||||||
|
private $mimeType;
|
||||||
|
private $authorPHID;
|
||||||
|
|
||||||
private $rope;
|
private $rope;
|
||||||
private $data;
|
private $data;
|
||||||
|
@ -51,6 +53,24 @@ abstract class PhabricatorFileUploadSource
|
||||||
return $this->byteLimit;
|
return $this->byteLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setMIMEType($mime_type) {
|
||||||
|
$this->mimeType = $mime_type;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMIMEType() {
|
||||||
|
return $this->mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAuthorPHID($author_phid) {
|
||||||
|
$this->authorPHID = $author_phid;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorPHID() {
|
||||||
|
return $this->authorPHID;
|
||||||
|
}
|
||||||
|
|
||||||
public function uploadFile() {
|
public function uploadFile() {
|
||||||
if (!$this->shouldChunkFile()) {
|
if (!$this->shouldChunkFile()) {
|
||||||
return $this->writeSingleFile();
|
return $this->writeSingleFile();
|
||||||
|
@ -245,6 +265,16 @@ abstract class PhabricatorFileUploadSource
|
||||||
$parameters['ttl.relative'] = $ttl;
|
$parameters['ttl.relative'] = $ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$mime_type = $this->getMimeType();
|
||||||
|
if ($mime_type !== null) {
|
||||||
|
$parameters['mime-type'] = $mime_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
if ($author_phid !== null) {
|
||||||
|
$parameters['authorPHID'] = $author_phid;
|
||||||
|
}
|
||||||
|
|
||||||
return $parameters;
|
return $parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,14 +50,13 @@ final class PhabricatorManiphestApplication extends PhabricatorApplication {
|
||||||
return array(
|
return array(
|
||||||
'/T(?P<id>[1-9]\d*)' => 'ManiphestTaskDetailController',
|
'/T(?P<id>[1-9]\d*)' => 'ManiphestTaskDetailController',
|
||||||
'/maniphest/' => array(
|
'/maniphest/' => array(
|
||||||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'ManiphestTaskListController',
|
$this->getQueryRoutePattern() => 'ManiphestTaskListController',
|
||||||
'report/(?:(?P<view>\w+)/)?' => 'ManiphestReportController',
|
'report/(?:(?P<view>\w+)/)?' => 'ManiphestReportController',
|
||||||
$this->getBulkRoutePattern('bulk/') => 'ManiphestBulkEditController',
|
$this->getBulkRoutePattern('bulk/') => 'ManiphestBulkEditController',
|
||||||
'task/' => array(
|
'task/' => array(
|
||||||
$this->getEditRoutePattern('edit/')
|
$this->getEditRoutePattern('edit/')
|
||||||
=> 'ManiphestTaskEditController',
|
=> 'ManiphestTaskEditController',
|
||||||
),
|
),
|
||||||
'export/(?P<key>[^/]+)/' => 'ManiphestExportController',
|
|
||||||
'subpriority/' => 'ManiphestSubpriorityController',
|
'subpriority/' => 'ManiphestSubpriorityController',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,135 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class ManiphestExportController extends ManiphestController {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @phutil-external-symbol class PHPExcel
|
|
||||||
* @phutil-external-symbol class PHPExcel_IOFactory
|
|
||||||
* @phutil-external-symbol class PHPExcel_Style_NumberFormat
|
|
||||||
* @phutil-external-symbol class PHPExcel_Cell_DataType
|
|
||||||
*/
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
|
||||||
$viewer = $this->getViewer();
|
|
||||||
$key = $request->getURIData('key');
|
|
||||||
|
|
||||||
$ok = @include_once 'PHPExcel.php';
|
|
||||||
if (!$ok) {
|
|
||||||
$dialog = $this->newDialog();
|
|
||||||
|
|
||||||
$inst1 = pht(
|
|
||||||
'This system does not have PHPExcel installed. This software '.
|
|
||||||
'component is required to export tasks to Excel. Have your system '.
|
|
||||||
'administrator install it from:');
|
|
||||||
|
|
||||||
$inst2 = pht(
|
|
||||||
'Your PHP "%s" needs to be updated to include the '.
|
|
||||||
'PHPExcel Classes directory.',
|
|
||||||
'include_path');
|
|
||||||
|
|
||||||
$dialog->setTitle(pht('Excel Export Not Configured'));
|
|
||||||
$dialog->appendChild(hsprintf(
|
|
||||||
'<p>%s</p>'.
|
|
||||||
'<br />'.
|
|
||||||
'<p>'.
|
|
||||||
'<a href="https://github.com/PHPOffice/PHPExcel">'.
|
|
||||||
'https://github.com/PHPOffice/PHPExcel'.
|
|
||||||
'</a>'.
|
|
||||||
'</p>'.
|
|
||||||
'<br />'.
|
|
||||||
'<p>%s</p>',
|
|
||||||
$inst1,
|
|
||||||
$inst2));
|
|
||||||
|
|
||||||
$dialog->addCancelButton('/maniphest/');
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: PHPExcel has a dependency on the PHP zip extension. We should test
|
|
||||||
// for that here, since it fatals if we don't have the ZipArchive class.
|
|
||||||
|
|
||||||
$saved = id(new PhabricatorSavedQueryQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withQueryKeys(array($key))
|
|
||||||
->executeOne();
|
|
||||||
if (!$saved) {
|
|
||||||
$engine = id(new ManiphestTaskSearchEngine())
|
|
||||||
->setViewer($viewer);
|
|
||||||
if ($engine->isBuiltinQuery($key)) {
|
|
||||||
$saved = $engine->buildSavedQueryFromBuiltin($key);
|
|
||||||
}
|
|
||||||
if (!$saved) {
|
|
||||||
return new Aphront404Response();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$formats = ManiphestExcelFormat::loadAllFormats();
|
|
||||||
$export_formats = array();
|
|
||||||
foreach ($formats as $format_class => $format_object) {
|
|
||||||
$export_formats[$format_class] = $format_object->getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$request->isDialogFormPost()) {
|
|
||||||
$dialog = new AphrontDialogView();
|
|
||||||
$dialog->setUser($viewer);
|
|
||||||
|
|
||||||
$dialog->setTitle(pht('Export Tasks to Excel'));
|
|
||||||
$dialog->appendChild(
|
|
||||||
phutil_tag(
|
|
||||||
'p',
|
|
||||||
array(),
|
|
||||||
pht('Do you want to export the query results to Excel?')));
|
|
||||||
|
|
||||||
$form = id(new PHUIFormLayoutView())
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormSelectControl())
|
|
||||||
->setLabel(pht('Format:'))
|
|
||||||
->setName('excel-format')
|
|
||||||
->setOptions($export_formats));
|
|
||||||
|
|
||||||
$dialog->appendChild($form);
|
|
||||||
|
|
||||||
$dialog->addCancelButton('/maniphest/');
|
|
||||||
$dialog->addSubmitButton(pht('Export to Excel'));
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
$format = idx($formats, $request->getStr('excel-format'));
|
|
||||||
if ($format === null) {
|
|
||||||
throw new Exception(pht('Excel format object not found.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$saved->makeEphemeral();
|
|
||||||
$saved->setParameter('limit', PHP_INT_MAX);
|
|
||||||
|
|
||||||
$engine = id(new ManiphestTaskSearchEngine())
|
|
||||||
->setViewer($viewer);
|
|
||||||
|
|
||||||
$query = $engine->buildQueryFromSavedQuery($saved);
|
|
||||||
$query->setViewer($viewer);
|
|
||||||
$tasks = $query->execute();
|
|
||||||
|
|
||||||
$all_projects = array_mergev(mpull($tasks, 'getProjectPHIDs'));
|
|
||||||
$all_assigned = mpull($tasks, 'getOwnerPHID');
|
|
||||||
|
|
||||||
$handles = id(new PhabricatorHandleQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withPHIDs(array_merge($all_projects, $all_assigned))
|
|
||||||
->execute();
|
|
||||||
|
|
||||||
$workbook = new PHPExcel();
|
|
||||||
$format->buildWorkbook($workbook, $tasks, $handles, $viewer);
|
|
||||||
$writer = PHPExcel_IOFactory::createWriter($workbook, 'Excel2007');
|
|
||||||
|
|
||||||
ob_start();
|
|
||||||
$writer->save('php://output');
|
|
||||||
$data = ob_get_clean();
|
|
||||||
|
|
||||||
$mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
||||||
|
|
||||||
return id(new AphrontFileResponse())
|
|
||||||
->setMimeType($mime)
|
|
||||||
->setDownload($format->getFileName().'.xlsx')
|
|
||||||
->setContent($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -196,6 +196,7 @@ EODOCS
|
||||||
pht('New task owner, or `null` to unassign.'))
|
pht('New task owner, or `null` to unassign.'))
|
||||||
->setTransactionType(ManiphestTaskOwnerTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskOwnerTransaction::TRANSACTIONTYPE)
|
||||||
->setIsCopyable(true)
|
->setIsCopyable(true)
|
||||||
|
->setIsNullable(true)
|
||||||
->setSingleValue($object->getOwnerPHID())
|
->setSingleValue($object->getOwnerPHID())
|
||||||
->setCommentActionLabel(pht('Assign / Claim'))
|
->setCommentActionLabel(pht('Assign / Claim'))
|
||||||
->setCommentActionValue($owner_value),
|
->setCommentActionValue($owner_value),
|
||||||
|
|
|
@ -1,140 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class ManiphestExcelDefaultFormat extends ManiphestExcelFormat {
|
|
||||||
|
|
||||||
public function getName() {
|
|
||||||
return pht('Default');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFileName() {
|
|
||||||
return 'maniphest_tasks_'.date('Ymd');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @phutil-external-symbol class PHPExcel
|
|
||||||
* @phutil-external-symbol class PHPExcel_IOFactory
|
|
||||||
* @phutil-external-symbol class PHPExcel_Style_NumberFormat
|
|
||||||
* @phutil-external-symbol class PHPExcel_Cell_DataType
|
|
||||||
*/
|
|
||||||
public function buildWorkbook(
|
|
||||||
PHPExcel $workbook,
|
|
||||||
array $tasks,
|
|
||||||
array $handles,
|
|
||||||
PhabricatorUser $user) {
|
|
||||||
|
|
||||||
$sheet = $workbook->setActiveSheetIndex(0);
|
|
||||||
$sheet->setTitle(pht('Tasks'));
|
|
||||||
|
|
||||||
$widths = array(
|
|
||||||
null,
|
|
||||||
15,
|
|
||||||
null,
|
|
||||||
10,
|
|
||||||
15,
|
|
||||||
15,
|
|
||||||
60,
|
|
||||||
30,
|
|
||||||
20,
|
|
||||||
100,
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($widths as $col => $width) {
|
|
||||||
if ($width !== null) {
|
|
||||||
$sheet->getColumnDimension($this->col($col))->setWidth($width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$status_map = ManiphestTaskStatus::getTaskStatusMap();
|
|
||||||
$pri_map = ManiphestTaskPriority::getTaskPriorityMap();
|
|
||||||
|
|
||||||
$date_format = null;
|
|
||||||
|
|
||||||
$rows = array();
|
|
||||||
$rows[] = array(
|
|
||||||
pht('ID'),
|
|
||||||
pht('Owner'),
|
|
||||||
pht('Status'),
|
|
||||||
pht('Priority'),
|
|
||||||
pht('Date Created'),
|
|
||||||
pht('Date Updated'),
|
|
||||||
pht('Title'),
|
|
||||||
pht('Tags'),
|
|
||||||
pht('URI'),
|
|
||||||
pht('Description'),
|
|
||||||
);
|
|
||||||
|
|
||||||
$is_date = array(
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
$header_format = array(
|
|
||||||
'font' => array(
|
|
||||||
'bold' => true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($tasks as $task) {
|
|
||||||
$task_owner = null;
|
|
||||||
if ($task->getOwnerPHID()) {
|
|
||||||
$task_owner = $handles[$task->getOwnerPHID()]->getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
$projects = array();
|
|
||||||
foreach ($task->getProjectPHIDs() as $phid) {
|
|
||||||
$projects[] = $handles[$phid]->getName();
|
|
||||||
}
|
|
||||||
$projects = implode(', ', $projects);
|
|
||||||
|
|
||||||
$rows[] = array(
|
|
||||||
'T'.$task->getID(),
|
|
||||||
$task_owner,
|
|
||||||
idx($status_map, $task->getStatus(), '?'),
|
|
||||||
idx($pri_map, $task->getPriority(), '?'),
|
|
||||||
$this->computeExcelDate($task->getDateCreated()),
|
|
||||||
$this->computeExcelDate($task->getDateModified()),
|
|
||||||
$task->getTitle(),
|
|
||||||
$projects,
|
|
||||||
PhabricatorEnv::getProductionURI('/T'.$task->getID()),
|
|
||||||
id(new PhutilUTF8StringTruncator())
|
|
||||||
->setMaximumBytes(512)
|
|
||||||
->truncateString($task->getDescription()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($rows as $row => $cols) {
|
|
||||||
foreach ($cols as $col => $spec) {
|
|
||||||
$cell_name = $this->col($col).($row + 1);
|
|
||||||
$cell = $sheet
|
|
||||||
->setCellValue($cell_name, $spec, $return_cell = true);
|
|
||||||
|
|
||||||
if ($row == 0) {
|
|
||||||
$sheet->getStyle($cell_name)->applyFromArray($header_format);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($is_date[$col]) {
|
|
||||||
$code = PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2;
|
|
||||||
$sheet
|
|
||||||
->getStyle($cell_name)
|
|
||||||
->getNumberFormat()
|
|
||||||
->setFormatCode($code);
|
|
||||||
} else {
|
|
||||||
$cell->setDataType(PHPExcel_Cell_DataType::TYPE_STRING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function col($n) {
|
|
||||||
return chr(ord('A') + $n);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
abstract class ManiphestExcelFormat extends Phobject {
|
|
||||||
|
|
||||||
final public static function loadAllFormats() {
|
|
||||||
return id(new PhutilClassMapQuery())
|
|
||||||
->setAncestorClass(__CLASS__)
|
|
||||||
->setSortMethod('getOrder')
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract public function getName();
|
|
||||||
abstract public function getFileName();
|
|
||||||
|
|
||||||
public function getOrder() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function computeExcelDate($epoch) {
|
|
||||||
$seconds_per_day = (60 * 60 * 24);
|
|
||||||
$offset = ($seconds_per_day * 25569);
|
|
||||||
|
|
||||||
return ($epoch + $offset) / $seconds_per_day;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @phutil-external-symbol class PHPExcel
|
|
||||||
*/
|
|
||||||
abstract public function buildWorkbook(
|
|
||||||
PHPExcel $workbook,
|
|
||||||
array $tasks,
|
|
||||||
array $handles,
|
|
||||||
PhabricatorUser $user);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class ManiphestExcelFormatTestCase extends PhabricatorTestCase {
|
|
||||||
|
|
||||||
public function testLoadAllFormats() {
|
|
||||||
ManiphestExcelFormat::loadAllFormats();
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -432,4 +432,111 @@ final class ManiphestTaskSearchEngine
|
||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function newExportFields() {
|
||||||
|
$fields = array(
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('monogram')
|
||||||
|
->setLabel(pht('Monogram')),
|
||||||
|
id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('authorPHID')
|
||||||
|
->setLabel(pht('Author PHID')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('author')
|
||||||
|
->setLabel(pht('Author')),
|
||||||
|
id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('ownerPHID')
|
||||||
|
->setLabel(pht('Owner PHID')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('owner')
|
||||||
|
->setLabel(pht('Owner')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('status')
|
||||||
|
->setLabel(pht('Status')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('statusName')
|
||||||
|
->setLabel(pht('Status Name')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('priority')
|
||||||
|
->setLabel(pht('Priority')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('priorityName')
|
||||||
|
->setLabel(pht('Priority Name')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('subtype')
|
||||||
|
->setLabel('Subtype'),
|
||||||
|
id(new PhabricatorURIExportField())
|
||||||
|
->setKey('uri')
|
||||||
|
->setLabel(pht('URI')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('title')
|
||||||
|
->setLabel(pht('Title')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('description')
|
||||||
|
->setLabel(pht('Description')),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ManiphestTaskPoints::getIsEnabled()) {
|
||||||
|
$fields[] = id(new PhabricatorIntExportField())
|
||||||
|
->setKey('points')
|
||||||
|
->setLabel('Points');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newExportData(array $tasks) {
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$phids = array();
|
||||||
|
foreach ($tasks as $task) {
|
||||||
|
$phids[] = $task->getAuthorPHID();
|
||||||
|
$phids[] = $task->getOwnerPHID();
|
||||||
|
}
|
||||||
|
$handles = $viewer->loadHandles($phids);
|
||||||
|
|
||||||
|
$export = array();
|
||||||
|
foreach ($tasks as $task) {
|
||||||
|
|
||||||
|
$author_phid = $task->getAuthorPHID();
|
||||||
|
if ($author_phid) {
|
||||||
|
$author_name = $handles[$author_phid]->getName();
|
||||||
|
} else {
|
||||||
|
$author_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$owner_phid = $task->getOwnerPHID();
|
||||||
|
if ($owner_phid) {
|
||||||
|
$owner_name = $handles[$owner_phid]->getName();
|
||||||
|
} else {
|
||||||
|
$owner_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$status_value = $task->getStatus();
|
||||||
|
$status_name = ManiphestTaskStatus::getTaskStatusName($status_value);
|
||||||
|
|
||||||
|
$priority_value = $task->getPriority();
|
||||||
|
$priority_name = ManiphestTaskPriority::getTaskPriorityName(
|
||||||
|
$priority_value);
|
||||||
|
|
||||||
|
$export[] = array(
|
||||||
|
'monogram' => $task->getMonogram(),
|
||||||
|
'authorPHID' => $author_phid,
|
||||||
|
'author' => $author_name,
|
||||||
|
'ownerPHID' => $owner_phid,
|
||||||
|
'owner' => $owner_name,
|
||||||
|
'status' => $status_value,
|
||||||
|
'statusName' => $status_name,
|
||||||
|
'priority' => $priority_value,
|
||||||
|
'priorityName' => $priority_name,
|
||||||
|
'points' => $task->getPoints(),
|
||||||
|
'subtype' => $task->getSubtype(),
|
||||||
|
'title' => $task->getTitle(),
|
||||||
|
'uri' => PhabricatorEnv::getProductionURI($task->getURI()),
|
||||||
|
'description' => $task->getDescription(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $export;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,8 +175,7 @@ final class ManiphestTaskResultListView extends ManiphestView {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$user->isLoggedIn()) {
|
if (!$user->isLoggedIn()) {
|
||||||
// Don't show the batch editor or excel export for logged-out users.
|
// Don't show the batch editor for logged-out users.
|
||||||
// Technically we //could// let them export, but ehh.
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,14 +219,6 @@ final class ManiphestTaskResultListView extends ManiphestView {
|
||||||
),
|
),
|
||||||
pht("Bulk Edit Selected \xC2\xBB"));
|
pht("Bulk Edit Selected \xC2\xBB"));
|
||||||
|
|
||||||
$export = javelin_tag(
|
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'href' => '/maniphest/export/'.$saved_query->getQueryKey().'/',
|
|
||||||
'class' => 'button button-grey',
|
|
||||||
),
|
|
||||||
pht('Export to Excel'));
|
|
||||||
|
|
||||||
$hidden = phutil_tag(
|
$hidden = phutil_tag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
|
@ -239,14 +230,12 @@ final class ManiphestTaskResultListView extends ManiphestView {
|
||||||
'<table class="maniphest-batch-editor-layout">'.
|
'<table class="maniphest-batch-editor-layout">'.
|
||||||
'<tr>'.
|
'<tr>'.
|
||||||
'<td>%s%s</td>'.
|
'<td>%s%s</td>'.
|
||||||
'<td>%s</td>'.
|
|
||||||
'<td id="batch-select-status-cell">%s</td>'.
|
'<td id="batch-select-status-cell">%s</td>'.
|
||||||
'<td class="batch-select-submit-cell">%s%s</td>'.
|
'<td class="batch-select-submit-cell">%s%s</td>'.
|
||||||
'</tr>'.
|
'</tr>'.
|
||||||
'</table>',
|
'</table>',
|
||||||
$select_all,
|
$select_all,
|
||||||
$select_none,
|
$select_none,
|
||||||
$export,
|
|
||||||
'',
|
'',
|
||||||
$submit,
|
$submit,
|
||||||
$hidden);
|
$hidden);
|
||||||
|
|
|
@ -42,8 +42,9 @@ final class PhabricatorPeopleApplication extends PhabricatorApplication {
|
||||||
return array(
|
return array(
|
||||||
'/people/' => array(
|
'/people/' => array(
|
||||||
$this->getQueryRoutePattern() => 'PhabricatorPeopleListController',
|
$this->getQueryRoutePattern() => 'PhabricatorPeopleListController',
|
||||||
'logs/(?:query/(?P<queryKey>[^/]+)/)?'
|
'logs/' => array(
|
||||||
=> 'PhabricatorPeopleLogsController',
|
$this->getQueryRoutePattern() => 'PhabricatorPeopleLogsController',
|
||||||
|
),
|
||||||
'invite/' => array(
|
'invite/' => array(
|
||||||
'(?:query/(?P<queryKey>[^/]+)/)?'
|
'(?:query/(?P<queryKey>[^/]+)/)?'
|
||||||
=> 'PhabricatorPeopleInviteListController',
|
=> 'PhabricatorPeopleInviteListController',
|
||||||
|
|
|
@ -9,6 +9,8 @@ final class PhabricatorPeopleLogQuery
|
||||||
private $sessionKeys;
|
private $sessionKeys;
|
||||||
private $actions;
|
private $actions;
|
||||||
private $remoteAddressPrefix;
|
private $remoteAddressPrefix;
|
||||||
|
private $dateCreatedMin;
|
||||||
|
private $dateCreatedMax;
|
||||||
|
|
||||||
public function withActorPHIDs(array $actor_phids) {
|
public function withActorPHIDs(array $actor_phids) {
|
||||||
$this->actorPHIDs = $actor_phids;
|
$this->actorPHIDs = $actor_phids;
|
||||||
|
@ -40,70 +42,81 @@ final class PhabricatorPeopleLogQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
public function withDateCreatedBetween($min, $max) {
|
||||||
$table = new PhabricatorUserLog();
|
$this->dateCreatedMin = $min;
|
||||||
$conn_r = $table->establishConnection('r');
|
$this->dateCreatedMax = $max;
|
||||||
|
return $this;
|
||||||
$data = queryfx_all(
|
|
||||||
$conn_r,
|
|
||||||
'SELECT * FROM %T %Q %Q %Q',
|
|
||||||
$table->getTableName(),
|
|
||||||
$this->buildWhereClause($conn_r),
|
|
||||||
$this->buildOrderClause($conn_r),
|
|
||||||
$this->buildLimitClause($conn_r));
|
|
||||||
|
|
||||||
return $table->loadAllFromArray($data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
public function newResultObject() {
|
||||||
$where = array();
|
return new PhabricatorUserLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadPage() {
|
||||||
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
if ($this->actorPHIDs !== null) {
|
if ($this->actorPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'actorPHID IN (%Ls)',
|
'actorPHID IN (%Ls)',
|
||||||
$this->actorPHIDs);
|
$this->actorPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->userPHIDs !== null) {
|
if ($this->userPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'userPHID IN (%Ls)',
|
'userPHID IN (%Ls)',
|
||||||
$this->userPHIDs);
|
$this->userPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->relatedPHIDs !== null) {
|
if ($this->relatedPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'actorPHID IN (%Ls) OR userPHID IN (%Ls)',
|
'(actorPHID IN (%Ls) OR userPHID IN (%Ls))',
|
||||||
$this->relatedPHIDs,
|
$this->relatedPHIDs,
|
||||||
$this->relatedPHIDs);
|
$this->relatedPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->sessionKeys !== null) {
|
if ($this->sessionKeys !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'session IN (%Ls)',
|
'session IN (%Ls)',
|
||||||
$this->sessionKeys);
|
$this->sessionKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->actions !== null) {
|
if ($this->actions !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'action IN (%Ls)',
|
'action IN (%Ls)',
|
||||||
$this->actions);
|
$this->actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->remoteAddressPrefix !== null) {
|
if ($this->remoteAddressPrefix !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'remoteAddr LIKE %>',
|
'remoteAddr LIKE %>',
|
||||||
$this->remoteAddressPrefix);
|
$this->remoteAddressPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
if ($this->dateCreatedMin !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'dateCreated >= %d',
|
||||||
|
$this->dateCreatedMin);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
if ($this->dateCreatedMax !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'dateCreated <= %d',
|
||||||
|
$this->dateCreatedMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryApplicationClass() {
|
public function getQueryApplicationClass() {
|
||||||
|
|
|
@ -15,34 +15,8 @@ final class PhabricatorPeopleLogSearchEngine
|
||||||
return 500;
|
return 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
public function newQuery() {
|
||||||
$saved = new PhabricatorSavedQuery();
|
$query = new PhabricatorPeopleLogQuery();
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'userPHIDs',
|
|
||||||
$this->readUsersFromRequest($request, 'users'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'actorPHIDs',
|
|
||||||
$this->readUsersFromRequest($request, 'actors'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'actions',
|
|
||||||
$this->readListFromRequest($request, 'actions'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'ip',
|
|
||||||
$request->getStr('ip'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'sessions',
|
|
||||||
$this->readListFromRequest($request, 'sessions'));
|
|
||||||
|
|
||||||
return $saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
|
||||||
$query = id(new PhabricatorPeopleLogQuery());
|
|
||||||
|
|
||||||
// NOTE: If the viewer isn't an administrator, always restrict the query to
|
// NOTE: If the viewer isn't an administrator, always restrict the query to
|
||||||
// related records. This echoes the policy logic of these logs. This is
|
// related records. This echoes the policy logic of these logs. This is
|
||||||
|
@ -54,82 +28,73 @@ final class PhabricatorPeopleLogSearchEngine
|
||||||
$query->withRelatedPHIDs(array($viewer->getPHID()));
|
$query->withRelatedPHIDs(array($viewer->getPHID()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$actor_phids = $saved->getParameter('actorPHIDs', array());
|
return $query;
|
||||||
if ($actor_phids) {
|
}
|
||||||
$query->withActorPHIDs($actor_phids);
|
|
||||||
|
protected function buildQueryFromParameters(array $map) {
|
||||||
|
$query = $this->newQuery();
|
||||||
|
|
||||||
|
if ($map['userPHIDs']) {
|
||||||
|
$query->withUserPHIDs($map['userPHIDs']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user_phids = $saved->getParameter('userPHIDs', array());
|
if ($map['actorPHIDs']) {
|
||||||
if ($user_phids) {
|
$query->withActorPHIDs($map['actorPHIDs']);
|
||||||
$query->withUserPHIDs($user_phids);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$actions = $saved->getParameter('actions', array());
|
if ($map['actions']) {
|
||||||
if ($actions) {
|
$query->withActions($map['actions']);
|
||||||
$query->withActions($actions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$remote_prefix = $saved->getParameter('ip');
|
if (strlen($map['ip'])) {
|
||||||
if (strlen($remote_prefix)) {
|
$query->withRemoteAddressPrefix($map['ip']);
|
||||||
$query->withRemoteAddressprefix($remote_prefix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$sessions = $saved->getParameter('sessions', array());
|
if ($map['sessions']) {
|
||||||
if ($sessions) {
|
$query->withSessionKeys($map['sessions']);
|
||||||
$query->withSessionKeys($sessions);
|
}
|
||||||
|
|
||||||
|
if ($map['createdStart'] || $map['createdEnd']) {
|
||||||
|
$query->withDateCreatedBetween(
|
||||||
|
$map['createdStart'],
|
||||||
|
$map['createdEnd']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSearchForm(
|
protected function buildCustomSearchFields() {
|
||||||
AphrontFormView $form,
|
return array(
|
||||||
PhabricatorSavedQuery $saved) {
|
id(new PhabricatorUsersSearchField())
|
||||||
|
->setKey('userPHIDs')
|
||||||
$actor_phids = $saved->getParameter('actorPHIDs', array());
|
->setAliases(array('users', 'user', 'userPHID'))
|
||||||
$user_phids = $saved->getParameter('userPHIDs', array());
|
->setLabel(pht('Users'))
|
||||||
|
->setDescription(pht('Search for activity affecting specific users.')),
|
||||||
$actions = $saved->getParameter('actions', array());
|
id(new PhabricatorUsersSearchField())
|
||||||
$remote_prefix = $saved->getParameter('ip');
|
->setKey('actorPHIDs')
|
||||||
$sessions = $saved->getParameter('sessions', array());
|
->setAliases(array('actors', 'actor', 'actorPHID'))
|
||||||
|
->setLabel(pht('Actors'))
|
||||||
$actions = array_fuse($actions);
|
->setDescription(pht('Search for activity by specific users.')),
|
||||||
$action_control = id(new AphrontFormCheckboxControl())
|
id(new PhabricatorSearchCheckboxesField())
|
||||||
->setLabel(pht('Actions'));
|
->setKey('actions')
|
||||||
$action_types = PhabricatorUserLog::getActionTypeMap();
|
->setLabel(pht('Actions'))
|
||||||
foreach ($action_types as $type => $label) {
|
->setDescription(pht('Search for particular types of activity.'))
|
||||||
$action_control->addCheckbox(
|
->setOptions(PhabricatorUserLog::getActionTypeMap()),
|
||||||
'actions[]',
|
id(new PhabricatorSearchTextField())
|
||||||
$type,
|
->setKey('ip')
|
||||||
$label,
|
->setLabel(pht('Filter IP'))
|
||||||
isset($actions[$label]));
|
->setDescription(pht('Search for actions by remote address.')),
|
||||||
}
|
id(new PhabricatorSearchStringListField())
|
||||||
|
->setKey('sessions')
|
||||||
$form
|
->setLabel(pht('Sessions'))
|
||||||
->appendControl(
|
->setDescription(pht('Search for activity in particular sessions.')),
|
||||||
id(new AphrontFormTokenizerControl())
|
id(new PhabricatorSearchDateField())
|
||||||
->setDatasource(new PhabricatorPeopleDatasource())
|
->setLabel(pht('Created After'))
|
||||||
->setName('actors')
|
->setKey('createdStart'),
|
||||||
->setLabel(pht('Actors'))
|
id(new PhabricatorSearchDateField())
|
||||||
->setValue($actor_phids))
|
->setLabel(pht('Created Before'))
|
||||||
->appendControl(
|
->setKey('createdEnd'),
|
||||||
id(new AphrontFormTokenizerControl())
|
);
|
||||||
->setDatasource(new PhabricatorPeopleDatasource())
|
|
||||||
->setName('users')
|
|
||||||
->setLabel(pht('Users'))
|
|
||||||
->setValue($user_phids))
|
|
||||||
->appendChild($action_control)
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormTextControl())
|
|
||||||
->setLabel(pht('Filter IP'))
|
|
||||||
->setName('ip')
|
|
||||||
->setValue($remote_prefix))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormTextControl())
|
|
||||||
->setLabel(pht('Sessions'))
|
|
||||||
->setName('sessions')
|
|
||||||
->setValue(implode(', ', $sessions)));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getURI($path) {
|
protected function getURI($path) {
|
||||||
|
@ -156,19 +121,6 @@ final class PhabricatorPeopleLogSearchEngine
|
||||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getRequiredHandlePHIDsForResultList(
|
|
||||||
array $logs,
|
|
||||||
PhabricatorSavedQuery $query) {
|
|
||||||
|
|
||||||
$phids = array();
|
|
||||||
foreach ($logs as $log) {
|
|
||||||
$phids[$log->getActorPHID()] = true;
|
|
||||||
$phids[$log->getUserPHID()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_keys($phids);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function renderResultList(
|
protected function renderResultList(
|
||||||
array $logs,
|
array $logs,
|
||||||
PhabricatorSavedQuery $query,
|
PhabricatorSavedQuery $query,
|
||||||
|
@ -179,16 +131,111 @@ final class PhabricatorPeopleLogSearchEngine
|
||||||
|
|
||||||
$table = id(new PhabricatorUserLogView())
|
$table = id(new PhabricatorUserLogView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setLogs($logs)
|
->setLogs($logs);
|
||||||
->setHandles($handles);
|
|
||||||
|
|
||||||
if ($viewer->getIsAdmin()) {
|
if ($viewer->getIsAdmin()) {
|
||||||
$table->setSearchBaseURI($this->getApplicationURI('logs/'));
|
$table->setSearchBaseURI($this->getApplicationURI('logs/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = new PhabricatorApplicationSearchResultView();
|
return id(new PhabricatorApplicationSearchResultView())
|
||||||
$result->setTable($table);
|
->setTable($table);
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newExportFields() {
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$fields = array(
|
||||||
|
$fields[] = id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('actorPHID')
|
||||||
|
->setLabel(pht('Actor PHID')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('actor')
|
||||||
|
->setLabel(pht('Actor')),
|
||||||
|
$fields[] = id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('userPHID')
|
||||||
|
->setLabel(pht('User PHID')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('user')
|
||||||
|
->setLabel(pht('User')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('action')
|
||||||
|
->setLabel(pht('Action')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('actionName')
|
||||||
|
->setLabel(pht('Action Name')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('session')
|
||||||
|
->setLabel(pht('Session')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('old')
|
||||||
|
->setLabel(pht('Old Value')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('new')
|
||||||
|
->setLabel(pht('New Value')),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($viewer->getIsAdmin()) {
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('remoteAddress')
|
||||||
|
->setLabel(pht('Remote Address'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newExportData(array $logs) {
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
|
||||||
|
$phids = array();
|
||||||
|
foreach ($logs as $log) {
|
||||||
|
$phids[] = $log->getUserPHID();
|
||||||
|
$phids[] = $log->getActorPHID();
|
||||||
|
}
|
||||||
|
$handles = $viewer->loadHandles($phids);
|
||||||
|
|
||||||
|
$action_map = PhabricatorUserLog::getActionTypeMap();
|
||||||
|
|
||||||
|
$export = array();
|
||||||
|
foreach ($logs as $log) {
|
||||||
|
|
||||||
|
$user_phid = $log->getUserPHID();
|
||||||
|
if ($user_phid) {
|
||||||
|
$user_name = $handles[$user_phid]->getName();
|
||||||
|
} else {
|
||||||
|
$user_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$actor_phid = $log->getActorPHID();
|
||||||
|
if ($actor_phid) {
|
||||||
|
$actor_name = $handles[$actor_phid]->getName();
|
||||||
|
} else {
|
||||||
|
$actor_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$action = $log->getAction();
|
||||||
|
$action_name = idx($action_map, $action, pht('Unknown ("%s")', $action));
|
||||||
|
|
||||||
|
$map = array(
|
||||||
|
'actorPHID' => $actor_phid,
|
||||||
|
'actor' => $actor_name,
|
||||||
|
'userPHID' => $user_phid,
|
||||||
|
'user' => $user_name,
|
||||||
|
'action' => $action,
|
||||||
|
'actionName' => $action_name,
|
||||||
|
'session' => substr($log->getSession(), 0, 6),
|
||||||
|
'old' => $log->getOldValue(),
|
||||||
|
'new' => $log->getNewValue(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($viewer->getIsAdmin()) {
|
||||||
|
$map['remoteAddress'] = $log->getRemoteAddr();
|
||||||
|
}
|
||||||
|
|
||||||
|
$export[] = $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $export;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -322,35 +322,23 @@ final class PhabricatorPeopleSearchEngine
|
||||||
|
|
||||||
protected function newExportFields() {
|
protected function newExportFields() {
|
||||||
return array(
|
return array(
|
||||||
id(new PhabricatorIDExportField())
|
|
||||||
->setKey('id')
|
|
||||||
->setLabel(pht('ID')),
|
|
||||||
id(new PhabricatorPHIDExportField())
|
|
||||||
->setKey('phid')
|
|
||||||
->setLabel(pht('PHID')),
|
|
||||||
id(new PhabricatorStringExportField())
|
id(new PhabricatorStringExportField())
|
||||||
->setKey('username')
|
->setKey('username')
|
||||||
->setLabel(pht('Username')),
|
->setLabel(pht('Username')),
|
||||||
id(new PhabricatorStringExportField())
|
id(new PhabricatorStringExportField())
|
||||||
->setKey('realName')
|
->setKey('realName')
|
||||||
->setLabel(pht('Real Name')),
|
->setLabel(pht('Real Name')),
|
||||||
id(new PhabricatorEpochExportField())
|
|
||||||
->setKey('created')
|
|
||||||
->setLabel(pht('Date Created')),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newExport(array $users) {
|
protected function newExportData(array $users) {
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
$export = array();
|
$export = array();
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
$export[] = array(
|
$export[] = array(
|
||||||
'id' => $user->getID(),
|
|
||||||
'phid' => $user->getPHID(),
|
|
||||||
'username' => $user->getUsername(),
|
'username' => $user->getUsername(),
|
||||||
'realName' => $user->getRealName(),
|
'realName' => $user->getRealName(),
|
||||||
'created' => $user->getDateCreated(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
final class PhabricatorUserLogView extends AphrontView {
|
final class PhabricatorUserLogView extends AphrontView {
|
||||||
|
|
||||||
private $logs;
|
private $logs;
|
||||||
private $handles;
|
|
||||||
private $searchBaseURI;
|
private $searchBaseURI;
|
||||||
|
|
||||||
public function setSearchBaseURI($search_base_uri) {
|
public function setSearchBaseURI($search_base_uri) {
|
||||||
|
@ -17,45 +16,79 @@ final class PhabricatorUserLogView extends AphrontView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setHandles(array $handles) {
|
|
||||||
assert_instances_of($handles, 'PhabricatorObjectHandle');
|
|
||||||
$this->handles = $handles;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
$logs = $this->logs;
|
$logs = $this->logs;
|
||||||
$handles = $this->handles;
|
|
||||||
$viewer = $this->getUser();
|
$viewer = $this->getUser();
|
||||||
|
|
||||||
|
$phids = array();
|
||||||
|
foreach ($logs as $log) {
|
||||||
|
$phids[] = $log->getActorPHID();
|
||||||
|
$phids[] = $log->getUserPHID();
|
||||||
|
}
|
||||||
|
$handles = $viewer->loadHandles($phids);
|
||||||
|
|
||||||
$action_map = PhabricatorUserLog::getActionTypeMap();
|
$action_map = PhabricatorUserLog::getActionTypeMap();
|
||||||
$base_uri = $this->searchBaseURI;
|
$base_uri = $this->searchBaseURI;
|
||||||
|
|
||||||
|
$viewer_phid = $viewer->getPHID();
|
||||||
|
|
||||||
$rows = array();
|
$rows = array();
|
||||||
foreach ($logs as $log) {
|
foreach ($logs as $log) {
|
||||||
$ip = $log->getRemoteAddr();
|
|
||||||
$session = substr($log->getSession(), 0, 6);
|
$session = substr($log->getSession(), 0, 6);
|
||||||
|
|
||||||
if ($base_uri) {
|
$actor_phid = $log->getActorPHID();
|
||||||
$ip = phutil_tag(
|
$user_phid = $log->getUserPHID();
|
||||||
'a',
|
|
||||||
array(
|
if ($viewer->getIsAdmin()) {
|
||||||
'href' => $base_uri.'?ip='.$ip.'#R',
|
$can_see_ip = true;
|
||||||
),
|
} else if ($viewer_phid == $actor_phid) {
|
||||||
$ip);
|
// You can see the address if you took the action.
|
||||||
|
$can_see_ip = true;
|
||||||
|
} else if (!$actor_phid && ($viewer_phid == $user_phid)) {
|
||||||
|
// You can see the address if it wasn't authenticated and applied
|
||||||
|
// to you (partial login).
|
||||||
|
$can_see_ip = true;
|
||||||
|
} else {
|
||||||
|
// You can't see the address when an administrator disables your
|
||||||
|
// account, since it's their address.
|
||||||
|
$can_see_ip = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($can_see_ip) {
|
||||||
|
$ip = $log->getRemoteAddr();
|
||||||
|
if ($base_uri) {
|
||||||
|
$ip = phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => $base_uri.'?ip='.$ip.'#R',
|
||||||
|
),
|
||||||
|
$ip);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$ip = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$action = $log->getAction();
|
$action = $log->getAction();
|
||||||
$action_name = idx($action_map, $action, $action);
|
$action_name = idx($action_map, $action, $action);
|
||||||
|
|
||||||
|
if ($actor_phid) {
|
||||||
|
$actor_name = $handles[$actor_phid]->renderLink();
|
||||||
|
} else {
|
||||||
|
$actor_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user_phid) {
|
||||||
|
$user_name = $handles[$user_phid]->renderLink();
|
||||||
|
} else {
|
||||||
|
$user_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
$rows[] = array(
|
$rows[] = array(
|
||||||
phabricator_date($log->getDateCreated(), $viewer),
|
phabricator_date($log->getDateCreated(), $viewer),
|
||||||
phabricator_time($log->getDateCreated(), $viewer),
|
phabricator_time($log->getDateCreated(), $viewer),
|
||||||
$action_name,
|
$action_name,
|
||||||
$log->getActorPHID()
|
$actor_name,
|
||||||
? $handles[$log->getActorPHID()]->getName()
|
$user_name,
|
||||||
: null,
|
|
||||||
$username = $handles[$log->getUserPHID()]->renderLink(),
|
|
||||||
$ip,
|
$ip,
|
||||||
$session,
|
$session,
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,6 +7,8 @@ final class PhabricatorRepositoryPullEventQuery
|
||||||
private $phids;
|
private $phids;
|
||||||
private $repositoryPHIDs;
|
private $repositoryPHIDs;
|
||||||
private $pullerPHIDs;
|
private $pullerPHIDs;
|
||||||
|
private $epochMin;
|
||||||
|
private $epochMax;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
|
@ -28,6 +30,12 @@ final class PhabricatorRepositoryPullEventQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withEpochBetween($min, $max) {
|
||||||
|
$this->epochMin = $min;
|
||||||
|
$this->epochMax = $max;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newResultObject() {
|
||||||
return new PhabricatorRepositoryPullEvent();
|
return new PhabricatorRepositoryPullEvent();
|
||||||
}
|
}
|
||||||
|
@ -103,6 +111,20 @@ final class PhabricatorRepositoryPullEventQuery
|
||||||
$this->pullerPHIDs);
|
$this->pullerPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->epochMin !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'epoch >= %d',
|
||||||
|
$this->epochMin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->epochMax !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'epoch <= %d',
|
||||||
|
$this->epochMax);
|
||||||
|
}
|
||||||
|
|
||||||
return $where;
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ final class PhabricatorRepositoryPushLogQuery
|
||||||
private $refTypes;
|
private $refTypes;
|
||||||
private $newRefs;
|
private $newRefs;
|
||||||
private $pushEventPHIDs;
|
private $pushEventPHIDs;
|
||||||
|
private $epochMin;
|
||||||
|
private $epochMax;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
|
@ -46,19 +48,18 @@ final class PhabricatorRepositoryPushLogQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withEpochBetween($min, $max) {
|
||||||
|
$this->epochMin = $min;
|
||||||
|
$this->epochMax = $max;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhabricatorRepositoryPushLog();
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new PhabricatorRepositoryPushLog();
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
$conn_r = $table->establishConnection('r');
|
|
||||||
|
|
||||||
$data = queryfx_all(
|
|
||||||
$conn_r,
|
|
||||||
'SELECT * FROM %T %Q %Q %Q',
|
|
||||||
$table->getTableName(),
|
|
||||||
$this->buildWhereClause($conn_r),
|
|
||||||
$this->buildOrderClause($conn_r),
|
|
||||||
$this->buildLimitClause($conn_r));
|
|
||||||
|
|
||||||
return $table->loadAllFromArray($data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function willFilterPage(array $logs) {
|
protected function willFilterPage(array $logs) {
|
||||||
|
@ -82,61 +83,73 @@ final class PhabricatorRepositoryPushLogQuery
|
||||||
return $logs;
|
return $logs;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$where = array();
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
if ($this->ids) {
|
if ($this->ids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'id IN (%Ld)',
|
'id IN (%Ld)',
|
||||||
$this->ids);
|
$this->ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->phids) {
|
if ($this->phids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'phid IN (%Ls)',
|
'phid IN (%Ls)',
|
||||||
$this->phids);
|
$this->phids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->repositoryPHIDs) {
|
if ($this->repositoryPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'repositoryPHID IN (%Ls)',
|
'repositoryPHID IN (%Ls)',
|
||||||
$this->repositoryPHIDs);
|
$this->repositoryPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->pusherPHIDs) {
|
if ($this->pusherPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'pusherPHID in (%Ls)',
|
'pusherPHID in (%Ls)',
|
||||||
$this->pusherPHIDs);
|
$this->pusherPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->pushEventPHIDs) {
|
if ($this->pushEventPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'pushEventPHID in (%Ls)',
|
'pushEventPHID in (%Ls)',
|
||||||
$this->pushEventPHIDs);
|
$this->pushEventPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->refTypes) {
|
if ($this->refTypes !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'refType IN (%Ls)',
|
'refType IN (%Ls)',
|
||||||
$this->refTypes);
|
$this->refTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->newRefs) {
|
if ($this->newRefs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'refNew IN (%Ls)',
|
'refNew IN (%Ls)',
|
||||||
$this->newRefs);
|
$this->newRefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
if ($this->epochMin !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'epoch >= %d',
|
||||||
|
$this->epochMin);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
if ($this->epochMax !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'epoch <= %d',
|
||||||
|
$this->epochMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryApplicationClass() {
|
public function getQueryApplicationClass() {
|
||||||
|
|
|
@ -26,6 +26,12 @@ final class PhabricatorRepositoryPushLogSearchEngine
|
||||||
$query->withPusherPHIDs($map['pusherPHIDs']);
|
$query->withPusherPHIDs($map['pusherPHIDs']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($map['createdStart'] || $map['createdEnd']) {
|
||||||
|
$query->withEpochBetween(
|
||||||
|
$map['createdStart'],
|
||||||
|
$map['createdEnd']);
|
||||||
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +50,12 @@ final class PhabricatorRepositoryPushLogSearchEngine
|
||||||
->setLabel(pht('Pushers'))
|
->setLabel(pht('Pushers'))
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht('Search for pull logs by specific users.')),
|
pht('Search for pull logs by specific users.')),
|
||||||
|
id(new PhabricatorSearchDateField())
|
||||||
|
->setLabel(pht('Created After'))
|
||||||
|
->setKey('createdStart'),
|
||||||
|
id(new PhabricatorSearchDateField())
|
||||||
|
->setLabel(pht('Created Before'))
|
||||||
|
->setKey('createdEnd'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,4 +94,146 @@ final class PhabricatorRepositoryPushLogSearchEngine
|
||||||
->setTable($table);
|
->setTable($table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newExportFields() {
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$fields = array(
|
||||||
|
$fields[] = id(new PhabricatorIDExportField())
|
||||||
|
->setKey('pushID')
|
||||||
|
->setLabel(pht('Push ID')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('protocol')
|
||||||
|
->setLabel(pht('Protocol')),
|
||||||
|
$fields[] = id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('repositoryPHID')
|
||||||
|
->setLabel(pht('Repository PHID')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('repository')
|
||||||
|
->setLabel(pht('Repository')),
|
||||||
|
$fields[] = id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('pusherPHID')
|
||||||
|
->setLabel(pht('Pusher PHID')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('pusher')
|
||||||
|
->setLabel(pht('Pusher')),
|
||||||
|
$fields[] = id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('devicePHID')
|
||||||
|
->setLabel(pht('Device PHID')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('device')
|
||||||
|
->setLabel(pht('Device')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('type')
|
||||||
|
->setLabel(pht('Ref Type')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('name')
|
||||||
|
->setLabel(pht('Ref Name')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('old')
|
||||||
|
->setLabel(pht('Ref Old')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('new')
|
||||||
|
->setLabel(pht('Ref New')),
|
||||||
|
$fields[] = id(new PhabricatorIntExportField())
|
||||||
|
->setKey('flags')
|
||||||
|
->setLabel(pht('Flags')),
|
||||||
|
$fields[] = id(new PhabricatorStringListExportField())
|
||||||
|
->setKey('flagNames')
|
||||||
|
->setLabel(pht('Flag Names')),
|
||||||
|
$fields[] = id(new PhabricatorIntExportField())
|
||||||
|
->setKey('result')
|
||||||
|
->setLabel(pht('Result')),
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('resultName')
|
||||||
|
->setLabel(pht('Result Name')),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($viewer->getIsAdmin()) {
|
||||||
|
$fields[] = id(new PhabricatorStringExportField())
|
||||||
|
->setKey('remoteAddress')
|
||||||
|
->setLabel(pht('Remote Address'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newExportData(array $logs) {
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$phids = array();
|
||||||
|
foreach ($logs as $log) {
|
||||||
|
$phids[] = $log->getPusherPHID();
|
||||||
|
$phids[] = $log->getDevicePHID();
|
||||||
|
$phids[] = $log->getPushEvent()->getRepositoryPHID();
|
||||||
|
}
|
||||||
|
$handles = $viewer->loadHandles($phids);
|
||||||
|
|
||||||
|
$flag_map = PhabricatorRepositoryPushLog::getFlagDisplayNames();
|
||||||
|
$reject_map = PhabricatorRepositoryPushLog::getRejectCodeDisplayNames();
|
||||||
|
|
||||||
|
$export = array();
|
||||||
|
foreach ($logs as $log) {
|
||||||
|
$event = $log->getPushEvent();
|
||||||
|
|
||||||
|
$repository_phid = $event->getRepositoryPHID();
|
||||||
|
if ($repository_phid) {
|
||||||
|
$repository_name = $handles[$repository_phid]->getName();
|
||||||
|
} else {
|
||||||
|
$repository_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pusher_phid = $log->getPusherPHID();
|
||||||
|
if ($pusher_phid) {
|
||||||
|
$pusher_name = $handles[$pusher_phid]->getName();
|
||||||
|
} else {
|
||||||
|
$pusher_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$device_phid = $log->getDevicePHID();
|
||||||
|
if ($device_phid) {
|
||||||
|
$device_name = $handles[$device_phid]->getName();
|
||||||
|
} else {
|
||||||
|
$device_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$flags = $log->getChangeFlags();
|
||||||
|
$flag_names = array();
|
||||||
|
foreach ($flag_map as $flag_key => $flag_name) {
|
||||||
|
if (($flags & $flag_key) === $flag_key) {
|
||||||
|
$flag_names[] = $flag_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $event->getRejectCode();
|
||||||
|
$result_name = idx($reject_map, $result, pht('Unknown ("%s")', $result));
|
||||||
|
|
||||||
|
$map = array(
|
||||||
|
'pushID' => $event->getID(),
|
||||||
|
'protocol' => $event->getRemoteProtocol(),
|
||||||
|
'repositoryPHID' => $repository_phid,
|
||||||
|
'repository' => $repository_name,
|
||||||
|
'pusherPHID' => $pusher_phid,
|
||||||
|
'pusher' => $pusher_name,
|
||||||
|
'devicePHID' => $device_phid,
|
||||||
|
'device' => $device_name,
|
||||||
|
'type' => $log->getRefType(),
|
||||||
|
'name' => $log->getRefName(),
|
||||||
|
'old' => $log->getRefOld(),
|
||||||
|
'new' => $log->getRefNew(),
|
||||||
|
'flags' => $flags,
|
||||||
|
'flagNames' => $flag_names,
|
||||||
|
'result' => $result,
|
||||||
|
'resultName' => $result_name,
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($viewer->getIsAdmin()) {
|
||||||
|
$map['remoteAddress'] = $event->getRemoteAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
$export[] = $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $export;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,28 @@ final class PhabricatorRepositoryPushLog
|
||||||
->setPusherPHID($viewer->getPHID());
|
->setPusherPHID($viewer->getPHID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getFlagDisplayNames() {
|
||||||
|
return array(
|
||||||
|
self::CHANGEFLAG_ADD => pht('Create'),
|
||||||
|
self::CHANGEFLAG_DELETE => pht('Delete'),
|
||||||
|
self::CHANGEFLAG_APPEND => pht('Append'),
|
||||||
|
self::CHANGEFLAG_REWRITE => pht('Rewrite'),
|
||||||
|
self::CHANGEFLAG_DANGEROUS => pht('Dangerous'),
|
||||||
|
self::CHANGEFLAG_ENORMOUS => pht('Enormous'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRejectCodeDisplayNames() {
|
||||||
|
return array(
|
||||||
|
self::REJECT_ACCEPT => pht('Accepted'),
|
||||||
|
self::REJECT_DANGEROUS => pht('Rejected: Dangerous'),
|
||||||
|
self::REJECT_HERALD => pht('Rejected: Herald'),
|
||||||
|
self::REJECT_EXTERNAL => pht('Rejected: External Hook'),
|
||||||
|
self::REJECT_BROKEN => pht('Rejected: Broken'),
|
||||||
|
self::REJECT_ENORMOUS => pht('Rejected: Enormous'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static function getHeraldChangeFlagConditionOptions() {
|
public static function getHeraldChangeFlagConditionOptions() {
|
||||||
return array(
|
return array(
|
||||||
self::CHANGEFLAG_ADD =>
|
self::CHANGEFLAG_ADD =>
|
||||||
|
@ -102,6 +124,9 @@ final class PhabricatorRepositoryPushLog
|
||||||
'key_pusher' => array(
|
'key_pusher' => array(
|
||||||
'columns' => array('pusherPHID'),
|
'columns' => array('pusherPHID'),
|
||||||
),
|
),
|
||||||
|
'key_epoch' => array(
|
||||||
|
'columns' => array('epoch'),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ final class PhabricatorRepositoryCommitHeraldWorker
|
||||||
protected function parseCommit(
|
protected function parseCommit(
|
||||||
PhabricatorRepository $repository,
|
PhabricatorRepository $repository,
|
||||||
PhabricatorRepositoryCommit $commit) {
|
PhabricatorRepositoryCommit $commit) {
|
||||||
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
|
||||||
if ($this->shouldSkipImportStep()) {
|
if ($this->shouldSkipImportStep()) {
|
||||||
// This worker has no followup tasks, so we can just bail out
|
// This worker has no followup tasks, so we can just bail out
|
||||||
|
@ -50,7 +51,7 @@ final class PhabricatorRepositoryCommitHeraldWorker
|
||||||
id(new PhabricatorDiffusionApplication())->getPHID());
|
id(new PhabricatorDiffusionApplication())->getPHID());
|
||||||
|
|
||||||
$editor = id(new PhabricatorAuditEditor())
|
$editor = id(new PhabricatorAuditEditor())
|
||||||
->setActor(PhabricatorUser::getOmnipotentUser())
|
->setActor($viewer)
|
||||||
->setActingAsPHID($acting_as_phid)
|
->setActingAsPHID($acting_as_phid)
|
||||||
->setContinueOnMissingFields(true)
|
->setContinueOnMissingFields(true)
|
||||||
->setContinueOnNoEffect(true)
|
->setContinueOnNoEffect(true)
|
||||||
|
@ -69,29 +70,6 @@ final class PhabricatorRepositoryCommitHeraldWorker
|
||||||
'committerPHID' => $data->getCommitDetail('committerPHID'),
|
'committerPHID' => $data->getCommitDetail('committerPHID'),
|
||||||
));
|
));
|
||||||
|
|
||||||
$reverts_refs = id(new DifferentialCustomFieldRevertsParser())
|
|
||||||
->parseCorpus($data->getCommitMessage());
|
|
||||||
$reverts = array_mergev(ipull($reverts_refs, 'monograms'));
|
|
||||||
|
|
||||||
if ($reverts) {
|
|
||||||
$reverted_commits = id(new DiffusionCommitQuery())
|
|
||||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
||||||
->withRepository($repository)
|
|
||||||
->withIdentifiers($reverts)
|
|
||||||
->execute();
|
|
||||||
$reverted_commit_phids = mpull($reverted_commits, 'getPHID', 'getPHID');
|
|
||||||
|
|
||||||
// NOTE: Skip any write attempts if a user cleverly implies a commit
|
|
||||||
// reverts itself.
|
|
||||||
unset($reverted_commit_phids[$commit->getPHID()]);
|
|
||||||
|
|
||||||
$reverts_edge = DiffusionCommitRevertsCommitEdgeType::EDGECONST;
|
|
||||||
$xactions[] = id(new PhabricatorAuditTransaction())
|
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
|
||||||
->setMetadataValue('edge:type', $reverts_edge)
|
|
||||||
->setNewValue(array('+' => array_fuse($reverted_commit_phids)));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$raw_patch = $this->loadRawPatchText($repository, $commit);
|
$raw_patch = $this->loadRawPatchText($repository, $commit);
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ final class PhabricatorApplicationSearchController
|
||||||
private $navigation;
|
private $navigation;
|
||||||
private $queryKey;
|
private $queryKey;
|
||||||
private $preface;
|
private $preface;
|
||||||
|
private $activeQuery;
|
||||||
|
|
||||||
public function setPreface($preface) {
|
public function setPreface($preface) {
|
||||||
$this->preface = $preface;
|
$this->preface = $preface;
|
||||||
|
@ -45,6 +46,14 @@ final class PhabricatorApplicationSearchController
|
||||||
return $this->searchEngine;
|
return $this->searchEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getActiveQuery() {
|
||||||
|
if (!$this->activeQuery) {
|
||||||
|
throw new Exception(pht('There is no active query yet.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->activeQuery;
|
||||||
|
}
|
||||||
|
|
||||||
protected function validateDelegatingController() {
|
protected function validateDelegatingController() {
|
||||||
$parent = $this->getDelegatingController();
|
$parent = $this->getDelegatingController();
|
||||||
|
|
||||||
|
@ -154,10 +163,12 @@ final class PhabricatorApplicationSearchController
|
||||||
$saved_query = $engine->buildSavedQueryFromRequest($request);
|
$saved_query = $engine->buildSavedQueryFromRequest($request);
|
||||||
|
|
||||||
// Save the query to generate a query key, so "Save Custom Query..." and
|
// Save the query to generate a query key, so "Save Custom Query..." and
|
||||||
// other features like Maniphest's "Export..." work correctly.
|
// other features like "Bulk Edit" and "Export Data" work correctly.
|
||||||
$engine->saveQuery($saved_query);
|
$engine->saveQuery($saved_query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->activeQuery = $saved_query;
|
||||||
|
|
||||||
$nav->selectFilter(
|
$nav->selectFilter(
|
||||||
'query/'.$saved_query->getQueryKey(),
|
'query/'.$saved_query->getQueryKey(),
|
||||||
'query/advanced');
|
'query/advanced');
|
||||||
|
@ -410,20 +421,72 @@ final class PhabricatorApplicationSearchController
|
||||||
|
|
||||||
if ($named_query) {
|
if ($named_query) {
|
||||||
$filename = $named_query->getQueryName();
|
$filename = $named_query->getQueryName();
|
||||||
|
$sheet_title = $named_query->getQueryName();
|
||||||
} else {
|
} else {
|
||||||
$filename = $engine->getResultTypeDescription();
|
$filename = $engine->getResultTypeDescription();
|
||||||
|
$sheet_title = $engine->getResultTypeDescription();
|
||||||
}
|
}
|
||||||
$filename = phutil_utf8_strtolower($filename);
|
$filename = phutil_utf8_strtolower($filename);
|
||||||
$filename = PhabricatorFile::normalizeFileName($filename);
|
$filename = PhabricatorFile::normalizeFileName($filename);
|
||||||
|
|
||||||
$formats = PhabricatorExportFormat::getAllEnabledExportFormats();
|
$all_formats = PhabricatorExportFormat::getAllExportFormats();
|
||||||
$format_options = mpull($formats, 'getExportFormatName');
|
|
||||||
|
$available_options = array();
|
||||||
|
$unavailable_options = array();
|
||||||
|
$formats = array();
|
||||||
|
$unavailable_formats = array();
|
||||||
|
foreach ($all_formats as $key => $format) {
|
||||||
|
if ($format->isExportFormatEnabled()) {
|
||||||
|
$available_options[$key] = $format->getExportFormatName();
|
||||||
|
$formats[$key] = $format;
|
||||||
|
} else {
|
||||||
|
$unavailable_options[$key] = pht(
|
||||||
|
'%s (Not Available)',
|
||||||
|
$format->getExportFormatName());
|
||||||
|
$unavailable_formats[$key] = $format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$format_options = $available_options + $unavailable_options;
|
||||||
|
|
||||||
|
// Try to default to the format the user used last time. If you just
|
||||||
|
// exported to Excel, you probably want to export to Excel again.
|
||||||
|
$format_key = $this->readExportFormatPreference();
|
||||||
|
if (!isset($formats[$format_key])) {
|
||||||
|
$format_key = head_key($format_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is a large result set or not. If we're exporting a
|
||||||
|
// large amount of data, we'll build the actual export file in the daemons.
|
||||||
|
|
||||||
|
$threshold = 1000;
|
||||||
|
$query = $engine->buildQueryFromSavedQuery($saved_query);
|
||||||
|
$pager = $engine->newPagerForSavedQuery($saved_query);
|
||||||
|
$pager->setPageSize($threshold + 1);
|
||||||
|
$objects = $engine->executeQuery($query, $pager);
|
||||||
|
$object_count = count($objects);
|
||||||
|
$is_large_export = ($object_count > $threshold);
|
||||||
|
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
|
||||||
$e_format = null;
|
$e_format = null;
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$format_key = $request->getStr('format');
|
$format_key = $request->getStr('format');
|
||||||
|
|
||||||
|
if (isset($unavailable_formats[$format_key])) {
|
||||||
|
$unavailable = $unavailable_formats[$format_key];
|
||||||
|
$instructions = $unavailable->getInstallInstructions();
|
||||||
|
|
||||||
|
$markup = id(new PHUIRemarkupView($viewer, $instructions))
|
||||||
|
->setRemarkupOption(
|
||||||
|
PHUIRemarkupView::OPTION_PRESERVE_LINEBREAKS,
|
||||||
|
false);
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Export Format Not Available'))
|
||||||
|
->appendChild($markup)
|
||||||
|
->addCancelButton($cancel_uri, pht('Done'));
|
||||||
|
}
|
||||||
|
|
||||||
$format = idx($formats, $format_key);
|
$format = idx($formats, $format_key);
|
||||||
|
|
||||||
if (!$format) {
|
if (!$format) {
|
||||||
|
@ -432,63 +495,33 @@ final class PhabricatorApplicationSearchController
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$errors) {
|
if (!$errors) {
|
||||||
$query = $engine->buildQueryFromSavedQuery($saved_query);
|
$this->writeExportFormatPreference($format_key);
|
||||||
|
|
||||||
// NOTE: We aren't reading the pager from the request. Exports always
|
$export_engine = id(new PhabricatorExportEngine())
|
||||||
// affect the entire result set.
|
->setViewer($viewer)
|
||||||
$pager = $engine->newPagerForSavedQuery($saved_query);
|
->setSearchEngine($engine)
|
||||||
$pager->setPageSize(0x7FFFFFFF);
|
->setSavedQuery($saved_query)
|
||||||
|
->setTitle($sheet_title)
|
||||||
|
->setFilename($filename)
|
||||||
|
->setExportFormat($format);
|
||||||
|
|
||||||
$objects = $engine->executeQuery($query, $pager);
|
if ($is_large_export) {
|
||||||
|
$job = $export_engine->newBulkJob($request);
|
||||||
|
|
||||||
$extension = $format->getFileExtension();
|
return id(new AphrontRedirectResponse())
|
||||||
$mime_type = $format->getMIMEContentType();
|
->setURI($job->getMonitorURI());
|
||||||
$filename = $filename.'.'.$extension;
|
} else {
|
||||||
|
$file = $export_engine->exportFile();
|
||||||
|
|
||||||
$format = clone $format;
|
return $this->newDialog()
|
||||||
$format->setViewer($viewer);
|
->setTitle(pht('Download Results'))
|
||||||
|
->appendParagraph(
|
||||||
$export_data = $engine->newExport($objects);
|
pht('Click the download button to download the exported data.'))
|
||||||
|
->addCancelButton($cancel_uri, pht('Done'))
|
||||||
if (count($export_data) !== count($objects)) {
|
->setSubmitURI($file->getDownloadURI())
|
||||||
throw new Exception(
|
->setDisableWorkflowOnSubmit(true)
|
||||||
pht(
|
->addSubmitButton(pht('Download Data'));
|
||||||
'Search engine exported the wrong number of objects, expected '.
|
|
||||||
'%s but got %s.',
|
|
||||||
phutil_count($objects),
|
|
||||||
phutil_count($export_data)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$objects = array_values($objects);
|
|
||||||
$export_data = array_values($export_data);
|
|
||||||
|
|
||||||
$field_list = $engine->newExportFieldList();
|
|
||||||
$field_list = mpull($field_list, null, 'getKey');
|
|
||||||
|
|
||||||
for ($ii = 0; $ii < count($objects); $ii++) {
|
|
||||||
$format->addObject($objects[$ii], $field_list, $export_data[$ii]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$export_result = $format->newFileData();
|
|
||||||
|
|
||||||
$file = PhabricatorFile::newFromFileData(
|
|
||||||
$export_result,
|
|
||||||
array(
|
|
||||||
'name' => $filename,
|
|
||||||
'authorPHID' => $viewer->getPHID(),
|
|
||||||
'ttl.relative' => phutil_units('15 minutes in seconds'),
|
|
||||||
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
|
|
||||||
'mime-type' => $mime_type,
|
|
||||||
));
|
|
||||||
|
|
||||||
return $this->newDialog()
|
|
||||||
->setTitle(pht('Download Results'))
|
|
||||||
->appendParagraph(
|
|
||||||
pht('Click the download button to download the exported data.'))
|
|
||||||
->addCancelButton($cancel_uri, pht('Done'))
|
|
||||||
->setSubmitURI($file->getDownloadURI())
|
|
||||||
->setDisableWorkflowOnSubmit(true)
|
|
||||||
->addSubmitButton(pht('Download Data'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,6 +532,7 @@ final class PhabricatorApplicationSearchController
|
||||||
->setName('format')
|
->setName('format')
|
||||||
->setLabel(pht('Format'))
|
->setLabel(pht('Format'))
|
||||||
->setError($e_format)
|
->setError($e_format)
|
||||||
|
->setValue($format_key)
|
||||||
->setOptions($format_options));
|
->setOptions($format_options));
|
||||||
|
|
||||||
return $this->newDialog()
|
return $this->newDialog()
|
||||||
|
@ -844,10 +878,8 @@ final class PhabricatorApplicationSearchController
|
||||||
|
|
||||||
$engine = $this->getSearchEngine();
|
$engine = $this->getSearchEngine();
|
||||||
$engine_class = get_class($engine);
|
$engine_class = get_class($engine);
|
||||||
$query_key = $this->getQueryKey();
|
|
||||||
if (!$query_key) {
|
$query_key = $this->getActiveQuery()->getQueryKey();
|
||||||
$query_key = $engine->getDefaultQueryKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
$can_use = $engine->canUseInPanelContext();
|
$can_use = $engine->canUseInPanelContext();
|
||||||
$is_installed = PhabricatorApplication::isClassInstalledForViewer(
|
$is_installed = PhabricatorApplication::isClassInstalledForViewer(
|
||||||
|
@ -914,4 +946,32 @@ final class PhabricatorApplicationSearchController
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function readExportFormatPreference() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$export_key = PhabricatorPolicyFavoritesSetting::SETTINGKEY;
|
||||||
|
return $viewer->getUserSetting($export_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function writeExportFormatPreference($value) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$request = $this->getRequest();
|
||||||
|
|
||||||
|
if (!$viewer->isLoggedIn()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$export_key = PhabricatorPolicyFavoritesSetting::SETTINGKEY;
|
||||||
|
$preferences = PhabricatorUserPreferences::loadUserPreferences($viewer);
|
||||||
|
|
||||||
|
$editor = id(new PhabricatorUserPreferencesEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true);
|
||||||
|
|
||||||
|
$xactions = array();
|
||||||
|
$xactions[] = $preferences->newTransaction($export_key, $value);
|
||||||
|
$editor->applyTransactions($preferences, $xactions);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1455,11 +1455,145 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
final public function newExportFieldList() {
|
final public function newExportFieldList() {
|
||||||
return $this->newExportFields();
|
$object = $this->newResultObject();
|
||||||
|
|
||||||
|
$builtin_fields = array(
|
||||||
|
id(new PhabricatorIDExportField())
|
||||||
|
->setKey('id')
|
||||||
|
->setLabel(pht('ID')),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($object->getConfigOption(LiskDAO::CONFIG_AUX_PHID)) {
|
||||||
|
$builtin_fields[] = id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('phid')
|
||||||
|
->setLabel(pht('PHID'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields = mpull($builtin_fields, null, 'getKey');
|
||||||
|
|
||||||
|
$export_fields = $this->newExportFields();
|
||||||
|
foreach ($export_fields as $export_field) {
|
||||||
|
$key = $export_field->getKey();
|
||||||
|
|
||||||
|
if (isset($fields[$key])) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Search engine ("%s") defines an export field with a key ("%s") '.
|
||||||
|
'that collides with another field. Each field must have a '.
|
||||||
|
'unique key.',
|
||||||
|
get_class($this),
|
||||||
|
$key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields[$key] = $export_field;
|
||||||
|
}
|
||||||
|
|
||||||
|
$extensions = $this->newExportExtensions();
|
||||||
|
foreach ($extensions as $extension) {
|
||||||
|
$extension_fields = $extension->newExportFields();
|
||||||
|
foreach ($extension_fields as $extension_field) {
|
||||||
|
$key = $extension_field->getKey();
|
||||||
|
|
||||||
|
if (isset($fields[$key])) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Export engine extension ("%s") defines an export field with '.
|
||||||
|
'a key ("%s") that collides with another field. Each field '.
|
||||||
|
'must have a unique key.',
|
||||||
|
get_class($extension_field),
|
||||||
|
$key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields[$key] = $extension_field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function newExport(array $objects) {
|
||||||
|
$object = $this->newResultObject();
|
||||||
|
$has_phid = $object->getConfigOption(LiskDAO::CONFIG_AUX_PHID);
|
||||||
|
|
||||||
|
$objects = array_values($objects);
|
||||||
|
$n = count($objects);
|
||||||
|
|
||||||
|
$maps = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$map = array(
|
||||||
|
'id' => $object->getID(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($has_phid) {
|
||||||
|
$map['phid'] = $object->getPHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
$maps[] = $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
$export_data = $this->newExportData($objects);
|
||||||
|
$export_data = array_values($export_data);
|
||||||
|
if (count($export_data) !== count($objects)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Search engine ("%s") exported the wrong number of objects, '.
|
||||||
|
'expected %s but got %s.',
|
||||||
|
get_class($this),
|
||||||
|
phutil_count($objects),
|
||||||
|
phutil_count($export_data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($ii = 0; $ii < $n; $ii++) {
|
||||||
|
$maps[$ii] += $export_data[$ii];
|
||||||
|
}
|
||||||
|
|
||||||
|
$extensions = $this->newExportExtensions();
|
||||||
|
foreach ($extensions as $extension) {
|
||||||
|
$extension_data = $extension->newExportData($objects);
|
||||||
|
$extension_data = array_values($extension_data);
|
||||||
|
if (count($export_data) !== count($objects)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Export engine extension ("%s") exported the wrong number of '.
|
||||||
|
'objects, expected %s but got %s.',
|
||||||
|
get_class($extension),
|
||||||
|
phutil_count($objects),
|
||||||
|
phutil_count($export_data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($ii = 0; $ii < $n; $ii++) {
|
||||||
|
$maps[$ii] += $extension_data[$ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newExportFields() {
|
protected function newExportFields() {
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newExportData(array $objects) {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newExportExtensions() {
|
||||||
|
$object = $this->newResultObject();
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$extensions = PhabricatorExportEngineExtension::getAllExtensions();
|
||||||
|
|
||||||
|
$supported = array();
|
||||||
|
foreach ($extensions as $extension) {
|
||||||
|
$extension = clone $extension;
|
||||||
|
$extension->setViewer($viewer);
|
||||||
|
|
||||||
|
if ($extension->supportsObject($object)) {
|
||||||
|
$supported[] = $extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $supported;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,25 +26,9 @@ final class PhabricatorActivitySettingsPanel extends PhabricatorSettingsPanel {
|
||||||
->withRelatedPHIDs(array($user->getPHID()))
|
->withRelatedPHIDs(array($user->getPHID()))
|
||||||
->executeWithCursorPager($pager);
|
->executeWithCursorPager($pager);
|
||||||
|
|
||||||
$phids = array();
|
|
||||||
foreach ($logs as $log) {
|
|
||||||
$phids[] = $log->getUserPHID();
|
|
||||||
$phids[] = $log->getActorPHID();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($phids) {
|
|
||||||
$handles = id(new PhabricatorHandleQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withPHIDs($phids)
|
|
||||||
->execute();
|
|
||||||
} else {
|
|
||||||
$handles = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$table = id(new PhabricatorUserLogView())
|
$table = id(new PhabricatorUserLogView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setLogs($logs)
|
->setLogs($logs);
|
||||||
->setHandles($handles);
|
|
||||||
|
|
||||||
$panel = $this->newBox(pht('Account Activity Logs'), $table);
|
$panel = $this->newBox(pht('Account Activity Logs'), $table);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorBulkManagementExportWorkflow
|
||||||
|
extends PhabricatorBulkManagementWorkflow {
|
||||||
|
|
||||||
|
protected function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('export')
|
||||||
|
->setExamples('**export** [options]')
|
||||||
|
->setSynopsis(
|
||||||
|
pht('Export data to a flat file (JSON, CSV, Excel, etc).'))
|
||||||
|
->setArguments(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'name' => 'class',
|
||||||
|
'param' => 'class',
|
||||||
|
'help' => pht(
|
||||||
|
'SearchEngine class to export data from.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'format',
|
||||||
|
'param' => 'format',
|
||||||
|
'help' => pht('Export format.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'query',
|
||||||
|
'param' => 'key',
|
||||||
|
'help' => pht(
|
||||||
|
'Export the data selected by this query.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'output',
|
||||||
|
'param' => 'path',
|
||||||
|
'help' => pht(
|
||||||
|
'Write output to a file. If omitted, output will be sent to '.
|
||||||
|
'stdout.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'overwrite',
|
||||||
|
'help' => pht(
|
||||||
|
'If the output file already exists, overwrite it instead of '.
|
||||||
|
'raising an error.'),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$class = $args->getArg('class');
|
||||||
|
|
||||||
|
if (!strlen($class)) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Specify a search engine class to export data from with '.
|
||||||
|
'"--class".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_subclass_of($class, 'PhabricatorApplicationSearchEngine')) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'SearchEngine class ("%s") is unknown.',
|
||||||
|
$class));
|
||||||
|
}
|
||||||
|
|
||||||
|
$engine = newv($class, array())
|
||||||
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
if (!$engine->canExport()) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'SearchEngine class ("%s") does not support data export.',
|
||||||
|
$class));
|
||||||
|
}
|
||||||
|
|
||||||
|
$query_key = $args->getArg('query');
|
||||||
|
if (!strlen($query_key)) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Specify a query to export with "--query".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($engine->isBuiltinQuery($query_key)) {
|
||||||
|
$saved_query = $engine->buildSavedQueryFromBuiltin($query_key);
|
||||||
|
} else if ($query_key) {
|
||||||
|
$saved_query = id(new PhabricatorSavedQueryQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withQueryKeys(array($query_key))
|
||||||
|
->executeOne();
|
||||||
|
} else {
|
||||||
|
$saved_query = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$saved_query) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Failed to load saved query ("%s").',
|
||||||
|
$query_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$format_key = $args->getArg('format');
|
||||||
|
if (!strlen($format_key)) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Specify an export format with "--format".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$all_formats = PhabricatorExportFormat::getAllExportFormats();
|
||||||
|
$format = idx($all_formats, $format_key);
|
||||||
|
if (!$format) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Unknown export format ("%s"). Known formats are: %s.',
|
||||||
|
$format_key,
|
||||||
|
implode(', ', array_keys($all_formats))));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$format->isExportFormatEnabled()) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Export format ("%s") is not enabled.',
|
||||||
|
$format_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_overwrite = $args->getArg('overwrite');
|
||||||
|
$output_path = $args->getArg('output');
|
||||||
|
|
||||||
|
if (!strlen($output_path) && $is_overwrite) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Flag "--overwrite" has no effect without "--output".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$is_overwrite) {
|
||||||
|
if (Filesystem::pathExists($output_path)) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Output path already exists. Use "--overwrite" to overwrite '.
|
||||||
|
'it.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$export_engine = id(new PhabricatorExportEngine())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setTitle(pht('Export'))
|
||||||
|
->setFilename(pht('export'))
|
||||||
|
->setSearchEngine($engine)
|
||||||
|
->setSavedQuery($saved_query)
|
||||||
|
->setExportFormat($format);
|
||||||
|
|
||||||
|
$file = $export_engine->exportFile();
|
||||||
|
|
||||||
|
$iterator = $file->getFileDataIterator();
|
||||||
|
|
||||||
|
if (strlen($output_path)) {
|
||||||
|
foreach ($iterator as $chunk) {
|
||||||
|
Filesystem::appendFile($output_path, $chunk);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($iterator as $chunk) {
|
||||||
|
echo $chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ abstract class PhabricatorPHIDListEditField
|
||||||
|
|
||||||
private $useEdgeTransactions;
|
private $useEdgeTransactions;
|
||||||
private $isSingleValue;
|
private $isSingleValue;
|
||||||
|
private $isNullable;
|
||||||
|
|
||||||
public function setUseEdgeTransactions($use_edge_transactions) {
|
public function setUseEdgeTransactions($use_edge_transactions) {
|
||||||
$this->useEdgeTransactions = $use_edge_transactions;
|
$this->useEdgeTransactions = $use_edge_transactions;
|
||||||
|
@ -30,13 +31,23 @@ abstract class PhabricatorPHIDListEditField
|
||||||
return $this->isSingleValue;
|
return $this->isSingleValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setIsNullable($is_nullable) {
|
||||||
|
$this->isNullable = $is_nullable;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsNullable() {
|
||||||
|
return $this->isNullable;
|
||||||
|
}
|
||||||
|
|
||||||
protected function newHTTPParameterType() {
|
protected function newHTTPParameterType() {
|
||||||
return new AphrontPHIDListHTTPParameterType();
|
return new AphrontPHIDListHTTPParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newConduitParameterType() {
|
protected function newConduitParameterType() {
|
||||||
if ($this->getIsSingleValue()) {
|
if ($this->getIsSingleValue()) {
|
||||||
return new ConduitPHIDParameterType();
|
return id(new ConduitPHIDParameterType())
|
||||||
|
->setIsNullable($this->getIsNullable());
|
||||||
} else {
|
} else {
|
||||||
return new ConduitPHIDListParameterType();
|
return new ConduitPHIDListParameterType();
|
||||||
}
|
}
|
||||||
|
@ -99,7 +110,8 @@ abstract class PhabricatorPHIDListEditField
|
||||||
}
|
}
|
||||||
|
|
||||||
return id(new PhabricatorDatasourceEditType())
|
return id(new PhabricatorDatasourceEditType())
|
||||||
->setIsSingleValue($this->getIsSingleValue());
|
->setIsSingleValue($this->getIsSingleValue())
|
||||||
|
->setIsNullable($this->getIsNullable());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newBulkEditTypes() {
|
protected function newBulkEditTypes() {
|
||||||
|
|
|
@ -6,6 +6,7 @@ abstract class PhabricatorPHIDListEditType
|
||||||
private $datasource;
|
private $datasource;
|
||||||
private $isSingleValue;
|
private $isSingleValue;
|
||||||
private $defaultValue;
|
private $defaultValue;
|
||||||
|
private $isNullable;
|
||||||
|
|
||||||
public function setDatasource(PhabricatorTypeaheadDatasource $datasource) {
|
public function setDatasource(PhabricatorTypeaheadDatasource $datasource) {
|
||||||
$this->datasource = $datasource;
|
$this->datasource = $datasource;
|
||||||
|
@ -30,16 +31,17 @@ abstract class PhabricatorPHIDListEditType
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDefaultValue() {
|
public function setIsNullable($is_nullable) {
|
||||||
return $this->defaultValue;
|
$this->isNullable = $is_nullable;
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValueType() {
|
public function getIsNullable() {
|
||||||
if ($this->getIsSingleValue()) {
|
return $this->isNullable;
|
||||||
return 'phid';
|
}
|
||||||
} else {
|
|
||||||
return 'list<phid>';
|
public function getDefaultValue() {
|
||||||
}
|
return $this->defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newConduitParameterType() {
|
protected function newConduitParameterType() {
|
||||||
|
@ -49,7 +51,8 @@ abstract class PhabricatorPHIDListEditType
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->getIsSingleValue()) {
|
if ($this->getIsSingleValue()) {
|
||||||
return new ConduitPHIDParameterType();
|
return id(new ConduitPHIDParameterType())
|
||||||
|
->setIsNullable($this->getIsNullable());
|
||||||
} else {
|
} else {
|
||||||
return new ConduitPHIDListParameterType();
|
return new ConduitPHIDListParameterType();
|
||||||
}
|
}
|
||||||
|
|
|
@ -458,6 +458,12 @@ abstract class PhabricatorApplicationTransaction
|
||||||
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
||||||
return 'fa-lock';
|
return 'fa-lock';
|
||||||
case PhabricatorTransactions::TYPE_EDGE:
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
|
switch ($this->getMetadataValue('edge:type')) {
|
||||||
|
case DiffusionCommitRevertedByCommitEdgeType::EDGECONST:
|
||||||
|
return 'fa-undo';
|
||||||
|
case DiffusionCommitRevertsCommitEdgeType::EDGECONST:
|
||||||
|
return 'fa-ambulance';
|
||||||
|
}
|
||||||
return 'fa-link';
|
return 'fa-link';
|
||||||
case PhabricatorTransactions::TYPE_BUILDABLE:
|
case PhabricatorTransactions::TYPE_BUILDABLE:
|
||||||
return 'fa-wrench';
|
return 'fa-wrench';
|
||||||
|
@ -496,6 +502,14 @@ abstract class PhabricatorApplicationTransaction
|
||||||
return 'black';
|
return 'black';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
|
switch ($this->getMetadataValue('edge:type')) {
|
||||||
|
case DiffusionCommitRevertedByCommitEdgeType::EDGECONST:
|
||||||
|
return 'pink';
|
||||||
|
case DiffusionCommitRevertsCommitEdgeType::EDGECONST:
|
||||||
|
return 'sky';
|
||||||
|
}
|
||||||
|
break;
|
||||||
case PhabricatorTransactions::TYPE_BUILDABLE:
|
case PhabricatorTransactions::TYPE_BUILDABLE:
|
||||||
switch ($this->getNewValue()) {
|
switch ($this->getNewValue()) {
|
||||||
case HarbormasterBuildable::STATUS_PASSED:
|
case HarbormasterBuildable::STATUS_PASSED:
|
||||||
|
|
|
@ -35,6 +35,7 @@ abstract class PhabricatorCustomField extends Phobject {
|
||||||
const ROLE_HERALD = 'herald';
|
const ROLE_HERALD = 'herald';
|
||||||
const ROLE_EDITENGINE = 'EditEngine';
|
const ROLE_EDITENGINE = 'EditEngine';
|
||||||
const ROLE_HERALDACTION = 'herald.action';
|
const ROLE_HERALDACTION = 'herald.action';
|
||||||
|
const ROLE_EXPORT = 'export';
|
||||||
|
|
||||||
|
|
||||||
/* -( Building Applications with Custom Fields )--------------------------- */
|
/* -( Building Applications with Custom Fields )--------------------------- */
|
||||||
|
@ -299,6 +300,8 @@ abstract class PhabricatorCustomField extends Phobject {
|
||||||
case self::ROLE_EDITENGINE:
|
case self::ROLE_EDITENGINE:
|
||||||
return $this->shouldAppearInEditView() ||
|
return $this->shouldAppearInEditView() ||
|
||||||
$this->shouldAppearInEditEngine();
|
$this->shouldAppearInEditEngine();
|
||||||
|
case self::ROLE_EXPORT:
|
||||||
|
return $this->shouldAppearInDataExport();
|
||||||
case self::ROLE_DEFAULT:
|
case self::ROLE_DEFAULT:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
@ -1362,6 +1365,46 @@ abstract class PhabricatorCustomField extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Data Export )-------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function shouldAppearInDataExport() {
|
||||||
|
if ($this->proxy) {
|
||||||
|
return $this->proxy->shouldAppearInDataExport();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->newExportFieldType();
|
||||||
|
return true;
|
||||||
|
} catch (PhabricatorCustomFieldImplementationIncompleteException $ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportField() {
|
||||||
|
if ($this->proxy) {
|
||||||
|
return $this->proxy->newExportField();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newExportFieldType()
|
||||||
|
->setLabel($this->getFieldName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportData() {
|
||||||
|
if ($this->proxy) {
|
||||||
|
return $this->proxy->newExportData();
|
||||||
|
}
|
||||||
|
throw new PhabricatorCustomFieldImplementationIncompleteException($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newExportFieldType() {
|
||||||
|
if ($this->proxy) {
|
||||||
|
return $this->proxy->newExportFieldType();
|
||||||
|
}
|
||||||
|
throw new PhabricatorCustomFieldImplementationIncompleteException($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Conduit )------------------------------------------------------------ */
|
/* -( Conduit )------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -496,5 +496,8 @@ abstract class PhabricatorStandardCustomField
|
||||||
return $this->getFieldValue();
|
return $this->getFieldValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newExportData() {
|
||||||
|
return $this->getFieldValue();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,4 +124,8 @@ final class PhabricatorStandardCustomFieldInt
|
||||||
return new ConduitIntParameterType();
|
return new ConduitIntParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newExportFieldType() {
|
||||||
|
return new PhabricatorIntExportField();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,4 +76,8 @@ final class PhabricatorStandardCustomFieldText
|
||||||
return new ConduitStringParameterType();
|
return new ConduitStringParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newExportFieldType() {
|
||||||
|
return new PhabricatorStringExportField();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,4 +25,24 @@ abstract class PhabricatorWorkerBulkJobType extends Phobject {
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCurtainActions(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
PhabricatorWorkerBulkJob $job) {
|
||||||
|
|
||||||
|
if ($job->isConfirming()) {
|
||||||
|
$continue_uri = $job->getMonitorURI();
|
||||||
|
} else {
|
||||||
|
$continue_uri = $job->getDoneURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
$continue = id(new PhabricatorActionView())
|
||||||
|
->setHref($continue_uri)
|
||||||
|
->setIcon('fa-arrow-circle-o-right')
|
||||||
|
->setName(pht('Continue'));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$continue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,10 @@ abstract class PhabricatorWorkerBulkJobWorker
|
||||||
pht('Job actor does not have permission to edit job.'));
|
pht('Job actor does not have permission to edit job.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow the worker to fill user caches inline; bulk jobs occasionally
|
||||||
|
// need to access user preferences.
|
||||||
|
$actor->setAllowInlineCacheGeneration(true);
|
||||||
|
|
||||||
return $actor;
|
return $actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An bulk job which can not be parallelized and executes only one task.
|
||||||
|
*/
|
||||||
|
abstract class PhabricatorWorkerSingleBulkJobType
|
||||||
|
extends PhabricatorWorkerBulkJobType {
|
||||||
|
|
||||||
|
public function getDescriptionForConfirm(PhabricatorWorkerBulkJob $job) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJobSize(PhabricatorWorkerBulkJob $job) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createTasks(PhabricatorWorkerBulkJob $job) {
|
||||||
|
$tasks = array();
|
||||||
|
|
||||||
|
$tasks[] = PhabricatorWorkerBulkTask::initializeNewTask(
|
||||||
|
$job,
|
||||||
|
$job->getPHID());
|
||||||
|
|
||||||
|
return $tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -180,6 +180,10 @@ final class PhabricatorWorkerBulkJob
|
||||||
return $this->getJobImplementation()->getJobName($this);
|
return $this->getJobImplementation()->getJobName($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCurtainActions(PhabricatorUser $viewer) {
|
||||||
|
return $this->getJobImplementation()->getCurtainActions($viewer, $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PhabricatorEpochExportField
|
|
||||||
extends PhabricatorExportField {
|
|
||||||
|
|
||||||
private $zone;
|
|
||||||
|
|
||||||
public function getTextValue($value) {
|
|
||||||
if (!isset($this->zone)) {
|
|
||||||
$this->zone = new DateTimeZone('UTC');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$date = new DateTime('@'.$value);
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$date->setTimezone($this->zone);
|
|
||||||
return $date->format('c');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNaturalValue($value) {
|
|
||||||
return (int)$value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PhabricatorIntExportField
|
|
||||||
extends PhabricatorExportField {
|
|
||||||
|
|
||||||
public function getNaturalValue($value) {
|
|
||||||
return (int)$value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PhabricatorStringExportField
|
|
||||||
extends PhabricatorExportField {}
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCustomFieldExportEngineExtension
|
||||||
|
extends PhabricatorExportEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'custom-field';
|
||||||
|
|
||||||
|
private $object;
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
$this->object = $object;
|
||||||
|
return ($object instanceof PhabricatorCustomFieldInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportFields() {
|
||||||
|
$prototype = $this->object;
|
||||||
|
|
||||||
|
$fields = $this->newCustomFields($prototype);
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$field_key = $field->getModernFieldKey();
|
||||||
|
|
||||||
|
$results[] = $field->newExportField()
|
||||||
|
->setKey($field_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportData(array $objects) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$field_map = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$object_phid = $object->getPHID();
|
||||||
|
|
||||||
|
$fields = PhabricatorCustomField::getObjectFields(
|
||||||
|
$object,
|
||||||
|
PhabricatorCustomField::ROLE_EXPORT);
|
||||||
|
|
||||||
|
$fields
|
||||||
|
->setViewer($viewer)
|
||||||
|
->readFieldsFromObject($object);
|
||||||
|
|
||||||
|
$field_map[$object_phid] = $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
$all_fields = array();
|
||||||
|
foreach ($field_map as $field_list) {
|
||||||
|
foreach ($field_list->getFields() as $field) {
|
||||||
|
$all_fields[] = $field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
id(new PhabricatorCustomFieldStorageQuery())
|
||||||
|
->addFields($all_fields)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$object_phid = $object->getPHID();
|
||||||
|
$object_fields = $field_map[$object_phid];
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($object_fields->getFields() as $field) {
|
||||||
|
$key = $field->getModernFieldKey();
|
||||||
|
$map[$key] = $field->newExportData();
|
||||||
|
}
|
||||||
|
|
||||||
|
$results[] = $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newCustomFields($object) {
|
||||||
|
$fields = PhabricatorCustomField::getObjectFields(
|
||||||
|
$object,
|
||||||
|
PhabricatorCustomField::ROLE_EXPORT);
|
||||||
|
$fields->setViewer($this->getViewer());
|
||||||
|
|
||||||
|
return $fields->getFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
168
src/infrastructure/export/engine/PhabricatorExportEngine.php
Normal file
168
src/infrastructure/export/engine/PhabricatorExportEngine.php
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorExportEngine
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
private $searchEngine;
|
||||||
|
private $savedQuery;
|
||||||
|
private $exportFormat;
|
||||||
|
private $filename;
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
public function setViewer(PhabricatorUser $viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSearchEngine(
|
||||||
|
PhabricatorApplicationSearchEngine $search_engine) {
|
||||||
|
$this->searchEngine = $search_engine;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSearchEngine() {
|
||||||
|
return $this->searchEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSavedQuery(PhabricatorSavedQuery $saved_query) {
|
||||||
|
$this->savedQuery = $saved_query;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSavedQuery() {
|
||||||
|
return $this->savedQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setExportFormat(
|
||||||
|
PhabricatorExportFormat $export_format) {
|
||||||
|
$this->exportFormat = $export_format;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExportFormat() {
|
||||||
|
return $this->exportFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFilename($filename) {
|
||||||
|
$this->filename = $filename;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilename() {
|
||||||
|
return $this->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTitle($title) {
|
||||||
|
$this->title = $title;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newBulkJob(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$engine = $this->getSearchEngine();
|
||||||
|
$saved_query = $this->getSavedQuery();
|
||||||
|
$format = $this->getExportFormat();
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'engineClass' => get_class($engine),
|
||||||
|
'queryKey' => $saved_query->getQueryKey(),
|
||||||
|
'formatKey' => $format->getExportFormatKey(),
|
||||||
|
'title' => $this->getTitle(),
|
||||||
|
'filename' => $this->getFilename(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$job = PhabricatorWorkerBulkJob::initializeNewJob(
|
||||||
|
$viewer,
|
||||||
|
new PhabricatorExportEngineBulkJobType(),
|
||||||
|
$params);
|
||||||
|
|
||||||
|
// We queue these jobs directly into STATUS_WAITING without requiring
|
||||||
|
// a confirmation from the user.
|
||||||
|
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = id(new PhabricatorWorkerBulkJobTransaction())
|
||||||
|
->setTransactionType(PhabricatorWorkerBulkJobTransaction::TYPE_STATUS)
|
||||||
|
->setNewValue(PhabricatorWorkerBulkJob::STATUS_WAITING);
|
||||||
|
|
||||||
|
$editor = id(new PhabricatorWorkerBulkJobEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->applyTransactions($job, $xactions);
|
||||||
|
|
||||||
|
return $job;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportFile() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$engine = $this->getSearchEngine();
|
||||||
|
$saved_query = $this->getSavedQuery();
|
||||||
|
$format = $this->getExportFormat();
|
||||||
|
$title = $this->getTitle();
|
||||||
|
$filename = $this->getFilename();
|
||||||
|
|
||||||
|
$query = $engine->buildQueryFromSavedQuery($saved_query);
|
||||||
|
|
||||||
|
$extension = $format->getFileExtension();
|
||||||
|
$mime_type = $format->getMIMEContentType();
|
||||||
|
$filename = $filename.'.'.$extension;
|
||||||
|
|
||||||
|
$format = id(clone $format)
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setTitle($title);
|
||||||
|
|
||||||
|
$field_list = $engine->newExportFieldList();
|
||||||
|
$field_list = mpull($field_list, null, 'getKey');
|
||||||
|
$format->addHeaders($field_list);
|
||||||
|
|
||||||
|
// Iterate over the query results in large page so we don't have to hold
|
||||||
|
// too much stuff in memory.
|
||||||
|
$page_size = 1000;
|
||||||
|
$page_cursor = null;
|
||||||
|
do {
|
||||||
|
$pager = $engine->newPagerForSavedQuery($saved_query);
|
||||||
|
$pager->setPageSize($page_size);
|
||||||
|
|
||||||
|
if ($page_cursor !== null) {
|
||||||
|
$pager->setAfterID($page_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
$objects = $engine->executeQuery($query, $pager);
|
||||||
|
$objects = array_values($objects);
|
||||||
|
$page_cursor = $pager->getNextPageID();
|
||||||
|
|
||||||
|
$export_data = $engine->newExport($objects);
|
||||||
|
for ($ii = 0; $ii < count($objects); $ii++) {
|
||||||
|
$format->addObject($objects[$ii], $field_list, $export_data[$ii]);
|
||||||
|
}
|
||||||
|
} while ($pager->getHasMoreResults());
|
||||||
|
|
||||||
|
$export_result = $format->newFileData();
|
||||||
|
|
||||||
|
// We have all the data in one big string and aren't actually
|
||||||
|
// streaming it, but pretending that we are allows us to actviate
|
||||||
|
// the chunk engine and store large files.
|
||||||
|
$iterator = new ArrayIterator(array($export_result));
|
||||||
|
|
||||||
|
$source = id(new PhabricatorIteratorFileUploadSource())
|
||||||
|
->setName($filename)
|
||||||
|
->setViewPolicy(PhabricatorPolicies::POLICY_NOONE)
|
||||||
|
->setMIMEType($mime_type)
|
||||||
|
->setRelativeTTL(phutil_units('60 minutes in seconds'))
|
||||||
|
->setAuthorPHID($viewer->getPHID())
|
||||||
|
->setIterator($iterator);
|
||||||
|
|
||||||
|
return $source->uploadFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorExportEngineBulkJobType
|
||||||
|
extends PhabricatorWorkerSingleBulkJobType {
|
||||||
|
|
||||||
|
public function getBulkJobTypeKey() {
|
||||||
|
return 'export';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJobName(PhabricatorWorkerBulkJob $job) {
|
||||||
|
return pht('Data Export');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCurtainActions(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
PhabricatorWorkerBulkJob $job) {
|
||||||
|
$actions = array();
|
||||||
|
|
||||||
|
$file_phid = $job->getParameter('filePHID');
|
||||||
|
if (!$file_phid) {
|
||||||
|
$actions[] = id(new PhabricatorActionView())
|
||||||
|
->setHref('#')
|
||||||
|
->setIcon('fa-download')
|
||||||
|
->setDisabled(true)
|
||||||
|
->setName(pht('Exporting Data...'));
|
||||||
|
} else {
|
||||||
|
$file = id(new PhabricatorFileQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($file_phid))
|
||||||
|
->executeOne();
|
||||||
|
if (!$file) {
|
||||||
|
$actions[] = id(new PhabricatorActionView())
|
||||||
|
->setHref('#')
|
||||||
|
->setIcon('fa-download')
|
||||||
|
->setDisabled(true)
|
||||||
|
->setName(pht('Temporary File Expired'));
|
||||||
|
} else {
|
||||||
|
$actions[] = id(new PhabricatorActionView())
|
||||||
|
->setRenderAsForm(true)
|
||||||
|
->setHref($file->getDownloadURI())
|
||||||
|
->setIcon('fa-download')
|
||||||
|
->setName(pht('Download Data Export'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function runTask(
|
||||||
|
PhabricatorUser $actor,
|
||||||
|
PhabricatorWorkerBulkJob $job,
|
||||||
|
PhabricatorWorkerBulkTask $task) {
|
||||||
|
|
||||||
|
$engine_class = $job->getParameter('engineClass');
|
||||||
|
if (!is_subclass_of($engine_class, 'PhabricatorApplicationSearchEngine')) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Unknown search engine class "%s".',
|
||||||
|
$engine_class));
|
||||||
|
}
|
||||||
|
|
||||||
|
$engine = newv($engine_class, array())
|
||||||
|
->setViewer($actor);
|
||||||
|
|
||||||
|
$query_key = $job->getParameter('queryKey');
|
||||||
|
if ($engine->isBuiltinQuery($query_key)) {
|
||||||
|
$saved_query = $engine->buildSavedQueryFromBuiltin($query_key);
|
||||||
|
} else if ($query_key) {
|
||||||
|
$saved_query = id(new PhabricatorSavedQueryQuery())
|
||||||
|
->setViewer($actor)
|
||||||
|
->withQueryKeys(array($query_key))
|
||||||
|
->executeOne();
|
||||||
|
} else {
|
||||||
|
$saved_query = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$saved_query) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to load saved query ("%s").',
|
||||||
|
$query_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$format_key = $job->getParameter('formatKey');
|
||||||
|
|
||||||
|
$all_formats = PhabricatorExportFormat::getAllExportFormats();
|
||||||
|
$format = idx($all_formats, $format_key);
|
||||||
|
if (!$format) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Unknown export format ("%s").',
|
||||||
|
$format_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$format->isExportFormatEnabled()) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Export format ("%s") is not enabled.',
|
||||||
|
$format_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$export_engine = id(new PhabricatorExportEngine())
|
||||||
|
->setViewer($actor)
|
||||||
|
->setTitle($job->getParameter('title'))
|
||||||
|
->setFilename($job->getParameter('filename'))
|
||||||
|
->setSearchEngine($engine)
|
||||||
|
->setSavedQuery($saved_query)
|
||||||
|
->setExportFormat($format);
|
||||||
|
|
||||||
|
$file = $export_engine->exportFile();
|
||||||
|
|
||||||
|
$job
|
||||||
|
->setParameter('filePHID', $file->getPHID())
|
||||||
|
->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorExportEngineExtension extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
|
||||||
|
final public function getExtensionKey() {
|
||||||
|
return $this->getPhobjectClassConstant('EXTENSIONKEY');
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function setViewer($viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function supportsObject($object);
|
||||||
|
abstract public function newExportFields();
|
||||||
|
abstract public function newExportData(array $objects);
|
||||||
|
|
||||||
|
final public static function getAllExtensions() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getExtensionKey')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorExportFormatSetting
|
||||||
|
extends PhabricatorInternalSetting {
|
||||||
|
|
||||||
|
const SETTINGKEY = 'export.format';
|
||||||
|
|
||||||
|
public function getSettingName() {
|
||||||
|
return pht('Export Format');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSettingDefaultValue() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorLiskExportEngineExtension
|
||||||
|
extends PhabricatorExportEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'lisk';
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
if (!($object instanceof LiskDAO)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$object->getConfigOption(LiskDAO::CONFIG_TIMESTAMPS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportFields() {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorEpochExportField())
|
||||||
|
->setKey('dateCreated')
|
||||||
|
->setLabel(pht('Created')),
|
||||||
|
id(new PhabricatorEpochExportField())
|
||||||
|
->setKey('dateModified')
|
||||||
|
->setLabel(pht('Modified')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportData(array $objects) {
|
||||||
|
$map = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$map[] = array(
|
||||||
|
'dateCreated' => $object->getDateCreated(),
|
||||||
|
'dateModified' => $object->getDateModified(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProjectsExportEngineExtension
|
||||||
|
extends PhabricatorExportEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'projects';
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
return ($object instanceof PhabricatorProjectInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportFields() {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorPHIDListExportField())
|
||||||
|
->setKey('tagPHIDs')
|
||||||
|
->setLabel(pht('Tag PHIDs')),
|
||||||
|
id(new PhabricatorStringListExportField())
|
||||||
|
->setKey('tags')
|
||||||
|
->setLabel(pht('Tags')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportData(array $objects) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$object_phids = mpull($objects, 'getPHID');
|
||||||
|
|
||||||
|
$projects_query = id(new PhabricatorEdgeQuery())
|
||||||
|
->withSourcePHIDs($object_phids)
|
||||||
|
->withEdgeTypes(
|
||||||
|
array(
|
||||||
|
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
|
||||||
|
));
|
||||||
|
$projects_query->execute();
|
||||||
|
|
||||||
|
$handles = $viewer->loadHandles($projects_query->getDestinationPHIDs());
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$object_phid = $object->getPHID();
|
||||||
|
|
||||||
|
$project_phids = $projects_query->getDestinationPHIDs(
|
||||||
|
array($object_phid),
|
||||||
|
array(PhabricatorProjectObjectHasProjectEdgeType::EDGECONST));
|
||||||
|
|
||||||
|
$handle_list = $handles->newSublist($project_phids);
|
||||||
|
$handle_list = iterator_to_array($handle_list);
|
||||||
|
$handle_names = mpull($handle_list, 'getName');
|
||||||
|
$handle_names = array_values($handle_names);
|
||||||
|
|
||||||
|
$map[] = array(
|
||||||
|
'tagPHIDs' => $project_phids,
|
||||||
|
'tags' => $handle_names,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSpacesExportEngineExtension
|
||||||
|
extends PhabricatorExportEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'spaces';
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
if (!PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($object instanceof PhabricatorSpacesInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportFields() {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('spacePHID')
|
||||||
|
->setLabel(pht('Space PHID')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('space')
|
||||||
|
->setLabel(pht('Space')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportData(array $objects) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$space_phids = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$space_phids[] = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
|
||||||
|
$object);
|
||||||
|
}
|
||||||
|
$handles = $viewer->loadHandles($space_phids);
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
|
||||||
|
$object);
|
||||||
|
|
||||||
|
$map[] = array(
|
||||||
|
'spacePHID' => $space_phid,
|
||||||
|
'space' => $handles[$space_phid]->getName(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSubscriptionsExportEngineExtension
|
||||||
|
extends PhabricatorExportEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'subscriptions';
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
return ($object instanceof PhabricatorSubscribableInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportFields() {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorPHIDListExportField())
|
||||||
|
->setKey('subscriberPHIDs')
|
||||||
|
->setLabel(pht('Subscriber PHIDs')),
|
||||||
|
id(new PhabricatorStringListExportField())
|
||||||
|
->setKey('subscribers')
|
||||||
|
->setLabel(pht('Subscribers')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportData(array $objects) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$object_phids = mpull($objects, 'getPHID');
|
||||||
|
|
||||||
|
$projects_query = id(new PhabricatorEdgeQuery())
|
||||||
|
->withSourcePHIDs($object_phids)
|
||||||
|
->withEdgeTypes(
|
||||||
|
array(
|
||||||
|
PhabricatorObjectHasSubscriberEdgeType::EDGECONST,
|
||||||
|
));
|
||||||
|
$projects_query->execute();
|
||||||
|
|
||||||
|
$handles = $viewer->loadHandles($projects_query->getDestinationPHIDs());
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$object_phid = $object->getPHID();
|
||||||
|
|
||||||
|
$project_phids = $projects_query->getDestinationPHIDs(
|
||||||
|
array($object_phid),
|
||||||
|
array(PhabricatorObjectHasSubscriberEdgeType::EDGECONST));
|
||||||
|
|
||||||
|
$handle_list = $handles->newSublist($project_phids);
|
||||||
|
$handle_list = iterator_to_array($handle_list);
|
||||||
|
$handle_names = mpull($handle_list, 'getName');
|
||||||
|
$handle_names = array_values($handle_names);
|
||||||
|
|
||||||
|
$map[] = array(
|
||||||
|
'subscriberPHIDs' => $project_phids,
|
||||||
|
'subscribers' => $handle_names,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorEpochExportField
|
||||||
|
extends PhabricatorExportField {
|
||||||
|
|
||||||
|
private $zone;
|
||||||
|
|
||||||
|
public function getTextValue($value) {
|
||||||
|
if (!isset($this->zone)) {
|
||||||
|
$this->zone = new DateTimeZone('UTC');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$date = new DateTime('@'.$value);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$date->setTimezone($this->zone);
|
||||||
|
return $date->format('c');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNaturalValue($value) {
|
||||||
|
return (int)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHPExcelValue($value) {
|
||||||
|
$epoch = $this->getNaturalValue($value);
|
||||||
|
|
||||||
|
$seconds_per_day = phutil_units('1 day in seconds');
|
||||||
|
$offset = ($seconds_per_day * 25569);
|
||||||
|
|
||||||
|
return ($epoch + $offset) / $seconds_per_day;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phutil-external-symbol class PHPExcel_Style_NumberFormat
|
||||||
|
*/
|
||||||
|
public function formatPHPExcelCell($cell, $style) {
|
||||||
|
$code = PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2;
|
||||||
|
|
||||||
|
$style
|
||||||
|
->getNumberFormat()
|
||||||
|
->setFormatCode($code);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -25,11 +25,32 @@ abstract class PhabricatorExportField
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTextValue($value) {
|
public function getTextValue($value) {
|
||||||
return (string)$this->getNaturalValue($value);
|
$natural_value = $this->getNaturalValue($value);
|
||||||
|
|
||||||
|
if ($natural_value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string)$natural_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNaturalValue($value) {
|
public function getNaturalValue($value) {
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPHPExcelValue($value) {
|
||||||
|
return $this->getTextValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phutil-external-symbol class PHPExcel_Cell_DataType
|
||||||
|
*/
|
||||||
|
public function formatPHPExcelCell($cell, $style) {
|
||||||
|
$cell->setDataType(PHPExcel_Cell_DataType::TYPE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCharacterWidth() {
|
||||||
|
return 24;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,4 +7,8 @@ final class PhabricatorIDExportField
|
||||||
return (int)$value;
|
return (int)$value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCharacterWidth() {
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorIntExportField
|
||||||
|
extends PhabricatorExportField {
|
||||||
|
|
||||||
|
public function getNaturalValue($value) {
|
||||||
|
if ($value === null) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phutil-external-symbol class PHPExcel_Cell_DataType
|
||||||
|
*/
|
||||||
|
public function formatPHPExcelCell($cell, $style) {
|
||||||
|
$cell->setDataType(PHPExcel_Cell_DataType::TYPE_NUMERIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCharacterWidth() {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorListExportField
|
||||||
|
extends PhabricatorExportField {
|
||||||
|
|
||||||
|
public function getTextValue($value) {
|
||||||
|
return implode("\n", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPHIDExportField
|
||||||
|
extends PhabricatorExportField {
|
||||||
|
|
||||||
|
public function getCharacterWidth() {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPHIDListExportField
|
||||||
|
extends PhabricatorListExportField {
|
||||||
|
|
||||||
|
public function getCharacterWidth() {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorStringExportField
|
||||||
|
extends PhabricatorExportField {
|
||||||
|
|
||||||
|
public function getNaturalValue($value) {
|
||||||
|
if ($value === null) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strlen($value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorStringListExportField
|
||||||
|
extends PhabricatorListExportField {}
|
|
@ -1,4 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhabricatorPHIDExportField
|
final class PhabricatorURIExportField
|
||||||
extends PhabricatorExportField {}
|
extends PhabricatorExportField {}
|
|
@ -23,21 +23,44 @@ final class PhabricatorCSVExportFormat
|
||||||
return 'text/csv';
|
return 'text/csv';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addHeaders(array $fields) {
|
||||||
|
$headers = mpull($fields, 'getLabel');
|
||||||
|
$this->addRow($headers);
|
||||||
|
}
|
||||||
|
|
||||||
public function addObject($object, array $fields, array $map) {
|
public function addObject($object, array $fields, array $map) {
|
||||||
$values = array();
|
$values = array();
|
||||||
foreach ($fields as $key => $field) {
|
foreach ($fields as $key => $field) {
|
||||||
$value = $map[$key];
|
$value = $map[$key];
|
||||||
$value = $field->getTextValue($value);
|
$value = $field->getTextValue($value);
|
||||||
|
$values[] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addRow($values);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addRow(array $values) {
|
||||||
|
$row = array();
|
||||||
|
foreach ($values as $value) {
|
||||||
|
|
||||||
|
// Excel is extremely interested in executing arbitrary code it finds in
|
||||||
|
// untrusted CSV files downloaded from the internet. When a cell looks
|
||||||
|
// like it might be too tempting for Excel to ignore, mangle the value
|
||||||
|
// to dissuade remote code execution. See T12800.
|
||||||
|
|
||||||
|
if (preg_match('/^\s*[+=@-]/', $value)) {
|
||||||
|
$value = '(!) '.$value;
|
||||||
|
}
|
||||||
|
|
||||||
if (preg_match('/\s|,|\"/', $value)) {
|
if (preg_match('/\s|,|\"/', $value)) {
|
||||||
$value = str_replace('"', '""', $value);
|
$value = str_replace('"', '""', $value);
|
||||||
$value = '"'.$value.'"';
|
$value = '"'.$value.'"';
|
||||||
}
|
}
|
||||||
|
|
||||||
$values[] = $value;
|
$row[] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->rows[] = implode(',', $values);
|
$this->rows[] = implode(',', $row);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newFileData() {
|
public function newFileData() {
|
|
@ -0,0 +1,168 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorExcelExportFormat
|
||||||
|
extends PhabricatorExportFormat {
|
||||||
|
|
||||||
|
const EXPORTKEY = 'excel';
|
||||||
|
|
||||||
|
private $workbook;
|
||||||
|
private $sheet;
|
||||||
|
private $rowCursor;
|
||||||
|
|
||||||
|
public function getExportFormatName() {
|
||||||
|
return pht('Excel (.xlsx)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isExportFormatEnabled() {
|
||||||
|
// TODO: PHPExcel has a dependency on the PHP zip extension. We should test
|
||||||
|
// for that here, since it fatals if we don't have the ZipArchive class.
|
||||||
|
return @include_once 'PHPExcel.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInstallInstructions() {
|
||||||
|
return pht(<<<EOHELP
|
||||||
|
Data can not be exported to Excel because the PHPExcel library is not
|
||||||
|
installed. This software component is required for Phabricator to create
|
||||||
|
Excel files.
|
||||||
|
|
||||||
|
You can install PHPExcel from GitHub:
|
||||||
|
|
||||||
|
> https://github.com/PHPOffice/PHPExcel
|
||||||
|
|
||||||
|
Briefly:
|
||||||
|
|
||||||
|
- Clone that repository somewhere on the sever
|
||||||
|
(like `/path/to/example/PHPExcel`).
|
||||||
|
- Update your PHP `%s` setting (in `php.ini`) to include the PHPExcel
|
||||||
|
`Classes` directory (like `/path/to/example/PHPExcel/Classes`).
|
||||||
|
EOHELP
|
||||||
|
,
|
||||||
|
'include_path');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFileExtension() {
|
||||||
|
return 'xlsx';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMIMEContentType() {
|
||||||
|
return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phutil-external-symbol class PHPExcel_Cell_DataType
|
||||||
|
*/
|
||||||
|
public function addHeaders(array $fields) {
|
||||||
|
$sheet = $this->getSheet();
|
||||||
|
|
||||||
|
$header_format = array(
|
||||||
|
'font' => array(
|
||||||
|
'bold' => true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$row = 1;
|
||||||
|
$col = 0;
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$cell_value = $field->getLabel();
|
||||||
|
|
||||||
|
$cell_name = $this->getCellName($col, $row);
|
||||||
|
|
||||||
|
$cell = $sheet->setCellValue(
|
||||||
|
$cell_name,
|
||||||
|
$cell_value,
|
||||||
|
$return_cell = true);
|
||||||
|
|
||||||
|
$sheet->getStyle($cell_name)->applyFromArray($header_format);
|
||||||
|
$cell->setDataType(PHPExcel_Cell_DataType::TYPE_STRING);
|
||||||
|
|
||||||
|
$width = $field->getCharacterWidth();
|
||||||
|
if ($width !== null) {
|
||||||
|
$col_name = $this->getCellName($col);
|
||||||
|
$sheet->getColumnDimension($col_name)
|
||||||
|
->setWidth($width);
|
||||||
|
}
|
||||||
|
|
||||||
|
$col++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addObject($object, array $fields, array $map) {
|
||||||
|
$sheet = $this->getSheet();
|
||||||
|
|
||||||
|
$col = 0;
|
||||||
|
foreach ($fields as $key => $field) {
|
||||||
|
$cell_value = $map[$key];
|
||||||
|
$cell_value = $field->getPHPExcelValue($cell_value);
|
||||||
|
|
||||||
|
$cell_name = $this->getCellName($col, $this->rowCursor);
|
||||||
|
|
||||||
|
$cell = $sheet->setCellValue(
|
||||||
|
$cell_name,
|
||||||
|
$cell_value,
|
||||||
|
$return_cell = true);
|
||||||
|
|
||||||
|
$style = $sheet->getStyle($cell_name);
|
||||||
|
$field->formatPHPExcelCell($cell, $style);
|
||||||
|
|
||||||
|
$col++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rowCursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phutil-external-symbol class PHPExcel_IOFactory
|
||||||
|
*/
|
||||||
|
public function newFileData() {
|
||||||
|
$workbook = $this->getWorkbook();
|
||||||
|
$writer = PHPExcel_IOFactory::createWriter($workbook, 'Excel2007');
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$writer->save('php://output');
|
||||||
|
$data = ob_get_clean();
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getWorkbook() {
|
||||||
|
if (!$this->workbook) {
|
||||||
|
$this->workbook = $this->newWorkbook();
|
||||||
|
}
|
||||||
|
return $this->workbook;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phutil-external-symbol class PHPExcel
|
||||||
|
*/
|
||||||
|
private function newWorkbook() {
|
||||||
|
include_once 'PHPExcel.php';
|
||||||
|
return new PHPExcel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSheet() {
|
||||||
|
if (!$this->sheet) {
|
||||||
|
$workbook = $this->getWorkbook();
|
||||||
|
|
||||||
|
$sheet = $workbook->setActiveSheetIndex(0);
|
||||||
|
$sheet->setTitle($this->getTitle());
|
||||||
|
|
||||||
|
$this->sheet = $sheet;
|
||||||
|
|
||||||
|
// The row cursor starts on the second row, after the header row.
|
||||||
|
$this->rowCursor = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->sheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCellName($col, $row = null) {
|
||||||
|
$col_name = chr(ord('A') + $col);
|
||||||
|
|
||||||
|
if ($row === null) {
|
||||||
|
return $col_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $col_name.$row;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ abstract class PhabricatorExportFormat
|
||||||
extends Phobject {
|
extends Phobject {
|
||||||
|
|
||||||
private $viewer;
|
private $viewer;
|
||||||
|
private $title;
|
||||||
|
|
||||||
final public function getExportFormatKey() {
|
final public function getExportFormatKey() {
|
||||||
return $this->getPhobjectClassConstant('EXPORTKEY');
|
return $this->getPhobjectClassConstant('EXPORTKEY');
|
||||||
|
@ -18,10 +19,23 @@ abstract class PhabricatorExportFormat
|
||||||
return $this->viewer;
|
return $this->viewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function setTitle($title) {
|
||||||
|
$this->title = $title;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getTitle() {
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
abstract public function getExportFormatName();
|
abstract public function getExportFormatName();
|
||||||
abstract public function getMIMEContentType();
|
abstract public function getMIMEContentType();
|
||||||
abstract public function getFileExtension();
|
abstract public function getFileExtension();
|
||||||
|
|
||||||
|
public function addHeaders(array $fields) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
abstract public function addObject($object, array $fields, array $map);
|
abstract public function addObject($object, array $fields, array $map);
|
||||||
abstract public function newFileData();
|
abstract public function newFileData();
|
||||||
|
|
||||||
|
@ -36,16 +50,4 @@ abstract class PhabricatorExportFormat
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
final public static function getAllEnabledExportFormats() {
|
|
||||||
$formats = self::getAllExportFormats();
|
|
||||||
|
|
||||||
foreach ($formats as $key => $format) {
|
|
||||||
if (!$format->isExportFormatEnabled()) {
|
|
||||||
unset($formats[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $formats;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,17 +23,29 @@ final class PhabricatorTextExportFormat
|
||||||
return 'text/plain';
|
return 'text/plain';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addHeaders(array $fields) {
|
||||||
|
$headers = mpull($fields, 'getLabel');
|
||||||
|
$this->addRow($headers);
|
||||||
|
}
|
||||||
|
|
||||||
public function addObject($object, array $fields, array $map) {
|
public function addObject($object, array $fields, array $map) {
|
||||||
$values = array();
|
$values = array();
|
||||||
foreach ($fields as $key => $field) {
|
foreach ($fields as $key => $field) {
|
||||||
$value = $map[$key];
|
$value = $map[$key];
|
||||||
$value = $field->getTextValue($value);
|
$value = $field->getTextValue($value);
|
||||||
$value = addcslashes($value, "\0..\37\\\177..\377");
|
|
||||||
|
|
||||||
$values[] = $value;
|
$values[] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->rows[] = implode("\t", $values);
|
$this->addRow($values);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addRow(array $values) {
|
||||||
|
$row = array();
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$row[] = addcslashes($value, "\0..\37\\\177..\377");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rows[] = implode("\t", $row);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newFileData() {
|
public function newFileData() {
|
|
@ -676,73 +676,73 @@ final class PhabricatorUSEnglishTranslation
|
||||||
'%s edited commit(s), added %s: %s; removed %s: %s.' =>
|
'%s edited commit(s), added %s: %s; removed %s: %s.' =>
|
||||||
'%s edited commits, added %3$s; removed %5$s.',
|
'%s edited commits, added %3$s; removed %5$s.',
|
||||||
|
|
||||||
'%s added %s reverted commit(s): %s.' => array(
|
'%s added %s reverted change(s): %s.' => array(
|
||||||
array(
|
array(
|
||||||
'%s added a reverted commit: %3$s.',
|
'%s added a reverted change: %3$s.',
|
||||||
'%s added reverted commits: %3$s.',
|
'%s added reverted changes: %3$s.',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
'%s removed %s reverted commit(s): %s.' => array(
|
'%s removed %s reverted change(s): %s.' => array(
|
||||||
array(
|
array(
|
||||||
'%s removed a reverted commit: %3$s.',
|
'%s removed a reverted change: %3$s.',
|
||||||
'%s removed reverted commits: %3$s.',
|
'%s removed reverted changes: %3$s.',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
'%s edited reverted commit(s), added %s: %s; removed %s: %s.' =>
|
'%s edited reverted change(s), added %s: %s; removed %s: %s.' =>
|
||||||
'%s edited reverted commits, added %3$s; removed %5$s.',
|
'%s edited reverted changes, added %3$s; removed %5$s.',
|
||||||
|
|
||||||
'%s added %s reverted commit(s) for %s: %s.' => array(
|
'%s added %s reverted change(s) for %s: %s.' => array(
|
||||||
array(
|
array(
|
||||||
'%s added a reverted commit for %3$s: %4$s.',
|
'%s added a reverted change for %3$s: %4$s.',
|
||||||
'%s added reverted commits for %3$s: %4$s.',
|
'%s added reverted changes for %3$s: %4$s.',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
'%s removed %s reverted commit(s) for %s: %s.' => array(
|
'%s removed %s reverted change(s) for %s: %s.' => array(
|
||||||
array(
|
array(
|
||||||
'%s removed a reverted commit for %3$s: %4$s.',
|
'%s removed a reverted change for %3$s: %4$s.',
|
||||||
'%s removed reverted commits for %3$s: %4$s.',
|
'%s removed reverted changes for %3$s: %4$s.',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
'%s edited reverted commit(s) for %s, added %s: %s; removed %s: %s.' =>
|
'%s edited reverted change(s) for %s, added %s: %s; removed %s: %s.' =>
|
||||||
'%s edited reverted commits for %2$s, added %4$s; removed %6$s.',
|
'%s edited reverted changes for %2$s, added %4$s; removed %6$s.',
|
||||||
|
|
||||||
'%s added %s reverting commit(s): %s.' => array(
|
'%s added %s reverting change(s): %s.' => array(
|
||||||
array(
|
array(
|
||||||
'%s added a reverting commit: %3$s.',
|
'%s added a reverting change: %3$s.',
|
||||||
'%s added reverting commits: %3$s.',
|
'%s added reverting changes: %3$s.',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
'%s removed %s reverting commit(s): %s.' => array(
|
'%s removed %s reverting change(s): %s.' => array(
|
||||||
array(
|
array(
|
||||||
'%s removed a reverting commit: %3$s.',
|
'%s removed a reverting change: %3$s.',
|
||||||
'%s removed reverting commits: %3$s.',
|
'%s removed reverting changes: %3$s.',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
'%s edited reverting commit(s), added %s: %s; removed %s: %s.' =>
|
'%s edited reverting change(s), added %s: %s; removed %s: %s.' =>
|
||||||
'%s edited reverting commits, added %3$s; removed %5$s.',
|
'%s edited reverting changes, added %3$s; removed %5$s.',
|
||||||
|
|
||||||
'%s added %s reverting commit(s) for %s: %s.' => array(
|
'%s added %s reverting change(s) for %s: %s.' => array(
|
||||||
array(
|
array(
|
||||||
'%s added a reverting commit for %3$s: %4$s.',
|
'%s added a reverting change for %3$s: %4$s.',
|
||||||
'%s added reverting commits for %3$s: %4$s.',
|
'%s added reverting changes for %3$s: %4$s.',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
'%s removed %s reverting commit(s) for %s: %s.' => array(
|
'%s removed %s reverting change(s) for %s: %s.' => array(
|
||||||
array(
|
array(
|
||||||
'%s removed a reverting commit for %3$s: %4$s.',
|
'%s removed a reverting change for %3$s: %4$s.',
|
||||||
'%s removed reverting commits for %3$s: %4$s.',
|
'%s removed reverting changes for %3$s: %4$s.',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
'%s edited reverting commit(s) for %s, added %s: %s; removed %s: %s.' =>
|
'%s edited reverting change(s) for %s, added %s: %s; removed %s: %s.' =>
|
||||||
'%s edited reverting commits for %s, added %4$s; removed %6$s.',
|
'%s edited reverting changes for %s, added %4$s; removed %6$s.',
|
||||||
|
|
||||||
'%s changed project member(s), added %d: %s; removed %d: %s.' =>
|
'%s changed project member(s), added %d: %s; removed %d: %s.' =>
|
||||||
'%s changed project members, added %3$s; removed %5$s.',
|
'%s changed project members, added %3$s; removed %5$s.',
|
||||||
|
|
|
@ -301,18 +301,14 @@ final class PHUITimelineEventView extends AphrontView {
|
||||||
|
|
||||||
$menu = null;
|
$menu = null;
|
||||||
$items = array();
|
$items = array();
|
||||||
$has_menu = false;
|
|
||||||
if (!$this->getIsPreview() && !$this->getHideCommentOptions()) {
|
if (!$this->getIsPreview() && !$this->getHideCommentOptions()) {
|
||||||
foreach ($this->getEventGroup() as $event) {
|
foreach ($this->getEventGroup() as $event) {
|
||||||
$items[] = $event->getMenuItems($this->anchor);
|
$items[] = $event->getMenuItems($this->anchor);
|
||||||
if ($event->hasChildren()) {
|
|
||||||
$has_menu = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$items = array_mergev($items);
|
$items = array_mergev($items);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($items || $has_menu) {
|
if ($items) {
|
||||||
$icon = id(new PHUIIconView())
|
$icon = id(new PHUIIconView())
|
||||||
->setIcon('fa-caret-down');
|
->setIcon('fa-caret-down');
|
||||||
$aural = javelin_tag(
|
$aural = javelin_tag(
|
||||||
|
@ -351,6 +347,8 @@ final class PHUITimelineEventView extends AphrontView {
|
||||||
));
|
));
|
||||||
|
|
||||||
$has_menu = true;
|
$has_menu = true;
|
||||||
|
} else {
|
||||||
|
$has_menu = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render "extra" information (timestamp, etc).
|
// Render "extra" information (timestamp, etc).
|
||||||
|
|
|
@ -390,10 +390,6 @@
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-timeline-menu .phui-icon-view {
|
|
||||||
color: {$lightgreytext};
|
|
||||||
}
|
|
||||||
|
|
||||||
a.phui-timeline-menu .phui-icon-view {
|
a.phui-timeline-menu .phui-icon-view {
|
||||||
color: {$bluetext};
|
color: {$bluetext};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue