diff --git a/src/applications/phid/conduit/ConduitAPI_phid_lookup_Method.php b/src/applications/phid/conduit/ConduitAPI_phid_lookup_Method.php index d69987afd8..ea602ec3cb 100644 --- a/src/applications/phid/conduit/ConduitAPI_phid_lookup_Method.php +++ b/src/applications/phid/conduit/ConduitAPI_phid_lookup_Method.php @@ -1,52 +1,52 @@ 'required list', ); } public function defineReturnType() { return 'nonempty dict'; } public function defineErrorTypes() { return array(); } protected function execute(ConduitAPIRequest $request) { $names = $request->getValue('names'); $phids = array(); foreach ($names as $name) { - $phid = PhabricatorPHID::fromObjectName($name); + $phid = PhabricatorPHID::fromObjectName($name, $request->getUser()); if ($phid) { $phids[$name] = $phid; } } $handles = id(new PhabricatorObjectHandleData($phids)) ->setViewer($request->getUser()) ->loadHandles(); $result = array(); foreach ($phids as $name => $phid) { if (isset($handles[$phid]) && $handles[$phid]->isComplete()) { $result[$name] = $this->buildHandleInformationDictionary( $handles[$phid]); } } return $result; } } diff --git a/src/applications/phid/storage/PhabricatorPHID.php b/src/applications/phid/storage/PhabricatorPHID.php index 2e8d114318..5f32bd15ab 100644 --- a/src/applications/phid/storage/PhabricatorPHID.php +++ b/src/applications/phid/storage/PhabricatorPHID.php @@ -1,65 +1,73 @@ loadOneWhere('callsign = %s', $match[1]); if ($match[2] == '') { $object = $repository; } else if ($repository) { $object = id(new PhabricatorRepositoryCommit())->loadOneWhere( 'repositoryID = %d AND commitIdentifier = %s', $repository->getID(), $match[2]); if (!$object) { try { $object = id(new PhabricatorRepositoryCommit())->loadOneWhere( 'repositoryID = %d AND commitIdentifier LIKE %>', $repository->getID(), $match[2]); } catch (AphrontQueryCountException $ex) { // Ambiguous; return nothing. } } } } else if (preg_match('/^d(\d+)$/i', $name, $match)) { $object = id(new DifferentialRevision())->load($match[1]); } else if (preg_match('/^t(\d+)$/i', $name, $match)) { $object = id(new ManiphestTask())->load($match[1]); + } else if (preg_match('/^m(\d+)$/i', $name, $match)) { + $objects = id(new PholioMockQuery()) + ->setViewer($viewer) + ->withIDs(array($match[1])) + ->execute(); + $object = head($objects); } + if ($object) { return $object->getPHID(); } + return null; } } diff --git a/src/applications/search/controller/PhabricatorSearchController.php b/src/applications/search/controller/PhabricatorSearchController.php index 2293c97c0c..6bb6654d01 100644 --- a/src/applications/search/controller/PhabricatorSearchController.php +++ b/src/applications/search/controller/PhabricatorSearchController.php @@ -1,272 +1,272 @@ key = idx($data, 'key'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->key) { $query = id(new PhabricatorSearchQuery())->loadOneWhere( 'queryKey = %s', $this->key); if (!$query) { return new Aphront404Response(); } } else { $query = new PhabricatorSearchQuery(); if ($request->isFormPost()) { $query_str = $request->getStr('query'); $pref_jump = PhabricatorUserPreferences::PREFERENCE_SEARCHBAR_JUMP; if ($request->getStr('jump') != 'no' && $user && $user->loadPreferences()->getPreference($pref_jump, 1)) { $response = PhabricatorJumpNavHandler::jumpPostResponse($query_str); } else { $response = null; } if ($response) { return $response; } else { $query->setQuery($query_str); if ($request->getStr('scope')) { switch ($request->getStr('scope')) { case PhabricatorSearchScope::SCOPE_OPEN_REVISIONS: $query->setParameter('open', 1); $query->setParameter( 'type', PhabricatorPHIDConstants::PHID_TYPE_DREV); break; case PhabricatorSearchScope::SCOPE_OPEN_TASKS: $query->setParameter('open', 1); $query->setParameter( 'type', PhabricatorPHIDConstants::PHID_TYPE_TASK); break; case PhabricatorSearchScope::SCOPE_WIKI: $query->setParameter( 'type', PhabricatorPHIDConstants::PHID_TYPE_WIKI); break; case PhabricatorSearchScope::SCOPE_COMMITS: $query->setParameter( 'type', PhabricatorPHIDConstants::PHID_TYPE_CMIT); break; default: break; } } else { if (strlen($request->getStr('type'))) { $query->setParameter('type', $request->getStr('type')); } if ($request->getArr('author')) { $query->setParameter('author', $request->getArr('author')); } if ($request->getArr('owner')) { $query->setParameter('owner', $request->getArr('owner')); } if ($request->getArr('subscribers')) { $query->setParameter('subscribers', $request->getArr('subscribers')); } if ($request->getInt('open')) { $query->setParameter('open', $request->getInt('open')); } if ($request->getArr('project')) { $query->setParameter('project', $request->getArr('project')); } } $query->save(); return id(new AphrontRedirectResponse()) ->setURI('/search/'.$query->getQueryKey().'/'); } } } $options = array( '' => 'All Documents', ) + PhabricatorSearchAbstractDocument::getSupportedTypes(); $status_options = array( 0 => 'Open and Closed Documents', 1 => 'Open Documents', ); $phids = array_merge( $query->getParameter('author', array()), $query->getParameter('owner', array()), $query->getParameter('subscribers', array()), $query->getParameter('project', array())); $handles = $this->loadViewerHandles($phids); $author_value = array_select_keys( $handles, $query->getParameter('author', array())); $author_value = mpull($author_value, 'getFullName', 'getPHID'); $owner_value = array_select_keys( $handles, $query->getParameter('owner', array())); $owner_value = mpull($owner_value, 'getFullName', 'getPHID'); $subscribers_value = array_select_keys( $handles, $query->getParameter('subscribers', array())); $subscribers_value = mpull($subscribers_value, 'getFullName', 'getPHID'); $project_value = array_select_keys( $handles, $query->getParameter('project', array())); $project_value = mpull($project_value, 'getFullName', 'getPHID'); $search_form = new AphrontFormView(); $search_form ->setUser($user) ->setAction('/search/') ->appendChild( phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'jump', 'value' => 'no', ))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Search') ->setName('query') ->setValue($query->getQuery())) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Document Type') ->setName('type') ->setOptions($options) ->setValue($query->getParameter('type'))) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Document Status') ->setName('open') ->setOptions($status_options) ->setValue($query->getParameter('open'))) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('author') ->setLabel('Author') ->setDatasource('/typeahead/common/users/') ->setValue($author_value)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('owner') ->setLabel('Owner') ->setDatasource('/typeahead/common/searchowner/') ->setValue($owner_value) ->setCaption( 'Tip: search for "Up For Grabs" to find unowned documents.')) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('subscribers') ->setLabel('Subscribers') ->setDatasource('/typeahead/common/users/') ->setValue($subscribers_value)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('project') ->setLabel('Project') ->setDatasource('/typeahead/common/projects/') ->setValue($project_value)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Search')); $search_panel = new AphrontPanelView(); $search_panel->setHeader('Search Phabricator'); $search_panel->appendChild($search_form); require_celerity_resource('phabricator-search-results-css'); if ($query->getID()) { $limit = 20; $pager = new AphrontPagerView(); $pager->setURI($request->getRequestURI(), 'page'); $pager->setPageSize($limit); $pager->setOffset($request->getInt('page')); $query->setParameter('limit', $limit + 1); $query->setParameter('offset', $pager->getOffset()); $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); $results = $engine->executeSearch($query); $results = $pager->sliceResults($results); if (!$request->getInt('page')) { - $jump = PhabricatorPHID::fromObjectName($query->getQuery()); + $jump = PhabricatorPHID::fromObjectName($query->getQuery(), $user); if ($jump) { array_unshift($results, $jump); } } if ($results) { $loader = id(new PhabricatorObjectHandleData($results)) ->setViewer($user); $handles = $loader->loadHandles(); $objects = $loader->loadObjects(); $results = array(); foreach ($handles as $phid => $handle) { $view = id(new PhabricatorSearchResultView()) ->setHandle($handle) ->setQuery($query) ->setObject(idx($objects, $phid)); $results[] = $view->render(); } $results = hsprintf( '
'. '%s'. '
%s
'. '
', phutil_implode_html("\n", $results), $pager->render()); } else { $results = hsprintf( '
'. '

No search results.

'. '
'); } } else { $results = null; } return $this->buildStandardPageResponse( array( $search_panel, $results, ), array( 'title' => 'Search Results', )); } } diff --git a/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php b/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php index acd0b6108a..10863b3c60 100644 --- a/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php +++ b/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php @@ -1,136 +1,138 @@ setName('index') ->setSynopsis('Build or rebuild search indexes.') ->setExamples( "**index** D123\n". "**index** --type DREV\n". "**index** --all") ->setArguments( array( array( 'name' => 'all', 'help' => 'Reindex all documents.', ), array( 'name' => 'type', 'param' => 'TYPE', 'help' => 'PHID type to reindex, like "TASK" or "DREV".', ), array( 'name' => 'background', 'help' => 'Instead of indexing in this process, queue tasks for '. 'the daemons. This is better if you are indexing a lot '. 'of stuff, but less helpful for debugging.', ), array( 'name' => 'foreground', 'help' => 'Index in this process, even if there are many objects '. 'to index. This is helpful for debugging.', ), array( 'name' => 'objects', 'wildcard' => true, ), )); } public function execute(PhutilArgumentParser $args) { $console = PhutilConsole::getConsole(); $is_all = $args->getArg('all'); $is_type = $args->getArg('type'); $obj_names = $args->getArg('objects'); if ($obj_names && ($is_all || $is_type)) { throw new PhutilArgumentUsageException( "You can not name objects to index alongside the '--all' or '--type' ". "flags."); } else if (!$obj_names && !($is_all || $is_type)) { throw new PhutilArgumentUsageException( "Provide one of '--all', '--type' or a list of object names."); } if ($obj_names) { $phids = $this->loadPHIDsByNames($obj_names); } else { $phids = $this->loadPHIDsByTypes($is_type); } if (!$phids) { throw new PhutilArgumentUsageException( "Nothing to index!"); } $groups = phid_group_by_type($phids); foreach ($groups as $group_type => $group) { $console->writeOut( pht( "Indexing %d object(s) of type %s.", count($group), $group_type)."\n"); } $indexer = new PhabricatorSearchIndexer(); foreach ($phids as $phid) { $indexer->indexDocumentByPHID($phid); $console->writeOut(pht("Indexing '%s'...\n", $phid)); } $console->writeOut("Done.\n"); } private function loadPHIDsByNames(array $names) { $phids = array(); foreach ($names as $name) { - $phid = PhabricatorPHID::fromObjectName($name); + $phid = PhabricatorPHID::fromObjectName( + $name, + PhabricatorUser::getOmnipotentUser()); if (!$phid) { throw new PhutilArgumentUsageException( "'{$name}' is not the name of a known object."); } $phids[] = $phid; } return $phids; } private function loadPHIDsByTypes($type) { $indexer_symbols = id(new PhutilSymbolLoader()) ->setAncestorClass('PhabricatorSearchDocumentIndexer') ->setConcreteOnly(true) ->setType('class') ->selectAndLoadSymbols(); $indexers = array(); foreach ($indexer_symbols as $symbol) { $indexers[] = newv($symbol['name'], array()); } $phids = array(); foreach ($indexers as $indexer) { $indexer_phid = $indexer->getIndexableObject()->generatePHID(); $indexer_type = phid_get_type($indexer_phid); if ($type && ($indexer_type != $type)) { continue; } $iterator = $indexer->getIndexIterator(); foreach ($iterator as $object) { $phids[] = $object->getPHID(); } } return $phids; } } diff --git a/src/infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php b/src/infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php index 588bd39017..4f43b04399 100644 --- a/src/infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php +++ b/src/infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php @@ -1,194 +1,193 @@ getCommand()) { case 'MESSAGE': $message = $original_message->getBody(); $matches = null; + $paste_ids = array(); + $commit_names = array(); + $vote_ids = array(); + $file_ids = array(); + $object_names = array(); + $output = array(); + $pattern = '@'. - '(?getConduit()->callMethodSynchronous( - 'differential.query', + if ($object_names) { + $objects = $this->getConduit()->callMethodSynchronous( + 'phid.lookup', array( - 'ids' => $revision_ids, + 'names' => $object_names, )); - $revisions = array_select_keys( - ipull($revisions, null, 'id'), - $revision_ids); - foreach ($revisions as $revision) { - $output[$revision['phid']] = - 'D'.$revision['id'].' '.$revision['title'].' - '. - $revision['uri']; - } - } - - if ($task_ids) { - foreach ($task_ids as $task_id) { - if ($task_id == 1000) { - $output[1000] = 'T1000: A nanomorph mimetic poly-alloy' - .'(liquid metal) assassin controlled by Skynet: ' - .'http://en.wikipedia.org/wiki/T-1000'; - continue; - } - $task = $this->getConduit()->callMethodSynchronous( - 'maniphest.info', - array( - 'task_id' => $task_id, - )); - $output[$task['phid']] = 'T'.$task['id'].': '.$task['title']. - ' (Priority: '.$task['priority'].') - '.$task['uri']; + foreach ($objects as $object) { + $output[$object['phid']] = $object['fullName'].' - '.$object['uri']; } } if ($vote_ids) { foreach ($vote_ids as $vote_id) { $vote = $this->getConduit()->callMethodSynchronous( 'slowvote.info', array( 'poll_id' => $vote_id, )); $output[$vote['phid']] = 'V'.$vote['id'].': '.$vote['question']. ' Come Vote '.$vote['uri']; } } if ($file_ids) { foreach ($file_ids as $file_id) { $file = $this->getConduit()->callMethodSynchronous( 'file.info', array( 'id' => $file_id, )); $output[$file['phid']] = $file['objectName'].": ".$file['uri']." - ". $file['name']; } } if ($paste_ids) { foreach ($paste_ids as $paste_id) { $paste = $this->getConduit()->callMethodSynchronous( 'paste.info', array( 'paste_id' => $paste_id, )); // Eventually I'd like to show the username of the paster as well, // however that will need something like a user.username_from_phid // since we (ideally) want to keep the bot to Conduit calls...and // not call to Phabricator-specific stuff (like actually loading // the User object and fetching his/her username.) $output[$paste['phid']] = 'P'.$paste['id'].': '.$paste['uri'].' - '. $paste['title']; if ($paste['language']) { $output[$paste['phid']] .= ' ('.$paste['language'].')'; } } } if ($commit_names) { $commits = $this->getConduit()->callMethodSynchronous( 'diffusion.getcommits', array( 'commits' => $commit_names, )); foreach ($commits as $commit) { if (isset($commit['error'])) { continue; } $output[$commit['commitPHID']] = $commit['uri']; } } foreach ($output as $phid => $description) { // Don't mention the same object more than once every 10 minutes // in public channels, so we avoid spamming the chat over and over // again for discsussions of a specific revision, for example. $target_name = $original_message->getTarget()->getName(); if (empty($this->recentlyMentioned[$target_name])) { $this->recentlyMentioned[$target_name] = array(); } $quiet_until = idx( $this->recentlyMentioned[$target_name], $phid, 0) + (60 * 10); if (time() < $quiet_until) { // Remain quiet on this channel. continue; } $this->recentlyMentioned[$target_name][$phid] = time(); $this->replyTo($original_message, $description); } break; } } }