@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+248 -7
+16
src/__phutil_library_map__.php
··· 156 156 'AphrontPageView' => 'view/page/AphrontPageView.php', 157 157 'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php', 158 158 'AphrontProgressBarView' => 'view/widget/bars/AphrontProgressBarView.php', 159 + 'AphrontProjectListHTTPParameterType' => 'aphront/httpparametertype/AphrontProjectListHTTPParameterType.php', 159 160 'AphrontProxyResponse' => 'aphront/response/AphrontProxyResponse.php', 160 161 'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php', 161 162 'AphrontRedirectResponseTestCase' => 'aphront/response/__tests__/AphrontRedirectResponseTestCase.php', ··· 179 180 'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php', 180 181 'AphrontTypeaheadTemplateView' => 'view/control/AphrontTypeaheadTemplateView.php', 181 182 'AphrontUnhandledExceptionResponse' => 'aphront/response/AphrontUnhandledExceptionResponse.php', 183 + 'AphrontUserListHTTPParameterType' => 'aphront/httpparametertype/AphrontUserListHTTPParameterType.php', 182 184 'AphrontView' => 'view/AphrontView.php', 183 185 'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php', 184 186 'ArcanistConduitAPIMethod' => 'applications/arcanist/conduit/ArcanistConduitAPIMethod.php', ··· 2549 2551 'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php', 2550 2552 'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php', 2551 2553 'PhabricatorPHIDInterface' => 'applications/phid/interface/PhabricatorPHIDInterface.php', 2554 + 'PhabricatorPHIDResolver' => 'applications/phid/resolver/PhabricatorPHIDResolver.php', 2552 2555 'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php', 2553 2556 'PhabricatorPHIDTypeTestCase' => 'applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php', 2554 2557 'PhabricatorPHPASTApplication' => 'applications/phpast/application/PhabricatorPHPASTApplication.php', ··· 2738 2741 'PhabricatorProjectObjectHasProjectEdgeType' => 'applications/project/edge/PhabricatorProjectObjectHasProjectEdgeType.php', 2739 2742 'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php', 2740 2743 'PhabricatorProjectOrUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserFunctionDatasource.php', 2744 + 'PhabricatorProjectPHIDResolver' => 'applications/phid/resolver/PhabricatorProjectPHIDResolver.php', 2741 2745 'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php', 2742 2746 'PhabricatorProjectProjectHasMemberEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasMemberEdgeType.php', 2743 2747 'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php', ··· 2760 2764 'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php', 2761 2765 'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php', 2762 2766 'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php', 2767 + 'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php', 2763 2768 'PhabricatorProjectsPolicyRule' => 'applications/policy/rule/PhabricatorProjectsPolicyRule.php', 2764 2769 'PhabricatorProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorProtocolAdapter.php', 2765 2770 'PhabricatorPygmentSetupCheck' => 'applications/config/check/PhabricatorPygmentSetupCheck.php', ··· 3040 3045 'PhabricatorStreamingProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php', 3041 3046 'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php', 3042 3047 'PhabricatorSubscribedToObjectEdgeType' => 'applications/transactions/edges/PhabricatorSubscribedToObjectEdgeType.php', 3048 + 'PhabricatorSubscribersEditField' => 'applications/transactions/editfield/PhabricatorSubscribersEditField.php', 3043 3049 'PhabricatorSubscribersQuery' => 'applications/subscriptions/query/PhabricatorSubscribersQuery.php', 3044 3050 'PhabricatorSubscriptionTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorSubscriptionTriggerClock.php', 3045 3051 'PhabricatorSubscriptionsAddSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsAddSelfHeraldAction.php', ··· 3154 3160 'PhabricatorUserEmailTestCase' => 'applications/people/storage/__tests__/PhabricatorUserEmailTestCase.php', 3155 3161 'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php', 3156 3162 'PhabricatorUserLogView' => 'applications/people/view/PhabricatorUserLogView.php', 3163 + 'PhabricatorUserPHIDResolver' => 'applications/phid/resolver/PhabricatorUserPHIDResolver.php', 3157 3164 'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php', 3158 3165 'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php', 3159 3166 'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php', ··· 3166 3173 'PhabricatorUserTestCase' => 'applications/people/storage/__tests__/PhabricatorUserTestCase.php', 3167 3174 'PhabricatorUserTitleField' => 'applications/people/customfield/PhabricatorUserTitleField.php', 3168 3175 'PhabricatorUserTransaction' => 'applications/people/storage/PhabricatorUserTransaction.php', 3176 + 'PhabricatorUsersEditField' => 'applications/transactions/editfield/PhabricatorUsersEditField.php', 3169 3177 'PhabricatorUsersPolicyRule' => 'applications/policy/rule/PhabricatorUsersPolicyRule.php', 3170 3178 'PhabricatorUsersSearchField' => 'applications/people/searchfield/PhabricatorUsersSearchField.php', 3171 3179 'PhabricatorVCSResponse' => 'applications/repository/response/PhabricatorVCSResponse.php', ··· 3895 3903 'AphrontPageView' => 'AphrontView', 3896 3904 'AphrontPlainTextResponse' => 'AphrontResponse', 3897 3905 'AphrontProgressBarView' => 'AphrontBarView', 3906 + 'AphrontProjectListHTTPParameterType' => 'AphrontHTTPParameterType', 3898 3907 'AphrontProxyResponse' => array( 3899 3908 'AphrontResponse', 3900 3909 'AphrontResponseProducerInterface', ··· 3920 3929 'AphrontTokenizerTemplateView' => 'AphrontView', 3921 3930 'AphrontTypeaheadTemplateView' => 'AphrontView', 3922 3931 'AphrontUnhandledExceptionResponse' => 'AphrontStandaloneHTMLResponse', 3932 + 'AphrontUserListHTTPParameterType' => 'AphrontHTTPParameterType', 3923 3933 'AphrontView' => array( 3924 3934 'Phobject', 3925 3935 'PhutilSafeHTMLProducerInterface', ··· 6654 6664 'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions', 6655 6665 'PhabricatorPHID' => 'Phobject', 6656 6666 'PhabricatorPHIDConstants' => 'Phobject', 6667 + 'PhabricatorPHIDResolver' => 'Phobject', 6657 6668 'PhabricatorPHIDType' => 'Phobject', 6658 6669 'PhabricatorPHIDTypeTestCase' => 'PhutilTestCase', 6659 6670 'PhabricatorPHPASTApplication' => 'PhabricatorApplication', ··· 6891 6902 'PhabricatorProjectObjectHasProjectEdgeType' => 'PhabricatorEdgeType', 6892 6903 'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 6893 6904 'PhabricatorProjectOrUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 6905 + 'PhabricatorProjectPHIDResolver' => 'PhabricatorPHIDResolver', 6894 6906 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', 6895 6907 'PhabricatorProjectProjectHasMemberEdgeType' => 'PhabricatorEdgeType', 6896 6908 'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType', ··· 6916 6928 'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 6917 6929 'PhabricatorProjectViewController' => 'PhabricatorProjectController', 6918 6930 'PhabricatorProjectWatchController' => 'PhabricatorProjectController', 6931 + 'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField', 6919 6932 'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule', 6920 6933 'PhabricatorProtocolAdapter' => 'Phobject', 6921 6934 'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck', ··· 7252 7265 'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck', 7253 7266 'PhabricatorStreamingProtocolAdapter' => 'PhabricatorProtocolAdapter', 7254 7267 'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType', 7268 + 'PhabricatorSubscribersEditField' => 'PhabricatorTokenizerEditField', 7255 7269 'PhabricatorSubscribersQuery' => 'PhabricatorQuery', 7256 7270 'PhabricatorSubscriptionTriggerClock' => 'PhabricatorTriggerClock', 7257 7271 'PhabricatorSubscriptionsAddSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction', ··· 7386 7400 'PhabricatorPolicyInterface', 7387 7401 ), 7388 7402 'PhabricatorUserLogView' => 'AphrontView', 7403 + 'PhabricatorUserPHIDResolver' => 'PhabricatorPHIDResolver', 7389 7404 'PhabricatorUserPreferences' => 'PhabricatorUserDAO', 7390 7405 'PhabricatorUserProfile' => 'PhabricatorUserDAO', 7391 7406 'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor', ··· 7398 7413 'PhabricatorUserTestCase' => 'PhabricatorTestCase', 7399 7414 'PhabricatorUserTitleField' => 'PhabricatorUserCustomField', 7400 7415 'PhabricatorUserTransaction' => 'PhabricatorApplicationTransaction', 7416 + 'PhabricatorUsersEditField' => 'PhabricatorTokenizerEditField', 7401 7417 'PhabricatorUsersPolicyRule' => 'PhabricatorPolicyRule', 7402 7418 'PhabricatorUsersSearchField' => 'PhabricatorSearchTokenizerField', 7403 7419 'PhabricatorVCSResponse' => 'AphrontResponse',
+42
src/aphront/httpparametertype/AphrontProjectListHTTPParameterType.php
··· 1 + <?php 2 + 3 + final class AphrontProjectListHTTPParameterType 4 + extends AphrontHTTPParameterType { 5 + 6 + protected function getParameterValue(AphrontRequest $request, $key) { 7 + $type = new AphrontStringListHTTPParameterType(); 8 + $list = $this->getValueWithType($type, $request, $key); 9 + 10 + return id(new PhabricatorProjectPHIDResolver()) 11 + ->setViewer($this->getViewer()) 12 + ->resolvePHIDs($list); 13 + } 14 + 15 + protected function getParameterTypeName() { 16 + return 'list<project>'; 17 + } 18 + 19 + protected function getParameterFormatDescriptions() { 20 + return array( 21 + pht('Comma-separated list of project PHIDs.'), 22 + pht('List of project PHIDs, as array.'), 23 + pht('Comma-separated list of project hashtags.'), 24 + pht('List of project hashtags, as array.'), 25 + pht('Mixture of hashtags and PHIDs.'), 26 + ); 27 + } 28 + 29 + protected function getParameterExamples() { 30 + return array( 31 + 'v=PHID-PROJ-1111', 32 + 'v=PHID-PROJ-1111,PHID-PROJ-2222', 33 + 'v=hashtag', 34 + 'v=frontend,backend', 35 + 'v[]=PHID-PROJ-1111&v[]=PHID-PROJ-2222', 36 + 'v[]=frontend&v[]=backend', 37 + 'v=PHID-PROJ-1111,frontend', 38 + 'v[]=PHID-PROJ-1111&v[]=backend', 39 + ); 40 + } 41 + 42 + }
+42
src/aphront/httpparametertype/AphrontUserListHTTPParameterType.php
··· 1 + <?php 2 + 3 + final class AphrontUserListHTTPParameterType 4 + extends AphrontHTTPParameterType { 5 + 6 + protected function getParameterValue(AphrontRequest $request, $key) { 7 + $type = new AphrontStringListHTTPParameterType(); 8 + $list = $this->getValueWithType($type, $request, $key); 9 + 10 + return id(new PhabricatorUserPHIDResolver()) 11 + ->setViewer($this->getViewer()) 12 + ->resolvePHIDs($list); 13 + } 14 + 15 + protected function getParameterTypeName() { 16 + return 'list<user>'; 17 + } 18 + 19 + protected function getParameterFormatDescriptions() { 20 + return array( 21 + pht('Comma-separated list of user PHIDs.'), 22 + pht('List of user PHIDs, as array.'), 23 + pht('Comma-separated list of usernames.'), 24 + pht('List of usernames, as array.'), 25 + pht('Mixture of usernames and PHIDs.'), 26 + ); 27 + } 28 + 29 + protected function getParameterExamples() { 30 + return array( 31 + 'v=PHID-USER-1111', 32 + 'v=PHID-USER-1111,PHID-USER-2222', 33 + 'v=username', 34 + 'v=alincoln,htaft', 35 + 'v[]=PHID-USER-1111&v[]=PHID-USER-2222', 36 + 'v[]=htaft&v[]=alincoln', 37 + 'v=PHID-USER-1111,alincoln', 38 + 'v[]=PHID-USER-1111&v[]=htaft', 39 + ); 40 + } 41 + 42 + }
+46
src/applications/phid/resolver/PhabricatorPHIDResolver.php
··· 1 + <?php 2 + 3 + /** 4 + * Resolve a list of identifiers into PHIDs. 5 + * 6 + * This class simplifies the process of convering a list of mixed token types 7 + * (like some PHIDs and some usernames) into a list of just PHIDs. 8 + */ 9 + abstract class PhabricatorPHIDResolver extends Phobject { 10 + 11 + private $viewer; 12 + 13 + final public function setViewer(PhabricatorUser $viewer) { 14 + $this->viewer = $viewer; 15 + return $this; 16 + } 17 + 18 + final public function getViewer() { 19 + return $this->viewer; 20 + } 21 + 22 + final public function resolvePHIDs(array $phids) { 23 + $type_unknown = PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN; 24 + 25 + $names = array(); 26 + foreach ($phids as $key => $phid) { 27 + if (phid_get_type($phid) == $type_unknown) { 28 + $names[$key] = $phid; 29 + } 30 + } 31 + 32 + if ($names) { 33 + $map = $this->getResolutionMap($names); 34 + foreach ($names as $key => $name) { 35 + if (isset($map[$name])) { 36 + $phids[$key] = $map[$name]; 37 + } 38 + } 39 + } 40 + 41 + return $phids; 42 + } 43 + 44 + abstract protected function getResolutionMap(array $names); 45 + 46 + }
+28
src/applications/phid/resolver/PhabricatorProjectPHIDResolver.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectPHIDResolver 4 + extends PhabricatorPHIDResolver { 5 + 6 + protected function getResolutionMap(array $names) { 7 + // This is a little awkward but we want to pick up the normalization 8 + // rules from the PHIDType. This flow could perhaps be made cleaner. 9 + 10 + foreach ($names as $key => $name) { 11 + $names[$key] = '#'.$name; 12 + } 13 + 14 + $query = id(new PhabricatorObjectQuery()) 15 + ->setViewer($this->getViewer()); 16 + 17 + $projects = id(new PhabricatorProjectProjectPHIDType()) 18 + ->loadNamedObjects($query, $names); 19 + 20 + $results = array(); 21 + foreach ($projects as $hashtag => $project) { 22 + $results[substr($hashtag, 1)] = $project->getPHID(); 23 + } 24 + 25 + return $results; 26 + } 27 + 28 + }
+27
src/applications/phid/resolver/PhabricatorUserPHIDResolver.php
··· 1 + <?php 2 + 3 + final class PhabricatorUserPHIDResolver 4 + extends PhabricatorPHIDResolver { 5 + 6 + protected function getResolutionMap(array $names) { 7 + // Pick up the normalization and case rules from the PHID type query. 8 + 9 + foreach ($names as $key => $name) { 10 + $names[$key] = '@'.$name; 11 + } 12 + 13 + $query = id(new PhabricatorObjectQuery()) 14 + ->setViewer($this->getViewer()); 15 + 16 + $users = id(new PhabricatorPeopleUserPHIDType()) 17 + ->loadNamedObjects($query, $names); 18 + 19 + $results = array(); 20 + foreach ($users as $at_username => $user) { 21 + $results[substr($at_username, 1)] = $user->getPHID(); 22 + } 23 + 24 + return $results; 25 + } 26 + 27 + }
+3 -7
src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php
··· 146 146 $project_phids = array(); 147 147 } 148 148 149 - $edge_field = id(new PhabricatorDatasourceEditField()) 149 + $edge_field = id(new PhabricatorProjectsEditField()) 150 150 ->setKey('projectPHIDs') 151 151 ->setLabel(pht('Projects')) 152 152 ->setEditTypeKey('projects') 153 - ->setDescription( 154 - pht( 155 - 'Add or remove associated projects.')) 156 - ->setDatasource(new PhabricatorProjectDatasource()) 153 + ->setDescription(pht('Add or remove associated projects.')) 157 154 ->setAliases(array('project', 'projects')) 158 155 ->setTransactionType($edge_type) 159 156 ->setMetadataValue('edge:type', $project_edge_type) ··· 175 172 $sub_phids = array(); 176 173 } 177 174 178 - $subscribers_field = id(new PhabricatorDatasourceEditField()) 175 + $subscribers_field = id(new PhabricatorSubscribersEditField()) 179 176 ->setKey('subscriberPHIDs') 180 177 ->setLabel(pht('Subscribers')) 181 178 ->setEditTypeKey('subscribers') 182 179 ->setDescription(pht('Manage subscribers.')) 183 - ->setDatasource(new PhabricatorMetaMTAMailableDatasource()) 184 180 ->setAliases(array('subscriber', 'subscribers')) 185 181 ->setTransactionType($subscribers_type) 186 182 ->setValue($sub_phids);
+14
src/applications/transactions/editfield/PhabricatorProjectsEditField.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectsEditField 4 + extends PhabricatorTokenizerEditField { 5 + 6 + protected function newDatasource() { 7 + return new PhabricatorProjectDatasource(); 8 + } 9 + 10 + protected function newHTTPParameterType() { 11 + return new AphrontProjectListHTTPParameterType(); 12 + } 13 + 14 + }
+16
src/applications/transactions/editfield/PhabricatorSubscribersEditField.php
··· 1 + <?php 2 + 3 + final class PhabricatorSubscribersEditField 4 + extends PhabricatorTokenizerEditField { 5 + 6 + protected function newDatasource() { 7 + return new PhabricatorMetaMTAMailableDatasource(); 8 + } 9 + 10 + protected function newHTTPParameterType() { 11 + // TODO: Implement a more expansive "Mailable" parameter type which 12 + // accepts users or projects. 13 + return new AphrontUserListHTTPParameterType(); 14 + } 15 + 16 + }
+14
src/applications/transactions/editfield/PhabricatorUsersEditField.php
··· 1 + <?php 2 + 3 + final class PhabricatorUsersEditField 4 + extends PhabricatorTokenizerEditField { 5 + 6 + protected function newDatasource() { 7 + return new PhabricatorPeopleDatasource(); 8 + } 9 + 10 + protected function newHTTPParameterType() { 11 + return new AphrontUserListHTTPParameterType(); 12 + } 13 + 14 + }