mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-21 21:10:56 +01:00
Implement very rough message context for Conpherence search
Summary: Ref T3165. This is pretty awful looking, but should pull the correct data. Test Plan: {F387567} Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T3165 Differential Revision: https://secure.phabricator.com/D12589
This commit is contained in:
parent
3c80292295
commit
cd7fec1729
3 changed files with 281 additions and 0 deletions
|
@ -4807,6 +4807,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPolicyInterface',
|
||||
'PhabricatorMarkupInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorSubscribableInterface',
|
||||
),
|
||||
'PhabricatorCalendarEventDeleteController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
|
||||
|
|
|
@ -4,6 +4,7 @@ final class ConpherenceFulltextQuery
|
|||
extends PhabricatorOffsetPagedQuery {
|
||||
|
||||
private $threadPHIDs;
|
||||
private $previousTransactionPHIDs;
|
||||
private $fulltext;
|
||||
|
||||
public function withThreadPHIDs(array $phids) {
|
||||
|
@ -11,6 +12,11 @@ final class ConpherenceFulltextQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withPreviousTransactionPHIDs(array $phids) {
|
||||
$this->previousTransactionPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withFulltext($fulltext) {
|
||||
$this->fulltext = $fulltext;
|
||||
return $this;
|
||||
|
@ -42,6 +48,13 @@ final class ConpherenceFulltextQuery
|
|||
$this->threadPHIDs);
|
||||
}
|
||||
|
||||
if ($this->previousTransactionPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'i.previousTransactionPHID IN (%Ls)',
|
||||
$this->previousTransactionPHIDs);
|
||||
}
|
||||
|
||||
if (strlen($this->fulltext)) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
|
|
|
@ -149,6 +149,27 @@ final class ConpherenceThreadSearchEngine
|
|||
$viewer,
|
||||
$conpherences);
|
||||
|
||||
$fulltext = $query->getParameter('fulltext');
|
||||
if (strlen($fulltext) && $conpherences) {
|
||||
$context = $this->loadContextMessages($conpherences, $fulltext);
|
||||
|
||||
$author_phids = array();
|
||||
foreach ($context as $messages) {
|
||||
foreach ($messages as $group) {
|
||||
foreach ($group as $message) {
|
||||
$xaction = $message['xaction'];
|
||||
if ($xaction) {
|
||||
$author_phids[] = $xaction->getAuthorPHID();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$handles = $viewer->loadHandles($author_phids);
|
||||
} else {
|
||||
$context = array();
|
||||
}
|
||||
|
||||
$list = new PHUIObjectItemListView();
|
||||
$list->setUser($viewer);
|
||||
foreach ($conpherences as $conpherence) {
|
||||
|
@ -181,6 +202,47 @@ final class ConpherenceThreadSearchEngine
|
|||
phabricator_datetime($conpherence->getDateModified(), $viewer)),
|
||||
));
|
||||
|
||||
$messages = idx($context, $conpherence->getPHID());
|
||||
if ($messages) {
|
||||
|
||||
// TODO: This is egregiously under-designed.
|
||||
|
||||
foreach ($messages as $group) {
|
||||
$rows = array();
|
||||
$rowc = array();
|
||||
foreach ($group as $message) {
|
||||
$xaction = $message['xaction'];
|
||||
if (!$xaction) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rowc[] = ($message['match'] ? 'highlighted' : null);
|
||||
$rows[] = array(
|
||||
$handles->renderHandle($xaction->getAuthorPHID()),
|
||||
$xaction->getComment()->getContent(),
|
||||
phabricator_datetime($xaction->getDateCreated(), $viewer),
|
||||
);
|
||||
}
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('User'),
|
||||
pht('Message'),
|
||||
pht('At'),
|
||||
))
|
||||
->setRowClasses($rowc)
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'wide',
|
||||
));
|
||||
$box = id(new PHUIBoxView())
|
||||
->appendChild($table)
|
||||
->addMargin(PHUI::MARGIN_SMALL);
|
||||
$item->appendChild($box);
|
||||
}
|
||||
}
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
|
@ -195,4 +257,209 @@ final class ConpherenceThreadSearchEngine
|
|||
);
|
||||
}
|
||||
|
||||
private function loadContextMessages(array $threads, $fulltext) {
|
||||
$phids = mpull($threads, 'getPHID');
|
||||
|
||||
// We want to load a few messages for each thread in the result list, to
|
||||
// show some of the actual content hits to help the user find what they
|
||||
// are looking for.
|
||||
|
||||
// This method is trying to batch this lookup in most cases, so we do
|
||||
// between one and "a handful" of queries instead of one per thread in
|
||||
// most cases. To do this:
|
||||
//
|
||||
// - Load a big block of results for all of the threads.
|
||||
// - If we didn't get a full block back, we have everything that matches
|
||||
// the query. Sort it out and exit.
|
||||
// - Otherwise, some threads had a ton of hits, so we might not be
|
||||
// getting everything we want (we could be getting back 1,000 hits for
|
||||
// the first thread). Remove any threads which we have enough results
|
||||
// for and try again.
|
||||
// - Repeat until we have everything or every thread has enough results.
|
||||
//
|
||||
// In the worst case, we could end up degrading to one query per thread,
|
||||
// but this is incredibly unlikely on real data.
|
||||
|
||||
// Size of the result blocks we're going to load.
|
||||
$limit = 1000;
|
||||
|
||||
// Number of messages we want for each thread.
|
||||
$want = 3;
|
||||
|
||||
$need = $phids;
|
||||
$hits = array();
|
||||
while ($need) {
|
||||
$rows = id(new ConpherenceFulltextQuery())
|
||||
->withThreadPHIDs($need)
|
||||
->withFulltext($fulltext)
|
||||
->setLimit($limit)
|
||||
->execute();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$hits[$row['threadPHID']][] = $row;
|
||||
}
|
||||
|
||||
if (count($rows) < $limit) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($need as $key => $phid) {
|
||||
if (count($hits[$phid]) >= $want) {
|
||||
unset($need[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have all the fulltext matches, throw away any extras that we
|
||||
// aren't going to render so we don't need to do lookups on them.
|
||||
foreach ($hits as $phid => $rows) {
|
||||
if (count($rows) > $want) {
|
||||
$hits[$phid] = array_slice($rows, 0, $want);
|
||||
}
|
||||
}
|
||||
|
||||
// For each fulltext match, we want to render a message before and after
|
||||
// the match to give it some context. We already know the transactions
|
||||
// before each match because the rows have a "previousTransactionPHID",
|
||||
// but we need to do one more query to figure out the transactions after
|
||||
// each match.
|
||||
|
||||
// Collect the transactions we want to find the next transactions for.
|
||||
$after = array();
|
||||
foreach ($hits as $phid => $rows) {
|
||||
foreach ($rows as $row) {
|
||||
$after[] = $row['transactionPHID'];
|
||||
}
|
||||
}
|
||||
|
||||
// Look up the next transactions.
|
||||
if ($after) {
|
||||
$after_rows = id(new ConpherenceFulltextQuery())
|
||||
->withPreviousTransactionPHIDs($after)
|
||||
->execute();
|
||||
} else {
|
||||
$after_rows = array();
|
||||
}
|
||||
|
||||
// Build maps from PHIDs to the previous and next PHIDs.
|
||||
$prev_map = array();
|
||||
$next_map = array();
|
||||
foreach ($after_rows as $row) {
|
||||
$next_map[$row['previousTransactionPHID']] = $row['transactionPHID'];
|
||||
}
|
||||
|
||||
foreach ($hits as $phid => $rows) {
|
||||
foreach ($rows as $row) {
|
||||
$prev = $row['previousTransactionPHID'];
|
||||
if ($prev) {
|
||||
$prev_map[$row['transactionPHID']] = $prev;
|
||||
$next_map[$prev] = $row['transactionPHID'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we're going to collect the actual transaction PHIDs, in order, that
|
||||
// we want to show for each thread.
|
||||
$groups = array();
|
||||
foreach ($hits as $thread_phid => $rows) {
|
||||
$rows = ipull($rows, null, 'transactionPHID');
|
||||
foreach ($rows as $phid => $row) {
|
||||
unset($rows[$phid]);
|
||||
|
||||
$group = array();
|
||||
|
||||
// Walk backward, finding all the previous results. We can just keep
|
||||
// going until we run out of results because we've only loaded things
|
||||
// that we want to show.
|
||||
$prev = $phid;
|
||||
while (true) {
|
||||
if (!isset($prev_map[$prev])) {
|
||||
// No previous transaction, so we're done.
|
||||
break;
|
||||
}
|
||||
|
||||
$prev = $prev_map[$prev];
|
||||
|
||||
if (isset($rows[$prev])) {
|
||||
$match = true;
|
||||
unset($rows[$prev]);
|
||||
} else {
|
||||
$match = false;
|
||||
}
|
||||
|
||||
$group[] = array(
|
||||
'phid' => $prev,
|
||||
'match' => $match,
|
||||
);
|
||||
}
|
||||
|
||||
if (count($group) > 1) {
|
||||
$group = array_reverse($group);
|
||||
}
|
||||
|
||||
$group[] = array(
|
||||
'phid' => $phid,
|
||||
'match' => true,
|
||||
);
|
||||
|
||||
$next = $phid;
|
||||
while (true) {
|
||||
if (!isset($next_map[$next])) {
|
||||
break;
|
||||
}
|
||||
|
||||
$next = $next_map[$next];
|
||||
|
||||
if (isset($rows[$next])) {
|
||||
$match = true;
|
||||
unset($rows[$next]);
|
||||
} else {
|
||||
$match = false;
|
||||
}
|
||||
|
||||
$group[] = array(
|
||||
'phid' => $next,
|
||||
'match' => $match,
|
||||
);
|
||||
}
|
||||
|
||||
$groups[$thread_phid][] = $group;
|
||||
}
|
||||
}
|
||||
|
||||
// Load all the actual transactions we need.
|
||||
$xaction_phids = array();
|
||||
foreach ($groups as $thread_phid => $group) {
|
||||
foreach ($group as $list) {
|
||||
foreach ($list as $item) {
|
||||
$xaction_phids[] = $item['phid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($xaction_phids) {
|
||||
$xactions = id(new ConpherenceTransactionQuery())
|
||||
->setViewer($this->requireViewer())
|
||||
->withPHIDs($xaction_phids)
|
||||
->needComments(true)
|
||||
->execute();
|
||||
$xactions = mpull($xactions, null, 'getPHID');
|
||||
} else {
|
||||
$xactions = array();
|
||||
}
|
||||
|
||||
foreach ($groups as $thread_phid => $group) {
|
||||
foreach ($group as $key => $list) {
|
||||
foreach ($list as $lkey => $item) {
|
||||
$xaction = idx($xactions, $item['phid']);
|
||||
$groups[$thread_phid][$key][$lkey]['xaction'] = $xaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Sort the groups chronologically?
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue