1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 14:00:56 +01:00

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
This commit is contained in:
epriestley 2015-11-04 10:20:38 -08:00
parent 20e4c3fbd4
commit 621f806e3b
10 changed files with 248 additions and 7 deletions

View file

@ -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',

View file

@ -0,0 +1,42 @@
<?php
final class AphrontProjectListHTTPParameterType
extends AphrontHTTPParameterType {
protected function getParameterValue(AphrontRequest $request, $key) {
$type = new AphrontStringListHTTPParameterType();
$list = $this->getValueWithType($type, $request, $key);
return id(new PhabricatorProjectPHIDResolver())
->setViewer($this->getViewer())
->resolvePHIDs($list);
}
protected function getParameterTypeName() {
return 'list<project>';
}
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',
);
}
}

View file

@ -0,0 +1,42 @@
<?php
final class AphrontUserListHTTPParameterType
extends AphrontHTTPParameterType {
protected function getParameterValue(AphrontRequest $request, $key) {
$type = new AphrontStringListHTTPParameterType();
$list = $this->getValueWithType($type, $request, $key);
return id(new PhabricatorUserPHIDResolver())
->setViewer($this->getViewer())
->resolvePHIDs($list);
}
protected function getParameterTypeName() {
return 'list<user>';
}
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',
);
}
}

View file

@ -0,0 +1,46 @@
<?php
/**
* Resolve a list of identifiers into PHIDs.
*
* This class simplifies the process of convering a list of mixed token types
* (like some PHIDs and some usernames) into a list of just PHIDs.
*/
abstract class PhabricatorPHIDResolver extends Phobject {
private $viewer;
final public function setViewer(PhabricatorUser $viewer) {
$this->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);
}

View file

@ -0,0 +1,28 @@
<?php
final class PhabricatorProjectPHIDResolver
extends PhabricatorPHIDResolver {
protected function getResolutionMap(array $names) {
// This is a little awkward but we want to pick up the normalization
// rules from the PHIDType. This flow could perhaps be made cleaner.
foreach ($names as $key => $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;
}
}

View file

@ -0,0 +1,27 @@
<?php
final class PhabricatorUserPHIDResolver
extends PhabricatorPHIDResolver {
protected function getResolutionMap(array $names) {
// Pick up the normalization and case rules from the PHID type query.
foreach ($names as $key => $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;
}
}

View file

@ -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);

View file

@ -0,0 +1,14 @@
<?php
final class PhabricatorProjectsEditField
extends PhabricatorTokenizerEditField {
protected function newDatasource() {
return new PhabricatorProjectDatasource();
}
protected function newHTTPParameterType() {
return new AphrontProjectListHTTPParameterType();
}
}

View file

@ -0,0 +1,16 @@
<?php
final class PhabricatorSubscribersEditField
extends PhabricatorTokenizerEditField {
protected function newDatasource() {
return new PhabricatorMetaMTAMailableDatasource();
}
protected function newHTTPParameterType() {
// TODO: Implement a more expansive "Mailable" parameter type which
// accepts users or projects.
return new AphrontUserListHTTPParameterType();
}
}

View file

@ -0,0 +1,14 @@
<?php
final class PhabricatorUsersEditField
extends PhabricatorTokenizerEditField {
protected function newDatasource() {
return new PhabricatorPeopleDatasource();
}
protected function newHTTPParameterType() {
return new AphrontUserListHTTPParameterType();
}
}