From bdef58216e9c634b38fa47ecaf55e01443132c1b Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 12 Sep 2013 13:03:14 -0700 Subject: [PATCH] Restore project filtering to Maniphest "pro" search Summary: Restores any/all/user/exclude project filters to the new search. Test Plan: Filtered stuff by projects. Reviewers: btrahan Reviewed By: btrahan CC: aran Differential Revision: https://secure.phabricator.com/D6951 --- .../maniphest/query/ManiphestTaskQuery.php | 7 ++ .../query/ManiphestTaskSearchEngine.php | 117 ++++++++++++++++-- .../control/AphrontFormTokenizerControl.php | 10 ++ 3 files changed, 124 insertions(+), 10 deletions(-) diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php index 2256348f13..e39f0aeb2b 100644 --- a/src/applications/maniphest/query/ManiphestTaskQuery.php +++ b/src/applications/maniphest/query/ManiphestTaskQuery.php @@ -184,6 +184,13 @@ final class ManiphestTaskQuery } public function loadPage() { + + // TODO: (T603) It is possible for a user to find the PHID of a project + // they can't see, then query for tasks in that project and deduce the + // identity of unknown/invisible projects. Before we allow the user to + // execute a project-based PHID query, we should verify that they + // can see the project. + $task_dao = new ManiphestTask(); $conn = $task_dao->establishConnection('r'); diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php index c0b25d927c..a8836c0535 100644 --- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php +++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php @@ -33,6 +33,26 @@ final class ManiphestTaskSearchEngine $saved->setParameter('fulltext', $request->getStr('fulltext')); + $saved->setParameter( + 'allProjectPHIDs', + $request->getArr('allProjects')); + + $saved->setParameter( + 'withNoProject', + $request->getBool('withNoProject')); + + $saved->setParameter( + 'anyProjectPHIDs', + $request->getArr('anyProjects')); + + $saved->setParameter( + 'excludeProjectPHIDs', + $request->getArr('excludeProjects')); + + $saved->setParameter( + 'userProjectPHIDs', + $this->readUsersFromRequest($request, 'userProjects')); + return $saved; } @@ -82,6 +102,31 @@ final class ManiphestTaskSearchEngine $query->withFullTextSearch($fulltext); } + $with_no_project = $saved->getParameter('withNoProject'); + if ($with_no_project) { + $query->withAllProjects(array(ManiphestTaskOwner::PROJECT_NO_PROJECT)); + } else { + $project_phids = $saved->getParameter('allProjectPHIDs'); + if ($project_phids) { + $query->withAllProjects($project_phids); + } + } + + $any_project_phids = $saved->getParameter('anyProjectPHIDs'); + if ($any_project_phids) { + $query->withAnyProjects($any_project_phids); + } + + $exclude_project_phids = $saved->getParameter('excludeProjectPHIDs'); + if ($exclude_project_phids) { + $query->withoutProjects($exclude_project_phids); + } + + $user_project_phids = $saved->getParameter('userProjectPHIDs'); + if ($user_project_phids) { + $query->withAnyUserProjects($user_project_phids); + } + return $query; } @@ -91,8 +136,26 @@ final class ManiphestTaskSearchEngine $assigned_phids = $saved->getParameter('assignedPHIDs', array()); $author_phids = $saved->getParameter('authorPHIDs', array()); + $all_project_phids = $saved->getParameter( + 'allProjectPHIDs', + array()); + $any_project_phids = $saved->getParameter( + 'anyProjectPHIDs', + array()); + $exclude_project_phids = $saved->getParameter( + 'excludeProjectPHIDs', + array()); + $user_project_phids = $saved->getParameter( + 'userProjectPHIDs', + array()); - $all_phids = array_merge($assigned_phids, $author_phids); + $all_phids = array_merge( + $assigned_phids, + $author_phids, + $all_project_phids, + $any_project_phids, + $exclude_project_phids, + $user_project_phids); if ($all_phids) { $handles = id(new PhabricatorHandleQuery()) @@ -103,13 +166,17 @@ final class ManiphestTaskSearchEngine $handles = array(); } - $assigned_tokens = array_select_keys($handles, $assigned_phids); - $assigned_tokens = mpull($assigned_tokens, 'getFullName', 'getPHID'); - - $author_tokens = array_select_keys($handles, $author_phids); - $author_tokens = mpull($author_tokens, 'getFullName', 'getPHID'); + $assigned_handles = array_select_keys($handles, $assigned_phids); + $author_handles = array_select_keys($handles, $author_phids); + $all_project_handles = array_select_keys($handles, $all_project_phids); + $any_project_handles = array_select_keys($handles, $any_project_phids); + $exclude_project_handles = array_select_keys( + $handles, + $exclude_project_phids); + $user_project_handles = array_select_keys($handles, $user_project_phids); $with_unassigned = $saved->getParameter('withUnassigned'); + $with_no_projects = $saved->getParameter('withNoProject'); $statuses = $saved->getParameter('statuses', array()); $statuses = array_fuse($statuses); @@ -143,7 +210,7 @@ final class ManiphestTaskSearchEngine ->setDatasource('/typeahead/common/accounts/') ->setName('assigned') ->setLabel(pht('Assigned To')) - ->setValue($assigned_tokens)) + ->setValue($assigned_handles)) ->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( @@ -151,12 +218,43 @@ final class ManiphestTaskSearchEngine 1, pht('Show only unassigned tasks.'), $with_unassigned)) + ->appendChild( + id(new AphrontFormTokenizerControl()) + ->setDatasource('/typeahead/common/projects/') + ->setName('allProjects') + ->setLabel(pht('In All Projects')) + ->setValue($all_project_handles)) + ->appendChild( + id(new AphrontFormCheckboxControl()) + ->addCheckbox( + 'withNoProject', + 1, + pht('Show only tasks with no projects.'), + $with_no_projects)) + ->appendChild( + id(new AphrontFormTokenizerControl()) + ->setDatasource('/typeahead/common/projects/') + ->setName('anyProjects') + ->setLabel(pht('In Any Project')) + ->setValue($any_project_handles)) + ->appendChild( + id(new AphrontFormTokenizerControl()) + ->setDatasource('/typeahead/common/projects/') + ->setName('excludeProjects') + ->setLabel(pht('Not In Projects')) + ->setValue($exclude_project_handles)) + ->appendChild( + id(new AphrontFormTokenizerControl()) + ->setDatasource('/typeahead/common/accounts/') + ->setName('userProjects') + ->setLabel(pht('In Users\' Projects')) + ->setValue($user_project_handles)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/accounts/') ->setName('authors') ->setLabel(pht('Authors')) - ->setValue($author_tokens)) + ->setValue($author_handles)) ->appendChild($status_control) ->appendChild($priority_control) ->appendChild( @@ -214,8 +312,7 @@ final class ManiphestTaskSearchEngine ->setParameter('statuses', array(ManiphestTaskStatus::STATUS_OPEN)); case 'authored': return $query - ->setParameter('authorPHIDs', array($viewer_phid)) - ->setParameter('statuses', array(ManiphestTaskStatus::STATUS_OPEN)); + ->setParameter('authorPHIDs', array($viewer_phid)); } return parent::buildSavedQueryFromBuiltin($query_key); diff --git a/src/view/form/control/AphrontFormTokenizerControl.php b/src/view/form/control/AphrontFormTokenizerControl.php index d8d7ecdc18..f8670c9dbe 100644 --- a/src/view/form/control/AphrontFormTokenizerControl.php +++ b/src/view/form/control/AphrontFormTokenizerControl.php @@ -35,6 +35,16 @@ final class AphrontFormTokenizerControl extends AphrontFormControl { $name = $this->getName(); $values = nonempty($this->getValue(), array()); + // TODO: Convert tokenizers to always take raw handles. For now, we + // accept either a list of handles or a `map`. + try { + assert_instances_of($values, 'PhabricatorObjectHandle'); + $values = mpull($values, 'getFullName', 'getPHID'); + } catch (InvalidArgumentException $ex) { + // Ignore this, just use the values as provided. + } + + if ($this->getID()) { $id = $this->getID(); } else {