Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/chatlog/controller/PhabricatorChatLogChannelLogController.php
12242 views
1
<?php
2
3
final class PhabricatorChatLogChannelLogController
4
extends PhabricatorChatLogController {
5
6
public function shouldAllowPublic() {
7
return true;
8
}
9
10
public function handleRequest(AphrontRequest $request) {
11
$viewer = $request->getViewer();
12
$id = $request->getURIData('channelID');
13
14
$uri = new PhutilURI($request->getPath());
15
16
$pager = new AphrontCursorPagerView();
17
$pager->setURI($uri);
18
$pager->setPageSize(250);
19
20
$query = id(new PhabricatorChatLogQuery())
21
->setViewer($viewer)
22
->withChannelIDs(array($id));
23
24
$channel = id(new PhabricatorChatLogChannelQuery())
25
->setViewer($viewer)
26
->withIDs(array($id))
27
->executeOne();
28
29
if (!$channel) {
30
return new Aphront404Response();
31
}
32
33
list($after, $before, $map) = $this->getPagingParameters($request, $query);
34
35
$pager->setAfterID($after);
36
$pager->setBeforeID($before);
37
38
$logs = $query->executeWithCursorPager($pager);
39
40
// Show chat logs oldest-first.
41
$logs = array_reverse($logs);
42
43
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.
47
48
$blocks = array();
49
$block = null;
50
51
$last_author = null;
52
$last_epoch = null;
53
foreach ($logs as $log) {
54
$this_author = $log->getAuthor();
55
$this_epoch = $log->getEpoch();
56
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);
60
61
if ($new_block) {
62
if ($block) {
63
$blocks[] = $block;
64
}
65
$block = array(
66
'id' => $log->getID(),
67
'epoch' => $this_epoch,
68
'author' => $this_author,
69
'logs' => array($log),
70
);
71
} else {
72
$block['logs'][] = $log;
73
}
74
75
$last_author = $this_author;
76
$last_epoch = $this_epoch;
77
}
78
if ($block) {
79
$blocks[] = $block;
80
}
81
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.
85
86
foreach ($blocks as $key => $block) {
87
$classes = array();
88
if ($key % 2) {
89
$classes[] = 'alternate';
90
}
91
$ids = mpull($block['logs'], 'getID', 'getID');
92
if (array_intersect_key($ids, $map)) {
93
$classes[] = 'highlight';
94
}
95
$blocks[$key]['class'] = $classes ? implode(' ', $classes) : null;
96
}
97
98
99
require_celerity_resource('phabricator-chatlog-css');
100
101
$out = array();
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);
108
109
$href = $uri->alter('at', $block['id']);
110
$timestamp = $block['epoch'];
111
$timestamp = phabricator_datetime($timestamp, $viewer);
112
$timestamp = phutil_tag(
113
'a',
114
array(
115
'href' => $href,
116
'class' => 'timestamp',
117
),
118
$timestamp);
119
120
$message = mpull($block['logs'], 'getMessage');
121
$message = implode("\n", $message);
122
$message = phutil_tag(
123
'td',
124
array(
125
'class' => 'message',
126
),
127
array(
128
$timestamp,
129
$message,
130
));
131
132
$out[] = phutil_tag(
133
'tr',
134
array(
135
'class' => $block['class'],
136
),
137
array(
138
$author,
139
$message,
140
));
141
}
142
143
$links = array();
144
145
$first_uri = $pager->getFirstPageURI();
146
if ($first_uri) {
147
$links[] = phutil_tag(
148
'a',
149
array(
150
'href' => $first_uri,
151
),
152
"\xC2\xAB ".pht('Newest'));
153
}
154
155
$prev_uri = $pager->getPrevPageURI();
156
if ($prev_uri) {
157
$links[] = phutil_tag(
158
'a',
159
array(
160
'href' => $prev_uri,
161
),
162
"\xE2\x80\xB9 ".pht('Newer'));
163
}
164
165
$next_uri = $pager->getNextPageURI();
166
if ($next_uri) {
167
$links[] = phutil_tag(
168
'a',
169
array(
170
'href' => $next_uri,
171
),
172
pht('Older')." \xE2\x80\xBA");
173
}
174
175
$pager_bottom = phutil_tag(
176
'div',
177
array('class' => 'phabricator-chat-log-pager-bottom'),
178
$links);
179
180
$crumbs = $this
181
->buildApplicationCrumbs()
182
->addTextCrumb($channel->getChannelName(), $uri);
183
184
$form = id(new AphrontFormView())
185
->setUser($viewer)
186
->setMethod('GET')
187
->setAction($uri)
188
->appendChild(
189
id(new AphrontFormTextControl())
190
->setLabel(pht('Date'))
191
->setName('date')
192
->setValue($request->getStr('date')))
193
->appendChild(
194
id(new AphrontFormSubmitControl())
195
->setValue(pht('Jump')));
196
197
$table = phutil_tag(
198
'table',
199
array(
200
'class' => 'phabricator-chat-log',
201
),
202
$out);
203
204
$log = phutil_tag(
205
'div',
206
array(
207
'class' => 'phabricator-chat-log-panel',
208
),
209
$table);
210
211
$jump_link = id(new PHUIButtonView())
212
->setTag('a')
213
->setHref('#latest')
214
->setText(pht('Jump to Bottom'))
215
->setIcon('fa-arrow-circle-down');
216
217
$jump_target = phutil_tag(
218
'div',
219
array(
220
'id' => 'latest',
221
));
222
223
$content = phutil_tag(
224
'div',
225
array(
226
'class' => 'phabricator-chat-log-wrap',
227
),
228
array(
229
$log,
230
$jump_target,
231
$pager_bottom,
232
));
233
234
$header = id(new PHUIHeaderView())
235
->setHeader($channel->getChannelName())
236
->setSubHeader($channel->getServiceName())
237
->addActionLink($jump_link);
238
239
$box = id(new PHUIObjectBoxView())
240
->setHeader($header)
241
->setCollapsed(true)
242
->appendChild($content);
243
244
$box->setShowHide(
245
pht('Search Dates'),
246
pht('Hide Dates'),
247
$form,
248
'#');
249
250
return $this->newPage()
251
->setTitle(pht('Channel Log'))
252
->setCrumbs($crumbs)
253
->appendChild($box);
254
255
}
256
257
/**
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.
261
*/
262
private function getPagingParameters(
263
AphrontRequest $request,
264
PhabricatorChatLogQuery $query) {
265
266
$viewer = $request->getViewer();
267
268
$at_id = $request->getInt('at');
269
$at_date = $request->getStr('date');
270
271
$context_log = null;
272
$map = array();
273
274
$query = clone $query;
275
$query->setLimit(8);
276
277
if ($at_id) {
278
// Jump to the log in question, and load a few lines of context before
279
// it.
280
$context_logs = $query
281
->setAfterID($at_id)
282
->execute();
283
284
$context_log = last($context_logs);
285
286
$map = array(
287
$at_id => true,
288
);
289
290
} else if ($at_date) {
291
$timestamp = PhabricatorTime::parseLocalTime($at_date, $viewer);
292
293
if ($timestamp) {
294
$context_logs = $query
295
->withMaximumEpoch($timestamp)
296
->execute();
297
298
$context_log = last($context_logs);
299
300
$target_log = head($context_logs);
301
if ($target_log) {
302
$map = array(
303
$target_log->getID() => true,
304
);
305
}
306
}
307
}
308
309
if ($context_log) {
310
$after = null;
311
$before = $context_log->getID() - 1;
312
} else {
313
$after = $request->getInt('after');
314
$before = $request->getInt('before');
315
}
316
317
return array($after, $before, $map);
318
}
319
320
}
321
322