1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Saito - The Threaded Web Forum |
7
|
|
|
* |
8
|
|
|
* @copyright Copyright (c) the Saito Project Developers |
9
|
|
|
* @link https://github.com/Schlaefer/Saito |
10
|
|
|
* @license http://opensource.org/licenses/MIT |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace App\Controller; |
14
|
|
|
|
15
|
|
|
use App\Controller\Component\AutoReloadComponent; |
16
|
|
|
use App\Controller\Component\MarkAsReadComponent; |
17
|
|
|
use App\Controller\Component\PostingComponent; |
18
|
|
|
use App\Controller\Component\RefererComponent; |
19
|
|
|
use App\Controller\Component\ThreadsComponent; |
20
|
|
|
use App\Model\Table\EntriesTable; |
21
|
|
|
use Cake\Core\Configure; |
22
|
|
|
use Cake\Datasource\Exception\RecordNotFoundException; |
23
|
|
|
use Cake\Event\Event; |
24
|
|
|
use Cake\Http\Exception\BadRequestException; |
25
|
|
|
use Cake\Http\Exception\MethodNotAllowedException; |
26
|
|
|
use Cake\Http\Exception\NotFoundException; |
27
|
|
|
use Cake\Http\Response; |
28
|
|
|
use Cake\Routing\RequestActionTrait; |
29
|
|
|
use Saito\Exception\SaitoForbiddenException; |
30
|
|
|
use Saito\Posting\Basic\BasicPostingInterface; |
31
|
|
|
use Saito\User\CurrentUser\CurrentUserInterface; |
32
|
|
|
use Saito\User\Permission\ResourceAI; |
33
|
|
|
use Stopwatch\Lib\Stopwatch; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Class EntriesController |
37
|
|
|
* |
38
|
|
|
* @property CurrentUserInterface $CurrentUser |
39
|
|
|
* @property EntriesTable $Entries |
40
|
|
|
* @property MarkAsReadComponent $MarkAsRead |
41
|
|
|
* @property PostingComponent $Posting |
42
|
|
|
* @property RefererComponent $Referer |
43
|
|
|
* @property ThreadsComponent $Threads |
44
|
|
|
*/ |
45
|
|
|
class EntriesController extends AppController |
46
|
|
|
{ |
47
|
|
|
use RequestActionTrait; |
|
|
|
|
48
|
|
|
|
49
|
|
|
public $helpers = ['Posting', 'Text']; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* {@inheritDoc} |
53
|
|
|
*/ |
54
|
|
|
public function initialize() |
55
|
|
|
{ |
56
|
|
|
parent::initialize(); |
57
|
|
|
|
58
|
|
|
$this->loadComponent('Posting'); |
59
|
|
|
$this->loadComponent('MarkAsRead'); |
60
|
|
|
$this->loadComponent('Referer'); |
61
|
|
|
$this->loadComponent('Threads', ['table' => $this->Entries]); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* posting index |
66
|
|
|
* |
67
|
|
|
* @return void|\Cake\Http\Response |
68
|
|
|
*/ |
69
|
|
|
public function index() |
70
|
|
|
{ |
71
|
|
|
Stopwatch::start('Entries->index()'); |
72
|
|
|
|
73
|
|
|
//= determine user sort order |
74
|
|
|
$sortKey = 'last_answer'; |
75
|
|
|
if (!$this->CurrentUser->get('user_sort_last_answer')) { |
76
|
|
|
$sortKey = 'time'; |
77
|
|
|
} |
78
|
|
|
$order = ['fixed' => 'DESC', $sortKey => 'DESC']; |
79
|
|
|
|
80
|
|
|
//= get threads |
81
|
|
|
$threads = $this->Threads->paginate($order, $this->CurrentUser); |
82
|
|
|
$this->set('entries', $threads); |
83
|
|
|
|
84
|
|
|
$currentPage = (int)$this->request->getQuery('page') ?: 1; |
85
|
|
|
if ($currentPage > 1) { |
86
|
|
|
$this->set('titleForLayout', __('page') . ' ' . $currentPage); |
87
|
|
|
} |
88
|
|
|
if ($currentPage === 1) { |
89
|
|
|
if ($this->MarkAsRead->refresh()) { |
90
|
|
|
return $this->redirect(['action' => 'index']); |
91
|
|
|
} |
92
|
|
|
$this->MarkAsRead->next(); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
// @bogus |
96
|
|
|
$this->request->getSession()->write('paginator.lastPage', $currentPage); |
97
|
|
|
$this->set('showDisclaimer', true); |
98
|
|
|
$this->set('showBottomNavigation', true); |
99
|
|
|
$this->Slidetabs->show(); |
100
|
|
|
|
101
|
|
|
$this->_setupCategoryChooser($this->CurrentUser); |
102
|
|
|
|
103
|
|
|
/** @var AutoReloadComponent */ |
104
|
|
|
$autoReload = $this->loadComponent('AutoReload'); |
105
|
|
|
$autoReload->after($this->CurrentUser); |
|
|
|
|
106
|
|
|
|
107
|
|
|
Stopwatch::stop('Entries->index()'); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* Mix view |
112
|
|
|
* |
113
|
|
|
* @param string $tid thread-ID |
114
|
|
|
* @return void|Response |
115
|
|
|
* @throws NotFoundException |
116
|
|
|
*/ |
117
|
|
|
public function mix($tid) |
118
|
|
|
{ |
119
|
|
|
$tid = (int)$tid; |
120
|
|
|
if ($tid <= 0) { |
121
|
|
|
throw new BadRequestException(); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
try { |
125
|
|
|
$postings = $this->Entries->postingsForThread($tid, true, $this->CurrentUser); |
126
|
|
|
} catch (RecordNotFoundException $e) { |
127
|
|
|
/// redirect sub-posting to mix view of thread |
128
|
|
|
$actualTid = $this->Entries->getThreadId($tid); |
129
|
|
|
|
130
|
|
|
return $this->redirect([$actualTid, '#' => $tid], 301); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
// check if anonymous tries to access internal categories |
134
|
|
|
$root = $postings; |
135
|
|
|
if (!$this->CurrentUser->getCategories()->permission('read', $root->get('category'))) { |
136
|
|
|
return $this->_requireAuth(); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
$this->_setRootEntry($root); |
140
|
|
|
$this->Title->setFromPosting($root, __('view.type.mix')); |
141
|
|
|
|
142
|
|
|
$this->set('showBottomNavigation', true); |
143
|
|
|
$this->set('entries', $postings); |
144
|
|
|
|
145
|
|
|
$this->_showAnsweringPanel(); |
146
|
|
|
|
147
|
|
|
$this->Threads->incrementViewsForThread($root, $this->CurrentUser); |
148
|
|
|
$this->MarkAsRead->thread($postings); |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* load front page force all entries mark-as-read |
153
|
|
|
* |
154
|
|
|
* @return void |
155
|
|
|
*/ |
156
|
|
|
public function update() |
157
|
|
|
{ |
158
|
|
|
$this->autoRender = false; |
159
|
|
|
$this->CurrentUser->getLastRefresh()->set(); |
160
|
|
|
$this->redirect('/entries/index'); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Outputs raw markup of an posting $id |
165
|
|
|
* |
166
|
|
|
* @param string $id posting-ID |
167
|
|
|
* @return void |
168
|
|
|
*/ |
169
|
|
|
public function source($id = null) |
170
|
|
|
{ |
171
|
|
|
$this->viewBuilder()->enableAutoLayout(false); |
172
|
|
|
$this->view($id); |
|
|
|
|
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* View posting. |
177
|
|
|
* |
178
|
|
|
* @param string $id posting-ID |
179
|
|
|
* @return \Cake\Http\Response|void |
180
|
|
|
*/ |
181
|
|
|
public function view(string $id) |
182
|
|
|
{ |
183
|
|
|
$id = (int)$id; |
184
|
|
|
Stopwatch::start('Entries->view()'); |
185
|
|
|
|
186
|
|
|
$entry = $this->Entries->get($id); |
187
|
|
|
$posting = $entry->toPosting()->withCurrentUser($this->CurrentUser); |
|
|
|
|
188
|
|
|
|
189
|
|
|
if (!$this->CurrentUser->getCategories()->permission('read', $posting->get('category'))) { |
190
|
|
|
return $this->_requireAuth(); |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
$this->set('entry', $posting); |
194
|
|
|
$this->Threads->incrementViewsForPosting($posting, $this->CurrentUser); |
195
|
|
|
$this->_setRootEntry($posting); |
196
|
|
|
$this->_showAnsweringPanel(); |
197
|
|
|
|
198
|
|
|
$this->MarkAsRead->posting($posting); |
199
|
|
|
|
200
|
|
|
// inline open |
201
|
|
|
if ($this->request->is('ajax')) { |
202
|
|
|
return $this->render('/Element/entry/view_posting'); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
// full page request |
206
|
|
|
$this->set( |
207
|
|
|
'tree', |
208
|
|
|
$this->Entries->postingsForThread($posting->get('tid'), false, $this->CurrentUser) |
209
|
|
|
); |
210
|
|
|
$this->Title->setFromPosting($posting); |
211
|
|
|
|
212
|
|
|
Stopwatch::stop('Entries->view()'); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Add new posting. |
217
|
|
|
* |
218
|
|
|
* @return void|\Cake\Http\Response |
219
|
|
|
*/ |
220
|
|
|
public function add() |
221
|
|
|
{ |
222
|
|
|
$titleForPage = __('Write a New Posting'); |
223
|
|
|
$this->set(compact('titleForPage')); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* Edit posting |
228
|
|
|
* |
229
|
|
|
* @param string $id posting-ID |
230
|
|
|
* @return void|\Cake\Http\Response |
231
|
|
|
* @throws NotFoundException |
232
|
|
|
* @throws BadRequestException |
233
|
|
|
*/ |
234
|
|
|
public function edit(string $id) |
235
|
|
|
{ |
236
|
|
|
$id = (int)$id; |
237
|
|
|
$entry = $this->Entries->get($id); |
238
|
|
|
$posting = $entry->toPosting()->withCurrentUser($this->CurrentUser); |
239
|
|
|
|
240
|
|
|
if (!$posting->isEditingAllowed()) { |
241
|
|
|
throw new SaitoForbiddenException( |
242
|
|
|
'Access to posting in EntriesController:edit() forbidden.', |
243
|
|
|
['CurrentUser' => $this->CurrentUser] |
244
|
|
|
); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
// show editing form |
248
|
|
|
if (!$posting->isEditingAsUserAllowed()) { |
249
|
|
|
$this->Flash->set( |
250
|
|
|
__('notice_you_are_editing_as_mod'), |
251
|
|
|
['element' => 'warning'] |
252
|
|
|
); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
$this->set(compact('posting')); |
256
|
|
|
|
257
|
|
|
// set headers |
258
|
|
|
$this->set( |
259
|
|
|
'headerSubnavLeftTitle', |
260
|
|
|
__('back_to_posting_from_linkname', $posting->get('name')) |
261
|
|
|
); |
262
|
|
|
$this->set('headerSubnavLeftUrl', ['action' => 'view', $id]); |
263
|
|
|
$this->set('form_title', __('edit_linkname')); |
264
|
|
|
$this->render('/Entries/add'); |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* Get thread-line to insert after an inline-answer |
269
|
|
|
* |
270
|
|
|
* @param string $id posting-ID |
271
|
|
|
* @return void|\Cake\Http\Response |
272
|
|
|
*/ |
273
|
|
|
public function threadLine($id = null) |
274
|
|
|
{ |
275
|
|
|
$posting = $this->Entries->get($id)->toPosting()->withCurrentUser($this->CurrentUser); |
|
|
|
|
276
|
|
|
if (!$this->CurrentUser->getCategories()->permission('read', $posting->get('category'))) { |
277
|
|
|
return $this->_requireAuth(); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
$this->set('entrySub', $posting); |
281
|
|
|
// ajax requests so far are always answers |
282
|
|
|
$this->response = $this->response->withType('json'); |
283
|
|
|
$this->set('level', '1'); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
/** |
287
|
|
|
* Delete posting |
288
|
|
|
* |
289
|
|
|
* @param string $id posting-ID |
290
|
|
|
* @return void |
291
|
|
|
* @throws NotFoundException |
292
|
|
|
* @throws MethodNotAllowedException |
293
|
|
|
*/ |
294
|
|
|
public function delete(string $id) |
295
|
|
|
{ |
296
|
|
|
//$this->request->allowMethod(['post', 'delete']); |
297
|
|
|
$id = (int)$id; |
298
|
|
|
if (!$id) { |
299
|
|
|
throw new NotFoundException(); |
300
|
|
|
} |
301
|
|
|
/* @var Entry $posting */ |
302
|
|
|
$posting = $this->Entries->get($id); |
303
|
|
|
|
304
|
|
|
$action = $posting->isRoot() ? 'thread' : 'answer'; |
305
|
|
|
$allowed = $this->CurrentUser->getCategories() |
306
|
|
|
->permission($action, $posting->get('category_id')); |
307
|
|
|
if (!$allowed) { |
308
|
|
|
throw new SaitoForbiddenException(); |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
$success = $this->Entries->deletePosting($id); |
312
|
|
|
|
313
|
|
|
if ($success) { |
314
|
|
|
$flashType = 'success'; |
315
|
|
|
if ($posting->isRoot()) { |
316
|
|
|
$message = __('delete_tree_success'); |
317
|
|
|
$redirect = '/'; |
318
|
|
|
} else { |
319
|
|
|
$message = __('delete_subtree_success'); |
320
|
|
|
$redirect = '/entries/view/' . $posting->get('pid'); |
321
|
|
|
} |
322
|
|
|
} else { |
323
|
|
|
$flashType = 'error'; |
324
|
|
|
$message = __('delete_tree_error'); |
325
|
|
|
$redirect = $this->referer(); |
326
|
|
|
} |
327
|
|
|
$this->Flash->set($message, ['element' => $flashType]); |
328
|
|
|
$this->redirect($redirect); |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
/** |
332
|
|
|
* Empty function for benchmarking |
333
|
|
|
* |
334
|
|
|
* @return void |
335
|
|
|
*/ |
336
|
|
|
public function e() |
337
|
|
|
{ |
338
|
|
|
Stopwatch::start('Entries->e()'); |
339
|
|
|
Stopwatch::stop('Entries->e()'); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
/** |
343
|
|
|
* Marks sub-entry $id as solution to its current root-entry |
344
|
|
|
* |
345
|
|
|
* @param string $id posting-ID |
346
|
|
|
* @return void |
347
|
|
|
* @throws BadRequestException |
348
|
|
|
*/ |
349
|
|
|
public function solve($id) |
350
|
|
|
{ |
351
|
|
|
$this->autoRender = false; |
352
|
|
|
try { |
353
|
|
|
$posting = $this->Entries->get($id); |
|
|
|
|
354
|
|
|
|
355
|
|
|
if (empty($posting)) { |
356
|
|
|
throw new \InvalidArgumentException('Posting to mark solved not found.'); |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
$rootId = $posting->get('tid'); |
360
|
|
|
$rootPosting = $this->Entries->get($rootId); |
361
|
|
|
|
362
|
|
|
$allowed = $this->CurrentUser->permission( |
363
|
|
|
'saito.core.posting.solves.set', |
364
|
|
|
(new ResourceAI())->onRole($rootPosting->get('user')->getRole())->onOwner($rootPosting->get('user_id')) |
365
|
|
|
); |
366
|
|
|
if (!$allowed) { |
367
|
|
|
throw new SaitoForbiddenException( |
368
|
|
|
sprintf('Attempt to mark posting %s as solution.', $posting->get('id')), |
369
|
|
|
['CurrentUser' => $this->CurrentUser] |
370
|
|
|
); |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
$value = $posting->get('solves') ? 0 : $rootPosting->get('tid'); |
374
|
|
|
$success = $this->Entries->updateEntry($posting, ['solves' => $value]); |
|
|
|
|
375
|
|
|
|
376
|
|
|
if (!$success) { |
|
|
|
|
377
|
|
|
throw new BadRequestException(); |
378
|
|
|
} |
379
|
|
|
} catch (\Exception $e) { |
380
|
|
|
throw new BadRequestException(); |
381
|
|
|
} |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
/** |
385
|
|
|
* Merge threads. |
386
|
|
|
* |
387
|
|
|
* @param string $sourceId posting-ID of thread to be merged |
388
|
|
|
* @return void |
389
|
|
|
* @throws NotFoundException |
390
|
|
|
* @td put into admin entries controller |
391
|
|
|
*/ |
392
|
|
|
public function merge(string $sourceId = null) |
393
|
|
|
{ |
394
|
|
|
$sourceId = (int)$sourceId; |
395
|
|
|
if (empty($sourceId)) { |
396
|
|
|
throw new NotFoundException(); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
/* @var Entry */ |
400
|
|
|
$entry = $this->Entries->findById($sourceId)->first(); |
|
|
|
|
401
|
|
|
|
402
|
|
|
if (!$entry || !$entry->isRoot()) { |
|
|
|
|
403
|
|
|
throw new NotFoundException(); |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
// perform move operation |
407
|
|
|
$targetId = $this->request->getData('targetId'); |
408
|
|
|
if (!empty($targetId)) { |
409
|
|
|
if ($this->Entries->threadMerge($sourceId, $targetId)) { |
|
|
|
|
410
|
|
|
$this->redirect('/entries/view/' . $sourceId); |
411
|
|
|
|
412
|
|
|
return; |
413
|
|
|
} else { |
414
|
|
|
$this->Flash->set(__('Error'), ['element' => 'error']); |
415
|
|
|
} |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
$this->viewBuilder()->setLayout('Admin.admin'); |
419
|
|
|
$this->set('posting', $entry); |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
/** |
423
|
|
|
* Toggle posting property via ajax request. |
424
|
|
|
* |
425
|
|
|
* @param string $id posting-ID |
426
|
|
|
* @param string $toggle property |
427
|
|
|
* |
428
|
|
|
* @return \Cake\Http\Response |
429
|
|
|
*/ |
430
|
|
|
public function ajaxToggle($id = null, $toggle = null) |
431
|
|
|
{ |
432
|
|
|
$allowed = ['fixed', 'locked']; |
433
|
|
|
if ( |
434
|
|
|
!$id |
435
|
|
|
|| !$toggle |
436
|
|
|
|| !$this->request->is('ajax') |
437
|
|
|
|| !in_array($toggle, $allowed) |
438
|
|
|
) { |
439
|
|
|
throw new BadRequestException(); |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
$posting = $this->Entries->get($id); |
|
|
|
|
443
|
|
|
$data = ['id' => (int)$id, $toggle => !$posting->get($toggle)]; |
444
|
|
|
$this->Posting->update($posting, $data, $this->CurrentUser); |
|
|
|
|
445
|
|
|
|
446
|
|
|
$this->response = $this->response->withType('json'); |
447
|
|
|
$this->response = $this->response->withStringBody(json_encode('OK')); |
448
|
|
|
|
449
|
|
|
return $this->response; |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
/** |
453
|
|
|
* {@inheritDoc} |
454
|
|
|
*/ |
455
|
|
|
public function beforeFilter(Event $event) |
456
|
|
|
{ |
457
|
|
|
parent::beforeFilter($event); |
458
|
|
|
Stopwatch::start('Entries->beforeFilter()'); |
459
|
|
|
|
460
|
|
|
$this->Security->setConfig( |
461
|
|
|
'unlockedActions', |
462
|
|
|
['solve', 'view'] |
463
|
|
|
); |
464
|
|
|
$this->Authentication->allowUnauthenticated(['index', 'view', 'mix', 'update']); |
465
|
|
|
|
466
|
|
|
$this->AuthUser->authorizeAction('ajaxToggle', 'saito.core.posting.pinAndLock'); |
467
|
|
|
$this->AuthUser->authorizeAction('merge', 'saito.core.posting.merge'); |
468
|
|
|
$this->AuthUser->authorizeAction('delete', 'saito.core.posting.delete'); |
469
|
|
|
|
470
|
|
|
Stopwatch::stop('Entries->beforeFilter()'); |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
/** |
474
|
|
|
* set view vars for category chooser |
475
|
|
|
* |
476
|
|
|
* @param CurrentUserInterface $User CurrentUser |
477
|
|
|
* @return void |
478
|
|
|
*/ |
479
|
|
|
protected function _setupCategoryChooser(CurrentUserInterface $User) |
480
|
|
|
{ |
481
|
|
|
if (!$User->isLoggedIn()) { |
482
|
|
|
return; |
483
|
|
|
} |
484
|
|
|
$globalActivation = Configure::read( |
485
|
|
|
'Saito.Settings.category_chooser_global' |
486
|
|
|
); |
487
|
|
|
if (!$globalActivation) { |
488
|
|
|
if ( |
489
|
|
|
!Configure::read( |
490
|
|
|
'Saito.Settings.category_chooser_user_override' |
491
|
|
|
) |
492
|
|
|
) { |
493
|
|
|
return; |
494
|
|
|
} |
495
|
|
|
if (!$User->get('user_category_override')) { |
496
|
|
|
return; |
497
|
|
|
} |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
$this->set( |
501
|
|
|
'categoryChooserChecked', |
502
|
|
|
$User->getCategories()->getCustom('read') |
503
|
|
|
); |
504
|
|
|
switch ($User->getCategories()->getType()) { |
505
|
|
|
case 'single': |
506
|
|
|
$title = $User->get('user_category_active'); |
507
|
|
|
break; |
508
|
|
|
case 'custom': |
509
|
|
|
$title = __('Custom'); |
510
|
|
|
break; |
511
|
|
|
default: |
512
|
|
|
$title = __('All Categories'); |
513
|
|
|
} |
514
|
|
|
$this->set('categoryChooserTitleId', $title); |
515
|
|
|
$this->set( |
516
|
|
|
'categoryChooser', |
517
|
|
|
$User->getCategories()->getAll('read', 'select') |
518
|
|
|
); |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
/** |
522
|
|
|
* Decide if an answering panel is show when rendering a posting |
523
|
|
|
* |
524
|
|
|
* @return void |
525
|
|
|
*/ |
526
|
|
|
protected function _showAnsweringPanel() |
527
|
|
|
{ |
528
|
|
|
$showAnsweringPanel = false; |
529
|
|
|
|
530
|
|
|
if ($this->CurrentUser->isLoggedIn()) { |
531
|
|
|
// Only logged in users see the answering buttons if they … |
532
|
|
|
if ( |
533
|
|
|
// … directly on entries/view but not inline |
534
|
|
|
($this->request->getParam('action') === 'view' && !$this->request->is('ajax')) |
535
|
|
|
// … directly in entries/mix |
536
|
|
|
|| $this->request->getParam('action') === 'mix' |
537
|
|
|
// … inline viewing … on entries/index. |
538
|
|
|
|| ($this->Referer->wasController('entries') |
539
|
|
|
&& $this->Referer->wasAction('index')) |
540
|
|
|
) { |
541
|
|
|
$showAnsweringPanel = true; |
542
|
|
|
} |
543
|
|
|
} |
544
|
|
|
$this->set('showAnsweringPanel', $showAnsweringPanel); |
545
|
|
|
} |
546
|
|
|
|
547
|
|
|
/** |
548
|
|
|
* makes root posting of $posting avaiable in view |
549
|
|
|
* |
550
|
|
|
* @param BasicPostingInterface $posting posting for root entry |
551
|
|
|
* @return void |
552
|
|
|
*/ |
553
|
|
|
protected function _setRootEntry(BasicPostingInterface $posting): void |
554
|
|
|
{ |
555
|
|
|
if (!$posting->isRoot()) { |
556
|
|
|
/** @var \App\Model\Entity\Entry root */ |
557
|
|
|
$root = $this->Entries->find() |
558
|
|
|
->select(['id', 'user_id', 'Users.user_type']) |
559
|
|
|
->where(['Entries.id' => $posting->get('tid')]) |
560
|
|
|
->contain(['Users']) |
561
|
|
|
->first(); |
562
|
|
|
$root = $root->toPosting(); |
563
|
|
|
} else { |
564
|
|
|
$root = $posting; |
565
|
|
|
} |
566
|
|
|
$this->set('rootEntry', $root); |
567
|
|
|
} |
568
|
|
|
} |
569
|
|
|
|
This trait has been deprecated. The supplier of the trait has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the trait will be removed and what other trait to use instead.