From 621f806e3b54cd7feb83c8b5d6e1fd0501e2f62a Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 4 Nov 2015 10:20:38 -0800 Subject: [PATCH] Provide formal Users/Projects/Mailable fields for EditEngine Summary: Ref T9132. This allows you to prefill EditEngine forms with stuff like `?subscribers=epriestley`, and we'll figure out what you mean. Test Plan: - Did `/?subscribers=...` with various values (good, bad, mis-capitalized). - Did `/?projects=...` with various values (good, bad, mis-capitalized). - Reviewed documentation. - Reviewed {nav Config > HTTP Parameter Types}. Reviewers: chad Reviewed By: chad Maniphest Tasks: T9132 Differential Revision: https://secure.phabricator.com/D14404 --- src/__phutil_library_map__.php | 16 +++++++ .../AphrontProjectListHTTPParameterType.php | 42 +++++++++++++++++ .../AphrontUserListHTTPParameterType.php | 42 +++++++++++++++++ .../phid/resolver/PhabricatorPHIDResolver.php | 46 +++++++++++++++++++ .../PhabricatorProjectPHIDResolver.php | 28 +++++++++++ .../resolver/PhabricatorUserPHIDResolver.php | 27 +++++++++++ .../PhabricatorApplicationEditEngine.php | 10 ++-- .../PhabricatorProjectsEditField.php | 14 ++++++ .../PhabricatorSubscribersEditField.php | 16 +++++++ .../editfield/PhabricatorUsersEditField.php | 14 ++++++ 10 files changed, 248 insertions(+), 7 deletions(-) create mode 100644 src/aphront/httpparametertype/AphrontProjectListHTTPParameterType.php create mode 100644 src/aphront/httpparametertype/AphrontUserListHTTPParameterType.php create mode 100644 src/applications/phid/resolver/PhabricatorPHIDResolver.php create mode 100644 src/applications/phid/resolver/PhabricatorProjectPHIDResolver.php create mode 100644 src/applications/phid/resolver/PhabricatorUserPHIDResolver.php create mode 100644 src/applications/transactions/editfield/PhabricatorProjectsEditField.php create mode 100644 src/applications/transactions/editfield/PhabricatorSubscribersEditField.php create mode 100644 src/applications/transactions/editfield/PhabricatorUsersEditField.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7dd3352fdd..383edbc0ea 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -156,6 +156,7 @@ phutil_register_library_map(array( 'AphrontPageView' => 'view/page/AphrontPageView.php', 'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php', 'AphrontProgressBarView' => 'view/widget/bars/AphrontProgressBarView.php', + 'AphrontProjectListHTTPParameterType' => 'aphront/httpparametertype/AphrontProjectListHTTPParameterType.php', 'AphrontProxyResponse' => 'aphront/response/AphrontProxyResponse.php', 'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php', 'AphrontRedirectResponseTestCase' => 'aphront/response/__tests__/AphrontRedirectResponseTestCase.php', @@ -179,6 +180,7 @@ phutil_register_library_map(array( 'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php', 'AphrontTypeaheadTemplateView' => 'view/control/AphrontTypeaheadTemplateView.php', 'AphrontUnhandledExceptionResponse' => 'aphront/response/AphrontUnhandledExceptionResponse.php', + 'AphrontUserListHTTPParameterType' => 'aphront/httpparametertype/AphrontUserListHTTPParameterType.php', 'AphrontView' => 'view/AphrontView.php', 'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php', 'ArcanistConduitAPIMethod' => 'applications/arcanist/conduit/ArcanistConduitAPIMethod.php', @@ -2549,6 +2551,7 @@ phutil_register_library_map(array( 'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php', 'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php', 'PhabricatorPHIDInterface' => 'applications/phid/interface/PhabricatorPHIDInterface.php', + 'PhabricatorPHIDResolver' => 'applications/phid/resolver/PhabricatorPHIDResolver.php', 'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php', 'PhabricatorPHIDTypeTestCase' => 'applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php', 'PhabricatorPHPASTApplication' => 'applications/phpast/application/PhabricatorPHPASTApplication.php', @@ -2738,6 +2741,7 @@ phutil_register_library_map(array( 'PhabricatorProjectObjectHasProjectEdgeType' => 'applications/project/edge/PhabricatorProjectObjectHasProjectEdgeType.php', 'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php', 'PhabricatorProjectOrUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserFunctionDatasource.php', + 'PhabricatorProjectPHIDResolver' => 'applications/phid/resolver/PhabricatorProjectPHIDResolver.php', 'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php', 'PhabricatorProjectProjectHasMemberEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasMemberEdgeType.php', 'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php', @@ -2760,6 +2764,7 @@ phutil_register_library_map(array( 'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php', 'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php', 'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php', + 'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php', 'PhabricatorProjectsPolicyRule' => 'applications/policy/rule/PhabricatorProjectsPolicyRule.php', 'PhabricatorProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorProtocolAdapter.php', 'PhabricatorPygmentSetupCheck' => 'applications/config/check/PhabricatorPygmentSetupCheck.php', @@ -3040,6 +3045,7 @@ phutil_register_library_map(array( 'PhabricatorStreamingProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php', 'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php', 'PhabricatorSubscribedToObjectEdgeType' => 'applications/transactions/edges/PhabricatorSubscribedToObjectEdgeType.php', + 'PhabricatorSubscribersEditField' => 'applications/transactions/editfield/PhabricatorSubscribersEditField.php', 'PhabricatorSubscribersQuery' => 'applications/subscriptions/query/PhabricatorSubscribersQuery.php', 'PhabricatorSubscriptionTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorSubscriptionTriggerClock.php', 'PhabricatorSubscriptionsAddSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsAddSelfHeraldAction.php', @@ -3154,6 +3160,7 @@ phutil_register_library_map(array( 'PhabricatorUserEmailTestCase' => 'applications/people/storage/__tests__/PhabricatorUserEmailTestCase.php', 'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php', 'PhabricatorUserLogView' => 'applications/people/view/PhabricatorUserLogView.php', + 'PhabricatorUserPHIDResolver' => 'applications/phid/resolver/PhabricatorUserPHIDResolver.php', 'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php', 'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php', 'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php', @@ -3166,6 +3173,7 @@ phutil_register_library_map(array( 'PhabricatorUserTestCase' => 'applications/people/storage/__tests__/PhabricatorUserTestCase.php', 'PhabricatorUserTitleField' => 'applications/people/customfield/PhabricatorUserTitleField.php', 'PhabricatorUserTransaction' => 'applications/people/storage/PhabricatorUserTransaction.php', + 'PhabricatorUsersEditField' => 'applications/transactions/editfield/PhabricatorUsersEditField.php', 'PhabricatorUsersPolicyRule' => 'applications/policy/rule/PhabricatorUsersPolicyRule.php', 'PhabricatorUsersSearchField' => 'applications/people/searchfield/PhabricatorUsersSearchField.php', 'PhabricatorVCSResponse' => 'applications/repository/response/PhabricatorVCSResponse.php', @@ -3895,6 +3903,7 @@ phutil_register_library_map(array( 'AphrontPageView' => 'AphrontView', 'AphrontPlainTextResponse' => 'AphrontResponse', 'AphrontProgressBarView' => 'AphrontBarView', + 'AphrontProjectListHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontProxyResponse' => array( 'AphrontResponse', 'AphrontResponseProducerInterface', @@ -3920,6 +3929,7 @@ phutil_register_library_map(array( 'AphrontTokenizerTemplateView' => 'AphrontView', 'AphrontTypeaheadTemplateView' => 'AphrontView', 'AphrontUnhandledExceptionResponse' => 'AphrontStandaloneHTMLResponse', + 'AphrontUserListHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontView' => array( 'Phobject', 'PhutilSafeHTMLProducerInterface', @@ -6654,6 +6664,7 @@ phutil_register_library_map(array( 'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPHID' => 'Phobject', 'PhabricatorPHIDConstants' => 'Phobject', + 'PhabricatorPHIDResolver' => 'Phobject', 'PhabricatorPHIDType' => 'Phobject', 'PhabricatorPHIDTypeTestCase' => 'PhutilTestCase', 'PhabricatorPHPASTApplication' => 'PhabricatorApplication', @@ -6891,6 +6902,7 @@ phutil_register_library_map(array( 'PhabricatorProjectObjectHasProjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectOrUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', + 'PhabricatorProjectPHIDResolver' => 'PhabricatorPHIDResolver', 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', 'PhabricatorProjectProjectHasMemberEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType', @@ -6916,6 +6928,7 @@ phutil_register_library_map(array( 'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectViewController' => 'PhabricatorProjectController', 'PhabricatorProjectWatchController' => 'PhabricatorProjectController', + 'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField', 'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorProtocolAdapter' => 'Phobject', 'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck', @@ -7252,6 +7265,7 @@ phutil_register_library_map(array( 'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorStreamingProtocolAdapter' => 'PhabricatorProtocolAdapter', 'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType', + 'PhabricatorSubscribersEditField' => 'PhabricatorTokenizerEditField', 'PhabricatorSubscribersQuery' => 'PhabricatorQuery', 'PhabricatorSubscriptionTriggerClock' => 'PhabricatorTriggerClock', 'PhabricatorSubscriptionsAddSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction', @@ -7386,6 +7400,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', ), 'PhabricatorUserLogView' => 'AphrontView', + 'PhabricatorUserPHIDResolver' => 'PhabricatorPHIDResolver', 'PhabricatorUserPreferences' => 'PhabricatorUserDAO', 'PhabricatorUserProfile' => 'PhabricatorUserDAO', 'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor', @@ -7398,6 +7413,7 @@ phutil_register_library_map(array( 'PhabricatorUserTestCase' => 'PhabricatorTestCase', 'PhabricatorUserTitleField' => 'PhabricatorUserCustomField', 'PhabricatorUserTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorUsersEditField' => 'PhabricatorTokenizerEditField', 'PhabricatorUsersPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorUsersSearchField' => 'PhabricatorSearchTokenizerField', 'PhabricatorVCSResponse' => 'AphrontResponse', diff --git a/src/aphront/httpparametertype/AphrontProjectListHTTPParameterType.php b/src/aphront/httpparametertype/AphrontProjectListHTTPParameterType.php new file mode 100644 index 0000000000..fd7e0db5cd --- /dev/null +++ b/src/aphront/httpparametertype/AphrontProjectListHTTPParameterType.php @@ -0,0 +1,42 @@ +getValueWithType($type, $request, $key); + + return id(new PhabricatorProjectPHIDResolver()) + ->setViewer($this->getViewer()) + ->resolvePHIDs($list); + } + + protected function getParameterTypeName() { + return 'list'; + } + + protected function getParameterFormatDescriptions() { + return array( + pht('Comma-separated list of project PHIDs.'), + pht('List of project PHIDs, as array.'), + pht('Comma-separated list of project hashtags.'), + pht('List of project hashtags, as array.'), + pht('Mixture of hashtags and PHIDs.'), + ); + } + + protected function getParameterExamples() { + return array( + 'v=PHID-PROJ-1111', + 'v=PHID-PROJ-1111,PHID-PROJ-2222', + 'v=hashtag', + 'v=frontend,backend', + 'v[]=PHID-PROJ-1111&v[]=PHID-PROJ-2222', + 'v[]=frontend&v[]=backend', + 'v=PHID-PROJ-1111,frontend', + 'v[]=PHID-PROJ-1111&v[]=backend', + ); + } + +} diff --git a/src/aphront/httpparametertype/AphrontUserListHTTPParameterType.php b/src/aphront/httpparametertype/AphrontUserListHTTPParameterType.php new file mode 100644 index 0000000000..3254542115 --- /dev/null +++ b/src/aphront/httpparametertype/AphrontUserListHTTPParameterType.php @@ -0,0 +1,42 @@ +getValueWithType($type, $request, $key); + + return id(new PhabricatorUserPHIDResolver()) + ->setViewer($this->getViewer()) + ->resolvePHIDs($list); + } + + protected function getParameterTypeName() { + return 'list'; + } + + protected function getParameterFormatDescriptions() { + return array( + pht('Comma-separated list of user PHIDs.'), + pht('List of user PHIDs, as array.'), + pht('Comma-separated list of usernames.'), + pht('List of usernames, as array.'), + pht('Mixture of usernames and PHIDs.'), + ); + } + + protected function getParameterExamples() { + return array( + 'v=PHID-USER-1111', + 'v=PHID-USER-1111,PHID-USER-2222', + 'v=username', + 'v=alincoln,htaft', + 'v[]=PHID-USER-1111&v[]=PHID-USER-2222', + 'v[]=htaft&v[]=alincoln', + 'v=PHID-USER-1111,alincoln', + 'v[]=PHID-USER-1111&v[]=htaft', + ); + } + +} diff --git a/src/applications/phid/resolver/PhabricatorPHIDResolver.php b/src/applications/phid/resolver/PhabricatorPHIDResolver.php new file mode 100644 index 0000000000..9070139a0b --- /dev/null +++ b/src/applications/phid/resolver/PhabricatorPHIDResolver.php @@ -0,0 +1,46 @@ +viewer = $viewer; + return $this; + } + + final public function getViewer() { + return $this->viewer; + } + + final public function resolvePHIDs(array $phids) { + $type_unknown = PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN; + + $names = array(); + foreach ($phids as $key => $phid) { + if (phid_get_type($phid) == $type_unknown) { + $names[$key] = $phid; + } + } + + if ($names) { + $map = $this->getResolutionMap($names); + foreach ($names as $key => $name) { + if (isset($map[$name])) { + $phids[$key] = $map[$name]; + } + } + } + + return $phids; + } + + abstract protected function getResolutionMap(array $names); + +} diff --git a/src/applications/phid/resolver/PhabricatorProjectPHIDResolver.php b/src/applications/phid/resolver/PhabricatorProjectPHIDResolver.php new file mode 100644 index 0000000000..7abecd730b --- /dev/null +++ b/src/applications/phid/resolver/PhabricatorProjectPHIDResolver.php @@ -0,0 +1,28 @@ + $name) { + $names[$key] = '#'.$name; + } + + $query = id(new PhabricatorObjectQuery()) + ->setViewer($this->getViewer()); + + $projects = id(new PhabricatorProjectProjectPHIDType()) + ->loadNamedObjects($query, $names); + + $results = array(); + foreach ($projects as $hashtag => $project) { + $results[substr($hashtag, 1)] = $project->getPHID(); + } + + return $results; + } + +} diff --git a/src/applications/phid/resolver/PhabricatorUserPHIDResolver.php b/src/applications/phid/resolver/PhabricatorUserPHIDResolver.php new file mode 100644 index 0000000000..a2a75fe310 --- /dev/null +++ b/src/applications/phid/resolver/PhabricatorUserPHIDResolver.php @@ -0,0 +1,27 @@ + $name) { + $names[$key] = '@'.$name; + } + + $query = id(new PhabricatorObjectQuery()) + ->setViewer($this->getViewer()); + + $users = id(new PhabricatorPeopleUserPHIDType()) + ->loadNamedObjects($query, $names); + + $results = array(); + foreach ($users as $at_username => $user) { + $results[substr($at_username, 1)] = $user->getPHID(); + } + + return $results; + } + +} diff --git a/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php b/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php index d459731fc7..86a03b51f4 100644 --- a/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php @@ -146,14 +146,11 @@ abstract class PhabricatorApplicationEditEngine extends Phobject { $project_phids = array(); } - $edge_field = id(new PhabricatorDatasourceEditField()) + $edge_field = id(new PhabricatorProjectsEditField()) ->setKey('projectPHIDs') ->setLabel(pht('Projects')) ->setEditTypeKey('projects') - ->setDescription( - pht( - 'Add or remove associated projects.')) - ->setDatasource(new PhabricatorProjectDatasource()) + ->setDescription(pht('Add or remove associated projects.')) ->setAliases(array('project', 'projects')) ->setTransactionType($edge_type) ->setMetadataValue('edge:type', $project_edge_type) @@ -175,12 +172,11 @@ abstract class PhabricatorApplicationEditEngine extends Phobject { $sub_phids = array(); } - $subscribers_field = id(new PhabricatorDatasourceEditField()) + $subscribers_field = id(new PhabricatorSubscribersEditField()) ->setKey('subscriberPHIDs') ->setLabel(pht('Subscribers')) ->setEditTypeKey('subscribers') ->setDescription(pht('Manage subscribers.')) - ->setDatasource(new PhabricatorMetaMTAMailableDatasource()) ->setAliases(array('subscriber', 'subscribers')) ->setTransactionType($subscribers_type) ->setValue($sub_phids); diff --git a/src/applications/transactions/editfield/PhabricatorProjectsEditField.php b/src/applications/transactions/editfield/PhabricatorProjectsEditField.php new file mode 100644 index 0000000000..60e497b4d2 --- /dev/null +++ b/src/applications/transactions/editfield/PhabricatorProjectsEditField.php @@ -0,0 +1,14 @@ +