@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.

Show login page if a search token requires a valid viewer

Summary:
A saved query can have tokens that require a valid current viewer. For example, this token:

viewer()

Before this change, visiting such saved queries would cause this:

This datasource ("PhabricatorPeopleUserFunctionDatasource") can not evaluate the function "viewer(...)".

After this change, instead of that, you are just redirected to the login page,
so, after you do the login, you are redirected back to that saved query and it works.

This fix was boosted during the Wikimedia Hackaton (wmhack) in Tallinn. Thanks Tallinn!

https://phabricator.wikimedia.org/T356384

Fixes T15704

Test Plan:
Go to Maniphest > Advanced Search > Assigned to > "Viewer". It still works.

Visit the same page in a new anonymous tab: now it redirects to the login page. You login,
and that page works again.

Do the same specific test for all these cases:

- Maniphest
- Assigned To: viewer
- Tags: current Viewer's Projects
- Authors: viewer
- Subscribers: ...
- Closed by
- Badges
- Subscribers
- Differential
- Responsible Users
- Authors
- Reviewers
- Subscribers
- Tags
- Dashboards
- Authored By
- Tags
- Dashboard Panels
- Authored By
- Dashboard Portals
- Tags
- Calendar:
- Hosts
- Invited
- Subscribers
- Tags
- Countdown
- Authors
- Diffusion
- Tags
- Subscribers
- Tags
- Diffusion commit
- Responsible Users
- Authors
- Subscribers
- Tags
- Diffusion identities
- Matching Users
- Feed
- Include Users
- Include Projects (interestingly it does not support "current Viewer's Projects")
- Files
- Authors
- Herald
- Authors
- Subscribers
- Legalpad
- Subscribers
- Nuance (none of their entity support search by token)
- Passphrase
- Subscribers
- Paste
- Authors
- Subscribers
- Tags
- Phame
- Subscribers
- Tags
- Pholio
- Authors
- Subscribers
- Tags
- Phrequent
- Users (interestingly it does not support "viewer")
- Ponder
- Authors
- Answered By
- Projects
- Members
- Watchers
- Transactions - /feed/transactions/
- Authors
- General search at /search/query/
- Authors
- Owners
- Subscribers
- Tags

All the above fields were tested in a clean search, one at a time, both logged-in and logged-out, with the function "viewer" or anything similar like "current Viewer's Projects":

For all cases, the login page appeared successfully where needed, instead of a crash.

Reviewers: O1 Blessed Committers, aklapper

Reviewed By: O1 Blessed Committers, aklapper

Subscribers: aklapper, avivey, tobiaswiese, Matthew, Cigaryno

Maniphest Tasks: T15704

Differential Revision: https://we.phorge.it/D25621

