3 final class PhabricatorChatLogChannelLogController
4 extends PhabricatorChatLogController
{
6 public function shouldAllowPublic() {
10 public function handleRequest(AphrontRequest
$request) {
11 $viewer = $request->getViewer();
12 $id = $request->getURIData('channelID');
14 $uri = new PhutilURI($request->getPath());
16 $pager = new AphrontCursorPagerView();
18 $pager->setPageSize(250);
20 $query = id(new PhabricatorChatLogQuery())
22 ->withChannelIDs(array($id));
24 $channel = id(new PhabricatorChatLogChannelQuery())
30 return new Aphront404Response();
33 list($after, $before, $map) = $this->getPagingParameters($request, $query);
35 $pager->setAfterID($after);
36 $pager->setBeforeID($before);
38 $logs = $query->executeWithCursorPager($pager);
40 // Show chat logs oldest-first.
41 $logs = array_reverse($logs);
44 // Divide all the logs into blocks, where a block is the same author saying
45 // several things in a row. A block ends when another user speaks, or when
46 // two minutes pass without the author speaking.
53 foreach ($logs as $log) {
54 $this_author = $log->getAuthor();
55 $this_epoch = $log->getEpoch();
57 // Decide whether we should start a new block or not.
58 $new_block = ($this_author !== $last_author) ||
59 ($this_epoch - (60 * 2) > $last_epoch);
66 'id' => $log->getID(),
67 'epoch' => $this_epoch,
68 'author' => $this_author,
69 'logs' => array($log),
72 $block['logs'][] = $log;
75 $last_author = $this_author;
76 $last_epoch = $this_epoch;
82 // Figure out CSS classes for the blocks. We alternate colors between
83 // lines, and highlight the entire block which contains the target ID or
84 // date, if applicable.
86 foreach ($blocks as $key => $block) {
89 $classes[] = 'alternate';
91 $ids = mpull($block['logs'], 'getID', 'getID');
92 if (array_intersect_key($ids, $map)) {
93 $classes[] = 'highlight';
95 $blocks[$key]['class'] = $classes ?
implode(' ', $classes) : null;
99 require_celerity_resource('phabricator-chatlog-css');
102 foreach ($blocks as $block) {
103 $author = $block['author'];
104 $author = id(new PhutilUTF8StringTruncator())
105 ->setMaximumGlyphs(18)
106 ->truncateString($author);
107 $author = phutil_tag('td', array('class' => 'author'), $author);
109 $href = $uri->alter('at', $block['id']);
110 $timestamp = $block['epoch'];
111 $timestamp = phabricator_datetime($timestamp, $viewer);
112 $timestamp = phutil_tag(
116 'class' => 'timestamp',
120 $message = mpull($block['logs'], 'getMessage');
121 $message = implode("\n", $message);
122 $message = phutil_tag(
125 'class' => 'message',
135 'class' => $block['class'],
145 $first_uri = $pager->getFirstPageURI();
147 $links[] = phutil_tag(
150 'href' => $first_uri,
152 "\xC2\xAB ".pht('Newest'));
155 $prev_uri = $pager->getPrevPageURI();
157 $links[] = phutil_tag(
162 "\xE2\x80\xB9 ".pht('Newer'));
165 $next_uri = $pager->getNextPageURI();
167 $links[] = phutil_tag(
172 pht('Older')." \xE2\x80\xBA");
175 $pager_bottom = phutil_tag(
177 array('class' => 'phabricator-chat-log-pager-bottom'),
181 ->buildApplicationCrumbs()
182 ->addTextCrumb($channel->getChannelName(), $uri);
184 $form = id(new AphrontFormView())
189 id(new AphrontFormTextControl())
190 ->setLabel(pht('Date'))
192 ->setValue($request->getStr('date')))
194 id(new AphrontFormSubmitControl())
195 ->setValue(pht('Jump')));
200 'class' => 'phabricator-chat-log',
207 'class' => 'phabricator-chat-log-panel',
211 $jump_link = id(new PHUIButtonView())
214 ->setText(pht('Jump to Bottom'))
215 ->setIcon('fa-arrow-circle-down');
217 $jump_target = phutil_tag(
223 $content = phutil_tag(
226 'class' => 'phabricator-chat-log-wrap',
234 $header = id(new PHUIHeaderView())
235 ->setHeader($channel->getChannelName())
236 ->setSubHeader($channel->getServiceName())
237 ->addActionLink($jump_link);
239 $box = id(new PHUIObjectBoxView())
242 ->appendChild($content);
250 return $this->newPage()
251 ->setTitle(pht('Channel Log'))
258 * From request parameters, figure out where we should jump to in the log.
259 * We jump to either a date or log ID, but load a few lines of context before
260 * it so the user can see the nearby conversation.
262 private function getPagingParameters(
263 AphrontRequest
$request,
264 PhabricatorChatLogQuery
$query) {
266 $viewer = $request->getViewer();
268 $at_id = $request->getInt('at');
269 $at_date = $request->getStr('date');
274 $query = clone $query;
278 // Jump to the log in question, and load a few lines of context before
280 $context_logs = $query
284 $context_log = last($context_logs);
290 } else if ($at_date) {
291 $timestamp = PhabricatorTime
::parseLocalTime($at_date, $viewer);
294 $context_logs = $query
295 ->withMaximumEpoch($timestamp)
298 $context_log = last($context_logs);
300 $target_log = head($context_logs);
303 $target_log->getID() => true,
311 $before = $context_log->getID() - 1;
313 $after = $request->getInt('after');
314 $before = $request->getInt('before');
317 return array($after, $before, $map);