Conpherence - paginate thread list
Summary: this is D5750 but just the conpherence part. fixes a few random conpherence bugs / quirks as well. Also messes with ApplicationTransactionEditor to expose the xactions so Conpherence doesn't over-update participation rows. Fixes T2429. Test Plan: set LIMIT to 3. verified I could scroll down all conpherences. next, picked a conpherence "in the middle" to load. verified I could page up and down. next, picked a conpherence in the middle then had another user update that conpherence. verified as I paged up the conpherence re-loaded properly selected Reviewers: epriestley Reviewed By: epriestley CC: chad, aran, Korvin, vrana Maniphest Tasks: T2429 Differential Revision: https://secure.phabricator.com/D5783
This commit is contained in:
@@ -6,6 +6,10 @@
|
||||
final class ConpherenceListController
|
||||
extends ConpherenceController {
|
||||
|
||||
const SELECTED_MODE = 'selected';
|
||||
const UNSELECTED_MODE = 'unselected';
|
||||
const PAGING_MODE = 'paging';
|
||||
|
||||
private $conpherenceID;
|
||||
|
||||
public function setConpherenceID($conpherence_id) {
|
||||
@@ -20,59 +24,227 @@ final class ConpherenceListController
|
||||
$this->setConpherenceID(idx($data, 'id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Three main modes of operation...
|
||||
*
|
||||
* 1 - /conpherence/ - UNSELECTED_MODE
|
||||
* 2 - /conpherence/<id>/ - SELECTED_MODE
|
||||
* 3 - /conpherence/?direction='up'&... - PAGING_MODE
|
||||
*
|
||||
* UNSELECTED_MODE is not an Ajax request while the other two are Ajax
|
||||
* requests.
|
||||
*/
|
||||
private function determineMode() {
|
||||
$request = $this->getRequest();
|
||||
|
||||
$mode = self::UNSELECTED_MODE;
|
||||
if ($request->isAjax()) {
|
||||
if ($request->getStr('direction')) {
|
||||
$mode = self::PAGING_MODE;
|
||||
} else {
|
||||
$mode = self::SELECTED_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
return $mode;
|
||||
}
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$title = pht('Conpherence');
|
||||
|
||||
$conpherence_id = $this->getConpherenceID();
|
||||
$current_selection_epoch = null;
|
||||
$conpherence = null;
|
||||
if ($conpherence_id) {
|
||||
$conpherence = id(new ConpherenceThreadQuery())
|
||||
->setViewer($user)
|
||||
->withIDs(array($conpherence_id))
|
||||
->executeOne();
|
||||
if (!$conpherence) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if ($conpherence->getTitle()) {
|
||||
$title = $conpherence->getTitle();
|
||||
}
|
||||
$scroll_up_participant = $this->getEmptyParticipant();
|
||||
$scroll_down_participant = $this->getEmptyParticipant();
|
||||
$too_many = ConpherenceParticipantQuery::LIMIT + 1;
|
||||
$all_participation = array();
|
||||
|
||||
$participant = $conpherence->getParticipant($user->getPHID());
|
||||
$current_selection_epoch = $participant->getDateTouched();
|
||||
$mode = $this->determineMode();
|
||||
switch ($mode) {
|
||||
case self::SELECTED_MODE:
|
||||
$conpherence_id = $this->getConpherenceID();
|
||||
$conpherence = id(new ConpherenceThreadQuery())
|
||||
->setViewer($user)
|
||||
->withIDs(array($conpherence_id))
|
||||
->executeOne();
|
||||
if (!$conpherence) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
if ($conpherence->getTitle()) {
|
||||
$title = $conpherence->getTitle();
|
||||
}
|
||||
$cursor = $conpherence->getParticipant($user->getPHID());
|
||||
$data = $this->loadParticipationWithMidCursor($cursor);
|
||||
$all_participation = $data['participation'];
|
||||
$scroll_up_participant = $data['scroll_up_participant'];
|
||||
$scroll_down_participant = $data['scroll_down_participant'];
|
||||
break;
|
||||
case self::PAGING_MODE:
|
||||
$direction = $request->getStr('direction');
|
||||
$id = $request->getInt('participant_id');
|
||||
$date_touched = $request->getInt('date_touched');
|
||||
$conpherence_phid = $request->getStr('conpherence_phid');
|
||||
if ($direction == 'up') {
|
||||
$order = ConpherenceParticipantQuery::ORDER_NEWER;
|
||||
} else {
|
||||
$order = ConpherenceParticipantQuery::ORDER_OLDER;
|
||||
}
|
||||
$scroller_participant = id(new ConpherenceParticipant())
|
||||
->makeEphemeral()
|
||||
->setID($id)
|
||||
->setDateTouched($date_touched)
|
||||
->setConpherencePHID($conpherence_phid);
|
||||
$participation = id(new ConpherenceParticipantQuery())
|
||||
->withParticipantPHIDs(array($user->getPHID()))
|
||||
->withParticipantCursor($scroller_participant)
|
||||
->setOrder($order)
|
||||
->setLimit($too_many)
|
||||
->execute();
|
||||
if (count($participation) == $too_many) {
|
||||
if ($direction == 'up') {
|
||||
$node = $scroll_up_participant = reset($participation);
|
||||
} else {
|
||||
$node = $scroll_down_participant = end($participation);
|
||||
}
|
||||
unset($participation[$node->getConpherencePHID()]);
|
||||
}
|
||||
$all_participation = $participation;
|
||||
break;
|
||||
case self::UNSELECTED_MODE:
|
||||
default:
|
||||
$too_many = ConpherenceParticipantQuery::LIMIT + 1;
|
||||
$all_participation = id(new ConpherenceParticipantQuery())
|
||||
->withParticipantPHIDs(array($user->getPHID()))
|
||||
->setLimit($too_many)
|
||||
->execute();
|
||||
if (count($all_participation) == $too_many) {
|
||||
$node = end($participation);
|
||||
unset($all_participation[$node->getConpherencePHID()]);
|
||||
$scroll_down_participant = $node;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
list($unread, $read) = $this->loadStartingConpherences(
|
||||
$current_selection_epoch);
|
||||
$threads = $this->loadConpherenceThreadData(
|
||||
$all_participation);
|
||||
|
||||
$thread_view = id(new ConpherenceThreadListView())
|
||||
->setUser($user)
|
||||
->setBaseURI($this->getApplicationURI())
|
||||
->setUnreadThreads($unread)
|
||||
->setReadThreads($read);
|
||||
->setThreads($threads)
|
||||
->setScrollUpParticipant($scroll_up_participant)
|
||||
->setScrollDownParticipant($scroll_down_participant);
|
||||
|
||||
if ($request->isAjax()) {
|
||||
return id(new AphrontAjaxResponse())->setContent($thread_view);
|
||||
switch ($mode) {
|
||||
case self::SELECTED_MODE:
|
||||
$response = id(new AphrontAjaxResponse())->setContent($thread_view);
|
||||
break;
|
||||
case self::PAGING_MODE:
|
||||
$thread_html = $thread_view->renderThreadsHTML();
|
||||
$phids = array_keys($participation);
|
||||
$content = array(
|
||||
'html' => $thread_html,
|
||||
'phids' => $phids);
|
||||
$response = id(new AphrontAjaxResponse())->setContent($content);
|
||||
break;
|
||||
case self::UNSELECTED_MODE:
|
||||
default:
|
||||
$layout = id(new ConpherenceLayoutView())
|
||||
->setBaseURI($this->getApplicationURI())
|
||||
->setThreadView($thread_view)
|
||||
->setRole('list');
|
||||
if ($conpherence) {
|
||||
$layout->setThread($conpherence);
|
||||
}
|
||||
$response = $this->buildApplicationPage(
|
||||
$layout,
|
||||
array(
|
||||
'title' => $title,
|
||||
'device' => true,
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
||||
$layout = id(new ConpherenceLayoutView())
|
||||
->setBaseURI($this->getApplicationURI())
|
||||
->setThreadView($thread_view)
|
||||
->setRole('list');
|
||||
return $response;
|
||||
|
||||
if ($conpherence) {
|
||||
$layout->setThread($conpherence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the curious case when we are visiting a conpherence directly
|
||||
* by issuing two separate queries. Otherwise, additional conpherences
|
||||
* are fetched asynchronously. Note these can be earlier or later
|
||||
* (up or down), depending on what conpherence was selected on initial
|
||||
* load.
|
||||
*/
|
||||
private function loadParticipationWithMidCursor(
|
||||
ConpherenceParticipant $cursor) {
|
||||
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
$scroll_up_participant = $this->getEmptyParticipant();
|
||||
$scroll_down_participant = $this->getEmptyParticipant();
|
||||
|
||||
// Note this is a bit dodgy since there may be less than this
|
||||
// amount in either the up or down direction, thus having us fail
|
||||
// to fetch LIMIT in total. Whatevs for now and re-visit if we're
|
||||
// fine-tuning this loading process.
|
||||
$too_many = ceil(ConpherenceParticipantQuery::LIMIT / 2) + 1;
|
||||
$participant_query = id(new ConpherenceParticipantQuery())
|
||||
->withParticipantPHIDs(array($user->getPHID()))
|
||||
->setLimit($too_many);
|
||||
$current_selection_epoch = $cursor->getDateTouched();
|
||||
$set_one = $participant_query
|
||||
->withParticipantCursor($cursor)
|
||||
->setOrder(ConpherenceParticipantQuery::ORDER_NEWER)
|
||||
->execute();
|
||||
|
||||
if (count($set_one) == $too_many) {
|
||||
$node = reset($set_one);
|
||||
unset($set_one[$node->getConpherencePHID()]);
|
||||
$scroll_up_participant = $node;
|
||||
}
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$layout,
|
||||
array(
|
||||
'title' => $title,
|
||||
'device' => true,
|
||||
));
|
||||
$set_two = $participant_query
|
||||
->withParticipantCursor($cursor)
|
||||
->setOrder(ConpherenceParticipantQuery::ORDER_OLDER)
|
||||
->execute();
|
||||
|
||||
if (count($set_two) == $too_many) {
|
||||
$node = end($set_two);
|
||||
unset($set_two[$node->getConpherencePHID()]);
|
||||
$scroll_down_participant = $node;
|
||||
}
|
||||
|
||||
$participation = array_merge(
|
||||
$set_one,
|
||||
$set_two);
|
||||
|
||||
return array(
|
||||
'scroll_up_participant' => $scroll_up_participant,
|
||||
'scroll_down_participant' => $scroll_down_participant,
|
||||
'participation' => $participation);
|
||||
}
|
||||
|
||||
private function loadConpherenceThreadData($participation) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
$conpherence_phids = array_keys($participation);
|
||||
if ($conpherence_phids) {
|
||||
$conpherences = id(new ConpherenceThreadQuery())
|
||||
->setViewer($user)
|
||||
->withPHIDs($conpherence_phids)
|
||||
->needParticipantCache(true)
|
||||
->execute();
|
||||
}
|
||||
|
||||
// this will re-sort by participation data
|
||||
$conpherences = array_select_keys($conpherences, $conpherence_phids);
|
||||
|
||||
return $conpherences;
|
||||
}
|
||||
|
||||
private function getEmptyParticipant() {
|
||||
return id(new ConpherenceParticipant())
|
||||
->makeEphemeral();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user