+75 -8
+2
src/__phutil_library_map__.php
··· 5078 5078 'PhabricatorTypeaheadDatasourceTestCase' => 'applications/typeahead/datasource/__tests__/PhabricatorTypeaheadDatasourceTestCase.php', 5079 5079 'PhabricatorTypeaheadFunctionHelpController' => 'applications/typeahead/controller/PhabricatorTypeaheadFunctionHelpController.php', 5080 5080 'PhabricatorTypeaheadInvalidTokenException' => 'applications/typeahead/exception/PhabricatorTypeaheadInvalidTokenException.php', 5081 + 'PhabricatorTypeaheadLoginRequiredException' => 'applications/typeahead/exception/PhabricatorTypeaheadLoginRequiredException.php', 5081 5082 'PhabricatorTypeaheadModularDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php', 5082 5083 'PhabricatorTypeaheadMonogramDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php', 5083 5084 'PhabricatorTypeaheadProxyDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadProxyDatasource.php', ··· 11819 11820 'PhabricatorTypeaheadDatasourceTestCase' => 'PhabricatorTestCase', 11820 11821 'PhabricatorTypeaheadFunctionHelpController' => 'PhabricatorTypeaheadDatasourceController', 11821 11822 'PhabricatorTypeaheadInvalidTokenException' => 'Exception', 11823 + 'PhabricatorTypeaheadLoginRequiredException' => 'Exception', 11822 11824 'PhabricatorTypeaheadModularDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 11823 11825 'PhabricatorTypeaheadMonogramDatasource' => 'PhabricatorTypeaheadDatasource', 11824 11826 'PhabricatorTypeaheadProxyDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
+6 -2
src/applications/calendar/typeahead/PhabricatorCalendarInviteeViewerFunctionDatasource.php
··· 28 28 ); 29 29 } 30 30 31 + protected function isFunctionWithLoginRequired($function) { 32 + return true; 33 + } 34 + 31 35 public function loadResults() { 32 - if ($this->getViewer()->getPHID()) { 36 + if ($this->getViewer()->isLoggedIn()) { 33 37 $results = array($this->renderViewerFunctionToken()); 34 38 } else { 35 39 $results = array(); ··· 39 43 } 40 44 41 45 protected function canEvaluateFunction($function) { 42 - if (!$this->getViewer()->getPHID()) { 46 + if (!$this->getViewer()->isLoggedIn()) { 43 47 return false; 44 48 } 45 49
+6 -2
src/applications/differential/typeahead/DifferentialResponsibleViewerFunctionDatasource.php
··· 28 28 ); 29 29 } 30 30 31 + protected function isFunctionWithLoginRequired($function) { 32 + return true; 33 + } 34 + 31 35 public function loadResults() { 32 - if ($this->getViewer()->getPHID()) { 36 + if ($this->getViewer()->isLoggedIn()) { 33 37 $results = array($this->renderViewerFunctionToken()); 34 38 } else { 35 39 $results = array(); ··· 39 43 } 40 44 41 45 protected function canEvaluateFunction($function) { 42 - if (!$this->getViewer()->getPHID()) { 46 + if (!$this->getViewer()->isLoggedIn()) { 43 47 return false; 44 48 } 45 49
+6 -2
src/applications/people/typeahead/PhabricatorViewerDatasource.php
··· 34 34 ); 35 35 } 36 36 37 + protected function isFunctionWithLoginRequired($function) { 38 + return true; 39 + } 40 + 37 41 public function loadResults() { 38 - if ($this->getViewer()->getPHID()) { 42 + if ($this->getViewer()->isLoggedIn()) { 39 43 $results = array($this->renderViewerFunctionToken()); 40 44 } else { 41 45 $results = array(); ··· 45 49 } 46 50 47 51 protected function canEvaluateFunction($function) { 48 - if (!$this->getViewer()->getPHID()) { 52 + if (!$this->getViewer()->isLoggedIn()) { 49 53 return false; 50 54 } 51 55
+6 -2
src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php
··· 35 35 ); 36 36 } 37 37 38 + protected function isFunctionWithLoginRequired($function) { 39 + return true; 40 + } 41 + 38 42 public function loadResults() { 39 - if ($this->getViewer()->getPHID()) { 43 + if ($this->getViewer()->isLoggedIn()) { 40 44 $results = array($this->renderViewerProjectsFunctionToken()); 41 45 } else { 42 46 $results = array(); ··· 46 50 } 47 51 48 52 protected function canEvaluateFunction($function) { 49 - if (!$this->getViewer()->getPHID()) { 53 + if (!$this->getViewer()->isLoggedIn()) { 50 54 return false; 51 55 } 52 56
+9
src/applications/search/controller/PhabricatorApplicationSearchController.php
··· 346 346 $body[] = $pager_box; 347 347 } 348 348 } 349 + } catch (PhabricatorTypeaheadLoginRequiredException $ex) { 350 + 351 + // A specific token requires login. Show login page. 352 + $auth_class = PhabricatorAuthApplication::class; 353 + $auth_application = PhabricatorApplication::getByClass($auth_class); 354 + $login_controller = new PhabricatorAuthStartController(); 355 + $this->setCurrentApplication($auth_application); 356 + return $this->delegateToController($login_controller); 357 + 349 358 } catch (PhabricatorTypeaheadInvalidTokenException $ex) { 350 359 $exec_errors[] = pht( 351 360 'This query specifies an invalid parameter. Review the '.
+9
src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
··· 304 304 return parent::evaluateFunction($function, $argv); 305 305 } 306 306 307 + protected function isFunctionWithLoginRequired($function) { 308 + foreach ($this->getUsableDatasources() as $source) { 309 + if ($source->isFunctionWithLoginRequired($function)) { 310 + return true; 311 + } 312 + } 313 + return parent::isFunctionWithLoginRequired($function); 314 + } 315 + 307 316 public function renderFunctionTokens($function, array $argv_list) { 308 317 foreach ($this->getUsableDatasources() as $source) { 309 318 if ($source->canEvaluateFunction($function)) {
+25
src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
··· 366 366 367 367 368 368 /** 369 + * Check if this datasource requires a logged-in viewer. 370 + * @task functions 371 + * @param string $function Function name. 372 + * @return bool 373 + */ 374 + protected function isFunctionWithLoginRequired($function) { 375 + // This is just a default. 376 + // Make sure to override this method to require login. 377 + return false; 378 + } 379 + 380 + 381 + /** 369 382 * @task functions 370 383 */ 371 384 protected function canEvaluateFunction($function) { ··· 498 511 499 512 if (!$this->canEvaluateFunction($function)) { 500 513 if (!$allow_partial) { 514 + 515 + if ($this->isFunctionWithLoginRequired($function)) { 516 + if (!$this->getViewer() || !$this->getViewer()->isLoggedIn()) { 517 + throw new PhabricatorTypeaheadLoginRequiredException( 518 + pht( 519 + 'This datasource ("%s") requires to be logged-in to use the '. 520 + 'function "%s(...)".', 521 + get_class($this), 522 + $function)); 523 + } 524 + } 525 + 501 526 throw new PhabricatorTypeaheadInvalidTokenException( 502 527 pht( 503 528 'This datasource ("%s") can not evaluate the function "%s(...)".',
+6
src/applications/typeahead/exception/PhabricatorTypeaheadLoginRequiredException.php
··· 1 + <?php 2 + 3 + /** 4 + * Exception thrown when a specific typehead requires login to be used. 5 + */ 6 + final class PhabricatorTypeaheadLoginRequiredException extends Exception {}