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:
parent
20e4c3fbd4
commit
621f806e3b
10 changed files with 248 additions and 7 deletions
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
46
src/applications/phid/resolver/PhabricatorPHIDResolver.php
Normal file
46
src/applications/phid/resolver/PhabricatorPHIDResolver.php
Normal 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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectsEditField
|
||||
extends PhabricatorTokenizerEditField {
|
||||
|
||||
protected function newDatasource() {
|
||||
return new PhabricatorProjectDatasource();
|
||||
}
|
||||
|
||||
protected function newHTTPParameterType() {
|
||||
return new AphrontProjectListHTTPParameterType();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUsersEditField
|
||||
extends PhabricatorTokenizerEditField {
|
||||
|
||||
protected function newDatasource() {
|
||||
return new PhabricatorPeopleDatasource();
|
||||
}
|
||||
|
||||
protected function newHTTPParameterType() {
|
||||
return new AphrontUserListHTTPParameterType();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue