ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilObjForumGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
27 
36 {
38 
39  private array $viewModeOptions = [
40  ilForumProperties::VIEW_TREE => 'sort_by_posts',
41  ilForumProperties::VIEW_DATE_ASC => 'sort_by_date',
42  ];
43 
44  private array $sortationOptions = [
45  ilForumProperties::VIEW_DATE_ASC => 'ascending_order',
46  ilForumProperties::VIEW_DATE_DESC => 'descending_order',
47  ];
48 
49  private \ILIAS\GlobalScreen\Services $globalScreen;
50  public string $modal_history = '';
54  private bool $display_confirm_post_activation = false;
55  private bool $is_moderator;
57  private bool $hideToolbar = false;
58  private \Psr\Http\Message\ServerRequestInterface $httpRequest;
59  private \ILIAS\HTTP\Services $http;
62  private ?array $forumObjects = null;
63  private string $confirmation_gui_html = '';
66  private string $requestAction;
67  private array $modalActionsContainer = [];
68 
70  public \ILIAS\DI\RBACServices $rbac;
72  private Factory $factory;
74 
75  private int $selectedSorting;
77  protected \ILIAS\Style\Content\Object\ObjectFacade $content_style_domain;
78  protected \ILIAS\Style\Content\GUIService $content_style_gui;
79  private array $modal_collection = [];
80  private readonly bool $in_page_editor_style_context;
81 
82  public function __construct($data, int $id = 0, bool $call_by_reference = true, bool $prepare_output = true)
83  {
84  global $DIC;
85  $this->ctrl = $DIC->ctrl();
86  $this->ctrl->saveParameter($this, ['ref_id']);
87 
88  $this->httpRequest = $DIC->http()->request();
89  $this->http = $DIC->http();
90 
91  $this->uiFactory = $DIC->ui()->factory();
92  $this->uiRenderer = $DIC->ui()->renderer();
93  $this->globalScreen = $DIC->globalScreen();
94 
95  $this->ilObjDataCache = $DIC['ilObjDataCache'];
96  $this->ilNavigationHistory = $DIC['ilNavigationHistory'];
97  $this->ilHelp = $DIC['ilHelp'];
98  $this->rbac = $DIC->rbac();
99  $this->factory = $DIC->ui()->factory();
100  $this->renderer = $DIC->ui()->renderer();
101 
102  $this->type = 'frm';
104 
105  $this->tpl->addJavaScript('./Services/JavaScript/js/Basic.js');
106 
107  $this->lng->loadLanguageModule('forum');
108  $this->lng->loadLanguageModule('content');
109 
110  $this->initSessionStorage();
111 
112  $ref_id = $this->retrieveRefId();
113  $thr_pk = $this->retrieveThrPk();
114 
115  $this->objProperties = ilForumProperties::getInstance($this->ilObjDataCache->lookupObjId($ref_id));
116  $this->is_moderator = $this->access->checkAccess('moderate_frm', '', $ref_id);
117 
118  $this->objCurrentTopic = new ilForumTopic($thr_pk, $this->is_moderator);
119  $this->requestAction = (string) ($this->httpRequest->getQueryParams()['action'] ?? '');
120  $cs = $DIC->contentStyle();
121  $this->content_style_gui = $cs->gui();
122  if (is_object($this->object)) {
123  $this->content_style_domain = $cs->domain()->styleForRefId($this->object->getRefId());
124  }
125  $this->in_page_editor_style_context = $this->http->wrapper()->query()->has('page_editor_style');
126  $this->ctrl->saveParameterByClass(ilObjectContentStyleSettingsGUI::class, 'page_editor_style');
127  }
128 
129  protected function initSessionStorage(): void
130  {
131  $forumValues = ilSession::get('frm');
132  if (!is_array($forumValues)) {
133  $forumValues = [];
134  ilSession::set('frm', $forumValues);
135  }
136 
137  $threadId = $this->httpRequest->getQueryParams()['thr_pk'] ?? 0;
138  if ((int) $threadId > 0 && !isset($forumValues[(int) $threadId])) {
139  $forumValues[(int) $threadId] = [];
140  ilSession::set('frm', $forumValues);
141  }
142 
143  $this->selected_post_storage = new ilForumThreadSettingsSessionStorage('frm_selected_post');
144  }
145 
146  private function retrieveRefId(): int
147  {
148  return $this->retrieveIntOrZeroFrom($this->http->wrapper()->query(), 'ref_id');
149  }
150 
151  private function retrieveThrPk(): int
152  {
153  return $this->retrieveIntOrZeroFrom($this->http->wrapper()->query(), 'thr_pk');
154  }
155 
156  private function retrieveDraftId(): int
157  {
158  return $this->retrieveIntOrZeroFrom($this->http->wrapper()->query(), 'draft_id');
159  }
160 
161  protected function toggleExplorerNodeStateObject(): void
162  {
163  $exp = new ilForumExplorerGUI(
164  'frm_exp_' . $this->objCurrentTopic->getId(),
165  $this,
166  'viewThread',
168  $this->objCurrentTopic->getPostRootNode($this->is_moderator)
169  );
170  $exp->toggleExplorerNodeState();
171  }
172 
174  array $subtree_nodes,
175  array $pagedPostings,
176  int $pageSize,
177  ilForumPost $firstForumPost
178  ): void {
179  if ($firstForumPost->getId() === $this->objCurrentPost->getId()) {
180  return;
181  }
182 
183  if ($subtree_nodes !== [] && $this->objCurrentPost->getId() > 0) {
184  $isCurrentPostingInPage = array_filter($pagedPostings, fn(ilForumPost $posting): bool => (
185  $posting->getId() === $this->objCurrentPost->getId()
186  ));
187 
188  if ([] === $isCurrentPostingInPage) {
189  $pageOfCurrentPosting = 0;
190  $i = 0;
191  foreach ($subtree_nodes as $node) {
192  if ($i > 0 && 0 === $i % $pageSize) {
193  ++$pageOfCurrentPosting;
194  }
195 
196  if ($node->getId() === $this->objCurrentPost->getId()) {
197  break;
198  }
199 
200  ++$i;
201  }
202 
203  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
204  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
205  $this->ctrl->setParameter($this, 'page', $pageOfCurrentPosting);
206  $this->ctrl->setParameter(
207  $this,
208  'orderby',
209  $this->getOrderByParam()
210  );
211  $this->ctrl->redirect($this, 'viewThread', (string) $this->objCurrentPost->getId());
212  }
213  }
214  }
215 
216  public function ensureThreadBelongsToForum(int $objId, ilForumTopic $thread): void
217  {
218  $forumId = ilObjForum::lookupForumIdByObjId($objId);
219  if ($thread->getForumId() !== $forumId) {
220  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
221  }
222  }
223 
224  private function decorateWithAutosave(ilPropertyFormGUI $form): void
225  {
226  $draft_id = $this->retrieveDraftId();
227 
230 
231  $this->tpl->addJavaScript('./Modules/Forum/js/autosave.js');
232  $autosave_cmd = 'autosaveDraftAsync';
233  if ($this->objCurrentPost->getId() === 0 && $this->objCurrentPost->getThreadId() === 0) {
234  $autosave_cmd = 'autosaveThreadDraftAsync';
235  }
236  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
237  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
238  $draft_id = max($draft_id, 0);
239  $this->ctrl->setParameter($this, 'draft_id', $draft_id);
240  $this->ctrl->setParameter($this, 'action', ilUtil::stripSlashes($this->requestAction));
241  $this->tpl->addOnLoadCode(
242  "il.Language.setLangVar('saving', " . json_encode($this->lng->txt('saving'), JSON_THROW_ON_ERROR) . ');'
243  );
244 
245  $this->tpl->addOnLoadCode('il.ForumDraftsAutosave.init(' . json_encode([
246  'loading_img_src' => ilUtil::getImagePath('media/loader.svg'),
247  'draft_id' => $draft_id,
248  'interval' => $interval * 1000,
249  'url' => $this->ctrl->getFormAction($this, $autosave_cmd, '', true),
250  'selectors' => [
251  'form' => '#form_' . $form->getId()
252  ]
253  ], JSON_THROW_ON_ERROR) . ');');
254  }
255  }
256 
257  private function isTopLevelReplyCommand(): bool
258  {
259  return in_array(
260  strtolower($this->ctrl->getCmd()),
261  array_map('strtolower', ['createTopLevelPost', 'saveTopLevelPost', 'saveTopLevelDraft']),
262  true
263  );
264  }
265 
266  public function getUnsafeGetCommands(): array
267  {
268  return [
269  'enableForumNotification',
270  'disableForumNotification',
271  'toggleThreadNotification'
272  ];
273  }
274 
275  public function getSafePostCommands(): array
276  {
277  return [];
278  }
279 
280  public function executeCommand(): void
281  {
282  $next_class = $this->ctrl->getNextClass($this);
283  $cmd = $this->ctrl->getCmd();
284 
285  $exclude_cmds = [
286  'viewThread',
287  'markPostUnread',
288  'markPostRead',
289  'showThreadNotification',
290  'performPostActivation',
291  'askForPostActivation',
292  'askForPostDeactivation',
293  'toggleThreadNotification',
294  'toggleThreadNotificationTab',
295  'toggleStickiness',
296  'cancelPost',
297  'savePost',
298  'saveTopLevelPost',
299  'createTopLevelPost',
300  'saveTopLevelDraft',
301  'quotePost',
302  'getQuotationHTMLAsynch',
303  'autosaveDraftAsync',
304  'autosaveThreadDraftAsync',
305  'saveAsDraft',
306  'editDraft',
307  'updateDraft',
308  'deliverDraftZipFile',
309  'deliverZipFile',
310  'cancelDraft',
311  'deleteThreadDrafts',
312  'deletePosting',
313  'deletePostingDraft',
314  'revokeCensorship',
315  'addCensorship',
316  'confirmDeleteThreadsObject'
317  ];
318 
319  if (!in_array($cmd, $exclude_cmds, true)) {
320  $this->prepareOutput();
321  }
322 
323  if (!$this->creation_mode) {
324  $this->checkUsersViewMode();
325  $pos_pk = $this->retrieveIntOrZeroFrom($this->http->wrapper()->query(), 'pos_pk');
326  if ($this->selectedSorting === ilForumProperties::VIEW_TREE &&
327  $this->selected_post_storage->get($this->objCurrentTopic->getId()) > 0) {
328  $this->objCurrentPost = new ilForumPost(
329  $this->selected_post_storage->get($this->objCurrentTopic->getId()) ?? 0,
330  $this->is_moderator
331  );
332  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
333  } else {
334  $this->selected_post_storage->set($this->objCurrentTopic->getId(), 0);
335  $this->objCurrentPost = new ilForumPost(
336  $pos_pk,
337  $this->is_moderator
338  );
339  }
340  }
341 
342  $ref_id = $this->retrieveRefId();
343 
344  if (!$this->getCreationMode() && !$this->ctrl->isAsynch() && $this->access->checkAccess(
345  'read',
346  '',
347  $ref_id
348  )) {
350  $ref_id,
351  ilLink::_getLink($ref_id, 'frm'),
352  'frm'
353  );
354  }
355 
356  switch (strtolower($next_class)) {
357  case strtolower(ilForumPageGUI::class):
358  if (in_array(strtolower($cmd), array_map('strtolower', [
359  self::UI_CMD_COPAGE_DOWNLOAD_FILE,
360  self::UI_CMD_COPAGE_DISPLAY_FULLSCREEN,
361  self::UI_CMD_COPAGE_DOWNLOAD_PARAGRAPH,
362  ]), true)
363  ) {
364  if (!$this->checkPermissionBool('read')) {
365  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
366  }
367  } elseif (!$this->checkPermissionBool('write') || $this->user->isAnonymous()) {
368  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
369  }
370 
371  $this->content_style_gui->addCss($this->tpl, $this->ref_id);
372  $this->tpl->setCurrentBlock('SyntaxStyle');
373  $this->tpl->setVariable('LOCATION_SYNTAX_STYLESHEET', ilObjStyleSheet::getSyntaxStylePath());
374  $this->tpl->parseCurrentBlock();
375 
377  $obj = $this->object;
378 
379  $forwarder = new ilForumPageCommandForwarder(
380  $this->http,
381  $this->ctrl,
382  $this->tabs_gui,
383  $this->lng,
384  $obj,
385  $this->user,
386  $this->content_style_domain
387  );
388 
389  $pageContent = $forwarder->forward();
390  if ($pageContent !== '') {
391  $this->tpl->setContent($pageContent);
392  }
393  break;
394 
395  case strtolower(ilLearningProgressGUI::class):
396  if (!ilLearningProgressAccess::checkAccess($this->object->getRefId())) {
397  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
398  }
399 
400  $this->tabs_gui->activateTab('learning_progress');
401 
402  $usrId = $this->user->getId();
403  if (
404  isset($this->request->getQueryParams()['user_id']) &&
405  is_numeric($this->request->getQueryParams()['user_id'])
406  ) {
407  $usrId = (int) $this->request->getQueryParams()['user_id'];
408  }
409 
410  $this->ctrl->forwardCommand(new ilLearningProgressGUI(
412  $this->object->getRefId(),
413  $usrId
414  ));
415  break;
416 
417  case strtolower(ilObjectContentStyleSettingsGUI::class):
418  $this->checkPermission('write');
419 
420  if ($this->in_page_editor_style_context) {
421  $this->tabs_gui->setBackTarget(
422  $this->lng->txt('back'),
423  $this->ctrl->getLinkTarget(new ilForumPageGUI($this->object->getId()), 'edit')
424  );
425  } else {
426  $forum_settings_gui = new ilForumSettingsGUI($this, $this->object);
427  $forum_settings_gui->settingsTabs();
428  }
429 
430  $settings_gui = $this->content_style_gui
431  ->objectSettingsGUIForRefId(
432  null,
433  $this->ref_id
434  );
435  $this->ctrl->forwardCommand($settings_gui);
436  break;
437 
438  case strtolower(ilForumSettingsGUI::class):
439  $forum_settings_gui = new ilForumSettingsGUI($this, $this->object);
440  $this->ctrl->forwardCommand($forum_settings_gui);
441  break;
442 
443  case strtolower(ilRepositoryObjectSearchGUI::class):
444  $this->addHeaderAction();
445  $this->setSideBlocks();
446  $this->tabs_gui->activateTab('forums_threads');
447  $this->ctrl->setReturn($this, 'view');
448  $search_gui = new ilRepositoryObjectSearchGUI(
449  $this->object->getRefId(),
450  $this,
451  'view'
452  );
453  $this->ctrl->forwardCommand($search_gui);
454  break;
455 
456  case strtolower(ilPermissionGUI::class):
457  $perm_gui = new ilPermissionGUI($this);
458  $this->ctrl->forwardCommand($perm_gui);
459  break;
460 
461  case strtolower(ilForumExportGUI::class):
462  $fex_gui = new ilForumExportGUI();
463  $this->ctrl->forwardCommand($fex_gui);
464  $this->http->close();
465  break;
466 
467  case strtolower(ilForumModeratorsGUI::class):
468  $fm_gui = new ilForumModeratorsGUI($this->object);
469  $this->ctrl->forwardCommand($fm_gui);
470  break;
471 
472  case strtolower(ilInfoScreenGUI::class):
473  $this->infoScreen();
474  break;
475 
476  case strtolower(ilColumnGUI::class):
477  $this->showThreadsObject();
478  break;
479 
480  case strtolower(ilPublicUserProfileGUI::class):
481  $user = $this->retrieveIntOrZeroFrom($this->http->wrapper()->query(), 'user');
482  $profile_gui = new ilPublicUserProfileGUI($user);
483  $add = $this->getUserProfileAdditional($ref_id, $user);
484  $profile_gui->setAdditional($add);
485  $ret = $this->ctrl->forwardCommand($profile_gui);
486  $this->tpl->setContent($ret);
487  break;
488 
489  case strtolower(ilObjectCopyGUI::class):
490  $cp = new ilObjectCopyGUI($this);
491  $cp->setType('frm');
492  $this->ctrl->forwardCommand($cp);
493  break;
494 
495  case strtolower(ilExportGUI::class):
496  $this->tabs_gui->activateTab('export');
497  $exp = new ilExportGUI($this);
498  $exp->addFormat('html');
499  $exp->addFormat('xml');
500  if ($cmd === 'createExportFile') {
501  if ($this->http->wrapper()->post()->has('format')) {
502  $format = $this->http->wrapper()->post()->retrieve('format', $this->refinery->kindlyTo()->string());
503  if ($format === 'html') {
504  $fex_gui = new ilForumExportGUI();
505  $fex_gui->exportHTML();
506  }
507  }
508  }
509  $this->ctrl->forwardCommand($exp);
510  break;
511 
512  case strtolower(ilRatingGUI::class):
513  if (!$this->objProperties->isIsThreadRatingEnabled() || $this->user->isAnonymous()) {
514  $this->error->raiseError($this->lng->txt('msg_no_perm_read'), $this->error->MESSAGE);
515  }
516 
517  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
518  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
519  }
520 
522 
523  $rating_gui = new ilRatingGUI();
524  $rating_gui->setObject(
525  $this->object->getId(),
526  $this->object->getType(),
527  $this->objCurrentTopic->getId(),
528  'thread'
529  );
530 
531  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
532  $this->ctrl->forwardCommand($rating_gui);
533 
535  $this->object->getId(),
536  $this->object->getType(),
537  $this->objCurrentTopic->getId(),
538  'thread'
539  );
540  $this->objCurrentTopic->setAverageRating($avg['avg']);
541  $this->objCurrentTopic->update();
542 
543  $this->ctrl->redirect($this, 'showThreads');
544 
545  // no break
546  case strtolower(ilCommonActionDispatcherGUI::class):
548  $this->ctrl->forwardCommand($gui);
549  break;
550 
551  case strtolower(ilContainerNewsSettingsGUI::class):
552  $this->checkPermission('write');
553 
554  $forum_settings_gui = new ilForumSettingsGUI($this, $this->object);
555  $forum_settings_gui->settingsTabs();
556 
557  $this->lng->loadLanguageModule('cont');
558  $news_set_gui = new ilContainerNewsSettingsGUI($this);
559  $news_set_gui->setNewsBlockForced(true);
560  $news_set_gui->setPublicNotification(true);
561  $this->ctrl->forwardCommand($news_set_gui);
562  break;
563 
564  default:
565  if (in_array($cmd, ['close', 'reopen', 'make_topics_non_sticky', 'makesticky', 'editThread', 'move'])) {
566  $cmd = 'performThreadsAction';
567  }
568  if (in_array($cmd, $this->getTableCommands(), true)) {
569  $notificationCommands = [
570  'enableAdminForceNoti',
571  'disableAdminForceNoti',
572  'enableHideUserToggleNoti',
573  'disableHideUserToggleNoti'
574  ];
575 
576  if (!in_array($cmd, $notificationCommands, true)) {
577  $cmd = 'performThreadsAction';
578  }
579  } elseif (($cmd === null || $cmd === '') && $this->getTableCommands() === []) {
580  $cmd = 'showThreads';
581  }
582 
583  $cmd .= 'Object';
584  $this->$cmd();
585 
586  break;
587  }
588 
589  if (!$this->in_page_editor_style_context &&
590  $cmd !== 'viewThreadObject' && $cmd !== 'showUserObject' && !in_array(
591  strtolower($next_class),
592  array_map('strtolower', [ilForumPageGUI::class]),
593  true
594  )) {
595  $this->addHeaderAction();
596  }
597  }
598 
602  private function getTableCommands(): array
603  {
604  $tableCommands = [];
605  if ($this->http->wrapper()->post()->has('selected_cmd')) {
606  $tableCommands[] = $this->http->wrapper()->post()->retrieve(
607  'selected_cmd',
608  $this->refinery->kindlyTo()->string()
609  );
610  }
611  if ($this->http->wrapper()->post()->has('selected_cmd2')) {
612  $tableCommands[] = $this->http->wrapper()->post()->retrieve(
613  'selected_cmd2',
614  $this->refinery->kindlyTo()->string()
615  );
616  }
617 
618  return $tableCommands;
619  }
620 
621  public function infoScreenObject(): void
622  {
623  $this->ctrl->setCmd('showSummary');
624  $this->ctrl->setCmdClass(ilInfoScreenGUI::class);
625  $this->infoScreen();
626  }
627 
628  protected function initEditCustomForm(ilPropertyFormGUI $a_form): void
629  {
630  $this->forum_settings_gui = new ilForumSettingsGUI($this, $this->object);
631  $this->forum_settings_gui->getCustomForm($a_form);
632  }
633 
634  protected function getEditFormCustomValues(array &$a_values): void
635  {
636  $this->forum_settings_gui->getCustomValues($a_values);
637  }
638 
639  protected function updateCustom(ilPropertyFormGUI $form): void
640  {
641  $this->forum_settings_gui->updateCustomValues($form);
642  }
643 
644  private function getThreadEditingForm(int $a_thread_id): ilPropertyFormGUI
645  {
646  $form = new ilPropertyFormGUI();
647  $this->ctrl->setParameter($this, 'thr_pk', $a_thread_id);
648  $form->setFormAction($this->ctrl->getFormAction($this, 'updateThread'));
649 
650  $ti_prop = new ilTextInputGUI($this->lng->txt('title'), 'title');
651  $ti_prop->setRequired(true);
652  $ti_prop->setMaxLength(255);
653  $ti_prop->setSize(50);
654  $form->addItem($ti_prop);
655 
656  $form->addCommandButton('updateThread', $this->lng->txt('save'));
657  $form->addCommandButton('showThreads', $this->lng->txt('cancel'));
658 
659  return $form;
660  }
661  public function updateThreadObject(): void
662  {
663  if (!$this->is_moderator) {
664  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
665  }
666 
667  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
668  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
669  }
670 
671  if ($this->objCurrentTopic->getId() === 0) {
672  $this->showThreadsObject();
673  return;
674  }
675 
677 
678  $title = $this->getEditTitleModal($this->objCurrentTopic)->withRequest($this->http->request())->getData();
679  if (array_key_exists(0, $title)) {
680  $new_subject = $title[0];
681  if ($new_subject !== '') {
682  $this->objCurrentTopic->setSubject($new_subject);
683  $this->objCurrentTopic->updateThreadTitle();
684  $this->tpl->setOnScreenMessage('success', $this->lng->txt('saved_successfully'));
685  }
686 
687  $this->showThreadsObject();
688  }
689  }
690 
691  public function markAllReadObject(): void
692  {
693  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
694  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
695  }
696 
697  $this->object->markAllThreadsRead($this->user->getId());
698  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_all_threads_marked_read'));
699  $this->showThreadsObject();
700  }
701 
702  public function showThreadsObject(): void
703  {
704  $this->setSideBlocks();
705  $this->getCenterColumnHTML();
706  }
707 
708  public function getContent(): string
709  {
710  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
711  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
712  }
713 
714  $cmd = $this->ctrl->getCmd();
715  $frm = $this->object->Forum;
716  $frm->setForumId($this->object->getId());
717  $frm->setForumRefId($this->object->getRefId());
718  $frm->setMDB2Wherecondition('top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
719  // Import information: Topic (variable $topicData) means frm object, not thread
720  $frm_object = $frm->getOneTopic();
721  if ($frm_object->getTopPk() > 0) {
722  $frm->setDbTable('frm_data');
723  $frm->setMDB2WhereCondition('top_pk = %s ', ['integer'], [$frm_object->getTopPk()]);
724  $frm->updateVisits($frm_object->getTopPk());
725 
727  $this->object->getType(),
728  $this->object->getRefId(),
729  $this->object->getId(),
730  $this->user->getId()
731  );
732 
733  if ($cmd !== 'showThreads') {
734  $cmd = 'showThreads';
735  }
736  }
737  $this->tpl->setPermanentLink($this->object->getType(), $this->object->getRefId());
738  $ref_id = $this->retrieveRefId();
739 
740  if (!$this->hideToolbar() && $this->access->checkAccess('add_thread', '', $this->object->getRefId())) {
741  $btn = $this->uiFactory->button()
742  ->standard(
743  $this->lng->txt('forums_new_thread'),
744  $this->ctrl->getLinkTarget($this, 'createThread')
745  );
746  $this->toolbar->addStickyItem($btn);
747  }
748 
750  $this->addDraftButtonIfDraftsExists($cmd);
751  }
752 
753  if ($this->confirmation_gui_html === '' && !$this->user->isAnonymous()) {
754  $this->toolbar->addButton(
755  $this->lng->txt('forums_mark_read'),
756  $this->ctrl->getLinkTarget($this, 'markAllRead')
757  );
758  $this->ctrl->clearParameters($this);
759  }
760 
761  if (!$this->user->isAnonymous() && $this->access->checkAccess('write', '', $this->ref_id)) {
762  $this->lng->loadLanguageModule('cntr');
763  $this->toolbar->addComponent(
764  $this->uiFactory->button()->standard(
765  $this->lng->txt('cntr_text_media_editor'),
766  $this->ctrl->getLinkTargetByClass(ilForumPageGUI::class, 'edit')
767  )
768  );
769  }
770 
771  $tbl = new ilForumThreadObjectTableGUI(
772  $this,
773  $cmd,
774  $ref_id,
775  $frm_object,
776  $this->is_moderator
777  );
778 
779  $this->initializeThreadSortation($tbl);
780  $this->initializeThreadOffsetAndLimit($tbl);
781 
782  $this->renderThreadOverview($tbl, $frm, $frm_object);
783  return '';
784  }
785 
786  private function renderThreadOverview(ilForumThreadObjectTableGUI $tbl, ilForum $frm, ForumDto $frm_object): void
787  {
788  $data_objects = $tbl->setMapper($frm)->fetchDataAnReturnObject();
789 
790  $sticky_threads = [];
791  $regular_threads = [];
792 
793  if (count($data_objects) > 0) {
794  foreach ($data_objects as $thread) {
795  if (array_key_exists('thread', $thread)) {
797  $current_thread = $thread['thread'];
798  $ref_id = $this->object->getRefId();
799  $subject = $current_thread->getSubject();
800  if ($current_thread->isClosed()) {
801  $subject .= ' (' . $this->lng->txt('forums_closed') . ')';
802  }
803 
804  $link = $this->getLinkActionForThread($ref_id, $subject, 'viewThread', $current_thread->getId());
805  $actions = $this->getActionsForThreadOverview($ref_id, $current_thread);
806 
807  $list_item = $this->factory
808  ->item()
809  ->standard($link)
810  ->withActions($actions)
811  ->withProperties($this->getThreadProperties($current_thread));
812  $list_item = $this->markTopThreadInOverview($current_thread, $list_item);
813  if ($current_thread->isSticky()) {
814  $sticky_threads[] = $list_item;
815  } else {
816  $regular_threads[] = $list_item;
817  }
818  }
819  }
820  }
821 
822  $sticky_threads_item_group = null;
823  if (count($sticky_threads) > 0) {
824  $sticky_threads_item_group = $this->factory->item()->group(
825  count($regular_threads) > 0 ? $this->lng->txt('top_thema') : '',
826  $sticky_threads
827  );
828  }
829 
830  $regular_threads_item_group = null;
831  if (count($regular_threads) > 0) {
832  $regular_threads_item_group = $this->factory->item()->group(
833  count($sticky_threads) > 0 ? $this->lng->txt('thema') : '',
834  $regular_threads
835  );
836  }
837 
838  $url = $this->http->request()->getRequestTarget();
839  $current_page = 0;
840  if ($this->http->wrapper()->query()->has(ilForumProperties::PAGE_NAME_THREAD_OVERVIEW)) {
841  $current_page = $this->http->wrapper()->query()->retrieve(
843  $this->refinery->kindlyTo()->int()
844  );
845  }
846 
847  $view_controls[] = $this->getSortationViewControl();
848  $view_controls[] = $this->factory
849  ->viewControl()
850  ->pagination()
852  ->withTotalEntries($frm_object->getTopNumThreads())
854  ->withMaxPaginationButtons(5)
855  ->withCurrentPage($current_page);
856 
857  $item_groups = array_filter([$sticky_threads_item_group, $regular_threads_item_group]);
858  if ($item_groups === []) {
859  $vc_container = $this->factory->panel()->listing()->standard(
860  $this->lng->txt('thread_overview'),
861  [$this->factory->item()->group($this->lng->txt('frm_no_threads'), [])]
862  );
863  } else {
864  $vc_container = $this->factory->panel()->listing()->standard(
865  $this->lng->txt('thread_overview'),
866  $item_groups
867  )->withViewControls($view_controls);
868  }
869 
870  $default_html = $this->renderer->render($vc_container);
871  $modals = $this->renderer->render($this->modal_collection);
872  $forwarder = new ilForumPageCommandForwarder(
873  $GLOBALS['DIC']['http'],
874  $this->ctrl,
875  $this->tabs_gui,
876  $this->lng,
877  $this->object,
878  $this->user,
879  $this->content_style_domain
880  );
881  $forwarder->setPresentationMode(ilForumPageCommandForwarder::PRESENTATION_MODE_PRESENTATION);
882  $this->initStyleSheets();
883 
884  $this->tpl->setContent($forwarder->forward() . $default_html . $modals);
885  }
886 
887  private function getRequestedThreadSortation(): ?int
888  {
889  return $this->http->wrapper()->query()->retrieve(
890  'thread_sortation',
891  $this->refinery->byTrying([
892  $this->refinery->kindlyTo()->int(),
893  $this->refinery->always(null)
894  ])
895  );
896  }
897 
898  private function getRequestedThreadOffset(): int
899  {
900  return $this->http->wrapper()->query()->retrieve(
901  'page',
902  $this->refinery->byTrying([
903  $this->refinery->kindlyTo()->int(),
904  $this->refinery->always(0)
905  ])
906  );
907  }
908 
910  {
912  $offset = $this->getRequestedThreadOffset() * $limit;
913 
914  $tbl->setOffset($offset);
915  $tbl->setLimit($limit);
916  }
917 
919  {
920  $sortation = ThreadSortation::tryFrom(
921  $this->getRequestedThreadSortation() ?? ThreadSortation::DEFAULT_SORTATION->value
922  );
923  if ($sortation === null) {
924  $sortation = ThreadSortation::DEFAULT_SORTATION;
925  }
926  $tbl->setOrderDirection($sortation->direction());
927  $tbl->setOrderField($sortation->field());
928  }
929 
930  private function getSortationViewControl(): \ILIAS\UI\Component\ViewControl\Sortation
931  {
932  $offset = $this->getRequestedThreadOffset();
933  if ($offset > 0) {
934  $this->ctrl->setParameter($this, 'page', $offset);
935  }
936 
937  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
938  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
939  $base_url = $this->ctrl->getLinkTarget($this, 'showThreads');
940 
941  $translationKeys = [];
942  foreach (ThreadSortation::cases() as $sortation) {
943  $this->ctrl->setParameter($this, 'thread_sortation', $sortation->value);
944  $url = $this->ctrl->getLinkTarget($this, 'showThreads');
945 
946  $translationKeys[$url] = $this->lng->txt($sortation->languageId());
947  }
948  $this->ctrl->clearParameters($this);
949 
950  return $this->factory
951  ->viewControl()
952  ->sortation($translationKeys)
953  ->withTargetURL($base_url, 'thread_sortation');
954  }
955 
959  private function retrieveThreadIds(): array
960  {
961  $thread_ids = [];
962  $query = $this->http->wrapper()->query()->has('thr_pk');
963  $post = $this->http->wrapper()->post()->has('thread_ids');
964  if ($post) {
965  $thread_ids = $this->http->wrapper()->post()->retrieve(
966  'thread_ids',
967  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int())
968  );
969  } elseif ($query) {
970  $thread_ids = $this->http->wrapper()->query()->retrieve(
971  'thr_pk',
972  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int())
973  );
974  }
975 
976  return $thread_ids;
977  }
978 
982  private function getThreadProperties(ilForumTopic $forum_topic): array
983  {
984  $this->ctrl->setParameter($this, 'thr_pk', $forum_topic->getId());
985  $unread_counter = $forum_topic->getNumUnreadPosts();
986  $is_top_thread = $forum_topic->isSticky();
987 
988  if ($unread_counter === 0) {
989  $unread = '';
990  } else {
991  $unread = ' (' . $unread_counter . ' ' . $this->lng->txt('unread') . ')';
992  }
993 
994  $authorinfo = new ilForumAuthorInformation(
995  $forum_topic->getThrAuthorId(),
996  $forum_topic->getDisplayUserId(),
997  (string) $forum_topic->getUserAlias(),
998  (string) $forum_topic->getImportName()
999  );
1000 
1001  $properties = [
1002  $this->lng->txt('forums_created_by') => $authorinfo->getAuthorName(),
1003  $this->lng->txt('forums_articles') => $forum_topic->getNumPosts() . $unread,
1004  $this->lng->txt('forums_last_post') => $this->object->Forum->convertDate($forum_topic->getLastPost()->getCreateDate()),
1005  $this->lng->txt('visits') => $forum_topic->getVisits(),
1006  ];
1007 
1008  if ($is_top_thread === true) {
1009  $is_top_thread = [$this->lng->txt('relevance') => $this->lng->txt('sticky')];
1010  $properties = array_merge($properties, $is_top_thread);
1011  }
1012 
1013  $rating_property = [];
1014  if ($this->objProperties->isIsThreadRatingEnabled()) {
1015  $rating = new ilRatingGUI();
1016  $rating->setObject(
1017  $this->object->getId(),
1018  $this->object->getType(),
1019  $forum_topic->getId(),
1020  'thread'
1021  );
1022  $rating->setUserId($this->user->getId());
1023  $rating_property = [$this->lng->txt('frm_rating') => $rating->getHTML()];
1024  }
1025  $this->ctrl->setParameter($this, 'thr_pk', null);
1026 
1027  return array_merge($properties, $rating_property);
1028  }
1029 
1030  private function getLinkActionForThread(
1031  int $ref_id,
1032  string $title,
1033  string $cmd,
1034  int $thread_id = null
1035  ): \ILIAS\UI\Component\Link\Link {
1036  $this->ctrl->setParameter($this, 'ref_id', $ref_id);
1037  $this->ctrl->setParameter($this, 'thr_pk', $thread_id);
1038  $this->ctrl->setParameter($this, 'page', 0);
1039  $url = $this->ctrl->getLinkTarget($this, $cmd);
1040  $this->ctrl->setParameter($this, 'ref_id', null);
1041  $this->ctrl->setParameter($this, 'thr_pk', null);
1042  $this->ctrl->setParameter($this, 'page', null);
1043 
1044  return $this->uiFactory->link()->standard($title, $url);
1045  }
1046 
1047  private function getActionsForThreadOverview(int $ref_id, ilForumTopic $forum_topic): Standard
1048  {
1049  $actions = $this->uiFactory->dropdown()->standard([]);
1050  if ($this->is_moderator) {
1051  $open_close = $this->getOpenCloseActionForThread($forum_topic, $ref_id);
1052  $stick_or_no_stick = $this->getStickyActionForThread($forum_topic, $ref_id);
1053  $edit_title_modal = $this->getEditTitleModal($forum_topic);
1054  $this->modal_collection[] = $edit_title_modal;
1055  $edit_title = $this->factory->button()->shy($this->lng->txt('frm_edit_title'), '#')->withOnClick(
1056  $edit_title_modal->getShowSignal()
1057  );
1058 
1059  $move = $this->getLinkActionForThread(
1060  $ref_id,
1061  $this->lng->txt('move_thread_to_forum'),
1062  'move',
1063  $forum_topic->getId()
1064  );
1065  $merge = $this->getLinkActionForThread(
1066  $ref_id,
1067  $this->lng->txt('merge_posts_into_thread'),
1068  'mergeThreads',
1069  $forum_topic->getId()
1070  );
1071  $delete = $this->getLinkActionForThread(
1072  $ref_id,
1073  $this->lng->txt('delete_thread'),
1074  'confirmDeleteThreads',
1075  $forum_topic->getId()
1076  );
1077  $actions = $this->uiFactory->dropdown()->standard([
1078  $stick_or_no_stick,
1079  $open_close,
1080  $edit_title,
1081  $move,
1082  $merge,
1083  $delete
1084  ]);
1085  }
1086 
1087  return $actions;
1088  }
1089 
1090  private function getEditTitleModal(ilForumTopic $topic): RoundTrip
1091  {
1092  $topic_id = $this->refinery->kindlyTo()->string()->transform($topic->getId());
1093  $this->ctrl->setParameter($this, 'thr_pk', (string) $topic_id);
1094  $target = $this->ctrl->getLinkTargetByClass(
1095  ilObjForumGUI::class,
1096  'editThread'
1097  );
1098  $this->ctrl->setParameter($this, 'thread_id', null);
1099 
1100  return $this->factory->modal()->roundtrip(
1101  $this->lng->txt('frm_edit_title'),
1102  [],
1103  [
1104  $this->factory->input()->field()->text($this->lng->txt('frm_edit_title'))->withValue($topic->getSubject()),
1105  ],
1106  $target
1107  );
1108  }
1109 
1110  private function addDraftButtonIfDraftsExists(string $cmd)
1111  {
1113  $this->user->getId(),
1114  ilObjForum::lookupForumIdByObjId($this->object->getId())
1115  );
1116  if ($drafts !== []) {
1117  $draftsTable = new ilForumDraftsTableGUI(
1118  $this,
1119  $cmd,
1120  $this->access->checkAccess('add_thread', '', $this->object->getRefId())
1121  );
1122  $draftsTable->setData($drafts);
1123  $threadsTemplate = new ilTemplate(
1124  'tpl.forums_threads_liste.html',
1125  true,
1126  true,
1127  'Modules/Forum'
1128  );
1129  $threadsTemplate->setVariable('THREADS_DRAFTS_TABLE', $draftsTable->getHTML());
1130 
1131  $draft_modal = $this->factory->modal()->roundtrip(
1132  $this->lng->txt('drafts'),
1133  [$this->factory->legacy($threadsTemplate->get())]
1134  );
1135  $this->modal_collection[] = $draft_modal;
1136  $edit_title = $this->factory->button()->standard($this->lng->txt('drafts'), '#')->withOnClick(
1137  $draft_modal->getShowSignal()
1138  );
1139  $this->toolbar->addComponent($edit_title);
1140 
1141  return $draft_modal;
1142  }
1143  }
1144 
1145  private function getStickyActionForThread(ilForumTopic $forum_topic, int $ref_id): \ILIAS\UI\Component\Link\Link
1146  {
1147  return $this->getLinkActionForThread(
1148  $ref_id,
1149  $this->lng->txt($forum_topic->isSticky() ? 'make_topics_non_sticky' : 'make_topics_sticky'),
1150  $forum_topic->isSticky() ? 'make_topics_non_sticky' : 'makesticky',
1151  $forum_topic->getId()
1152  );
1153  }
1154 
1155  private function getOpenCloseActionForThread(ilForumTopic $forum_topic, int $ref_id): \ILIAS\UI\Component\Link\Link
1156  {
1157  return $this->getLinkActionForThread(
1158  $ref_id,
1159  $this->lng->txt($forum_topic->isClosed() ? 'reopen_topics' : 'close_topics'),
1160  $forum_topic->isClosed() ? 'reopen' : 'close',
1161  $forum_topic->getId()
1162  );
1163  }
1164 
1165  private function markTopThreadInOverview(
1166  ilForumTopic $current_thread,
1167  Item $list_item
1168  ): Item {
1169  if ($current_thread->isSticky()) {
1170  $df = new \ILIAS\Data\Factory();
1171  $list_item = $list_item->withColor($df->color('#B54F00'));
1172  }
1173 
1174  return $list_item;
1175  }
1176 
1177  private function initStyleSheets(): void
1178  {
1179  $this->content_style_gui->addCss($this->tpl, $this->ref_id);
1180  $this->tpl->setCurrentBlock('SyntaxStyle');
1181  $this->tpl->setVariable('LOCATION_SYNTAX_STYLESHEET', ilObjStyleSheet::getSyntaxStylePath());
1182  $this->tpl->parseCurrentBlock();
1183  }
1184 
1185  private function editStylePropertiesObject(): void
1186  {
1187  $this->content_style_gui->redirectToObjectSettings();
1188  }
1189 
1193  private function renderDraftContent(
1194  ilTemplate $tpl,
1195  string $action,
1196  ilForumPost $referencePosting,
1197  array $drafts
1198  ): void {
1199  $frm = $this->object->Forum;
1200 
1201  $ref_id = $this->retrieveRefId();
1202  $draft_id = $this->retrieveDraftId();
1203 
1204  foreach ($drafts as $draft) {
1205  $tmp_file_obj = new ilFileDataForumDrafts($this->object->getId(), $draft->getDraftId());
1206  $filesOfDraft = $tmp_file_obj->getFilesOfPost();
1207  ksort($filesOfDraft);
1208 
1209  if ($action !== 'showdraft' && $filesOfDraft !== []) {
1210  foreach ($filesOfDraft as $file) {
1211  $tpl->setCurrentBlock('attachment_download_row');
1212  $this->ctrl->setParameter($this, 'draft_id', $draft->getDraftId());
1213  $this->ctrl->setParameter($this, 'file', $file['md5']);
1214  $tpl->setVariable('HREF_DOWNLOAD', $this->ctrl->getLinkTarget($this, 'viewThread'));
1215  $tpl->setVariable('TXT_FILENAME', $file['name']);
1216  $this->ctrl->setParameter($this, 'file', '');
1217  $this->ctrl->setParameter($this, 'draft_id', '');
1218  $this->ctrl->clearParameters($this);
1219  $tpl->parseCurrentBlock();
1220  }
1221 
1222  $tpl->setCurrentBlock('attachments');
1223  $tpl->setVariable('TXT_ATTACHMENTS_DOWNLOAD', $this->lng->txt('forums_attachments'));
1224  $tpl->setVariable(
1225  'DOWNLOAD_IMG',
1226  $this->uiRenderer->render(
1227  $this->uiFactory->symbol()->glyph()->attachment($this->lng->txt('forums_download_attachment'))
1228  )
1229  );
1230  if (count($filesOfDraft) > 1) {
1231  $this->ctrl->setParameter($this, 'draft_id', $draft->getDraftId());
1232  $download_zip_button = $this->uiFactory->button()
1233  ->standard(
1234  $this->lng->txt('download'),
1235  $this->ctrl->getLinkTarget($this, 'deliverDraftZipFile')
1236  );
1237  $this->ctrl->setParameter($this, 'draft_id', '');
1238  $tpl->setVariable('DOWNLOAD_ZIP', $this->uiRenderer->render($download_zip_button));
1239  }
1240  $tpl->parseCurrentBlock();
1241  }
1242 
1243  $page = $this->http->wrapper()->query()->retrieve(
1244  'page',
1245  $this->refinery->byTrying([$this->refinery->kindlyTo()->int(), $this->refinery->always(0)])
1246  );
1247 
1248  $this->renderSplitButton(
1249  $tpl,
1250  $action,
1251  false,
1252  $referencePosting,
1253  (int) $page,
1254  $draft
1255  );
1256 
1257  $rowCol = 'tblrowmarked';
1258  $tpl->setVariable('ROWCOL', ' ' . $rowCol);
1259  $depth = $referencePosting->getDepth() - 1;
1260  if ($this->selectedSorting === ilForumProperties::VIEW_TREE) {
1261  ++$depth;
1262  }
1263  $tpl->setVariable('DEPTH', $depth);
1264 
1265  $this->ctrl->setParameter($this, 'pos_pk', $referencePosting->getId());
1266  $this->ctrl->setParameter($this, 'thr_pk', $referencePosting->getThreadId());
1267  $this->ctrl->setParameter($this, 'draft_id', $draft->getDraftId());
1268 
1269  $backurl = urlencode($this->ctrl->getLinkTarget($this, 'viewThread', (string) $referencePosting->getId()));
1270 
1271  $this->ctrl->setParameter($this, 'backurl', $backurl);
1272  $this->ctrl->setParameter($this, 'thr_pk', $referencePosting->getThreadId());
1273  $this->ctrl->setParameter($this, 'user', $draft->getPostDisplayUserId());
1274 
1275  $authorinfo = new ilForumAuthorInformation(
1276  $draft->getPostAuthorId(),
1277  $draft->getPostDisplayUserId(),
1278  $draft->getPostUserAlias(),
1279  '',
1280  [
1281  'href' => $this->ctrl->getLinkTarget($this, 'showUser')
1282  ]
1283  );
1284 
1285  $this->ctrl->clearParameters($this);
1286 
1287  if ($authorinfo->hasSuffix()) {
1288  $tpl->setVariable('AUTHOR', $authorinfo->getSuffix());
1289  $tpl->setVariable('USR_NAME', $draft->getPostUserAlias());
1290  } else {
1291  $tpl->setVariable('AUTHOR', $authorinfo->getLinkedAuthorShortName());
1292  if ($authorinfo->getAuthorName(true) && !$this->objProperties->isAnonymized()) {
1293  $tpl->setVariable('USR_NAME', $authorinfo->getAuthorName(true));
1294  }
1295  }
1296  $tpl->setVariable('DRAFT_ANCHOR', 'draft_' . $draft->getDraftId());
1297 
1298  $tpl->setVariable('USR_IMAGE', $authorinfo->getProfilePicture());
1299  $tpl->setVariable(
1300  'USR_ICON_ALT',
1301  ilLegacyFormElementsUtil::prepareFormOutput($authorinfo->getAuthorShortName())
1302  );
1303  if ($authorinfo->getAuthor()->getId() && ilForum::_isModerator(
1304  $ref_id,
1305  $draft->getPostAuthorId()
1306  )) {
1307  if ($authorinfo->getAuthor()->getGender() === 'f') {
1308  $tpl->setVariable('ROLE', $this->lng->txt('frm_moderator_f'));
1309  } elseif ($authorinfo->getAuthor()->getGender() === 'm') {
1310  $tpl->setVariable('ROLE', $this->lng->txt('frm_moderator_m'));
1311  } elseif ($authorinfo->getAuthor()->getGender() === 'n') {
1312  $tpl->setVariable('ROLE', $this->lng->txt('frm_moderator_n'));
1313  }
1314  }
1315 
1316  if ($draft->getUpdateUserId() > 0) {
1317  $draft->setPostUpdate($draft->getPostUpdate());
1318 
1319  $this->ctrl->setParameter($this, 'backurl', $backurl);
1320  $this->ctrl->setParameter($this, 'thr_pk', $referencePosting->getThreadId());
1321  $this->ctrl->setParameter($this, 'user', $referencePosting->getUpdateUserId());
1322  $this->ctrl->setParameter($this, 'draft_id', $draft->getDraftId());
1323 
1324  $authorinfo = new ilForumAuthorInformation(
1325  $draft->getPostAuthorId(),
1326  // We assume the editor is the author here
1327  $draft->getPostDisplayUserId(),
1328  $draft->getPostUserAlias(),
1329  '',
1330  ['href' => $this->ctrl->getLinkTarget($this, 'showUser')]
1331  );
1332 
1333  $this->ctrl->clearParameters($this);
1334 
1335  $tpl->setVariable(
1336  'POST_UPDATE_TXT',
1337  $this->lng->txt('edited_on') . ': ' . $frm->convertDate($draft->getPostUpdate()) . ' - ' . strtolower($this->lng->txt('by'))
1338  );
1339  $tpl->setVariable('UPDATE_AUTHOR', $authorinfo->getLinkedAuthorShortName());
1340  if ($authorinfo->getAuthorName(true) && !$this->objProperties->isAnonymized() && !$authorinfo->hasSuffix()) {
1341  $tpl->setVariable('UPDATE_USR_NAME', $authorinfo->getAuthorName(true));
1342  }
1343  }
1344 
1345  $draft->setPostMessage($frm->prepareText($draft->getPostMessage()));
1346 
1347  $tpl->setVariable('SUBJECT', $draft->getPostSubject());
1348  $tpl->setVariable('POST_DATE', $frm->convertDate($draft->getPostDate()));
1349 
1350  $tpl->setVariable('POST_DRAFT_TEXT', $this->lng->txt('post_draft_info'));
1351 
1352  if (!$referencePosting->isCensored() || ($this->objCurrentPost->getId() === $referencePosting->getId() && $action === 'censor')) {
1353  $spanClass = '';
1354  if (ilForum::_isModerator($this->ref_id, $draft->getPostDisplayUserId())) {
1355  $spanClass = 'moderator';
1356  }
1357 
1358  if ($draft->getPostMessage() === strip_tags($draft->getPostMessage())) {
1359  // We can be sure, that there are not html tags
1360  $draft->setPostMessage(nl2br($draft->getPostMessage()));
1361  }
1362 
1363  if ($spanClass !== '') {
1364  $tpl->setVariable(
1365  'POST',
1366  '<span class="' . $spanClass . '">' . ilRTE::_replaceMediaObjectImageSrc(
1367  $draft->getPostMessage(),
1368  1
1369  ) . '</span>'
1370  );
1371  } else {
1372  $tpl->setVariable('POST', ilRTE::_replaceMediaObjectImageSrc($draft->getPostMessage(), 1));
1373  }
1374  }
1375 
1376  if ($action === 'editdraft' && $draft->getDraftId() === $draft_id) {
1377  $oEditReplyForm = $this->getReplyEditForm();
1378 
1379  if (!$this->objCurrentTopic->isClosed() && in_array($this->requestAction, ['showdraft', 'editdraft'])) {
1380  $this->renderPostingForm($tpl, $frm, $referencePosting, $this->requestAction);
1381  }
1382 
1383  $tpl->setVariable('EDIT_DRAFT_ANCHOR', 'draft_edit_' . $draft->getDraftId());
1384  $tpl->setVariable('DRAFT_FORM', $oEditReplyForm->getHTML() . $this->modal_history);
1385  }
1386 
1387  $tpl->parseCurrentBlock();
1388  }
1389  }
1390 
1391  protected function renderPostContent(
1392  ilTemplate $tpl,
1393  ilForumPost $node,
1394  string $action,
1395  int $pageIndex,
1396  int $postIndex
1397  ): void {
1398  $forumObj = $this->object;
1399  $frm = $this->object->Forum;
1400 
1401  $fileDataOfForum = new ilFileDataForum($forumObj->getId(), $node->getId());
1402 
1403  $filesOfPost = $fileDataOfForum->getFilesOfPost();
1404  ksort($filesOfPost);
1405  if ($filesOfPost !== [] && ($action !== 'showedit' || $node->getId() !== $this->objCurrentPost->getId())) {
1406  foreach ($filesOfPost as $file) {
1407  $tpl->setCurrentBlock('attachment_download_row');
1408  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
1409  $this->ctrl->setParameter($this, 'file', $file['md5']);
1410  $tpl->setVariable('HREF_DOWNLOAD', $this->ctrl->getLinkTarget($this, 'viewThread'));
1411  $tpl->setVariable('TXT_FILENAME', $file['name']);
1412  $this->ctrl->clearParameters($this);
1413  $tpl->parseCurrentBlock();
1414  }
1415  $tpl->setCurrentBlock('attachments');
1416  $tpl->setVariable('TXT_ATTACHMENTS_DOWNLOAD', $this->lng->txt('forums_attachments'));
1417  $tpl->setVariable(
1418  'DOWNLOAD_IMG',
1419  $this->uiRenderer->render(
1420  $this->uiFactory->symbol()->glyph()->attachment($this->lng->txt('forums_download_attachment'))
1421  )
1422  );
1423  if (count($filesOfPost) > 1) {
1424  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
1425  $download_zip_button = $this->uiFactory->button()
1426  ->standard(
1427  $this->lng->txt('download'),
1428  $this->ctrl->getLinkTarget($this, 'deliverZipFile')
1429  );
1430  $tpl->setVariable('DOWNLOAD_ZIP', $this->uiRenderer->render($download_zip_button));
1431  }
1432  $tpl->parseCurrentBlock();
1433  }
1434  $this->renderSplitButton($tpl, $action, true, $node, $pageIndex);
1435 
1436  $tpl->setVariable('POST_ANKER', $node->getId());
1437  $tpl->setVariable('TXT_PERMA_LINK', $this->lng->txt('perma_link'));
1438  $tpl->setVariable('PERMA_TARGET', '_top');
1439 
1440  $rowCol = ilUtil::switchColor($postIndex, 'tblrow1', 'tblrow2');
1441  if (($this->is_moderator || $node->isOwner($this->user->getId())) && !$node->isActivated() && !$this->objCurrentTopic->isClosed()) {
1442  $rowCol = 'ilPostingNeedsActivation';
1443  } elseif ($this->objProperties->getMarkModeratorPosts()) {
1444  $isAuthorModerator = ilForum::_isModerator($this->object->getRefId(), $node->getPosAuthorId());
1445  if ($isAuthorModerator && $node->isAuthorModerator() === null) {
1446  $rowCol = 'ilModeratorPosting';
1447  } elseif ($node->isAuthorModerator()) {
1448  $rowCol = 'ilModeratorPosting';
1449  }
1450  }
1451 
1452  if (
1453  (!in_array($action, ['delete', 'censor']) && !$this->displayConfirmPostActivation()) ||
1454  $this->objCurrentPost->getId() !== $node->getId()
1455  ) {
1456  $tpl->setVariable('ROWCOL', ' ' . $rowCol);
1457  } else {
1458  $rowCol = 'tblrowmarked';
1459  }
1460 
1461  if ($node->isCensored()) {
1462  if ($action !== 'censor') {
1463  $tpl->setVariable('TXT_CENSORSHIP_ADVICE', $this->lng->txt('post_censored_comment_by_moderator'));
1464  }
1465 
1466  $rowCol = 'tblrowmarked';
1467  }
1468 
1469  $tpl->setVariable('ROWCOL', ' ' . $rowCol);
1470  $tpl->setVariable('DEPTH', $node->getDepth() - 1);
1471  if (!$node->isActivated() && ($node->isOwner($this->user->getId()) || $this->is_moderator)) {
1472  $tpl->setVariable('POST_NOT_ACTIVATED_YET', $this->lng->txt('frm_post_not_activated_yet'));
1473  }
1474 
1475  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
1476  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
1477  $backurl = urlencode($this->ctrl->getLinkTarget($this, 'viewThread', (string) $node->getId()));
1478  $this->ctrl->clearParameters($this);
1479 
1480  $this->ctrl->setParameter($this, 'backurl', $backurl);
1481  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
1482  $this->ctrl->setParameter($this, 'user', $node->getDisplayUserId());
1483  $authorinfo = new ilForumAuthorInformation(
1484  $node->getPosAuthorId(),
1485  $node->getDisplayUserId(),
1486  (string) $node->getUserAlias(),
1487  (string) $node->getImportName(),
1488  [
1489  'href' => $this->ctrl->getLinkTarget($this, 'showUser')
1490  ]
1491  );
1492  $this->ctrl->clearParameters($this);
1493 
1494  if ($authorinfo->hasSuffix()) {
1495  if (!$authorinfo->isDeleted()) {
1496  $tpl->setVariable('USR_NAME', $authorinfo->getAlias());
1497  }
1498  $tpl->setVariable('AUTHOR', $authorinfo->getSuffix());
1499  } else {
1500  if ($authorinfo->getAuthorName(true) && !$this->objProperties->isAnonymized()) {
1501  $tpl->setVariable('USR_NAME', $authorinfo->getAuthorName(true));
1502  }
1503  $tpl->setVariable('AUTHOR', $authorinfo->getLinkedAuthorShortName());
1504  }
1505 
1506  $tpl->setVariable('USR_IMAGE', $authorinfo->getProfilePicture());
1507  $tpl->setVariable(
1508  'USR_ICON_ALT',
1509  ilLegacyFormElementsUtil::prepareFormOutput($authorinfo->getAuthorShortName())
1510  );
1511  $isModerator = ilForum::_isModerator($this->ref_id, $node->getPosAuthorId());
1512  if ($isModerator && $authorinfo->getAuthor()->getId()) {
1513  $authorRole = $this->lng->txt('frm_moderator_n');
1514  if (is_string($authorinfo->getAuthor()->getGender()) && $authorinfo->getAuthor()->getGender() !== '') {
1515  $authorRole = $this->lng->txt('frm_moderator_' . $authorinfo->getAuthor()->getGender());
1516  }
1517  $tpl->setVariable('ROLE', $authorRole);
1518  }
1519 
1520  if ($node->getUpdateUserId() > 0) {
1521  $node->setChangeDate($node->getChangeDate());
1522 
1523  $this->ctrl->setParameter($this, 'backurl', $backurl);
1524  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
1525  $this->ctrl->setParameter($this, 'user', $node->getUpdateUserId());
1526  $update_user_id = $node->getUpdateUserId();
1527  if ($node->getDisplayUserId() === 0 && $node->getPosAuthorId() === $node->getUpdateUserId()) {
1528  $update_user_id = $node->getDisplayUserId();
1529  }
1530  $authorinfo = new ilForumAuthorInformation(
1531  $node->getPosAuthorId(),
1532  $update_user_id,
1533  (string) $node->getUserAlias(),
1534  (string) $node->getImportName(),
1535  [
1536  'href' => $this->ctrl->getLinkTarget($this, 'showUser')
1537  ]
1538  );
1539  $this->ctrl->clearParameters($this);
1540 
1541  $tpl->setVariable(
1542  'POST_UPDATE_TXT',
1543  $this->lng->txt('edited_on') . ': ' . $frm->convertDate($node->getChangeDate()) . ' - ' . strtolower($this->lng->txt('by'))
1544  );
1545  $tpl->setVariable('UPDATE_AUTHOR', $authorinfo->getLinkedAuthorShortName());
1546  if ($authorinfo->getAuthorName(true) && !$this->objProperties->isAnonymized() && !$authorinfo->hasSuffix()) {
1547  $tpl->setVariable('UPDATE_USR_NAME', $authorinfo->getAuthorName(true));
1548  }
1549  }
1550 
1551  if ($this->selectedSorting === ilForumProperties::VIEW_TREE
1552  && $node->getId() !== $this->selected_post_storage->get($node->getThreadId())) {
1553  $target = $this->uiFactory->symbol()->icon()->custom(
1554  ilUtil::getImagePath('object/target.svg'),
1555  $this->lng->txt('target_select')
1556  );
1557 
1558  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
1559  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
1560 
1561  $tpl->setVariable(
1562  'TARGET',
1563  $this->uiRenderer->render(
1564  $this->uiFactory->link()->bulky(
1565  $target,
1566  $this->lng->txt('select'),
1567  new \ILIAS\Data\URI(
1568  ILIAS_HTTP_PATH . '/' . $this->ctrl->getLinkTarget($this, 'selectPost', (string) $node->getId())
1569  )
1570  )
1571  )
1572  );
1573  }
1574 
1575  $node->setMessage($frm->prepareText($node->getMessage()));
1576 
1577  if ($this->user->isAnonymous() || $node->isPostRead()) {
1578  $tpl->setVariable('SUBJECT', $node->getSubject());
1579  } else {
1580  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
1581  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
1582  $this->ctrl->setParameter($this, 'page', $pageIndex);
1583  $this->ctrl->setParameter(
1584  $this,
1585  'orderby',
1586  $this->getOrderByParam()
1587  );
1588  $this->ctrl->setParameter($this, 'viewmode', $this->selectedSorting);
1589  $mark_post_target = $this->ctrl->getLinkTarget($this, 'markPostRead', (string) $node->getId());
1590 
1591  $tpl->setVariable(
1592  'SUBJECT',
1593  '<a href="' . $mark_post_target . '"><b>' . $node->getSubject() . '</b></a>'
1594  );
1595  }
1596 
1597  $tpl->setVariable('POST_DATE', $frm->convertDate($node->getCreateDate()));
1598 
1599  if (!$node->isCensored() || ($this->objCurrentPost->getId() === $node->getId() && $action === 'censor')) {
1600  $spanClass = '';
1601  if (ilForum::_isModerator($this->ref_id, $node->getDisplayUserId())) {
1602  $spanClass = 'moderator';
1603  }
1604 
1605  // possible bugfix for mantis #8223
1606  if ($node->getMessage() === strip_tags($node->getMessage())) {
1607  // We can be sure, that there are not html tags
1608  $node->setMessage(nl2br($node->getMessage()));
1609  }
1610 
1611  if ($spanClass !== '') {
1612  $tpl->setVariable(
1613  'POST',
1614  '<span class="' . $spanClass . '">' .
1616  '</span>'
1617  );
1618  } else {
1619  $tpl->setVariable('POST', ilRTE::_replaceMediaObjectImageSrc($node->getMessage(), 1));
1620  }
1621  } else {
1622  $tpl->setVariable(
1623  'POST',
1624  '<span class="moderator">' . nl2br((string) $node->getCensorshipComment()) . '</span>'
1625  );
1626  }
1627 
1628  $tpl->parseCurrentBlock();
1629  }
1630 
1631  protected function selectPostObject(): void
1632  {
1633  $thr_pk = (int) $this->httpRequest->getQueryParams()['thr_pk'];
1634  $pos_pk = (int) $this->httpRequest->getQueryParams()['pos_pk'];
1635 
1636  $this->selected_post_storage->set(
1637  $thr_pk,
1638  $pos_pk
1639  );
1640 
1641  $this->viewThreadObject();
1642  }
1643 
1647  protected function afterSave(ilObject $new_object): void
1648  {
1649  $this->tpl->setOnScreenMessage('success', $this->lng->txt('frm_added'), true);
1650  $this->ctrl->setParameter($this, 'ref_id', $new_object->getRefId());
1651  $this->ctrl->redirect($this, 'createThread');
1652  }
1653 
1654  protected function getTabs(): void
1655  {
1656  if ($this->in_page_editor_style_context) {
1657  return;
1658  }
1659 
1660  $this->ilHelp->setScreenIdComponent('frm');
1661 
1662  $this->ctrl->setParameter($this, 'ref_id', $this->ref_id);
1663 
1664  $active = [
1665  '',
1666  'showThreads',
1667  'view',
1668  'markAllRead',
1669  'enableForumNotification',
1670  'disableForumNotification',
1671  'moveThreads',
1672  'performMoveThreads',
1673  'cancelMoveThreads',
1674  'performThreadsAction',
1675  'createThread',
1676  'addThread',
1677  'showUser',
1678  'confirmDeleteThreads',
1679  'merge',
1680  'mergeThreads',
1681  'performMergeThreads'
1682  ];
1683 
1684  $force_active = false;
1685  if (in_array($this->ctrl->getCmd(), $active, true)) {
1686  $force_active = true;
1687  }
1688 
1689  if ($this->access->checkAccess(
1690  'read',
1691  '',
1692  $this->ref_id
1693  )) {
1694  $this->tabs_gui->addTarget(
1695  self::UI_TAB_ID_THREADS,
1696  $this->ctrl->getLinkTarget($this, 'showThreads'),
1697  $this->ctrl->getCmd(),
1698  $this::class,
1699  '',
1700  $force_active
1701  );
1702  }
1703 
1704  if ($this->access->checkAccess('visible', '', $this->ref_id) || $this->access->checkAccess(
1705  'read',
1706  '',
1707  $this->ref_id
1708  )) {
1709  $cmdClass = $this->http->wrapper()->query()->retrieve(
1710  'cmdClass',
1711  $this->refinery->byTrying([$this->refinery->kindlyTo()->string(), $this->refinery->always('')])
1712  );
1713 
1714  $force_active = $this->ctrl->getNextClass() === 'ilinfoscreengui' || strtolower($cmdClass) === 'ilnotegui';
1715  $this->tabs_gui->addTarget(
1716  self::UI_TAB_ID_INFO,
1717  $this->ctrl->getLinkTargetByClass([__CLASS__, ilInfoScreenGUI::class], 'showSummary'),
1718  ['showSummary', 'infoScreen'],
1719  '',
1720  '',
1721  $force_active
1722  );
1723  }
1724 
1725  if ($this->access->checkAccess('write', '', $this->ref_id)) {
1726  $force_active = $this->ctrl->getCmd() === 'edit';
1727  $this->tabs_gui->addTarget(
1728  self::UI_TAB_ID_SETTINGS,
1729  $this->ctrl->getLinkTarget($this, 'edit'),
1730  'edit',
1731  $this::class,
1732  '',
1733  $force_active
1734  );
1735  }
1736 
1737  if ($this->access->checkAccess('write', '', $this->ref_id)) {
1738  $this->tabs_gui->addTarget(
1739  self::UI_TAB_ID_MODERATORS,
1740  $this->ctrl->getLinkTargetByClass(ilForumModeratorsGUI::class, 'showModerators'),
1741  'showModerators',
1742  $this::class
1743  );
1744  }
1745 
1746  if (ilLearningProgressAccess::checkAccess($this->object->getRefId())) {
1747  $this->tabs_gui->addTab(
1748  'learning_progress',
1749  $this->lng->txt('learning_progress'),
1750  $this->ctrl->getLinkTargetByClass(ilLearningProgressGUI::class)
1751  );
1752  }
1753 
1754  if ($this->settings->get('enable_fora_statistics', '0')) {
1755  $hasStatisticsAccess = $this->access->checkAccess('write', '', $this->ref_id);
1756  if (!$hasStatisticsAccess) {
1757  $hasStatisticsAccess = (
1758  $this->objProperties->isStatisticEnabled() &&
1759  $this->access->checkAccess('read', '', $this->ref_id)
1760  );
1761  }
1762 
1763  if ($hasStatisticsAccess) {
1764  $force_active = $this->ctrl->getCmd() === 'showStatistics';
1765  $this->tabs_gui->addTarget(
1766  self::UI_TAB_ID_STATS,
1767  $this->ctrl->getLinkTarget($this, 'showStatistics'),
1768  'showStatistics',
1769  $this::class,
1770  '',
1771  $force_active
1772  );
1773  }
1774  }
1775 
1776  if ($this->access->checkAccess('write', '', $this->object->getRefId())) {
1777  $this->tabs_gui->addTarget(
1778  self::UI_TAB_ID_EXPORT,
1779  $this->ctrl->getLinkTargetByClass(ilExportGUI::class, ''),
1780  '',
1781  'ilexportgui'
1782  );
1783  }
1784 
1785  if ($this->access->checkAccess('edit_permission', '', $this->ref_id)) {
1786  $this->tabs_gui->addTarget(
1787  self::UI_TAB_ID_PERMISSIONS,
1788  $this->ctrl->getLinkTargetByClass([$this::class, ilPermissionGUI::class], 'perm'),
1789  ['perm', 'info', 'owner'],
1790  'ilpermissiongui'
1791  );
1792  }
1793  }
1794 
1795  public function showStatisticsObject(): void
1796  {
1797  if (!$this->settings->get('enable_fora_statistics', '0')) {
1798  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
1799  }
1800 
1801  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
1802  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
1803  }
1804 
1805  if (!$this->objProperties->isStatisticEnabled()) {
1806  if ($this->access->checkAccess('write', '', $this->object->getRefId())) {
1807  $this->tpl->setOnScreenMessage('info', $this->lng->txt('frm_statistics_disabled_for_participants'));
1808  } else {
1809  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
1810  }
1811  }
1812 
1813  $this->object->Forum->setForumId($this->object->getId());
1814 
1815  $tbl = new ilForumStatisticsTableGUI(
1816  $this,
1817  'showStatistics',
1818  $this->object,
1819  $this->user,
1820  ilLearningProgressAccess::checkAccess($this->object->getRefId()),
1821  $this->access->checkRbacOrPositionPermissionAccess(
1822  'read_learning_progress',
1823  'read_learning_progress',
1824  $this->object->getRefId()
1825  )
1826  );
1827  $tbl->setId('il_frm_statistic_table_' . $this->object->getRefId());
1828  $tbl->setTitle(
1829  $this->lng->txt('statistic'),
1830  'standard/icon_usr.svg',
1831  $this->lng->txt('obj_' . $this->object->getType())
1832  );
1833 
1834  $data = $this->object->Forum->getUserStatistics($this->objProperties->isPostActivationEnabled());
1835  $result = [];
1836  $counter = 0;
1837  foreach ($data as $row) {
1838  $result[$counter]['usr_id'] = $row['usr_id'];
1839  $result[$counter]['ranking'] = $row['num_postings'];
1840  $result[$counter]['login'] = $row['login'];
1841  $result[$counter]['lastname'] = $row['lastname'];
1842  $result[$counter]['firstname'] = $row['firstname'];
1843 
1844  ++$counter;
1845  }
1846  $tbl->setData($result);
1847 
1848  $this->tpl->setContent($tbl->getHTML());
1849  }
1850 
1851  public static function _goto($a_target, $a_thread = 0, $a_posting = 0): void
1852  {
1853  global $DIC;
1854  $main_tpl = $DIC->ui()->mainTemplate();
1855 
1856  $ilAccess = $DIC->access();
1857  $lng = $DIC->language();
1858  $ilErr = $DIC['ilErr'];
1859 
1860  $a_target = is_numeric($a_target) ? (int) $a_target : 0;
1861  $a_thread = is_numeric($a_thread) ? (int) $a_thread : 0;
1862  if ($ilAccess->checkAccess('read', '', $a_target)) {
1863  if ($a_thread !== 0) {
1864  $objTopic = new ilForumTopic($a_thread);
1865  if ($objTopic->getFrmObjId() &&
1866  $objTopic->getFrmObjId() !== ilObject::_lookupObjectId($a_target)) {
1867  $ref_ids = ilObject::_getAllReferences($objTopic->getFrmObjId());
1868  foreach ($ref_ids as $ref_id) {
1869  if ($ilAccess->checkAccess('read', '', $ref_id)) {
1870  $new_ref_id = $ref_id;
1871  break;
1872  }
1873  }
1874 
1875  if (isset($new_ref_id) && $new_ref_id !== $a_target) {
1876  $DIC->ctrl()->redirectToURL(
1877  ILIAS_HTTP_PATH . '/goto.php?target=frm_' . $new_ref_id . '_' . $a_thread . '_' . $a_posting
1878  );
1879  }
1880  }
1881 
1882  $DIC->ctrl()->setParameterByClass(__CLASS__, 'ref_id', (string) ((int) $a_target));
1883  if (is_numeric($a_thread)) {
1884  $DIC->ctrl()->setParameterByClass(__CLASS__, 'thr_pk', (string) ((int) $a_thread));
1885  }
1886  if (is_numeric($a_posting)) {
1887  $DIC->ctrl()->setParameterByClass(__CLASS__, 'pos_pk', (string) ((int) $a_posting));
1888  }
1889  $DIC->ctrl()->redirectByClass(
1890  [ilRepositoryGUI::class, self::class],
1891  'viewThread',
1892  is_numeric($a_posting) ? (string) ((int) $a_posting) : ''
1893  );
1894  } else {
1895  $DIC->ctrl()->setParameterByClass(self::class, 'ref_id', $a_target);
1896  $DIC->ctrl()->redirectByClass([ilRepositoryGUI::class, self::class,], '');
1897  $DIC->http()->close();
1898  }
1899  } elseif ($ilAccess->checkAccess('visible', '', $a_target)) {
1900  $DIC->ctrl()->setParameterByClass(ilInfoScreenGUI::class, 'ref_id', $a_target);
1901  $DIC->ctrl()->redirectByClass(
1902  [
1903  ilRepositoryGUI::class,
1904  self::class,
1905  ilInfoScreenGUI::class
1906  ],
1907  'showSummary'
1908  );
1909  } elseif ($ilAccess->checkAccess('read', '', ROOT_FOLDER_ID)) {
1910  $main_tpl->setOnScreenMessage('info', sprintf(
1911  $lng->txt('msg_no_perm_read_item'),
1913  ), true);
1914  $DIC->http()->close();
1915  }
1916 
1917  $ilErr->raiseError($lng->txt('msg_no_perm_read'), $ilErr->FATAL);
1918  }
1919 
1920  public function performDeleteThreadsObject(): void
1921  {
1922  $threadIds = $this->retrieveThreadIds();
1923  if ($threadIds === []) {
1924  $this->tpl->setOnScreenMessage('info', $this->lng->txt('select_at_least_one_thread'), true);
1925  $this->ctrl->redirect($this, 'showThreads');
1926  }
1927 
1928  if (!$this->is_moderator) {
1929  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
1930  }
1931 
1932  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
1933  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
1934  }
1935 
1936  $forumObj = new ilObjForum($this->object->getRefId());
1937  $this->objProperties->setObjId($forumObj->getId());
1938 
1939  $frm = new ilForum();
1940 
1941  $success_message = 'forums_thread_deleted';
1942  if (count($threadIds) > 1) {
1943  $success_message = 'forums_threads_deleted';
1944  }
1945 
1946  $threads = [];
1947  array_walk($threadIds, function (int $threadId) use (&$threads): void {
1948  $thread = new ilForumTopic($threadId);
1949  $this->ensureThreadBelongsToForum($this->object->getId(), $thread);
1950 
1951  $threads[] = $thread;
1952  });
1953 
1954  $frm->setForumId($forumObj->getId());
1955  $frm->setForumRefId($forumObj->getRefId());
1956  foreach ($threads as $thread) {
1957  $first_node = $frm->getFirstPostNode($thread->getId());
1958  if (isset($first_node['pos_pk']) && (int) $first_node['pos_pk']) {
1959  $frm->deletePost((int) $first_node['pos_pk']);
1960  $this->tpl->setOnScreenMessage('info', $this->lng->txt($success_message), true);
1961  }
1962  }
1963  $this->ctrl->redirect($this, 'showThreads');
1964  }
1965 
1966  public function confirmDeleteThreadsObject(): void
1967  {
1968  $thread_ids = $this->retrieveThreadIds();
1969  if ($thread_ids === []) {
1970  $this->tpl->setOnScreenMessage('info', $this->lng->txt('select_at_least_one_thread'));
1971  $this->ctrl->redirect($this, 'showThreads');
1972  }
1973 
1974  if (!$this->is_moderator) {
1975  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
1976  }
1977 
1978  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
1979  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
1980  }
1981 
1983  $threads = [];
1984  array_walk($thread_ids, function (int $threadId) use (&$threads): void {
1985  $thread = new ilForumTopic($threadId);
1986  $this->ensureThreadBelongsToForum($this->object->getId(), $thread);
1987 
1988  $threads[] = $thread;
1989  });
1990 
1991  $c_gui = new ilConfirmationGUI();
1992 
1993  $c_gui->setFormAction($this->ctrl->getFormAction($this, 'performDeleteThreads'));
1994  $c_gui->setHeaderText($this->lng->txt('frm_sure_delete_threads'));
1995  $c_gui->setCancel($this->lng->txt('cancel'), 'showThreads');
1996  $c_gui->setConfirm($this->lng->txt('confirm'), 'performDeleteThreads');
1997 
1998  foreach ($threads as $thread) {
1999  $c_gui->addItem('thread_ids[]', (string) $thread->getId(), $thread->getSubject());
2000  }
2001 
2002  $this->confirmation_gui_html = $c_gui->getHTML();
2003 
2004  $this->hideToolbar(true);
2005  $this->tpl->setContent($c_gui->getHTML());
2006  }
2007 
2008  protected function confirmDeleteThreadDraftsObject(): void
2009  {
2010  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
2011  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2012  }
2013 
2014  $draftIds = array_filter((array) ($this->httpRequest->getParsedBody()['draft_ids'] ?? []));
2015  if ($draftIds === []) {
2016  $this->tpl->setOnScreenMessage('info', $this->lng->txt('select_at_least_one_thread'));
2017  $this->showThreadsObject();
2018  return;
2019  }
2020 
2021  $confirmation = new ilConfirmationGUI();
2022  $confirmation->setFormAction($this->ctrl->getFormAction($this, 'deleteThreadDrafts'));
2023  $confirmation->setHeaderText($this->lng->txt('sure_delete_drafts'));
2024  $confirmation->setCancel($this->lng->txt('cancel'), 'showThreads');
2025  $confirmation->setConfirm($this->lng->txt('confirm'), 'deleteThreadDrafts');
2026  $instances = ilForumPostDraft::getDraftInstancesByUserId($this->user->getId());
2027  foreach ($draftIds as $draftId) {
2028  if (array_key_exists($draftId, $instances)) {
2029  $confirmation->addItem('draft_ids[]', (string) $draftId, $instances[$draftId]->getPostSubject());
2030  }
2031  }
2032 
2033  $this->tpl->setContent($confirmation->getHTML());
2034  }
2035 
2036  public function prepareThreadScreen(ilObjForum $a_forum_obj): void
2037  {
2038  $this->ilHelp->setScreenIdComponent('frm');
2039 
2040  $this->tpl->loadStandardTemplate();
2041 
2042  $this->tpl->setTitleIcon(ilObject::_getIcon(0, 'big', 'frm'));
2043 
2044  $this->tabs_gui->setBackTarget(
2045  $this->lng->txt('frm_all_threads'),
2046  $this->ctrl->getLinkTarget(
2047  $this,
2048  'showThreads'
2049  )
2050  );
2051 
2053  $frm = $a_forum_obj->Forum;
2054  $frm->setForumId($a_forum_obj->getId());
2055  }
2056 
2057  public function performPostActivationObject(): void
2058  {
2059  if (!$this->is_moderator) {
2060  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2061  }
2062 
2063  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
2064  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2065  }
2066 
2067  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentPost->getThread());
2068 
2069  $this->objCurrentPost->activatePost();
2070  $GLOBALS['ilAppEventHandler']->raise(
2071  'Modules/Forum',
2072  'activatedPost',
2073  [
2074  'object' => $this->object,
2075  'ref_id' => $this->object->getRefId(),
2076  'post' => $this->objCurrentPost
2077  ]
2078  );
2079  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_post_was_activated'), true);
2080 
2081  $this->viewThreadObject();
2082  }
2083 
2084  private function deletePostingObject(): void
2085  {
2086  if (
2087  !$this->user->isAnonymous() &&
2088  !$this->objCurrentTopic->isClosed() && (
2089  $this->is_moderator ||
2090  ($this->objCurrentPost->isOwner($this->user->getId()) && !$this->objCurrentPost->hasReplies())
2091  )
2092  ) {
2093  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentPost->getThread());
2094 
2095  $oForumObjects = $this->getForumObjects();
2096  $forumObj = $oForumObjects['forumObj'];
2097 
2098  $frm = new ilForum();
2099  $frm->setForumId($forumObj->getId());
2100  $frm->setForumRefId($forumObj->getRefId());
2101  $dead_thr = $frm->deletePost($this->objCurrentPost->getId());
2102 
2103  // if complete thread was deleted ...
2104  if ($dead_thr === $this->objCurrentTopic->getId()) {
2105  $frm->setMDB2WhereCondition('top_frm_fk = %s ', ['integer'], [$forumObj->getId()]);
2106  $topicData = $frm->getOneTopic();
2107  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_post_deleted'), true);
2108  if ($topicData->getTopNumThreads() > 0) {
2109  $this->ctrl->redirect($this, 'showThreads');
2110  } else {
2111  $this->ctrl->redirect($this, 'createThread');
2112  }
2113  }
2114  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_post_deleted'), true);
2115  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
2116  $this->ctrl->redirect($this, 'viewThread');
2117  }
2118 
2119  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2120  }
2121 
2122  private function deletePostingDraftObject(): void
2123  {
2124  $this->deleteSelectedDraft();
2125  }
2126 
2127  private function revokeCensorshipObject(): void
2128  {
2129  $this->handleCensorship(true);
2130  }
2131 
2132  private function addCensorshipObject(): void
2133  {
2134  $this->handleCensorship();
2135  }
2136 
2137  private function getModalActions(): string
2138  {
2139  $modalString = '';
2140  foreach ($this->modalActionsContainer as $modal) {
2141  $modalString .= $this->uiRenderer->render($modal);
2142  }
2143 
2144  return $modalString;
2145  }
2146 
2147  private function handleCensorship(bool $wasRevoked = false): void
2148  {
2149  $message = '';
2150  if ($this->is_moderator && !$this->objCurrentTopic->isClosed()) {
2151  if ($this->http->wrapper()->post()->has('formData')) {
2152  $formData = $this->http->wrapper()->post()->retrieve(
2153  'formData',
2154  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->string())
2155  );
2156  $message = $this->handleFormInput($formData['cens_message']);
2157  }
2158 
2159  if ($message === '' && $this->http->wrapper()->post()->has('cens_message')) {
2160  $cens_message = $this->http->wrapper()->post()->retrieve(
2161  'cens_message',
2162  $this->refinery->kindlyTo()->string()
2163  );
2164  $message = $this->handleFormInput($cens_message);
2165  }
2166  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentPost->getThread());
2167 
2168  $oForumObjects = $this->getForumObjects();
2169  $frm = $oForumObjects['frm'];
2170 
2171  if ($wasRevoked) {
2172  $frm->postCensorship($this->object, $message, $this->objCurrentPost->getId());
2173  $this->tpl->setOnScreenMessage('success', $this->lng->txt('frm_censorship_revoked'));
2174  } else {
2175  $frm->postCensorship($this->object, $message, $this->objCurrentPost->getId(), 1);
2176  $this->tpl->setOnScreenMessage('success', $this->lng->txt('frm_censorship_applied'));
2177  }
2178 
2179  $this->viewThreadObject();
2180  return;
2181  }
2182 
2183  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2184  }
2185 
2186  public function askForPostActivationObject(): void
2187  {
2188  if (!$this->is_moderator) {
2189  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2190  }
2191 
2192  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
2193  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2194  }
2195 
2196  $this->setDisplayConfirmPostActivation(true);
2197 
2198  $this->viewThreadObject();
2199  }
2200 
2201  public function setDisplayConfirmPostActivation(bool $status = false): void
2202  {
2203  $this->display_confirm_post_activation = $status;
2204  }
2205 
2206  public function displayConfirmPostActivation(): bool
2207  {
2209  }
2210 
2211  protected function toggleThreadNotificationObject(): void
2212  {
2213  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
2214  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2215  }
2216 
2217  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentTopic);
2218 
2219  if ($this->objCurrentTopic->isNotificationEnabled($this->user->getId())) {
2220  $this->objCurrentTopic->disableNotification($this->user->getId());
2221  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_notification_disabled'), true);
2222  } else {
2223  $this->objCurrentTopic->enableNotification($this->user->getId());
2224  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_notification_enabled'), true);
2225  }
2226 
2227  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
2228  $this->ctrl->redirect($this, 'viewThread');
2229  }
2230 
2231  protected function toggleStickinessObject(): void
2232  {
2233  if (!$this->is_moderator) {
2234  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2235  }
2236 
2237  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
2238  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2239  }
2240 
2241  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentTopic);
2242 
2243  if ($this->objCurrentTopic->isSticky()) {
2244  $this->objCurrentTopic->unmakeSticky();
2245  } else {
2246  $this->objCurrentTopic->makeSticky();
2247  }
2248 
2249  $this->viewThreadObject();
2250  }
2251 
2252  public function cancelPostObject(): void
2253  {
2254  $draft_id = $this->http->wrapper()->post()->retrieve(
2255  'draft_id',
2256  $this->refinery->byTrying([$this->refinery->kindlyTo()->int(), $this->refinery->always(0)])
2257  );
2258 
2259  $this->requestAction = '';
2260  if ($draft_id > 0) {
2261  $draft = ilForumPostDraft::newInstanceByDraftId($draft_id);
2262  $draft->deleteDraftsByDraftIds([$draft_id]);
2263  }
2264 
2265  $this->viewThreadObject();
2266  }
2267 
2268  public function cancelDraftObject(): void
2269  {
2270  $draft_id = $this->retrieveDraftId();
2271 
2272  $this->requestAction = '';
2273  if ($draft_id > 0 && ilForumPostDraft::isAutoSavePostDraftAllowed()) {
2274  $history_obj = new ilForumDraftsHistory();
2275  $history_obj->getFirstAutosaveByDraftId($draft_id);
2276  $draft = ilForumPostDraft::newInstanceByDraftId($draft_id);
2277  $draft->setPostSubject($history_obj->getPostSubject());
2278  $draft->setPostMessage($history_obj->getPostMessage());
2279 
2281  $history_obj->getPostMessage(),
2283  $history_obj->getHistoryId(),
2285  $draft->getDraftId()
2286  );
2287 
2288  $draft->updateDraft();
2289 
2290  $history_obj->deleteHistoryByDraftIds([$draft->getDraftId()]);
2291  }
2292  $this->ctrl->clearParameters($this);
2293  $this->viewThreadObject();
2294  }
2295 
2297  {
2298  $form = new ilPropertyFormGUI();
2299  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
2300  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
2301  $this->ctrl->setParameter(
2302  $this,
2303  'orderby',
2304  $this->getOrderByParam()
2305  );
2306  $form->setFormAction($this->ctrl->getFormAction($this, 'performPostActivation'));
2307  $this->ctrl->clearParameters($this);
2308  $form->setId('frm_activate_post_' . $node->getId());
2309  $form_id = $form->getId();
2310  $message = $this->uiFactory->messageBox()->confirmation($this->lng->txt('activate_post_txt'));
2311  $submitBtn = $this->uiFactory->button()->primary(
2312  $this->lng->txt('activate_only_current'),
2313  '#'
2314  )->withOnLoadCode(
2315  static function (string $id) use ($form_id): string {
2316  return "$('#$id').click(function() { $('#form_$form_id').submit(); return false; });";
2317  }
2318  );
2319  $modal = $this->uiFactory->modal()->roundtrip(
2320  $this->lng->txt('activate_only_current'),
2321  [$this->uiFactory->legacy($form->getHTML()), $message]
2322  )->withActionButtons([$submitBtn]);
2323  $action_button = $this->uiFactory->button()->standard($this->lng->txt('activate_post'), '#')->withOnClick(
2324  $modal->getShowSignal()
2325  );
2326  $this->modalActionsContainer[] = $modal;
2327  $this->ctrl->clearParameters($this);
2328 
2329  return $action_button;
2330  }
2331 
2332  public function getCensorshipFormHTML(): string
2333  {
2335  $frm = $this->object->Forum;
2336  $form_tpl = new ilTemplate('tpl.frm_censorship_post_form.html', true, true, 'Modules/Forum');
2337 
2338  $form_tpl->setVariable('ANCHOR', $this->objCurrentPost->getId());
2339  $form_tpl->setVariable('SPACER', '<hr noshade="noshade" width="100%" size="1" align="center" />');
2340  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
2341  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
2342  $this->ctrl->setParameter(
2343  $this,
2344  'orderby',
2345  $this->getOrderByParam()
2346  );
2347  $form_tpl->setVariable('FORM_ACTION', $this->ctrl->getFormAction($this, 'viewThread'));
2348  $this->ctrl->clearParameters($this);
2349  $form_tpl->setVariable('TXT_CENS_MESSAGE', $this->lng->txt('forums_the_post'));
2350  $form_tpl->setVariable('TXT_CENS_COMMENT', $this->lng->txt('forums_censor_comment') . ':');
2351  $form_tpl->setVariable('CENS_MESSAGE', $frm->prepareText((string) $this->objCurrentPost->getCensorshipComment(), 2));
2352 
2353  if ($this->objCurrentPost->isCensored()) {
2354  $form_tpl->setVariable('TXT_CENS', $this->lng->txt('forums_info_censor2_post'));
2355  $form_tpl->setVariable('YES_BUTTON', $this->lng->txt('confirm'));
2356  $form_tpl->setVariable('NO_BUTTON', $this->lng->txt('cancel'));
2357  $form_tpl->setVariable('CMD_REVOKE_CENSORSHIP', 'revokeCensorship');
2358  $form_tpl->setVariable('CMD_CANCEL_REVOKE_CENSORSHIP', 'viewThread');
2359  } else {
2360  $form_tpl->setVariable('TXT_CENS', $this->lng->txt('forums_info_censor_post'));
2361  $form_tpl->setVariable('CANCEL_BUTTON', $this->lng->txt('cancel'));
2362  $form_tpl->setVariable('CONFIRM_BUTTON', $this->lng->txt('confirm'));
2363  $form_tpl->setVariable('CMD_ADD_CENSORSHIP', 'addCensorship');
2364  $form_tpl->setVariable('CMD_CANCEL_ADD_CENSORSHIP', 'viewThread');
2365  }
2366 
2367  return $form_tpl->get();
2368  }
2369 
2370  private function initReplyEditForm(): void
2371  {
2372  $isReply = in_array($this->requestAction, ['showreply', 'ready_showreply']);
2373  $isDraft = in_array($this->requestAction, ['publishDraft', 'editdraft']);
2374 
2375  $draft_id = $this->retrieveDraftId();
2376 
2377  // init objects
2378  $oForumObjects = $this->getForumObjects();
2379  $frm = $oForumObjects['frm'];
2380  $oFDForum = $oForumObjects['file_obj'];
2381 
2382  $this->replyEditForm = new ilPropertyFormGUI();
2383  $this->replyEditForm->setId('id_showreply');
2384  $this->replyEditForm->setTableWidth('100%');
2385  $cancel_cmd = 'cancelPost';
2386  if (in_array($this->requestAction, ['showreply', 'ready_showreply'])) {
2387  $this->ctrl->setParameter($this, 'action', 'ready_showreply');
2388  } elseif (in_array($this->requestAction, ['showdraft', 'editdraft'])) {
2389  $this->ctrl->setParameter($this, 'action', $this->requestAction);
2390  $this->ctrl->setParameter($this, 'draft_id', $draft_id);
2391  } else {
2392  $this->ctrl->setParameter($this, 'action', 'ready_showedit');
2393  }
2394 
2395  $this->ctrl->setParameter($this, 'page', (int) ($this->httpRequest->getQueryParams()['page'] ?? 0));
2396  $this->ctrl->setParameter(
2397  $this,
2398  'orderby',
2399  $this->getOrderByParam()
2400  );
2401  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
2402  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
2403  if ($this->isTopLevelReplyCommand()) {
2404  $this->replyEditForm->setFormAction(
2405  $this->ctrl->getFormAction($this, 'saveTopLevelPost', 'frm_page_bottom')
2406  );
2407  } elseif (in_array($this->requestAction, ['publishDraft', 'editdraft'])) {
2408  $this->replyEditForm->setFormAction(
2409  $this->ctrl->getFormAction($this, 'publishDraft', (string) $this->objCurrentPost->getId())
2410  );
2411  } else {
2412  $this->replyEditForm->setFormAction(
2413  $this->ctrl->getFormAction($this, 'savePost', (string) $this->objCurrentPost->getId())
2414  );
2415  }
2416  $this->ctrl->clearParameters($this);
2417 
2418  if ($isReply) {
2419  $this->replyEditForm->setTitle($this->lng->txt('forums_your_reply'));
2420  } elseif ($isDraft) {
2421  $this->replyEditForm->setTitle($this->lng->txt('forums_edit_draft'));
2422  } else {
2423  $this->replyEditForm->setTitle($this->lng->txt('forums_edit_post'));
2424  }
2425 
2426  if (
2427  $this->isWritingWithPseudonymAllowed() &&
2428  in_array($this->requestAction, ['showreply', 'ready_showreply', 'editdraft'])
2429  ) {
2430  $oAnonymousNameGUI = new ilTextInputGUI($this->lng->txt('forums_your_name'), 'alias');
2431  $oAnonymousNameGUI->setMaxLength(64);
2432  $oAnonymousNameGUI->setInfo(sprintf($this->lng->txt('forums_use_alias'), $this->lng->txt('forums_anonymous')));
2433 
2434  $this->replyEditForm->addItem($oAnonymousNameGUI);
2435  }
2436 
2437  $oSubjectGUI = new ilTextInputGUI($this->lng->txt('forums_subject'), 'subject');
2438  $oSubjectGUI->setMaxLength(255);
2439  $oSubjectGUI->setRequired(true);
2440 
2441  if ($this->objProperties->getSubjectSetting() === 'empty_subject') {
2442  $oSubjectGUI->setInfo($this->lng->txt('enter_new_subject'));
2443  }
2444 
2445  $this->replyEditForm->addItem($oSubjectGUI);
2446 
2447  $oPostGUI = new ilTextAreaInputGUI(
2448  $isReply ? $this->lng->txt('forums_your_reply') : $this->lng->txt('forums_edit_post'),
2449  'message'
2450  );
2451  $oPostGUI->setRequired(true);
2452  $oPostGUI->setRows(15);
2453  $oPostGUI->setUseRte(true);
2454  $oPostGUI->addPlugin('latex');
2455  $oPostGUI->addButton('latex');
2456  $oPostGUI->addButton('pastelatex');
2457 
2458  $quotingAllowed = (
2459  !$this->isTopLevelReplyCommand() && (
2460  ($isReply && $this->objCurrentPost->getDepth() >= 2) ||
2461  (!$isDraft && !$isReply && $this->objCurrentPost->getDepth() > 2) ||
2462  ($isDraft && $this->objCurrentPost->getDepth() >= 2)
2463  )
2464  );
2465  if ($quotingAllowed) {
2466  $oPostGUI->addPlugin('ilfrmquote');
2467  $oPostGUI->addButton('ilFrmQuoteAjaxCall');
2468  }
2469 
2470  $oPostGUI->removePlugin('advlink');
2471  $oPostGUI->setRTERootBlockElement('');
2472  $oPostGUI->usePurifier(true);
2473  $oPostGUI->disableButtons([
2474  'charmap',
2475  'undo',
2476  'redo',
2477  'alignleft',
2478  'aligncenter',
2479  'alignright',
2480  'alignjustify',
2481  'anchor',
2482  'fullscreen',
2483  'cut',
2484  'copy',
2485  'paste',
2486  'pastetext',
2487  'formatselect'
2488  ]);
2489 
2490  if (in_array($this->requestAction, ['showreply', 'ready_showreply', 'showdraft', 'editdraft'])) {
2491  $oPostGUI->setRTESupport(
2492  $this->user->getId(),
2493  'frm~',
2494  'frm_post',
2495  'tpl.tinymce_frm_post.js',
2496  false,
2497  '5.6.0'
2498  );
2499  } else {
2500  $oPostGUI->setRTESupport(
2501  $this->objCurrentPost->getId(),
2502  'frm',
2503  'frm_post',
2504  'tpl.tinymce_frm_post.js',
2505  false,
2506  '5.6.0'
2507  );
2508  }
2509 
2510  $oPostGUI->setPurifier(ilHtmlPurifierFactory::getInstanceByType('frm_post'));
2511 
2512  $this->replyEditForm->addItem($oPostGUI);
2513 
2514  $umail = new ilMail($this->user->getId());
2515  if (!$this->user->isAnonymous() &&
2516  !$this->objProperties->isAnonymized() &&
2517  $this->rbac->system()->checkAccess('internal_mail', $umail->getMailObjectReferenceId()) &&
2518  !$frm->isThreadNotificationEnabled($this->user->getId(), $this->objCurrentPost->getThreadId())) {
2519  $oNotificationGUI = new ilCheckboxInputGUI($this->lng->txt('forum_direct_notification'), 'notify');
2520  $oNotificationGUI->setInfo($this->lng->txt('forum_notify_me'));
2521  $this->replyEditForm->addItem($oNotificationGUI);
2522  }
2523 
2524  if ($this->objProperties->isFileUploadAllowed()) {
2525  $oFileUploadGUI = new ilFileWizardInputGUI($this->lng->txt('forums_attachments_add'), 'userfile');
2526  $oFileUploadGUI->setFilenames([0 => '']);
2527  $this->replyEditForm->addItem($oFileUploadGUI);
2528  }
2529 
2530  $attachments_of_node = $oFDForum->getFilesOfPost();
2531  if (count($attachments_of_node) && in_array($this->requestAction, ['showedit', 'ready_showedit'])) {
2532  $oExistingAttachmentsGUI = new ilCheckboxGroupInputGUI($this->lng->txt('forums_delete_file'), 'del_file');
2533  foreach ($oFDForum->getFilesOfPost() as $file) {
2534  $oExistingAttachmentsGUI->addOption(new ilCheckboxOption($file['name'], $file['md5']));
2535  }
2536  $this->replyEditForm->addItem($oExistingAttachmentsGUI);
2537  }
2538 
2540  if (in_array($this->requestAction, ['showdraft', 'editdraft'])) {
2541  $draftInfoGUI = new ilNonEditableValueGUI('', 'autosave_info', true);
2542  $draftInfoGUI->setValue(sprintf(
2543  $this->lng->txt('autosave_draft_info'),
2545  ));
2546  $this->replyEditForm->addItem($draftInfoGUI);
2547  } elseif (!in_array($this->requestAction, ['showedit', 'ready_showedit'])) {
2548  $draftInfoGUI = new ilNonEditableValueGUI('', 'autosave_info', true);
2549  $draftInfoGUI->setValue(sprintf(
2550  $this->lng->txt('autosave_post_draft_info'),
2552  ));
2553  $this->replyEditForm->addItem($draftInfoGUI);
2554  }
2555  }
2556 
2557  $selected_draft_id = $draft_id;
2558  $draftObj = new ilForumPostDraft(
2559  $this->user->getId(),
2560  $this->objCurrentPost->getId(),
2561  $selected_draft_id
2562  );
2563  if ($draftObj->getDraftId() > 0) {
2564  $oFDForumDrafts = new ilFileDataForumDrafts(0, $draftObj->getDraftId());
2565  $files_of_draft = $oFDForumDrafts->getFilesOfPost();
2566 
2567  if ($files_of_draft !== []) {
2568  $oExistingAttachmentsGUI = new ilCheckboxGroupInputGUI(
2569  $this->lng->txt('forums_delete_file'),
2570  'del_file'
2571  );
2572  foreach ($files_of_draft as $file) {
2573  $oExistingAttachmentsGUI->addOption(new ilCheckboxOption($file['name'], $file['md5']));
2574  }
2575  $this->replyEditForm->addItem($oExistingAttachmentsGUI);
2576  }
2577  }
2578 
2579  if ($this->isTopLevelReplyCommand()) {
2580  $this->replyEditForm->addCommandButton('saveTopLevelPost', $this->lng->txt('create'));
2581  } elseif ($this->requestAction === 'editdraft' && ilForumPostDraft::isSavePostDraftAllowed()) {
2582  $this->replyEditForm->addCommandButton('publishDraft', $this->lng->txt('publish'));
2583  } else {
2584  $this->replyEditForm->addCommandButton('savePost', $this->lng->txt('save'));
2585  }
2586  $hidden_draft_id = new ilHiddenInputGUI('draft_id');
2587  $auto_save_draft_id = $this->retrieveDraftId();
2588 
2589  $hidden_draft_id->setValue((string) $auto_save_draft_id);
2590  $this->replyEditForm->addItem($hidden_draft_id);
2591 
2592  if (in_array($this->requestAction, ['showreply', 'ready_showreply', 'editdraft'])) {
2593  $rtestring = ilRTE::_getRTEClassname();
2594  $show_rte = $this->http->wrapper()->post()->retrieve(
2595  'show_rte',
2596  $this->refinery->byTrying([$this->refinery->kindlyTo()->int(), $this->refinery->always(0)])
2597  );
2598 
2599  if ($show_rte) {
2601  }
2602 
2603  if ((strtolower($rtestring) !== 'iltinymce' || !ilObjAdvancedEditing::_getRichTextEditorUserState()) &&
2604  $quotingAllowed) {
2605  $this->replyEditForm->addCommandButton('quotePost', $this->lng->txt('forum_add_quote'));
2606  }
2607 
2608  if (
2609  !$this->user->isAnonymous() &&
2610  in_array($this->requestAction, ['editdraft', 'showreply', 'ready_showreply']) &&
2612  ) {
2614  $this->decorateWithAutosave($this->replyEditForm);
2615  }
2616 
2617  if ($this->requestAction === 'editdraft') {
2618  $this->replyEditForm->addCommandButton('updateDraft', $this->lng->txt('save_message'));
2619  } elseif ($this->isTopLevelReplyCommand()) {
2620  $this->replyEditForm->addCommandButton('saveTopLevelDraft', $this->lng->txt('save_message'));
2621  } else {
2622  $this->replyEditForm->addCommandButton('saveAsDraft', $this->lng->txt('save_message'));
2623  }
2624 
2625  $cancel_cmd = 'cancelDraft';
2626  }
2627  }
2628  $this->replyEditForm->addCommandButton($cancel_cmd, $this->lng->txt('cancel'));
2629  }
2630 
2632  {
2633  if (null === $this->replyEditForm) {
2634  $this->initReplyEditForm();
2635  }
2636 
2637  return $this->replyEditForm;
2638  }
2639 
2640  public function createTopLevelPostObject(): void
2641  {
2642  $draft_obj = null;
2643  $draft_id = $this->retrieveDraftId();
2644 
2645  if ($draft_id > 0 && !$this->user->isAnonymous()
2647  $draft_obj = new ilForumPostDraft(
2648  $this->user->getId(),
2649  $this->objCurrentPost->getId(),
2650  $draft_id
2651  );
2652  }
2653 
2654  if ($draft_obj instanceof ilForumPostDraft && $draft_obj->getDraftId() > 0) {
2655  $this->ctrl->setParameter($this, 'action', 'editdraft');
2656  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
2657  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
2658  $this->ctrl->setParameter($this, 'draft_id', $draft_obj->getDraftId());
2659  $this->ctrl->setParameter($this, 'page', 0);
2660  $this->ctrl->setParameter(
2661  $this,
2662  'orderby',
2663  $this->getOrderByParam()
2664  );
2665  $this->ctrl->redirect($this, 'editDraft');
2666  } else {
2667  $this->viewThreadObject();
2668  }
2669  }
2670 
2671  public function saveTopLevelPostObject(): void
2672  {
2673  $this->savePostObject();
2674  }
2675 
2676  public function publishSelectedDraftObject(): void
2677  {
2678  $draft_id = $this->retrieveDraftId();
2679  if ($draft_id > 0) {
2680  $this->publishDraftObject(false);
2681  }
2682  }
2683 
2684  public function publishDraftObject(bool $use_replyform = true): void
2685  {
2686  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
2687  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2688  }
2689 
2690  if (!$this->access->checkAccess('add_reply', '', $this->object->getRefId())) {
2691  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2692  }
2693 
2694  if ($this->objCurrentTopic->getId() === 0) {
2695  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_thr_deleted'), true);
2696  $this->ctrl->redirect($this);
2697  }
2698 
2699  if ($this->objCurrentTopic->isClosed()) {
2700  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_thr_closed'), true);
2701  $this->ctrl->redirect($this);
2702  }
2703 
2704  if ($this->objCurrentPost->getId() === 0) {
2705  $this->requestAction = '';
2706  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_parent_deleted'));
2707  $this->viewThreadObject();
2708  return;
2709  }
2710 
2711  $post_id = $this->objCurrentPost->getId();
2712 
2713  $draft_id = $this->retrieveDraftId();
2714  $draft_obj = new ilForumPostDraft($this->user->getId(), $post_id, $draft_id);
2715 
2716  if ($use_replyform) {
2717  $oReplyEditForm = $this->getReplyEditForm();
2718  if (!$oReplyEditForm->checkInput()) {
2719  $oReplyEditForm->setValuesByPost();
2720  $this->viewThreadObject();
2721  return;
2722  }
2723  $post_subject = $oReplyEditForm->getInput('subject');
2724  $post_message = $oReplyEditForm->getInput('message');
2725  $mob_direction = 0;
2726  } else {
2727  $post_subject = $draft_obj->getPostSubject();
2728  $post_message = $draft_obj->getPostMessage();
2729  $mob_direction = 1;
2730  }
2731 
2732  if ($draft_obj->getDraftId() > 0) {
2733  $oForumObjects = $this->getForumObjects();
2734  $frm = $oForumObjects['frm'];
2735  $frm->setMDB2WhereCondition(' top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
2736 
2737  // reply: new post
2738  $status = true;
2739  $send_activation_mail = false;
2740 
2741  if ($this->objProperties->isPostActivationEnabled()) {
2742  if (!$this->is_moderator) {
2743  $status = false;
2744  $send_activation_mail = true;
2745  } elseif ($this->objCurrentPost->isAnyParentDeactivated()) {
2746  $status = false;
2747  }
2748  }
2749 
2750  $newPost = $frm->generatePost(
2751  $draft_obj->getForumId(),
2752  $draft_obj->getThreadId(),
2753  $this->user->getId(),
2754  $draft_obj->getPostDisplayUserId(),
2755  ilRTE::_replaceMediaObjectImageSrc($post_message, $mob_direction),
2756  $draft_obj->getPostId(),
2757  $draft_obj->isNotificationEnabled(),
2758  $this->handleFormInput($post_subject, false),
2759  $draft_obj->getPostUserAlias(),
2760  '',
2761  $status,
2762  $send_activation_mail
2763  );
2764 
2765  $this->object->markPostRead(
2766  $this->user->getId(),
2767  $this->objCurrentTopic->getId(),
2768  $this->objCurrentPost->getId()
2769  );
2770 
2771  $uploadedObjects = ilObjMediaObject::_getMobsOfObject('frm~:html', $this->user->getId());
2772 
2773  foreach ($uploadedObjects as $mob) {
2774  ilObjMediaObject::_removeUsage($mob, 'frm~:html', $this->user->getId());
2775  ilObjMediaObject::_saveUsage($mob, 'frm:html', $newPost);
2776  }
2777  ilForumUtil::saveMediaObjects($post_message, 'frm:html', $newPost, $mob_direction);
2778  $post_obj = new ilForumPost($newPost);
2779 
2780  if ($draft_obj->getRCID() > 0) {
2781  $post_obj->setRCID($draft_obj->getRCID());
2782  $post_obj->update();
2783  }
2784 
2785  if ($this->objProperties->isFileUploadAllowed()) {
2786  $file = $_FILES['userfile'] ?? [];
2787  if (is_array($file) && !empty($file)) {
2788  $tmp_file_obj = new ilFileDataForum($this->object->getId(), $newPost);
2789  $tmp_file_obj->storeUploadedFiles();
2790  }
2791  }
2792 
2794  $GLOBALS['ilAppEventHandler']->raise(
2795  'Modules/Forum',
2796  'publishedDraft',
2797  [
2798  'draftObj' => $draft_obj,
2799  'obj_id' => $this->object->getId(),
2800  'is_file_upload_allowed' => $this->objProperties->isFileUploadAllowed()
2801  ]
2802  );
2803  }
2804  $draft_obj->deleteDraft();
2805 
2806  $GLOBALS['ilAppEventHandler']->raise(
2807  'Modules/Forum',
2808  'createdPost',
2809  [
2810  'object' => $this->object,
2811  'ref_id' => $this->object->getRefId(),
2812  'post' => $post_obj,
2813  'notify_moderators' => $send_activation_mail
2814  ]
2815  );
2816 
2817  $message = '';
2818  if (!$this->is_moderator && !$status) {
2819  $message .= $this->lng->txt('forums_post_needs_to_be_activated');
2820  } else {
2821  $message .= $this->lng->txt('forums_post_new_entry');
2822  }
2823 
2824  $thr_pk = $this->retrieveThrPk();
2825 
2826  $frm_session_values = ilSession::get('frm');
2827  if (is_array($frm_session_values)) {
2828  $frm_session_values[$thr_pk]['openTreeNodes'][] = $this->objCurrentPost->getId();
2829  }
2830  ilSession::set('frm', $frm_session_values);
2831 
2832  $this->ctrl->clearParameters($this);
2833  $this->tpl->setOnScreenMessage('success', $message, true);
2834  $this->ctrl->setParameter($this, 'pos_pk', $newPost);
2835  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
2836 
2837  $this->ctrl->redirect($this, 'viewThread');
2838  }
2839  }
2840 
2841  public function savePostObject(): void
2842  {
2843  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
2844  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2845  }
2846 
2847  if ($this->objCurrentTopic->getId() === 0) {
2848  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_thr_deleted'), true);
2849  $this->ctrl->redirect($this);
2850  }
2851 
2852  if ($this->objCurrentTopic->isClosed()) {
2853  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_thr_closed'), true);
2854  $this->ctrl->redirect($this);
2855  }
2856 
2857  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentTopic);
2858 
2859  $oReplyEditForm = $this->getReplyEditForm();
2860  if ($oReplyEditForm->checkInput()) {
2861  if ($this->objCurrentPost->getId() === 0) {
2862  $this->requestAction = '';
2863  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_parent_deleted'), true);
2864  $this->viewThreadObject();
2865  return;
2866  }
2867 
2868  // init objects
2869  $oForumObjects = $this->getForumObjects();
2870  $forumObj = $oForumObjects['forumObj'];
2871  $frm = $oForumObjects['frm'];
2872  $frm->setMDB2WhereCondition(' top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
2873  $topicData = $frm->getOneTopic();
2874 
2875  $ref_id = $this->retrieveRefId();
2876  $post_draft_id = $this->http->wrapper()->post()->retrieve(
2877  'draft_id',
2878  $this->refinery->byTrying([$this->refinery->kindlyTo()->int(), $this->refinery->always(0)])
2879  );
2880 
2881  // Generating new posting
2882  if ($this->requestAction === 'ready_showreply') {
2883  if (!$this->access->checkAccess('add_reply', '', $ref_id)) {
2884  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2885  }
2886 
2887  // reply: new post
2888  $status = true;
2889  $send_activation_mail = false;
2890 
2891  if ($this->objProperties->isPostActivationEnabled()) {
2892  if (!$this->is_moderator) {
2893  $status = false;
2894  $send_activation_mail = true;
2895  } elseif ($this->objCurrentPost->isAnyParentDeactivated()) {
2896  $status = false;
2897  }
2898  }
2899 
2900  if ($this->isWritingWithPseudonymAllowed()) {
2901  if ((string) $oReplyEditForm->getInput('alias') === '') {
2902  $user_alias = $this->lng->txt('forums_anonymous');
2903  } else {
2904  $user_alias = $oReplyEditForm->getInput('alias');
2905  }
2906  $display_user_id = 0;
2907  } else {
2908  $user_alias = $this->user->getLogin();
2909  $display_user_id = $this->user->getId();
2910  }
2911 
2912  $newPost = $frm->generatePost(
2913  $topicData->getTopPk(),
2914  $this->objCurrentTopic->getId(),
2915  $this->user->getId(),
2916  $display_user_id,
2917  ilRTE::_replaceMediaObjectImageSrc($oReplyEditForm->getInput('message')),
2918  $this->objCurrentPost->getId(),
2919  $oReplyEditForm->getInput('notify') && !$this->user->isAnonymous(),
2920  $this->handleFormInput($oReplyEditForm->getInput('subject'), false),
2921  $user_alias,
2922  '',
2923  $status,
2924  $send_activation_mail
2925  );
2926 
2928  $draft_id = 0;
2930  $draft_id = $post_draft_id; // info aus dem autosave?
2931  }
2932  $draft_obj = new ilForumPostDraft($this->user->getId(), $this->objCurrentPost->getId(), $draft_id);
2933  $draft_obj->deleteDraft();
2934  }
2935 
2936  // mantis #8115: Mark parent as read
2937  $this->object->markPostRead(
2938  $this->user->getId(),
2939  $this->objCurrentTopic->getId(),
2940  $this->objCurrentPost->getId()
2941  );
2942 
2943  // copy temporary media objects (frm~)
2945  $oReplyEditForm->getInput('message'),
2946  'frm~:html',
2947  $this->user->getId(),
2948  'frm:html',
2949  $newPost
2950  );
2951 
2952  if ($this->objProperties->isFileUploadAllowed()) {
2953  $oFDForum = new ilFileDataForum($forumObj->getId(), $newPost);
2954  $file = $_FILES['userfile'];
2955  if (is_array($file) && !empty($file)) {
2956  $oFDForum->storeUploadedFiles();
2957  }
2958  }
2959 
2960  $GLOBALS['ilAppEventHandler']->raise(
2961  'Modules/Forum',
2962  'createdPost',
2963  [
2964  'object' => $this->object,
2965  'ref_id' => $this->object->getRefId(),
2966  'post' => new ilForumPost($newPost),
2967  'notify_moderators' => $send_activation_mail
2968  ]
2969  );
2970 
2971  $message = '';
2972  if (!$this->is_moderator && !$status) {
2973  $message .= $this->lng->txt('forums_post_needs_to_be_activated');
2974  } else {
2975  $message .= $this->lng->txt('forums_post_new_entry');
2976  }
2977 
2978  $this->tpl->setOnScreenMessage('success', $message, true);
2979  $this->ctrl->clearParameters($this);
2980  $this->ctrl->setParameter($this, 'post_created_below', $this->objCurrentPost->getId());
2981  $this->ctrl->setParameter($this, 'pos_pk', $newPost);
2982  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
2983  } else {
2984  if ((!$this->is_moderator &&
2985  !$this->objCurrentPost->isOwner($this->user->getId())) || $this->objCurrentPost->isCensored() ||
2986  $this->user->isAnonymous()) {
2987  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
2988  }
2989 
2990  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentPost->getThread());
2991 
2992  $oldMediaObjects = ilObjMediaObject::_getMobsOfObject('frm:html', $this->objCurrentPost->getId());
2993  $curMediaObjects = ilRTE::_getMediaObjects($oReplyEditForm->getInput('message'));
2994  foreach ($oldMediaObjects as $oldMob) {
2995  $found = false;
2996  foreach ($curMediaObjects as $curMob) {
2997  if ($oldMob === $curMob) {
2998  $found = true;
2999  break;
3000  }
3001  }
3002  if (!$found && ilObjMediaObject::_exists($oldMob)) {
3003  ilObjMediaObject::_removeUsage($oldMob, 'frm:html', $this->objCurrentPost->getId());
3004  $mob_obj = new ilObjMediaObject($oldMob);
3005  $mob_obj->delete();
3006  }
3007  }
3008 
3009  // save old activation status for send_notification decision
3010  $old_status_was_active = $this->objCurrentPost->isActivated();
3011 
3012  // if active post has been edited posting mus be activated again by moderator
3013  $status = true;
3014  $send_activation_mail = false;
3015 
3016  if ($this->objProperties->isPostActivationEnabled()) {
3017  if (!$this->is_moderator) {
3018  $status = false;
3019  $send_activation_mail = true;
3020  } elseif ($this->objCurrentPost->isAnyParentDeactivated()) {
3021  $status = false;
3022  }
3023  }
3024  $this->objCurrentPost->setStatus($status);
3025 
3026  $this->objCurrentPost->setSubject($this->handleFormInput($oReplyEditForm->getInput('subject'), false));
3027  $this->objCurrentPost->setMessage(ilRTE::_replaceMediaObjectImageSrc(
3028  $oReplyEditForm->getInput('message')
3029  ));
3030  $this->objCurrentPost->setNotification($oReplyEditForm->getInput('notify') && !$this->user->isAnonymous());
3031  $this->objCurrentPost->setChangeDate(date('Y-m-d H:i:s'));
3032  $this->objCurrentPost->setUpdateUserId($this->user->getId());
3033 
3034  if ($this->objCurrentPost->update()) {
3035  $this->objCurrentPost->reload();
3036 
3037  // Change news item accordingly
3038  // note: $this->objCurrentPost->getForumId() does not give us the forum ID here (why?)
3040  $forumObj->getId(),
3041  'frm',
3042  $this->objCurrentPost->getId(),
3043  'pos'
3044  );
3045  if ($news_id > 0) {
3046  $news_item = new ilNewsItem($news_id);
3047  $news_item->setTitle($this->objCurrentPost->getSubject());
3048  $news_item->setContent(
3050  $this->objCurrentPost->getMessage()
3051  ), 1)
3052  );
3053 
3054  if ($this->objCurrentPost->getMessage() !== strip_tags($this->objCurrentPost->getMessage())) {
3055  $news_item->setContentHtml(true);
3056  } else {
3057  $news_item->setContentHtml(false);
3058  }
3059  $news_item->update();
3060  }
3061 
3062  $oFDForum = $oForumObjects['file_obj'];
3063 
3064  $file2delete = $oReplyEditForm->getInput('del_file');
3065  if (is_array($file2delete) && count($file2delete)) {
3066  $oFDForum->unlinkFilesByMD5Filenames($file2delete);
3067  }
3068 
3069  if ($this->objProperties->isFileUploadAllowed()) {
3070  $file = $_FILES['userfile'];
3071  if (is_array($file) && !empty($file)) {
3072  $oFDForum->storeUploadedFiles();
3073  }
3074  }
3075 
3076  $GLOBALS['ilAppEventHandler']->raise(
3077  'Modules/Forum',
3078  'updatedPost',
3079  [
3080  'ref_id' => $this->object->getRefId(),
3081  'post' => $this->objCurrentPost,
3082  'notify_moderators' => $send_activation_mail,
3083  'old_status_was_active' => $old_status_was_active
3084  ]
3085  );
3086 
3087  $this->tpl->setOnScreenMessage('success', $this->lng->txt('forums_post_modified'), true);
3088  }
3089 
3090  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
3091  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
3092  $this->ctrl->setParameter($this, 'viewmode', $this->selectedSorting);
3093  }
3094  $this->ctrl->redirect($this, 'viewThread');
3095  } else {
3096  $this->requestAction = substr($this->requestAction, 6);
3097  }
3098  $this->viewThreadObject();
3099  }
3100 
3101  private function hideToolbar($a_flag = null)
3102  {
3103  if (null === $a_flag) {
3104  return $this->hideToolbar;
3105  }
3106 
3107  $this->hideToolbar = $a_flag;
3108  return $this;
3109  }
3110 
3111  public function quotePostObject(): void
3112  {
3113  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
3114  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3115  }
3116 
3117  if ($this->objCurrentTopic->isClosed()) {
3118  $this->requestAction = '';
3119  $this->viewThreadObject();
3120  return;
3121  }
3122 
3123  $oReplyEditForm = $this->getReplyEditForm();
3124 
3125  $oReplyEditForm->getItemByPostVar('subject')->setRequired(false);
3126  $oReplyEditForm->getItemByPostVar('message')->setRequired(false);
3127 
3128  $oReplyEditForm->checkInput();
3129 
3130  $oReplyEditForm->getItemByPostVar('subject')->setRequired(true);
3131  $oReplyEditForm->getItemByPostVar('message')->setRequired(true);
3132 
3133  $this->requestAction = 'showreply';
3134 
3135  $this->viewThreadObject();
3136  }
3137 
3138  public function getQuotationHTMLAsynchObject(): void
3139  {
3140  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
3141  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3142  }
3143 
3144  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentPost->getThread());
3145 
3146  $oForumObjects = $this->getForumObjects();
3147  $frm = $oForumObjects['frm'];
3148 
3149  $authorinfo = new ilForumAuthorInformation(
3150  $this->objCurrentPost->getPosAuthorId(),
3151  $this->objCurrentPost->getDisplayUserId(),
3152  (string) $this->objCurrentPost->getUserAlias(),
3153  (string) $this->objCurrentPost->getImportName()
3154  );
3155 
3157  $this->objCurrentPost->getMessage(),
3158  1,
3159  $authorinfo->getAuthorName()
3160  ), 1);
3161 
3162  $this->http->saveResponse($this->http->response()->withBody(
3163  \ILIAS\Filesystem\Stream\Streams::ofString($html)
3164  ));
3165  $this->http->sendResponse();
3166  $this->http->close();
3167  }
3168 
3172  private function getForumObjects(): array
3173  {
3174  if (null === $this->forumObjects) {
3175  $forumObj = $this->object;
3176  $file_obj = new ilFileDataForum($forumObj->getId(), $this->objCurrentPost->getId());
3177  $frm = $forumObj->Forum;
3178  $frm->setForumId($forumObj->getId());
3179  $frm->setForumRefId($forumObj->getRefId());
3180 
3181  $this->forumObjects['forumObj'] = $forumObj;
3182  $this->forumObjects['frm'] = $frm;
3183  $this->forumObjects['file_obj'] = $file_obj;
3184  }
3185 
3186  return $this->forumObjects;
3187  }
3188 
3189  public function checkUsersViewMode(): void
3190  {
3191  $this->selectedSorting = $this->objProperties->getDefaultView();
3192 
3193  if ($this->getObject() !== null) {
3194  $view_mode = 'viewmode_' . $this->getObject()->getId();
3195  if (in_array((int) ilSession::get($view_mode), [
3199  ], true)) {
3200  $this->selectedSorting = ilSession::get($view_mode);
3201  }
3202 
3203  if (
3204  isset($this->httpRequest->getQueryParams()['viewmode']) &&
3205  (int) $this->httpRequest->getQueryParams()['viewmode'] !== $this->selectedSorting
3206  ) {
3207  $this->selectedSorting = (int) $this->httpRequest->getQueryParams()['viewmode'];
3208  }
3209 
3210  if (!in_array($this->selectedSorting, [
3214  ], true)) {
3215  $this->selectedSorting = $this->objProperties->getDefaultView();
3216  }
3217 
3218  ilSession::set($view_mode, $this->selectedSorting);
3219  }
3220  }
3221 
3222  public function resetLimitedViewObject(): void
3223  {
3224  $this->selected_post_storage->set($this->objCurrentTopic->getId(), 0);
3225  $this->ctrl->redirect($this, 'viewThread');
3226  }
3227 
3228  public function viewThreadObject(): void
3229  {
3230  $ref_id = $this->retrieveRefId();
3231  $thr_pk = $this->retrieveThrPk();
3232 
3233  $bottom_toolbar = clone $this->toolbar;
3234  $toolbar_items = [];
3235 
3236  // quick and dirty: check for treeview
3237  $thread_control_session_values = ilSession::get('thread_control');
3238  if (is_array($thread_control_session_values)) {
3239  if (!isset($thread_control_session_values['old'])) {
3240  $thread_control_session_values['old'] = $thr_pk;
3241  $thread_control_session_values['new'] = $thr_pk;
3242  ilSession::set('thread_control', $thread_control_session_values);
3243  } elseif (isset($thread_control_session_values['old']) && $thr_pk !== $thread_control_session_values['old']) {
3244  $thread_control_session_values['new'] = $thr_pk;
3245  ilSession::set('thread_control', $thread_control_session_values);
3246  }
3247  }
3248 
3249  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
3250  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3251  }
3252 
3253  $oForumObjects = $this->getForumObjects();
3254  $forumObj = $oForumObjects['forumObj'];
3255  $frm = $oForumObjects['frm'];
3256  $file_obj = $oForumObjects['file_obj'];
3257 
3258  $selected_draft_id = (int) ($this->httpRequest->getQueryParams()['draft_id'] ?? 0);
3259  if (isset($this->httpRequest->getQueryParams()['file'])) {
3260  $file_obj_for_delivery = $file_obj;
3261  if ($selected_draft_id > 0 && ilForumPostDraft::isSavePostDraftAllowed()) {
3262  $file_obj_for_delivery = new ilFileDataForumDrafts($forumObj->getId(), $selected_draft_id);
3263  }
3264  $file_obj_for_delivery->deliverFile(ilUtil::stripSlashes($this->httpRequest->getQueryParams()['file']));
3265  }
3266 
3267  if ($this->objCurrentTopic->getId() === 0) {
3268  $this->ctrl->redirect($this, 'showThreads');
3269  }
3270 
3271  $pageIndex = 0;
3272  if (isset($this->httpRequest->getQueryParams()['page'])) {
3273  $pageIndex = max((int) $this->httpRequest->getQueryParams()['page'], $pageIndex);
3274  }
3275 
3276  if ($this->selected_post_storage->get($this->objCurrentTopic->getId()) > 0) {
3277  $firstNodeInThread = new ilForumPost(
3278  $this->selected_post_storage->get($this->objCurrentTopic->getId()),
3279  $this->is_moderator,
3280  false
3281  );
3282  } else {
3283  $firstNodeInThread = $this->objCurrentTopic->getPostRootNode();
3284  }
3285 
3286  $toolContext = $this->globalScreen
3287  ->tool()
3288  ->context()
3289  ->current();
3290 
3291  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentTopic);
3292 
3293  $threadContentTemplate = new ilTemplate(
3294  'tpl.forums_threads_view.html',
3295  true,
3296  true,
3297  'Modules/Forum'
3298  );
3299 
3300 
3301  if ($this->selectedSorting === ilForumProperties::VIEW_TREE) {
3302  $order_field = 'frm_posts_tree.rgt';
3303  $this->objCurrentTopic->setOrderDirection('DESC');
3304  $threadContentTemplate->setVariable('LIST_TYPE', $this->viewModeOptions[$this->selectedSorting]);
3305  } else {
3306  $order_field = 'frm_posts.pos_date';
3307  $this->objCurrentTopic->setOrderDirection(
3308  $this->selectedSorting === ilForumProperties::VIEW_DATE_DESC ? 'DESC' : 'ASC'
3309  );
3310  $threadContentTemplate->setVariable('LIST_TYPE', $this->sortationOptions[$this->selectedSorting]);
3311  }
3312  $this->objCurrentTopic->setOrderField($order_field);
3313 
3314  $additionalDataExists = $toolContext->getAdditionalData()->exists(ForumGlobalScreenToolsProvider::SHOW_FORUM_THREADS_TOOL);
3315  $subtree_nodes = $this->objCurrentTopic->getPostTree($firstNodeInThread);
3316  $numberOfPostings = count($subtree_nodes);
3317  if ($numberOfPostings > 0 && !$additionalDataExists && $this->selectedSorting === ilForumProperties::VIEW_TREE) {
3318  $toolContext
3320  ->addAdditionalData(ForumGlobalScreenToolsProvider::REF_ID, $this->ref_id)
3321  ->addAdditionalData(ForumGlobalScreenToolsProvider::FORUM_THEAD, $this->objCurrentTopic)
3322  ->addAdditionalData(ForumGlobalScreenToolsProvider::FORUM_THREAD_ROOT, $firstNodeInThread)
3323  ->addAdditionalData(ForumGlobalScreenToolsProvider::FORUM_BASE_CONTROLLER, $this)
3324  ->addAdditionalData(ForumGlobalScreenToolsProvider::PAGE, $pageIndex);
3325  }
3326  // Set context for login
3327  $append = '_' . $this->objCurrentTopic->getId() .
3328  ($this->objCurrentPost->getId() !== 0 ? '_' . $this->objCurrentPost->getId() : '');
3329  $this->tpl->setLoginTargetPar('frm_' . $ref_id . $append);
3330 
3331  // delete temporary media object (not in case a user adds media objects and wants to save an invalid form)
3332  if (!in_array($this->requestAction, ['showreply', 'showedit'])) {
3333  try {
3334  $mobs = ilObjMediaObject::_getMobsOfObject('frm~:html', $this->user->getId());
3335  foreach ($mobs as $mob) {
3336  if (ilObjMediaObject::_exists($mob)) {
3337  ilObjMediaObject::_removeUsage($mob, 'frm~:html', $this->user->getId());
3338  $mob_obj = new ilObjMediaObject($mob);
3339  $mob_obj->delete();
3340  }
3341  }
3342  } catch (Exception) {
3343  }
3344  }
3345 
3346  if (!$this->getCreationMode() && $this->access->checkAccess('read', '', $this->object->getRefId())) {
3347  $this->ilNavigationHistory->addItem(
3348  $this->object->getRefId(),
3349  ilLink::_getLink($this->object->getRefId(), 'frm'),
3350  'frm'
3351  );
3352  }
3353 
3354  $this->prepareThreadScreen($forumObj);
3355 
3356 
3357  if (isset($this->httpRequest->getQueryParams()['anchor'])) {
3358  $threadContentTemplate->setVariable('JUMP2ANCHOR_ID', (int) $this->httpRequest->getQueryParams()['anchor']);
3359  }
3360  $frm->setMDB2WhereCondition('top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
3361 
3363  $this->object->getType(),
3364  $this->object->getRefId(),
3365  $this->object->getId(),
3366  $this->user->getId()
3367  );
3368 
3369  if ($firstNodeInThread) {
3370  $this->objCurrentTopic->updateVisits();
3371 
3372  $this->tpl->setTitle($this->lng->txt('forums_thread') . ' "' . $this->objCurrentTopic->getSubject() . '"');
3373 
3374  $this->locator->addRepositoryItems();
3375  $this->locator->addItem($this->object->getTitle(), $this->ctrl->getLinkTarget($this, ''), '_top');
3376  $this->tpl->setLocator();
3377 
3378  if (
3379  !$this->user->isAnonymous() &&
3380  $forumObj->getCountUnread($this->user->getId(), $this->objCurrentTopic->getId(), true)
3381  ) {
3382  $this->ctrl->setParameter($this, 'mark_read', '1');
3383  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
3384 
3385  $mark_thr_read_button = $this->uiFactory->button()->standard(
3386  $this->lng->txt('forums_mark_read'),
3387  $this->ctrl->getLinkTarget($this, 'viewThread')
3388  );
3389 
3390  $toolbar_items[] = $mark_thr_read_button;
3391 
3392  $this->ctrl->clearParameters($this);
3393  }
3394 
3395  $this->ctrl->setParameterByClass(ilForumExportGUI::class, 'print_thread', $this->objCurrentTopic->getId());
3396  $this->ctrl->setParameterByClass(
3397  ilForumExportGUI::class,
3398  'thr_top_fk',
3399  $this->objCurrentTopic->getForumId()
3400  );
3401 
3402  if ($numberOfPostings > 0 && $this->settings->get('forum_enable_print', '0')) {
3403  $print_thr_button = $this->uiFactory->button()->standard(
3404  $this->lng->txt('forums_print_thread'),
3405  $this->ctrl->getLinkTargetByClass(ilForumExportGUI::class, 'printThread')
3406  );
3407  $toolbar_items[] = $print_thr_button;
3408  }
3409 
3410 
3411  $this->ctrl->clearParametersByClass(ilForumExportGUI::class);
3412 
3413  $this->addHeaderAction();
3414 
3415  if (isset($this->httpRequest->getQueryParams()['mark_read'])) {
3416  $forumObj->markThreadRead($this->user->getId(), $this->objCurrentTopic->getId());
3417  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_thread_marked'), true);
3418  }
3419 
3420 
3421  if (
3422  $firstNodeInThread instanceof ilForumPost &&
3423  !$this->isTopLevelReplyCommand() &&
3424  !$this->objCurrentTopic->isClosed() &&
3425  $this->access->checkAccess('add_reply', '', $ref_id)
3426  ) {
3427  $this->ctrl->setParameter($this, 'action', 'showreply');
3428  $this->ctrl->setParameter($this, 'pos_pk', $firstNodeInThread->getId());
3429  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
3430  $this->ctrl->setParameter(
3431  $this,
3432  'page',
3433  (int) ($this->httpRequest->getQueryParams()['page'] ?? 0)
3434  );
3435  $this->ctrl->setParameter(
3436  $this,
3437  'orderby',
3438  $this->getOrderByParam()
3439  );
3440  if ($numberOfPostings > 0) {
3441  $reply_button = $this->uiFactory->button()->standard(
3442  $this->lng->txt('add_new_answer'),
3443  $this->ctrl->getLinkTarget($this, 'createTopLevelPost', 'frm_page_bottom')
3444  );
3445  } else {
3446  $reply_button = $this->uiFactory->button()->primary(
3447  $this->lng->txt('add_new_answer'),
3448  $this->ctrl->getLinkTarget($this, 'createTopLevelPost', 'frm_page_bottom')
3449  );
3450  }
3451  $this->ctrl->clearParameters($this);
3452  array_unshift($toolbar_items, $reply_button);
3453  }
3454 
3455  // no posts
3456  if ($numberOfPostings === 0 && $firstNodeInThread->getId() === 0) {
3457  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_no_posts_available'));
3458  }
3459 
3460  $pageSize = $frm->getPageHits();
3461  $postIndex = 0;
3462  if ($numberOfPostings > $pageSize) {
3463  $this->ctrl->setParameter($this, 'ref_id', $this->object->getRefId());
3464  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
3465  $this->ctrl->setParameter(
3466  $this,
3467  'orderby',
3468  $this->getOrderByParam()
3469  );
3470  $paginationUrl = $this->ctrl->getLinkTarget($this, 'viewThread', '');
3471  $this->ctrl->clearParameters($this);
3472 
3473  $pagination = $this->uiFactory->viewControl()
3474  ->pagination()
3475  ->withTargetURL($paginationUrl, 'page')
3476  ->withTotalEntries($numberOfPostings)
3477  ->withPageSize($pageSize)
3478  ->withMaxPaginationButtons(10)
3479  ->withCurrentPage($pageIndex);
3480 
3481  $threadContentTemplate->setVariable('THREAD_MENU', $this->uiRenderer->render(
3482  $pagination
3483  ));
3484  $threadContentTemplate->setVariable('THREAD_MENU_BOTTOM', $this->uiRenderer->render(
3485  $pagination
3486  ));
3487  }
3488 
3489  $doRenderDrafts = ilForumPostDraft::isSavePostDraftAllowed() && !$this->user->isAnonymous();
3490  $draftsObjects = [];
3491  if ($doRenderDrafts) {
3492  $draftsObjects = ilForumPostDraft::getSortedDrafts(
3493  $this->user->getId(),
3494  $this->objCurrentTopic->getId(),
3496  );
3497  }
3498 
3499  $pagedPostings = array_slice($subtree_nodes, $pageIndex * $pageSize, $pageSize);
3500 
3501  $this->ensureValidPageForCurrentPosting($subtree_nodes, $pagedPostings, $pageSize, $firstNodeInThread);
3502 
3503  if (
3504  $doRenderDrafts && 0 === $pageIndex &&
3505  $this->selectedSorting === ilForumProperties::VIEW_DATE_DESC
3506  ) {
3507  foreach ($draftsObjects as $draft) {
3508  $referencePosting = array_values(array_filter(
3509  $subtree_nodes,
3510  static function (ilForumPost $post) use ($draft): bool {
3511  return $draft->getPostId() === $post->getId();
3512  }
3513  ))[0] ?? $firstNodeInThread;
3514 
3515  $this->renderDraftContent(
3516  $threadContentTemplate,
3517  $this->requestAction,
3518  $referencePosting,
3519  [$draft]
3520  );
3521  }
3522  }
3523 
3524  foreach ($pagedPostings as $node) {
3525  $this->ctrl->clearParameters($this);
3526 
3527  if (!$this->isTopLevelReplyCommand() && $this->objCurrentPost->getId() === $node->getId() &&
3528  ($this->is_moderator || $node->isActivated() || $node->isOwner($this->user->getId()))) {
3529  if (!$this->objCurrentTopic->isClosed() && in_array($this->requestAction, [
3530  'showreply',
3531  'showedit',
3532  ])) {
3533  $this->renderPostingForm($threadContentTemplate, $frm, $node, $this->requestAction);
3534  } elseif ($this->requestAction === 'censor' &&
3535  !$this->objCurrentTopic->isClosed() && $this->is_moderator) {
3536  $threadContentTemplate->setVariable('FORM', $this->getCensorshipFormHTML());
3537  }
3538  }
3539 
3540  $this->renderPostContent($threadContentTemplate, $node, $this->requestAction, $pageIndex, $postIndex);
3541  if ($doRenderDrafts && $this->selectedSorting === ilForumProperties::VIEW_TREE) {
3542  $this->renderDraftContent(
3543  $threadContentTemplate,
3544  $this->requestAction,
3545  $node,
3546  $draftsObjects[$node->getId()] ?? []
3547  );
3548  }
3549 
3550  $postIndex++;
3551  }
3552 
3553  if (
3554  $this->selectedSorting === ilForumProperties::VIEW_DATE_ASC &&
3555  $doRenderDrafts && $pageIndex === max(0, (int) (ceil($numberOfPostings / $pageSize) - 1))
3556  ) {
3557  foreach ($draftsObjects as $draft) {
3558  $referencePosting = array_values(array_filter(
3559  $subtree_nodes,
3560  static function (ilForumPost $post) use ($draft): bool {
3561  return $draft->getPostId() === $post->getId();
3562  }
3563  ))[0] ?? $firstNodeInThread;
3564 
3565  $this->renderDraftContent(
3566  $threadContentTemplate,
3567  $this->requestAction,
3568  $referencePosting,
3569  [$draft]
3570  );
3571  }
3572  }
3573 
3574  if (
3575  $firstNodeInThread instanceof ilForumPost && $doRenderDrafts &&
3576  $this->selectedSorting === ilForumProperties::VIEW_TREE
3577  ) {
3578  $this->renderDraftContent(
3579  $threadContentTemplate,
3580  $this->requestAction,
3581  $firstNodeInThread,
3582  $draftsObjects[$firstNodeInThread->getId()] ?? []
3583  );
3584  }
3585 
3586  if (
3587  $firstNodeInThread instanceof ilForumPost &&
3588  !$this->objCurrentTopic->isClosed() &&
3589  in_array($this->ctrl->getCmd(), ['createTopLevelPost', 'saveTopLevelPost', 'saveTopLevelDraft'], true) &&
3590  $this->access->checkAccess('add_reply', '', $ref_id)) {
3591  // Important: Don't separate the following two lines (very fragile code ...)
3592  $this->objCurrentPost->setId($firstNodeInThread->getId());
3593  $form = $this->getReplyEditForm();
3594 
3595  if (in_array($this->ctrl->getCmd(), ['saveTopLevelPost', 'saveTopLevelDraft'])) {
3596  $form->setValuesByPost();
3597  }
3598  $this->ctrl->setParameter($this, 'pos_pk', $firstNodeInThread->getId());
3599  $this->ctrl->setParameter($this, 'thr_pk', $firstNodeInThread->getThreadId());
3600  $jsTpl = new ilTemplate('tpl.forum_post_quoation_ajax_handler.js', true, true, 'Modules/Forum');
3601  $jsTpl->setVariable(
3602  'IL_FRM_QUOTE_CALLBACK_SRC',
3603  $this->ctrl->getLinkTarget($this, 'getQuotationHTMLAsynch', '', true)
3604  );
3605  $this->ctrl->clearParameters($this);
3606  $this->tpl->addOnLoadCode($jsTpl->get());
3607  $threadContentTemplate->setVariable('BOTTOM_FORM', $form->getHTML());
3608  }
3609  } else {
3610  $threadContentTemplate->setCurrentBlock('posts_no');
3611  $threadContentTemplate->setVariable(
3612  'TXT_MSG_NO_POSTS_AVAILABLE',
3613  $this->lng->txt('forums_posts_not_available')
3614  );
3615  $threadContentTemplate->parseCurrentBlock();
3616  }
3617 
3618  $to_top_button = $this->uiFactory->button()
3619  ->standard($this->lng->txt('top_of_page'), '#frm_page_top');
3620  $bottom_toolbar->addComponent($to_top_button);
3621  if ($numberOfPostings > 0) {
3622  $threadContentTemplate->setVariable('TOOLBAR_BOTTOM', $bottom_toolbar->getHTML());
3623  }
3624 
3625  if ($toolbar_items !== []) {
3626  foreach ($toolbar_items as $component_index => $item) {
3627  $this->toolbar->addComponent($item);
3628  $bottom_toolbar->addComponent($item);
3629  if ($component_index === 0 && $numberOfPostings > 0) {
3630  $this->renderViewModeControl($this->selectedSorting);
3631  if ($this->selectedSorting !== ilForumProperties::VIEW_TREE) {
3632  $this->renderSortationControl($this->selectedSorting);
3633  }
3634  }
3635  }
3636  }
3637 
3638  $this->tpl->setPermanentLink(
3639  $this->object->getType(),
3640  $this->object->getRefId(),
3641  (string) $this->objCurrentTopic->getId()
3642  );
3643 
3644  $this->tpl->addOnLoadCode('$(".ilFrmPostContent img").each(function() {
3645  var $elm = $(this);
3646  $elm.css({
3647  maxWidth: $elm.attr("width") + "px",
3648  maxHeight: $elm.attr("height") + "px"
3649  });
3650  $elm.removeAttr("width");
3651  $elm.removeAttr("height");
3652  });');
3653 
3654  if ($this->selectedSorting === ilForumProperties::VIEW_TREE && ($this->selected_post_storage->get($thr_pk) > 0)) {
3655  $info = $this->getResetLimitedViewInfo();
3656  }
3657 
3658  $this->tpl->setContent(($info ?? '') . $threadContentTemplate->get() . $this->getModalActions());
3659  }
3660 
3661  private function renderViewModeControl(int $currentViewMode): void
3662  {
3663  if ($currentViewMode === 3) {
3664  $currentViewMode = 2;
3665  }
3666  $translationKeys = [];
3667  foreach ($this->viewModeOptions as $sortingConstantKey => $languageKey) {
3668  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
3669  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
3670  $this->ctrl->setParameter($this, 'viewmode', $sortingConstantKey);
3671 
3672  $translationKeys[$this->lng->txt($languageKey)] = $this->ctrl->getLinkTarget(
3673  $this,
3674  'viewThread',
3675  ''
3676  );
3677 
3678  $this->ctrl->clearParameters($this);
3679  }
3680 
3681  if ($currentViewMode > ilForumProperties::VIEW_DATE_ASC) {
3682  $currentViewMode = ilForumProperties::VIEW_DATE_ASC;
3683  }
3684 
3685  $sortViewControl = $this->uiFactory
3686  ->viewControl()
3687  ->mode($translationKeys, $this->lng->txt($this->viewModeOptions[$currentViewMode]))
3688  ->withActive($this->lng->txt($this->viewModeOptions[$currentViewMode]));
3689  $this->toolbar->addComponent($sortViewControl);
3690  }
3691 
3692  private function renderSortationControl(int $currentSorting): void
3693  {
3694  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
3695  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
3696  $target = $this->ctrl->getLinkTarget(
3697  $this,
3698  'viewThread',
3699  ''
3700  );
3701 
3702  $translatedSortationOptions = array_map(function ($value): string {
3703  return $this->lng->txt($value);
3705 
3706  $sortingDirectionViewControl = $this->uiFactory
3707  ->viewControl()
3708  ->sortation($translatedSortationOptions)
3709  ->withLabel($this->lng->txt($this->sortationOptions[$currentSorting]))
3710  ->withTargetURL($target, 'viewmode');
3711  $this->toolbar->addComponent($sortingDirectionViewControl);
3712  }
3713 
3714  private function getModifiedReOnSubject(): string
3715  {
3716  return (new PostingReplySubjectBuilder(
3717  $this->lng->txt('post_reply'),
3718  $this->lng->txt('post_reply_count')
3719  ))->build($this->objCurrentPost->getSubject());
3720  }
3721 
3722  public function showUserObject(): void
3723  {
3724  $user_id = $this->http->wrapper()->query()->retrieve(
3725  'user',
3726  $this->refinery->byTrying([$this->refinery->kindlyTo()->int(), $this->refinery->always(0)])
3727  );
3728  $ref_id = $this->retrieveRefId();
3729  $backurl = $this->http->wrapper()->query()->retrieve(
3730  'backurl',
3731  $this->refinery->byTrying([$this->refinery->kindlyTo()->string(), $this->refinery->always('')])
3732  );
3733 
3734  $profile_gui = new ilPublicUserProfileGUI($user_id);
3735  $add = $this->getUserProfileAdditional($ref_id, $user_id);
3736  $profile_gui->setAdditional($add);
3737  $profile_gui->setBackUrl(ilUtil::stripSlashes($backurl));
3738  $this->tpl->setContent($this->ctrl->getHTML($profile_gui));
3739  }
3740 
3741  protected function getUserProfileAdditional(int $a_forum_ref_id, int $a_user_id): array
3742  {
3743  if (!$this->access->checkAccess('read', '', $a_forum_ref_id)) {
3744  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3745  }
3746 
3748  $ref_obj = ilObjectFactory::getInstanceByRefId($a_forum_ref_id);
3749  if ($ref_obj->getType() === 'frm') {
3750  $forumObj = new ilObjForum($a_forum_ref_id);
3751  $frm = $forumObj->Forum;
3752  $frm->setForumId($forumObj->getId());
3753  $frm->setForumRefId($forumObj->getRefId());
3754  } else {
3755  $frm = new ilForum();
3756  }
3757 
3758  if ($this->access->checkAccess('moderate_frm', '', $a_forum_ref_id)) {
3759  $numPosts = $frm->countUserArticles($a_user_id);
3760  } else {
3761  $numPosts = $frm->countActiveUserArticles($a_user_id);
3762  }
3763 
3764  return [$this->lng->txt('forums_posts') => $numPosts];
3765  }
3766 
3767  public function performThreadsActionObject(): void
3768  {
3769  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
3770  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3771  }
3772 
3773  ilSession::set('threads2move', []);
3774 
3775  $thread_ids = $this->retrieveThreadIds();
3776  $cmd = $this->ctrl->getCmd();
3777  $message = null;
3778 
3779  if ($thread_ids !== []) {
3780  if ($cmd === 'move') {
3781  if ($this->is_moderator) {
3782  ilSession::set('threads2move', $thread_ids);
3783  $this->moveThreadsObject();
3784  }
3785  } elseif ($cmd === 'enable_notifications' && (int) $this->settings->get('forum_notification', '0') !== 0) {
3786  foreach ($thread_ids as $thread_id) {
3787  $tmp_obj = new ilForumTopic($thread_id);
3788  $this->ensureThreadBelongsToForum($this->object->getId(), $tmp_obj);
3789  $tmp_obj->enableNotification($this->user->getId());
3790  }
3791 
3792  $this->ctrl->redirect($this, 'showThreads');
3793  } elseif ($cmd === 'disable_notifications' && (int) $this->settings->get('forum_notification', '0') !== 0) {
3794  foreach ($thread_ids as $thread_id) {
3795  $tmp_obj = new ilForumTopic($thread_id);
3796  $this->ensureThreadBelongsToForum($this->object->getId(), $tmp_obj);
3797  $tmp_obj->disableNotification($this->user->getId());
3798  }
3799 
3800  $this->ctrl->redirect($this, 'showThreads');
3801  } elseif ($cmd === 'close') {
3802  if ($this->is_moderator) {
3803  foreach ($thread_ids as $thread_id) {
3804  $tmp_obj = new ilForumTopic($thread_id);
3805  $this->ensureThreadBelongsToForum($this->object->getId(), $tmp_obj);
3806  $tmp_obj->close();
3807  }
3808  }
3809  $this->tpl->setOnScreenMessage('success', $this->lng->txt('selected_threads_closed'), true);
3810  $this->ctrl->redirect($this, 'showThreads');
3811  } elseif ($cmd === 'reopen') {
3812  if ($this->is_moderator) {
3813  foreach ($thread_ids as $thread_id) {
3814  $tmp_obj = new ilForumTopic($thread_id);
3815  $this->ensureThreadBelongsToForum($this->object->getId(), $tmp_obj);
3816  $tmp_obj->reopen();
3817  }
3818  }
3819 
3820  $this->tpl->setOnScreenMessage('success', $this->lng->txt('selected_threads_reopened'), true);
3821  $this->ctrl->redirect($this, 'showThreads');
3822  } elseif ($cmd === 'makesticky') {
3823  if ($this->is_moderator) {
3824  $message = $this->lng->txt('sel_threads_make_sticky');
3825 
3826  foreach ($thread_ids as $thread_id) {
3827  $tmp_obj = new ilForumTopic($thread_id);
3828  $this->ensureThreadBelongsToForum($this->object->getId(), $tmp_obj);
3829  $makeSticky = $tmp_obj->makeSticky();
3830  if (!$makeSticky) {
3831  $message = $this->lng->txt('sel_threads_already_sticky');
3832  }
3833  }
3834  }
3835  if ($message !== null) {
3836  $this->tpl->setOnScreenMessage('info', $message, true);
3837  }
3838  $this->ctrl->redirect($this, 'showThreads');
3839  } elseif ($cmd === 'unmakesticky' || $cmd === 'make_topics_non_sticky') {
3840  if ($this->is_moderator) {
3841  $message = $this->lng->txt('sel_threads_make_unsticky');
3842  foreach ($thread_ids as $thread_id) {
3843  $tmp_obj = new ilForumTopic($thread_id);
3844  $this->ensureThreadBelongsToForum($this->object->getId(), $tmp_obj);
3845  $unmakeSticky = $tmp_obj->unmakeSticky();
3846  if (!$unmakeSticky) {
3847  $message = $this->lng->txt('sel_threads_already_unsticky');
3848  }
3849  }
3850  }
3851 
3852  if ($message !== null) {
3853  $this->tpl->setOnScreenMessage('info', $message, true);
3854  }
3855  $this->ctrl->redirect($this, 'showThreads');
3856  } elseif ($cmd === 'editThread') {
3857  if ($this->is_moderator) {
3858  $count = count($thread_ids);
3859  if ($count !== 1) {
3860  $this->tpl->setOnScreenMessage('info', $this->lng->txt('select_max_one_thread'), true);
3861  $this->ctrl->redirect($this, 'showThreads');
3862  } else {
3863  $this->updateThreadObject();
3864  return;
3865  }
3866  }
3867 
3868  $this->ctrl->redirect($this, 'showThreads');
3869  } elseif ($cmd === 'html') {
3870  $this->ctrl->setCmd('exportHTML');
3871  $this->ctrl->setCmdClass(ilForumExportGUI::class);
3872  $this->executeCommand();
3873  } elseif ($cmd === 'confirmDeleteThreads') {
3874  $this->confirmDeleteThreadsObject();
3875  } elseif ($cmd === 'mergeThreads') {
3876  $this->mergeThreadsObject();
3877  } else {
3878  $this->tpl->setOnScreenMessage('info', $this->lng->txt('topics_please_select_one_action'), true);
3879  $this->ctrl->redirect($this, 'showThreads');
3880  }
3881  } else {
3882  $this->tpl->setOnScreenMessage('info', $this->lng->txt('select_at_least_one_thread'), true);
3883  $this->ctrl->redirect($this, 'showThreads');
3884  }
3885  }
3886 
3887  public function performMoveThreadsObject(): void
3888  {
3889  if (!$this->is_moderator) {
3890  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3891  }
3892 
3893  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
3894  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3895  }
3896 
3897  $frm_ref_id = null;
3898  if ($this->http->wrapper()->post()->has('frm_ref_id')) {
3899  $frm_ref_id = $this->http->wrapper()->post()->retrieve(
3900  'frm_ref_id',
3901  $this->refinery->kindlyTo()->int()
3902  );
3903  } else {
3904  $this->error->raiseError('Please select a forum', $this->error->MESSAGE);
3905  }
3906 
3907  $threads2move = ilSession::get('threads2move');
3908  if (!is_array($threads2move) || $threads2move === []) {
3909  $this->tpl->setOnScreenMessage('info', $this->lng->txt('select_at_least_one_thread'), true);
3910  $this->ctrl->redirect($this, 'showThreads');
3911  }
3912 
3913  if (!$this->access->checkAccess('read', '', (int) $frm_ref_id)) {
3914  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3915  }
3916 
3917  $threads = [];
3918  array_walk($threads2move, function (int $threadId) use (&$threads): void {
3919  $thread = new ilForumTopic($threadId);
3920  $this->ensureThreadBelongsToForum($this->object->getId(), $thread);
3921 
3922  $threads[] = $threadId;
3923  });
3924 
3925  if (isset($frm_ref_id) && (int) $frm_ref_id) {
3926  $errorMessages = $this->object->Forum->moveThreads(
3927  (array) (ilSession::get('threads2move') ?? []),
3928  $this->object,
3929  $this->ilObjDataCache->lookupObjId((int) $frm_ref_id)
3930  );
3931 
3932  if ([] !== $errorMessages) {
3933  $this->tpl->setOnScreenMessage('failure', implode('<br><br>', $errorMessages), true);
3934  $this->ctrl->redirect($this, 'showThreads');
3935  }
3936 
3937  ilSession::set('threads2move', []);
3938  $this->tpl->setOnScreenMessage('info', $this->lng->txt('threads_moved_successfully'), true);
3939  $this->ctrl->redirect($this, 'showThreads');
3940  } else {
3941  $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_forum_selected'));
3942  $this->moveThreadsObject();
3943  }
3944  }
3945 
3946  public function cancelMoveThreadsObject(): void
3947  {
3948  ilSession::set('threads2move', []);
3949  $this->ctrl->redirect($this, 'showThreads');
3950  }
3951 
3952  public function moveThreadsObject(): bool
3953  {
3954  if (!$this->is_moderator) {
3955  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3956  }
3957 
3958  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
3959  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
3960  }
3961 
3962  $frm_ref_id = $this->http->wrapper()->post()->retrieve(
3963  'frm_ref_id',
3964  $this->refinery->byTrying([$this->refinery->kindlyTo()->int(), $this->refinery->always(null)])
3965  );
3966 
3967  $threads2move = ilSession::get('threads2move');
3968  if (!is_array($threads2move) || $threads2move === []) {
3969  $this->tpl->setOnScreenMessage('info', $this->lng->txt('select_at_least_one_thread'), true);
3970  $this->ctrl->redirect($this, 'showThreads');
3971  }
3972 
3973  $threads = [];
3974  $isModerator = $this->is_moderator;
3975  array_walk($threads2move, function (int $threadId) use (&$threads, $isModerator): void {
3976  $thread = new ilForumTopic($threadId, $isModerator);
3977  $this->ensureThreadBelongsToForum($this->object->getId(), $thread);
3978 
3979  $threads[] = $thread;
3980  });
3981 
3982  $exp = new ilForumMoveTopicsExplorer($this, 'moveThreads');
3983  $exp->setPathOpen($this->object->getRefId());
3984  $exp->setNodeSelected(isset($frm_ref_id) && (int) $frm_ref_id ? (int) $frm_ref_id : 0);
3985  $exp->setCurrentFrmRefId($this->object->getRefId());
3986  $exp->setHighlightedNode((string) $this->object->getRefId());
3987  if (!$exp->handleCommand()) {
3988  $moveThreadTemplate = new ilTemplate(
3989  'tpl.forums_threads_move.html',
3990  true,
3991  true,
3992  'Modules/Forum'
3993  );
3994 
3995  if (!$this->hideToolbar()) {
3996  $this->toolbar->addButton($this->lng->txt('back'), $this->ctrl->getLinkTarget($this));
3997  }
3998 
3999  $tblThr = new ilTable2GUI($this);
4000 
4001  $counter = 0;
4002  $result = [];
4003  foreach ($threads as $thread) {
4004  $result[$counter]['num'] = $counter + 1;
4005  $result[$counter]['thr_subject'] = $thread->getSubject();
4006  ++$counter;
4007  }
4008 
4009  $tblThr->setId('frmthrmv' . $this->object->getRefId());
4010  $tblThr->setTitle('');
4011  $tblThr->addColumn($this->lng->txt('subject'), 'top_name', '100%');
4012  $tblThr->disable('header');
4013  $tblThr->disable('footer');
4014  $tblThr->disable('linkbar');
4015  $tblThr->disable('sort');
4016  $tblThr->disable('linkbar');
4017  $tblThr->setLimit(PHP_INT_MAX);
4018  $tblThr->setRowTemplate('tpl.forums_threads_move_thr_row.html', 'Modules/Forum');
4019  $tblThr->setDefaultOrderField('is_sticky');
4020 
4021  $tblThr->setData($result);
4022  $moveThreadTemplate->setVariable('THREAD_TITLE', sprintf($this->lng->txt('move_chosen_topics'), $thread->getSubject()));
4023  $moveThreadTemplate->setVariable('THREADS_TABLE', $tblThr->getHTML());
4024  $moveThreadTemplate->setVariable('FRM_SELECTION_TREE', $exp->getHTML());
4025  $moveThreadTemplate->setVariable('CMD_SUBMIT', 'performMoveThreads');
4026  $moveThreadTemplate->setVariable('TXT_SUBMIT', $this->lng->txt('move'));
4027  $moveThreadTemplate->setVariable('FORMACTION', $this->ctrl->getFormAction($this, 'performMoveThreads'));
4028 
4029  $this->tpl->setContent($moveThreadTemplate->get());
4030  }
4031 
4032  return true;
4033  }
4034 
4035  private function isWritingWithPseudonymAllowed(): bool
4036  {
4037  return (
4038  $this->objProperties->isAnonymized() &&
4039  (!$this->is_moderator || !$this->objProperties->getMarkModeratorPosts())
4040  );
4041  }
4042 
4043  protected function deleteThreadDraftsObject(): void
4044  {
4045  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
4046  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4047  }
4048 
4049  $draftIds = array_filter((array) ($this->httpRequest->getParsedBody()['draft_ids'] ?? []));
4050  if ([] === $draftIds) {
4051  $draftIds = array_filter([(int) ($this->httpRequest->getQueryParams()['draft_id'] ?? 0)]);
4052  }
4053 
4054  $instances = ilForumPostDraft::getDraftInstancesByUserId($this->user->getId());
4055  $checkedDraftIds = [];
4056  foreach ($draftIds as $draftId) {
4057  if (array_key_exists($draftId, $instances)) {
4058  $checkedDraftIds[] = $draftId;
4059  $draft = $instances[$draftId];
4060 
4061  $this->deleteMobsOfDraft($draft->getDraftId(), $draft->getPostMessage());
4062 
4063  $GLOBALS['ilAppEventHandler']->raise(
4064  'Modules/Forum',
4065  'deletedDraft',
4066  [
4067  'draftObj' => $draft,
4068  'obj_id' => $this->object->getId(),
4069  'is_file_upload_allowed' => $this->objProperties->isFileUploadAllowed(),
4070  ]
4071  );
4072 
4073  $draftFileData = new ilFileDataForumDrafts();
4074  $draftFileData->delete([$draft->getDraftId()]);
4075 
4076  $draft->deleteDraft();
4077  }
4078  }
4079 
4080  if (count($checkedDraftIds) > 1) {
4081  $this->tpl->setOnScreenMessage('info', $this->lng->txt('delete_drafts_successfully'), true);
4082  } else {
4083  $this->tpl->setOnScreenMessage('info', $this->lng->txt('delete_draft_successfully'), true);
4084  }
4085  $this->ctrl->redirect($this, 'showThreads');
4086  }
4087 
4088  private function buildThreadForm(bool $isDraft = false): ilForumThreadFormGUI
4089  {
4090  $draftId = (int) ($this->httpRequest->getQueryParams()['draft_id'] ?? 0);
4091  $allowNotification = !$this->objProperties->isAnonymized() && !$this->user->isAnonymous();
4092 
4093  $mail = new ilMail($this->user->getId());
4094  if (!$this->rbac->system()->checkAccess('internal_mail', $mail->getMailObjectReferenceId())) {
4095  $allowNotification = false;
4096  }
4097 
4098  $default_form = new ilForumThreadFormGUI(
4099  $this,
4100  $this->objProperties,
4102  $allowNotification,
4103  $isDraft,
4104  $draftId
4105  );
4106 
4107  $default_form->addInputItem(ilForumThreadFormGUI::ALIAS_INPUT);
4108  $default_form->addInputItem(ilForumThreadFormGUI::SUBJECT_INPUT);
4109  $default_form->addInputItem(ilForumThreadFormGUI::MESSAGE_INPUT);
4110  $default_form->addInputItem(ilForumThreadFormGUI::FILE_UPLOAD_INPUT);
4111  $default_form->addInputItem(ilForumThreadFormGUI::ALLOW_NOTIFICATION_INPUT);
4112  $default_form->addInputItem(ilForumThreadFormGUI::AUTOSAVE_INFO);
4113 
4114  $default_form->generateDefaultForm();
4115 
4116  $this->decorateWithAutosave($default_form);
4117 
4118  return $default_form;
4119  }
4120 
4121  private function buildMinimalThreadForm(bool $isDraft = false): ilForumThreadFormGUI
4122  {
4123  $draftId = (int) ($this->httpRequest->getQueryParams()['draft_id'] ?? 0);
4124  $allowNotification = !$this->objProperties->isAnonymized() && !$this->user->isAnonymous();
4125 
4126  $mail = new ilMail($this->user->getId());
4127  if (!$this->rbac->system()->checkAccess('internal_mail', $mail->getMailObjectReferenceId())) {
4128  $allowNotification = false;
4129  }
4130 
4131  $minimal_form = new ilForumThreadFormGUI(
4132  $this,
4133  $this->objProperties,
4135  $allowNotification,
4136  $isDraft,
4137  $draftId
4138  );
4139 
4140  $minimal_form->addInputItem(ilForumThreadFormGUI::ALIAS_INPUT);
4141  $minimal_form->addInputItem(ilForumThreadFormGUI::SUBJECT_INPUT);
4142 
4143  $minimal_form->generateMinimalForm();
4144 
4145  return $minimal_form;
4146  }
4147 
4148  private function createThreadObject(): void
4149  {
4150  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
4151  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4152  }
4153 
4154  if (!$this->access->checkAccess('add_thread', '', $this->object->getRefId())) {
4155  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4156  }
4157 
4158  $tpl = new ilTemplate('tpl.create_thread_form.html', true, true, 'Modules/Forum');
4159 
4160  $accordion = new ilAccordionGUI();
4161  $accordion->setId('acc_' . $this->obj_id);
4162  $accordion->setBehaviour(ilAccordionGUI::FIRST_OPEN);
4163 
4164  $accordion->addItem($this->lng->txt('new_thread_with_post'), $this->buildThreadForm()->getHTML());
4165  $accordion->addItem($this->lng->txt('empty_thread'), $this->buildMinimalThreadForm()->getHTML());
4166 
4167  $tpl->setVariable('CREATE_FORM', $accordion->getHTML());
4169 
4170  $this->tpl->setContent($tpl->get());
4171  }
4172 
4176  private function createThread(ilForumPostDraft $draft, bool $createFromDraft = false): void
4177  {
4178  if (
4179  !$this->access->checkAccess('add_thread', '', $this->object->getRefId()) ||
4180  !$this->access->checkAccess('read', '', $this->object->getRefId())
4181  ) {
4182  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4183  }
4184 
4185  $frm = $this->object->Forum;
4186  $frm->setForumId($this->object->getId());
4187  $frm->setForumRefId($this->object->getRefId());
4188  $frm->setMDB2WhereCondition('top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
4189  $topicData = $frm->getOneTopic();
4190 
4191  $form = $this->buildThreadForm($createFromDraft);
4192  $minimal_form = $this->buildMinimalThreadForm($createFromDraft);
4193 
4194  if ($form->checkInput()) {
4195  $userIdForDisplayPurposes = $this->user->getId();
4196  if ($this->isWritingWithPseudonymAllowed()) {
4197  $userIdForDisplayPurposes = 0;
4198  }
4199 
4200  $status = true;
4201  if (
4202  ($this->objProperties->isPostActivationEnabled() && !$this->is_moderator) ||
4203  $this->objCurrentPost->isAnyParentDeactivated()
4204  ) {
4205  $status = false;
4206  }
4207 
4208  if ($createFromDraft) {
4209  $newThread = new ilForumTopic(0, true, true);
4210  $newThread->setForumId($topicData->getTopPk());
4211  $newThread->setThrAuthorId($draft->getPostAuthorId());
4212  $newThread->setDisplayUserId($draft->getPostDisplayUserId());
4213  $newThread->setSubject($this->handleFormInput($form->getInput('subject'), false));
4214  $newThread->setUserAlias($draft->getPostUserAlias());
4215 
4216  $newPost = $frm->generateThread(
4217  $newThread,
4218  ilRTE::_replaceMediaObjectImageSrc($form->getInput('message')),
4219  $draft->isNotificationEnabled() && !$this->user->isAnonymous(),
4220  $draft->isPostNotificationEnabled() && !$this->user->isAnonymous(),
4221  $status
4222  );
4223  } else {
4224  $userAlias = ilForumUtil::getPublicUserAlias(
4225  $form->getInput('alias'),
4226  $this->objProperties->isAnonymized()
4227  );
4228  $newThread = new ilForumTopic(0, true, true);
4229  $newThread->setForumId($topicData->getTopPk());
4230  $newThread->setThrAuthorId($this->user->getId());
4231  $newThread->setDisplayUserId($userIdForDisplayPurposes);
4232  $newThread->setSubject($this->handleFormInput($form->getInput('subject'), false));
4233  $newThread->setUserAlias($userAlias);
4234 
4235  $newPost = $frm->generateThread(
4236  $newThread,
4237  ilRTE::_replaceMediaObjectImageSrc($form->getInput('message')),
4238  $form->getItemByPostVar('notify') && $form->getInput('notify') && !$this->user->isAnonymous(),
4239  false, // #19980
4240  $status
4241  );
4242  }
4243 
4244  $post_obj = new ilForumPost($newPost);
4245  if ($draft->getRCID() > 0) {
4246  $post_obj->setRCID($draft->getRCID());
4247  $post_obj->update();
4248  }
4249 
4250  if ($this->objProperties->isFileUploadAllowed()) {
4251  $file = $_FILES['userfile'];
4252  if (is_array($file) && !empty($file)) {
4253  $fileData = new ilFileDataForum($this->object->getId(), $newPost);
4254  $fileData->storeUploadedFiles();
4255  }
4256  }
4257 
4258  $frm->setDbTable('frm_data');
4259  $frm->setMDB2WhereCondition('top_pk = %s ', ['integer'], [$topicData->getTopPk()]);
4260  $frm->updateVisits($topicData->getTopPk());
4261 
4262  if ($createFromDraft) {
4263  $mediaObjects = ilObjMediaObject::_getMobsOfObject('frm~:html', $this->user->getId());
4264  } else {
4265  $mediaObjects = ilRTE::_getMediaObjects($form->getInput('message'));
4266  }
4267  foreach ($mediaObjects as $mob) {
4268  if (ilObjMediaObject::_exists($mob)) {
4269  ilObjMediaObject::_removeUsage($mob, 'frm~:html', $this->user->getId());
4270  ilObjMediaObject::_saveUsage($mob, 'frm:html', $newPost);
4271  }
4272  }
4273 
4274  if ($draft->getDraftId() > 0) {
4275  $draftHistory = new ilForumDraftsHistory();
4276  $draftHistory->deleteHistoryByDraftIds([$draft->getDraftId()]);
4277  $draft->deleteDraft();
4278  }
4279 
4280  $GLOBALS['ilAppEventHandler']->raise(
4281  'Modules/Forum',
4282  'createdPost',
4283  [
4284  'object' => $this->object,
4285  'ref_id' => $this->object->getRefId(),
4286  'post' => $post_obj,
4287  'notify_moderators' => !$status
4288  ]
4289  );
4290 
4291  $this->tpl->setOnScreenMessage('success', $this->lng->txt('forums_thread_new_entry'), true);
4292  $this->ctrl->redirect($this);
4293  }
4294 
4295  $form->setValuesByPost();
4296  if (!$this->objProperties->isAnonymized()) {
4297  $form->getItemByPostVar('alias')->setValue($this->user->getLogin());
4298  }
4299 
4300  $accordion = new ilAccordionGUI();
4301  $accordion->setId('acc_' . $this->obj_id);
4302  $accordion->setBehaviour(ilAccordionGUI::FIRST_OPEN);
4303  $accordion->addItem($this->lng->txt('new_thread_with_post'), $form->getHTML());
4304  $accordion->addItem($this->lng->txt('empty_thread'), $minimal_form->getHTML());
4305 
4306  $this->tpl->setContent($accordion->getHTML());
4307  }
4308 
4312  private function createEmptyThread(bool $createFromDraft = false): void
4313  {
4314  if (
4315  !$this->access->checkAccess('add_thread', '', $this->object->getRefId()) ||
4316  !$this->access->checkAccess('read', '', $this->object->getRefId())
4317  ) {
4318  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4319  }
4320 
4321  $frm = $this->object->Forum;
4322  $frm->setForumId($this->object->getId());
4323  $frm->setForumRefId($this->object->getRefId());
4324  $frm->setMDB2WhereCondition('top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
4325  $topicData = $frm->getOneTopic();
4326 
4327  $form = $this->buildThreadForm($createFromDraft);
4328  $minimal_form = $this->buildMinimalThreadForm($createFromDraft);
4329 
4330  if ($minimal_form->checkInput()) {
4331  $userIdForDisplayPurposes = $this->user->getId();
4332  if ($this->isWritingWithPseudonymAllowed()) {
4333  $userIdForDisplayPurposes = 0;
4334  }
4335 
4336  $status = true;
4337  if (
4338  ($this->objProperties->isPostActivationEnabled() && !$this->is_moderator) ||
4339  $this->objCurrentPost->isAnyParentDeactivated()
4340  ) {
4341  $status = false;
4342  }
4343 
4344  $userAlias = ilForumUtil::getPublicUserAlias(
4345  $minimal_form->getInput('alias'),
4346  $this->objProperties->isAnonymized()
4347  );
4348  $newThread = new ilForumTopic(0, true, true);
4349  $newThread->setForumId($topicData->getTopPk());
4350  $newThread->setThrAuthorId($this->user->getId());
4351  $newThread->setDisplayUserId($userIdForDisplayPurposes);
4352  $newThread->setSubject($this->handleFormInput($minimal_form->getInput('subject'), false));
4353  $newThread->setUserAlias($userAlias);
4354 
4355  $frm->generateThread(
4356  $newThread,
4357  '',
4358  false,
4359  false, // #19980
4360  $status,
4361  false
4362  );
4363 
4364  $frm->setDbTable('frm_data');
4365  $frm->setMDB2WhereCondition('top_pk = %s ', ['integer'], [$topicData->getTopPk()]);
4366  $frm->updateVisits($topicData->getTopPk());
4367 
4368  $this->tpl->setOnScreenMessage('success', $this->lng->txt('forums_thread_new_entry'), true);
4369  $this->ctrl->redirect($this);
4370  }
4371 
4372  $form->setValuesByPost();
4373 
4374  if (!$this->objProperties->isAnonymized()) {
4375  $form->getItemByPostVar('alias')->setValue($this->user->getLogin());
4376  }
4377 
4378  $accordion = new ilAccordionGUI();
4379  $accordion->setId('acc_' . $this->obj_id);
4380  $accordion->setBehaviour(ilAccordionGUI::FIRST_OPEN);
4381  $accordion->addItem($this->lng->txt('new_thread_with_post'), $form->getHTML());
4382  $accordion->addItem($this->lng->txt('empty_thread'), $minimal_form->getHTML());
4383 
4384  $this->tpl->setContent($accordion->getHTML());
4385  }
4386 
4387  protected function publishThreadDraftObject(): void
4388  {
4390  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4391  }
4392 
4393  $draftId = (int) ($this->httpRequest->getQueryParams()['draft_id'] ?? 0);
4394  $draft = ilForumPostDraft::newInstanceByDraftId($draftId);
4395 
4396  if ($draft->getDraftId() <= 0) {
4397  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4398  }
4399 
4400  $this->createThread($draft, true);
4401  }
4402 
4403  protected function addThreadObject(): void
4404  {
4405  $draft = new ilForumPostDraft();
4407  $draftId = (int) ($this->httpRequest->getParsedBody()['draft_id'] ?? 0);
4408  if ($draftId > 0) {
4409  $draft = ilForumPostDraft::newInstanceByDraftId($draftId);
4410  }
4411  }
4412 
4413  $this->createThread($draft);
4414  }
4415 
4416  protected function addEmptyThreadObject(): void
4417  {
4418  $draft = new ilForumPostDraft();
4420  $draftId = (int) ($this->httpRequest->getParsedBody()['draft_id'] ?? 0);
4421  if ($draftId > 0) {
4422  $draft = ilForumPostDraft::newInstanceByDraftId($draftId);
4423  }
4424  }
4425 
4426  $this->createEmptyThread();
4427  }
4428 
4429  protected function enableForumNotificationObject(): void
4430  {
4431  if (!$this->access->checkAccess('read', '', $this->object->getRefId()) || $this->user->isAnonymous()) {
4432  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4433  }
4434 
4435  $frm = $this->object->Forum;
4436  $frm->setForumId($this->object->getId());
4437  $frm->enableForumNotification($this->user->getId());
4438 
4439  if ($this->objCurrentTopic->getId() > 0) {
4440  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
4441  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_forum_notification_enabled'), true);
4442  $this->ctrl->redirect($this, 'viewThread');
4443  }
4444 
4445  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_forum_notification_enabled'));
4446  $this->showThreadsObject();
4447  }
4448 
4449  protected function disableForumNotificationObject(): void
4450  {
4451  if (!$this->access->checkAccess('read', '', $this->object->getRefId()) || $this->user->isAnonymous()) {
4452  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4453  }
4454 
4455  $frm = $this->object->Forum;
4456  $frm->setForumId($this->object->getId());
4457  $frm->disableForumNotification($this->user->getId());
4458 
4459  if ($this->objCurrentTopic->getId() > 0) {
4460  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
4461  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_forum_notification_disabled'), true);
4462  $this->ctrl->redirect($this, 'viewThread');
4463  }
4464 
4465  $this->tpl->setOnScreenMessage('info', $this->lng->txt('forums_forum_notification_disabled'));
4466  $this->showThreadsObject();
4467  }
4468 
4469  public function setColumnSettings(ilColumnGUI $column_gui): void
4470  {
4471  $column_gui->setBlockProperty('news', 'title', $this->lng->txt('frm_latest_postings'));
4472  $column_gui->setBlockProperty('news', 'prevent_aggregation', '1');
4473  $column_gui->setRepositoryMode(true);
4474 
4475  if ($this->access->checkAccess('write', '', $this->object->getRefId())) {
4476  $news_set = new ilSetting('news');
4477  if ($news_set->get('enable_rss_for_internal')) {
4478  $column_gui->setBlockProperty('news', 'settings', '1');
4479  $column_gui->setBlockProperty('news', 'public_notifications_option', '1');
4480  }
4481  }
4482  }
4483 
4484  protected function addLocatorItems(): void
4485  {
4486  if ($this->object instanceof ilObjForum) {
4487  $this->locator->addItem(
4488  $this->object->getTitle(),
4489  $this->ctrl->getLinkTarget($this),
4490  '',
4491  $this->object->getRefId()
4492  );
4493  }
4494  }
4495 
4496  public function handleFormInput(string $a_text, bool $a_stripslashes = true): string
4497  {
4498  $a_text = str_replace(['<', '>'], ['&lt;', '&gt;'], $a_text);
4499  if ($a_stripslashes) {
4500  $a_text = ilUtil::stripSlashes($a_text);
4501  }
4502 
4503  return $a_text;
4504  }
4505 
4506  public function prepareFormOutput(string $a_text): string
4507  {
4508  $a_text = str_replace(['&lt;', '&gt;'], ['<', '>'], $a_text);
4509 
4511  }
4512 
4513  protected function infoScreen(): void
4514  {
4515  if (
4516  !$this->access->checkAccess('visible', '', $this->object->getRefId()) &&
4517  !$this->access->checkAccess('read', '', $this->object->getRefId())
4518  ) {
4519  $this->error->raiseError($this->lng->txt('msg_no_perm_read'), $this->error->MESSAGE);
4520  }
4521 
4522  $info = new ilInfoScreenGUI($this);
4523  $info->enablePrivateNotes();
4524  $this->ctrl->forwardCommand($info);
4525  }
4526 
4527  protected function markPostUnreadObject(): void
4528  {
4529  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
4530  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4531  }
4532 
4533  if ($this->objCurrentPost->getId() > 0) {
4534  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentPost->getThread());
4535 
4536  $this->object->markPostUnread($this->user->getId(), $this->objCurrentPost->getId());
4537  }
4538  $this->viewThreadObject();
4539  }
4540 
4541  protected function markPostReadObject(): void
4542  {
4543  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
4544  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4545  }
4546 
4547  if ($this->objCurrentTopic->getId() > 0 && $this->objCurrentPost->getId() > 0) {
4548  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentPost->getThread());
4549 
4550  $this->object->markPostRead(
4551  $this->user->getId(),
4552  $this->objCurrentTopic->getId(),
4553  $this->objCurrentPost->getId()
4554  );
4555  }
4556 
4557  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
4558  $this->ctrl->redirect($this, 'viewThread');
4559  }
4560 
4561  protected function initHeaderAction(?string $sub_type = null, ?int $sub_id = null): ?ilObjectListGUI
4562  {
4563  $lg = parent::initHeaderAction();
4564 
4565  if (!($lg instanceof ilObjForumListGUI) || !((bool) $this->settings->get('forum_notification', '0'))) {
4566  return $lg;
4567  }
4568 
4569  if ($this->user->isAnonymous() || !$this->access->checkAccess('read', '', $this->object->getRefId())) {
4570  return $lg;
4571  }
4572 
4573  $frm = $this->object->Forum;
4574  $frm->setForumId($this->object->getId());
4575  $frm->setForumRefId($this->object->getRefId());
4576  $frm->setMDB2Wherecondition('top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
4577 
4578  $isForumNotificationEnabled = $frm->isForumNotificationEnabled($this->user->getId());
4579  $userMayDisableNotifications = $this->isUserAllowedToDeactivateNotification();
4580 
4581  if ($this->objCurrentTopic->getId() > 0) {
4582  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
4583  }
4584 
4585  if (!$this->user->isAnonymous()) {
4586  if ($this->object->isParentMembershipEnabledContainer()) {
4587  if ($isForumNotificationEnabled && $userMayDisableNotifications) {
4588  $lg->addCustomCommand(
4589  $this->ctrl->getLinkTarget($this, 'disableForumNotification'),
4590  'forums_disable_forum_notification'
4591  );
4592  } elseif (!$isForumNotificationEnabled) {
4593  $lg->addCustomCommand(
4594  $this->ctrl->getLinkTarget($this, 'enableForumNotification'),
4595  'forums_enable_forum_notification'
4596  );
4597  }
4598  } elseif ($isForumNotificationEnabled) {
4599  $lg->addCustomCommand(
4600  $this->ctrl->getLinkTarget($this, 'disableForumNotification'),
4601  'forums_disable_forum_notification'
4602  );
4603  } else {
4604  $lg->addCustomCommand(
4605  $this->ctrl->getLinkTarget($this, 'enableForumNotification'),
4606  'forums_enable_forum_notification'
4607  );
4608  }
4609  }
4610 
4611  $ref_id = $this->retrieveRefId();
4612  if (!$this->user->isAnonymous() && $isForumNotificationEnabled && $userMayDisableNotifications) {
4613  $frm_noti = new ilForumNotification($ref_id);
4614  $frm_noti->setUserId($this->user->getId());
4615  $interested_events = $frm_noti->readInterestedEvents();
4616 
4617  $events_form_builder = $this->eventsFormBuilder([
4618  'hidden_value' => '',
4619  'notify_modified' => (bool) ($interested_events & ilForumNotificationEvents::UPDATED),
4620  'notify_censored' => (bool) ($interested_events & ilForumNotificationEvents::CENSORED),
4621  'notify_uncensored' => (bool) ($interested_events & ilForumNotificationEvents::UNCENSORED),
4622  'notify_post_deleted' => (bool) ($interested_events & ilForumNotificationEvents::POST_DELETED),
4623  'notify_thread_deleted' => (bool) ($interested_events & ilForumNotificationEvents::THREAD_DELETED),
4624  ]);
4625 
4626  $notificationsModal = $this->uiFactory->modal()->roundtrip(
4627  $this->lng->txt('notification_settings'),
4628  [$events_form_builder->build()]
4629  )->withActionButtons([
4630  $this->uiFactory
4631  ->button()
4632  ->primary($this->lng->txt('save'), '#')
4633  ->withOnLoadCode(function (string $id): string {
4634  return "
4635  $('#$id').closest('.modal').find('form').addClass('ilForumNotificationSettingsForm');
4636  $('#$id').closest('.modal').find('form .il-standard-form-header, .il-standard-form-footer').remove();
4637  $('#$id').click(function() { $(this).closest('.modal').find('form').submit(); return false; });
4638  ";
4639  })
4640  ]);
4641 
4642  $showNotificationSettingsBtn = $this->uiFactory->button()
4643  ->shy($this->lng->txt('notification_settings'), '#')
4644  ->withOnClick(
4645  $notificationsModal->getShowSignal()
4646  );
4647 
4648  $lg->addCustomCommandButton($showNotificationSettingsBtn, $notificationsModal);
4649  }
4650 
4651  $isThreadNotificationEnabled = false;
4652  if (!$this->user->isAnonymous() && $this->objCurrentTopic->getId() > 0) {
4653  $isThreadNotificationEnabled = $this->objCurrentTopic->isNotificationEnabled($this->user->getId());
4654  if ($isThreadNotificationEnabled) {
4655  $lg->addCustomCommand(
4656  $this->ctrl->getLinkTarget($this, 'toggleThreadNotification'),
4657  'forums_disable_notification'
4658  );
4659  } else {
4660  $lg->addCustomCommand(
4661  $this->ctrl->getLinkTarget($this, 'toggleThreadNotification'),
4662  'forums_enable_notification'
4663  );
4664  }
4665  }
4666  $this->ctrl->setParameter($this, 'thr_pk', '');
4667 
4668  if (!$this->user->isAnonymous()) {
4669  if ($isForumNotificationEnabled || $isThreadNotificationEnabled) {
4670  $lg->addHeaderIcon(
4671  'not_icon',
4672  ilUtil::getImagePath('object/notification_on.svg'),
4673  $this->lng->txt('frm_notification_activated')
4674  );
4675  } else {
4676  $lg->addHeaderIcon(
4677  'not_icon',
4678  ilUtil::getImagePath('object/notification_off.svg'),
4679  $this->lng->txt('frm_notification_deactivated')
4680  );
4681  }
4682  }
4683 
4684  return $lg;
4685  }
4686 
4691  private function eventsFormBuilder(?array $predefined_values = null): ilForumNotificationEventsFormGUI
4692  {
4693  if ($this->objCurrentTopic->getId() > 0) {
4694  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
4695  }
4696 
4698  $this->ctrl->getFormAction($this, 'saveUserNotificationSettings'),
4699  $predefined_values,
4701  $this->lng
4702  );
4703  }
4704 
4705  public function saveUserNotificationSettingsObject(): void
4706  {
4707  $events_form_builder = $this->eventsFormBuilder();
4708 
4709  if ($this->httpRequest->getMethod() === 'POST') {
4710  $form = $events_form_builder->build()->withRequest($this->httpRequest);
4711  $formData = $form->getData();
4712 
4713  $interested_events = ilForumNotificationEvents::DEACTIVATED;
4714 
4715  foreach ($events_form_builder->getValidEvents() as $event) {
4716  $interested_events += isset($formData[$event]) && $formData[$event] ? $events_form_builder->getValueForEvent(
4717  $event
4718  ) : 0;
4719  }
4720 
4721  $frm_noti = new ilForumNotification($this->object->getRefId());
4722  $frm_noti->setUserId($this->user->getId());
4723  $frm_noti->setInterestedEvents($interested_events);
4724  $frm_noti->updateInterestedEvents();
4725  }
4726 
4727  $this->tpl->setOnScreenMessage('success', $this->lng->txt('saved_successfully'), true);
4728 
4729  if ($this->objCurrentTopic->getId() > 0) {
4730  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
4731  $this->ctrl->redirect($this, 'viewThread');
4732  }
4733 
4734  $this->ctrl->redirect($this, 'showThreads');
4735  }
4736 
4738  {
4739  if ($this->objProperties->getNotificationType() === NotificationType::DEFAULT) {
4740  return true;
4741  }
4742 
4743  if (!$this->objProperties->isUserToggleNoti() &&
4744  $this->objProperties->getNotificationType() === NotificationType::ALL_USERS) {
4745  return true;
4746  }
4747 
4748  if ($this->objProperties->getNotificationType() === NotificationType::PER_USER &&
4749  $this->object->isParentMembershipEnabledContainer()) {
4750  $frm_noti = new ilForumNotification($this->retrieveRefId());
4751  $frm_noti->setUserId($this->user->getId());
4752 
4753  return !$frm_noti->isUserToggleNotification();
4754  }
4755 
4756  return false;
4757  }
4758 
4759  public function mergeThreadsObject(): void
4760  {
4761  if (!$this->is_moderator) {
4762  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4763  }
4764 
4765  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
4766  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4767  }
4768 
4769  $threadIdToMerge = $this->http->wrapper()->query()->retrieve(
4770  'thr_pk',
4771  $this->refinery->byTrying([
4772  $this->refinery->kindlyTo()->int(),
4773  $this->refinery->always(0)
4774  ])
4775  );
4776  if ($threadIdToMerge <= 0) {
4777  $threadIds = array_values(
4778  array_filter(array_map('intval', (array) ($this->httpRequest->getParsedBody()['thread_ids'] ?? [])))
4779  );
4780  if (1 === count($threadIds)) {
4781  $threadIdToMerge = current($threadIds);
4782  } else {
4783  $this->tpl->setOnScreenMessage('info', $this->lng->txt('select_one'));
4784  $this->showThreadsObject();
4785  return;
4786  }
4787  }
4788 
4789  $frm = $this->object->Forum;
4790  $frm->setForumId($this->object->getId());
4791  $frm->setForumRefId($this->object->getRefId());
4792 
4793  $threadToMerge = new ilForumTopic($threadIdToMerge);
4794 
4795  if (ilForum::_lookupObjIdForForumId($threadToMerge->getForumId()) !== $frm->getForumId()) {
4796  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('not_allowed_to_merge_into_another_forum'));
4797  $this->showThreadsObject();
4798  return;
4799  }
4800 
4801  $frm->setMDB2Wherecondition('top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
4802 
4803  $threadsTemplate = new ilTemplate(
4804  'tpl.forums_threads_liste.html',
4805  true,
4806  true,
4807  'Modules/Forum'
4808  );
4809 
4810  $topicData = $frm->getOneTopic();
4811  if ($topicData->getTopPk() > 0) {
4812  $this->ctrl->setParameter($this, 'merge_thread_id', $threadIdToMerge);
4813  $tbl = new ilForumTopicTableGUI(
4814  $this,
4815  'mergeThreads',
4816  (int) $this->httpRequest->getQueryParams()['ref_id'],
4817  $topicData,
4819  );
4820  $tbl->setSelectedThread($threadToMerge);
4821  $tbl->setMapper($frm)->fetchData();
4822  $tbl->init();
4823  $threadsTemplate->setVariable('THREADS_TABLE', $tbl->getHTML());
4824  $this->tpl->setContent($threadsTemplate->get());
4825  } else {
4826  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('select_one'));
4827  $this->showThreadsObject();
4828  }
4829  }
4830 
4831  public function confirmMergeThreadsObject(): void
4832  {
4833  if (!$this->is_moderator) {
4834  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4835  }
4836 
4837  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
4838  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4839  }
4840 
4841  $sourceThreadId = (int) ($this->httpRequest->getQueryParams()['merge_thread_id'] ?? 0);
4842  $targetThreadIds = array_values(
4843  array_filter(array_map('intval', (array) ($this->httpRequest->getParsedBody()['thread_ids'] ?? [])))
4844  );
4845 
4846  if ($sourceThreadId <= 0 || 1 !== count($targetThreadIds)) {
4847  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('select_one'));
4848  $this->mergeThreadsObject();
4849  return;
4850  }
4851 
4852  $targetThreadId = current($targetThreadIds);
4853  if ($sourceThreadId === $targetThreadId) {
4854  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('error_same_thread_ids'));
4855  $this->showThreadsObject();
4856  return;
4857  }
4858 
4859  if (ilForumTopic::lookupForumIdByTopicId($sourceThreadId) !== ilForumTopic::lookupForumIdByTopicId($targetThreadId)) {
4860  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('not_allowed_to_merge_into_another_forum'));
4861  $this->ctrl->clearParameters($this);
4862  $this->showThreadsObject();
4863  return;
4864  }
4865 
4866  if (ilForumTopic::lookupCreationDate($sourceThreadId) < ilForumTopic::lookupCreationDate($targetThreadId)) {
4867  $this->tpl->setOnScreenMessage('info', $this->lng->txt('switch_threads_for_merge'));
4868  }
4869 
4870  $this->ensureThreadBelongsToForum($this->object->getId(), new ilForumTopic($sourceThreadId));
4871  $this->ensureThreadBelongsToForum($this->object->getId(), new ilForumTopic($targetThreadId));
4872 
4873  $c_gui = new ilConfirmationGUI();
4874 
4875  $c_gui->setFormAction($this->ctrl->getFormAction($this, 'performMergeThreads'));
4876  $c_gui->setHeaderText($this->lng->txt('frm_sure_merge_threads'));
4877  $c_gui->setCancel($this->lng->txt('cancel'), 'showThreads');
4878  $c_gui->setConfirm($this->lng->txt('confirm'), 'performMergeThreads');
4879 
4880  $c_gui->addItem(
4881  'thread_ids[]',
4882  (string) $sourceThreadId,
4883  sprintf($this->lng->txt('frm_merge_src'), ilForumTopic::lookupTitle($sourceThreadId))
4884  );
4885  $c_gui->addItem(
4886  'thread_ids[]',
4887  (string) $targetThreadId,
4888  sprintf($this->lng->txt('frm_merge_target'), ilForumTopic::lookupTitle($targetThreadId))
4889  );
4890  $this->tpl->setContent($c_gui->getHTML());
4891  }
4892 
4893  public function performMergeThreadsObject(): void
4894  {
4895  if (!$this->is_moderator) {
4896  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4897  }
4898 
4899  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
4900  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4901  }
4902 
4903  $threadIds = array_values(
4904  array_filter(array_map('intval', (array) ($this->httpRequest->getParsedBody()['thread_ids'] ?? [])))
4905  );
4906  if (2 !== count($threadIds)) {
4907  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('select_one'));
4908  $this->showThreadsObject();
4909  return;
4910  }
4911 
4912  if ((int) $threadIds[0] === (int) $threadIds[1]) {
4913  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('error_same_thread_ids'));
4914  $this->showThreadsObject();
4915  return;
4916  }
4917 
4918  try {
4919  $frm = new ilForum();
4920  $frm->setForumId($this->object->getId());
4921  $frm->setForumRefId($this->object->getRefId());
4922 
4923  $this->ensureThreadBelongsToForum($this->object->getId(), new ilForumTopic((int) $threadIds[0]));
4924  $this->ensureThreadBelongsToForum($this->object->getId(), new ilForumTopic((int) $threadIds[1]));
4925 
4926  $frm->mergeThreads((int) $threadIds[0], (int) $threadIds[1]);
4927  $this->tpl->setOnScreenMessage('success', $this->lng->txt('merged_threads_successfully'));
4928  } catch (ilException $e) {
4929  $this->tpl->setOnScreenMessage('failure', $this->lng->txt($e->getMessage()));
4930  }
4931 
4932  $this->showThreadsObject();
4933  }
4934 
4935  protected function setSideBlocks(): void
4936  {
4937  $content = $this->getRightColumnHTML();
4938  if (!$this->ctrl->isAsynch()) {
4939  $content = implode('', [
4940  ilRepositoryObjectSearchGUI::getSearchBlockHTML($this->lng->txt('frm_search')),
4941  $content,
4942  ]);
4943  }
4944  $this->tpl->setRightContent($content);
4945  }
4946 
4947  protected function deliverDraftZipFileObject(): void
4948  {
4949  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
4950  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4951  }
4952 
4953  $draftId = $this->httpRequest->getQueryParams()['draft_id'] ?? 0;
4954  $draft = ilForumPostDraft::newInstanceByDraftId((int) $draftId);
4955  if ($draft->getPostAuthorId() === $this->user->getId()) {
4956  $fileData = new ilFileDataForumDrafts(0, $draft->getDraftId());
4957  if (!$fileData->deliverZipFile()) {
4958  $this->ctrl->redirect($this);
4959  }
4960  }
4961  }
4962 
4963  protected function deliverZipFileObject(): void
4964  {
4965  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
4966  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4967  }
4968 
4969  $this->ensureThreadBelongsToForum($this->object->getId(), $this->objCurrentPost->getThread());
4970 
4971  $fileData = new ilFileDataForum($this->object->getId(), $this->objCurrentPost->getId());
4972  if (!$fileData->deliverZipFile()) {
4973  $this->ctrl->redirect($this);
4974  }
4975  }
4976 
4980  protected function editThreadDraftObject(ilPropertyFormGUI $form = null): void
4981  {
4982  if (
4984  !$this->access->checkAccess('add_thread', '', $this->object->getRefId()) ||
4985  !$this->access->checkAccess('read', '', $this->object->getRefId())
4986  ) {
4987  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
4988  }
4989 
4990  $frm = $this->object->Forum;
4991  $frm->setForumId($this->object->getId());
4992  $frm->setForumRefId($this->object->getRefId());
4993 
4994  $draft = new ilForumPostDraft();
4995  $draftId = (int) ($this->httpRequest->getQueryParams()['draft_id'] ?? 0);
4996  if ($draftId > 0) {
4997  $draft = ilForumPostDraft::newInstanceByDraftId($draftId);
4998  }
4999 
5000  $historyCheck = (int) ($this->httpRequest->getQueryParams()['hist_check'] ?? 1);
5001  if (!($form instanceof ilPropertyFormGUI) && $historyCheck > 0) {
5002  $this->doHistoryCheck($draft->getDraftId());
5003  }
5004 
5005  if (!$form instanceof ilPropertyFormGUI) {
5006  $form = $this->buildThreadForm(true);
5007  $form->setValuesByArray([
5008  'alias' => $draft->getPostUserAlias(),
5009  'subject' => $draft->getPostSubject(),
5010  'message' => ilRTE::_replaceMediaObjectImageSrc($frm->prepareText($draft->getPostMessage(), 2), 1),
5011  'notify' => $draft->isNotificationEnabled() && !$this->user->isAnonymous(),
5012  'userfile' => '',
5013  'del_file' => [],
5014  'draft_id' => $draftId
5015  ]);
5016  } else {
5017  $this->ctrl->setParameter($this, 'draft_id', $draftId);
5018  }
5019 
5020  $this->tpl->setContent($form->getHTML() . $this->modal_history);
5021  }
5022 
5023  protected function restoreFromHistoryObject(): void
5024  {
5025  $historyId = (int) ($this->httpRequest->getQueryParams()['history_id'] ?? 0);
5026  $history = new ilForumDraftsHistory($historyId);
5027 
5028  $draft = $history->rollbackAutosave();
5029  if ($draft->getThreadId() === 0 && $draft->getPostId() === 0) {
5030  $this->ctrl->setParameter($this, 'draft_id', $history->getDraftId());
5031  $this->ctrl->redirect($this, 'editThreadDraft');
5032  }
5033 
5034  $this->ctrl->clearParameters($this);
5035  $this->ctrl->setParameter($this, 'pos_pk', $draft->getPostId());
5036  $this->ctrl->setParameter($this, 'thr_pk', $draft->getThreadId());
5037  $this->ctrl->setParameter($this, 'draft_id', $draft->getDraftId());
5038  $this->ctrl->setParameter($this, 'action', 'editdraft');
5039 
5040  ilForumPostDraft::createDraftBackup($draft->getDraftId());
5041 
5042  $this->ctrl->redirect($this, 'viewThread');
5043  }
5044 
5045  protected function saveThreadAsDraftObject(): void
5046  {
5047  if (
5049  !$this->access->checkAccess('add_thread', '', $this->object->getRefId()) ||
5050  !$this->access->checkAccess('read', '', $this->object->getRefId())
5051  ) {
5052  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5053  }
5054 
5055  $autoSavedDraftId = (int) ($this->httpRequest->getParsedBody()['draft_id'] ?? 0);
5056  if ($autoSavedDraftId <= 0) {
5057  $autoSavedDraftId = (int) ($this->httpRequest->getQueryParams()['draft_id'] ?? 0);
5058  }
5059 
5060  $frm = $this->object->Forum;
5061  $frm->setForumId($this->object->getId());
5062  $frm->setForumRefId($this->object->getRefId());
5063  $frm->setMDB2WhereCondition('top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
5064  $topicData = $frm->getOneTopic();
5065 
5066  $form = $this->buildThreadForm();
5067  if ($form->checkInput()) {
5068  if (0 === $autoSavedDraftId) {
5069  $draft = new ilForumPostDraft();
5070  } else {
5071  $draft = ilForumPostDraft::newInstanceByDraftId($autoSavedDraftId);
5072  }
5073 
5074  $draft->setForumId($topicData->getTopPk());
5075  $draft->setThreadId(0);
5076  $draft->setPostId(0);
5077  $draft->setPostSubject($this->handleFormInput($form->getInput('subject'), false));
5078  $draft->setPostMessage(ilRTE::_replaceMediaObjectImageSrc($form->getInput('message')));
5079  $userAlias = ilForumUtil::getPublicUserAlias(
5080  $form->getInput('alias'),
5081  $this->objProperties->isAnonymized()
5082  );
5083  $draft->setPostUserAlias($userAlias);
5084  $draft->setNotificationStatus($form->getInput('notify') && !$this->user->isAnonymous());
5085  $draft->setPostAuthorId($this->user->getId());
5086  $draft->setPostDisplayUserId($this->isWritingWithPseudonymAllowed() ? 0 : $this->user->getId());
5087 
5088  if (0 === $autoSavedDraftId) {
5089  $draftId = $draft->saveDraft();
5090  } else {
5091  $draft->updateDraft();
5092  $draftId = $draft->getDraftId();
5093  }
5094 
5095  $GLOBALS['ilAppEventHandler']->raise(
5096  'Modules/Forum',
5097  'savedAsDraft',
5098  [
5099  'draftObj' => $draft,
5100  'obj_id' => $this->object->getId(),
5101  'is_file_upload_allowed' => $this->objProperties->isFileUploadAllowed(),
5102  ]
5103  );
5104 
5105  ilForumUtil::moveMediaObjects($form->getInput('message'), 'frm~d:html', $draftId, 'frm~d:html', $draftId);
5106 
5107  $draftFileData = new ilFileDataForumDrafts($this->object->getId(), $draftId);
5108 
5109  $files2delete = $form->getInput('del_file');
5110  if (is_array($files2delete) && $files2delete !== []) {
5111  $draftFileData->unlinkFilesByMD5Filenames($files2delete);
5112  }
5113 
5114  if ($this->objProperties->isFileUploadAllowed()) {
5115  $file = $_FILES['userfile'];
5116  if (is_array($file) && !empty($file)) {
5117  $draftFileData->storeUploadedFiles();
5118  }
5119  }
5120 
5121  $this->tpl->setOnScreenMessage('success', $this->lng->txt('save_draft_successfully'), true);
5122  $this->ctrl->clearParameters($this);
5123  $this->ctrl->redirect($this, 'showThreads');
5124  }
5125 
5126  $this->requestAction = substr($this->requestAction, 6);
5127  $form->setValuesByPost();
5128  $this->ctrl->setParameter($this, 'draft_id', $autoSavedDraftId);
5129  $this->tpl->setContent($form->getHTML());
5130  }
5131 
5132  protected function updateThreadDraftObject(): void
5133  {
5134  if (
5136  !$this->access->checkAccess('add_thread', '', $this->object->getRefId()) ||
5137  !$this->access->checkAccess('read', '', $this->object->getRefId())
5138  ) {
5139  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5140  }
5141 
5142  $draftId = (int) ($this->httpRequest->getQueryParams()['draft_id'] ?? 0);
5143  if ($draftId <= 0 || !$this->checkDraftAccess($draftId)) {
5144  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5145  }
5146 
5147  $form = $this->buildThreadForm(true);
5148  if ($form->checkInput()) {
5149  $userAlias = ilForumUtil::getPublicUserAlias(
5150  $form->getInput('alias'),
5151  $this->objProperties->isAnonymized()
5152  );
5153 
5154  $draft = ilForumPostDraft::newInstanceByDraftId($draftId);
5155  $draft->setPostSubject($this->handleFormInput($form->getInput('subject'), false));
5156  $draft->setPostMessage(ilRTE::_replaceMediaObjectImageSrc($form->getInput('message')));
5157  $draft->setPostUserAlias($userAlias);
5158  $draft->setNotificationStatus($form->getInput('notify') && !$this->user->isAnonymous());
5159  $draft->setPostAuthorId($this->user->getId());
5160  $draft->setPostDisplayUserId($this->isWritingWithPseudonymAllowed() ? 0 : $this->user->getId());
5161  $draft->updateDraft();
5162 
5163  $GLOBALS['ilAppEventHandler']->raise(
5164  'Modules/Forum',
5165  'updatedDraft',
5166  [
5167  'draftObj' => $draft,
5168  'obj_id' => $this->object->getId(),
5169  'is_file_upload_allowed' => $this->objProperties->isFileUploadAllowed(),
5170  ]
5171  );
5172 
5174  $form->getInput('message'),
5175  'frm~d:html',
5176  $draft->getDraftId(),
5177  'frm~d:html',
5178  $draft->getDraftId()
5179  );
5180 
5181  $draftFileData = new ilFileDataForumDrafts($this->object->getId(), $draft->getDraftId());
5182 
5183  $files2delete = $form->getInput('del_file');
5184  if (is_array($files2delete) && $files2delete !== []) {
5185  $draftFileData->unlinkFilesByMD5Filenames($files2delete);
5186  }
5187 
5188  if ($this->objProperties->isFileUploadAllowed()) {
5189  $file = $_FILES['userfile'];
5190  if (is_array($file) && !empty($file)) {
5191  if (isset($file['full_path'][0]) && !empty($file['full_path'][0])) {
5192  $draftFileData->storeUploadedFiles();
5193  }
5194  }
5195  }
5196 
5197  $this->tpl->setOnScreenMessage('success', $this->lng->txt('save_draft_successfully'), true);
5198  $this->ctrl->clearParameters($this);
5199  $this->ctrl->redirect($this, 'showThreads');
5200  }
5201 
5202  $form->setValuesByPost();
5203  $this->ctrl->setParameter($this, 'hist_check', 0);
5204  $this->ctrl->setParameter($this, 'draft_id', $draftId);
5205  $this->editThreadDraftObject($form);
5206  }
5207 
5208  public function saveTopLevelDraftObject(): void
5209  {
5210  $this->saveAsDraftObject();
5211  }
5212 
5213  public function saveAsDraftObject(): void
5214  {
5215  $ref_id = $this->retrieveRefId();
5216  $thr_pk = $this->retrieveThrPk();
5217 
5218  $draft_id = $this->http->wrapper()->post()->retrieve(
5219  'draft_id',
5220  $this->refinery->byTrying([
5221  $this->refinery->kindlyTo()->int(),
5222  $this->refinery->always(null)
5223  ])
5224  );
5225 
5226  if ($this->objCurrentTopic->getId() === 0) {
5227  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_thr_deleted'), true);
5228  $this->ctrl->redirect($this);
5229  }
5230 
5231  if ($this->objCurrentTopic->isClosed()) {
5232  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_thr_closed'), true);
5233  $this->ctrl->redirect($this);
5234  }
5235 
5236  $autosave_draft_id = 0;
5237  if ($draft_id !== null && ilForumPostDraft::isAutoSavePostDraftAllowed()) {
5238  $autosave_draft_id = $draft_id;
5239  }
5240  $oReplyEditForm = $this->getReplyEditForm();
5241  if ($oReplyEditForm->checkInput()) {
5242  if ($this->objCurrentPost->getId() === 0) {
5243  $this->requestAction = '';
5244  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_parent_deleted'), true);
5245  $this->viewThreadObject();
5246  return;
5247  }
5248 
5249  $oForumObjects = $this->getForumObjects();
5250  $frm = $oForumObjects['frm'];
5251  $frm->setMDB2WhereCondition(' top_frm_fk = %s ', ['integer'], [$frm->getForumId()]);
5252  $topicData = $frm->getOneTopic();
5253 
5254  if ($this->requestAction === 'ready_showreply') {
5255  if (!$this->access->checkAccess('add_reply', '', $ref_id)) {
5256  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5257  }
5258 
5259  $user_alias = ilForumUtil::getPublicUserAlias(
5260  $oReplyEditForm->getInput('alias'),
5261  $this->objProperties->isAnonymized()
5262  );
5263 
5264  if ($autosave_draft_id === 0) {
5265  $draftObj = new ilForumPostDraft();
5266  } else {
5267  $draftObj = ilForumPostDraft::newInstanceByDraftId($autosave_draft_id);
5268  }
5269  $draftObj->setForumId($topicData->getTopPk());
5270  $draftObj->setThreadId($this->objCurrentTopic->getId());
5271  $draftObj->setPostId($this->objCurrentPost->getId());
5272 
5273  $draftObj->setPostSubject($this->handleFormInput($oReplyEditForm->getInput('subject'), false));
5274  $draftObj->setPostMessage(ilRTE::_replaceMediaObjectImageSrc($oReplyEditForm->getInput('message')));
5275  $draftObj->setPostUserAlias($user_alias);
5276  $draftObj->setNotificationStatus($oReplyEditForm->getInput('notify') && !$this->user->isAnonymous());
5277  $draftObj->setPostNotificationStatus($oReplyEditForm->getInput('notify_post') && !$this->user->isAnonymous());
5278 
5279  $draftObj->setPostAuthorId($this->user->getId());
5280  $draftObj->setPostDisplayUserId(($this->isWritingWithPseudonymAllowed() ? 0 : $this->user->getId()));
5281 
5282  if ($autosave_draft_id === 0) {
5283  $draft_id = $draftObj->saveDraft();
5284  } else {
5285  $draftObj->updateDraft();
5286  $draft_id = $draftObj->getDraftId();
5287  }
5288 
5289  // copy temporary media objects (frm~)
5291  $oReplyEditForm->getInput('message'),
5292  'frm~d:html',
5293  $draft_id,
5294  'frm~d:html',
5295  $draft_id
5296  );
5297 
5298  if ($this->objProperties->isFileUploadAllowed()) {
5299  $file = $_FILES['userfile'];
5300  if (is_array($file) && !empty($file)) {
5301  $oFDForumDrafts = new ilFileDataForumDrafts($this->object->getId(), $draftObj->getDraftId());
5302  $oFDForumDrafts->storeUploadedFiles();
5303  }
5304  }
5305 
5307  $GLOBALS['ilAppEventHandler']->raise(
5308  'Modules/Forum',
5309  'savedAsDraft',
5310  [
5311  'draftObj' => $draftObj,
5312  'obj_id' => $this->object->getId(),
5313  'is_file_upload_allowed' => $this->objProperties->isFileUploadAllowed()
5314  ]
5315  );
5316  }
5317 
5318  $frm_session_values = ilSession::get('frm');
5319  if (is_array($frm_session_values)) {
5320  $frm_session_values[$thr_pk]['openTreeNodes'][] = $this->objCurrentPost->getId();
5321  }
5322  ilSession::set('frm', $frm_session_values);
5323 
5324  $this->tpl->setOnScreenMessage('success', $this->lng->txt('save_draft_successfully'), true);
5325  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
5326  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
5327  $this->ctrl->redirect($this, 'viewThread');
5328  }
5329  } else {
5330  $oReplyEditForm->setValuesByPost();
5331  $this->requestAction = substr($this->requestAction, 6);
5332  }
5333  $this->viewThreadObject();
5334  }
5335 
5336  protected function editDraftObject(): void
5337  {
5339  $draftId = $this->retrieveDraftId();
5340  if ($this->checkDraftAccess($draftId)) {
5341  $this->doHistoryCheck($draftId);
5342  }
5343  }
5344 
5345  $this->viewThreadObject();
5346  }
5347 
5348  public function updateDraftObject(): void
5349  {
5350  $ref_id = $this->retrieveRefId();
5351  $draft_id = $this->retrieveDraftId();
5352  $thr_pk = $this->retrieveThrPk();
5353 
5354  if ($this->objCurrentTopic->getId() === 0) {
5355  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_thr_deleted'), true);
5356  $this->ctrl->redirect($this);
5357  }
5358 
5359  if ($this->objCurrentTopic->isClosed()) {
5360  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_thr_closed'), true);
5361  $this->ctrl->redirect($this);
5362  }
5363 
5364  if ($this->objCurrentPost->getId() === 0) {
5365  $this->requestAction = '';
5366  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('frm_action_not_possible_parent_deleted'));
5367  $this->viewThreadObject();
5368  return;
5369  }
5370 
5371  $oReplyEditForm = $this->getReplyEditForm();
5372  if ($oReplyEditForm->checkInput()) {
5373  // init objects
5374  $oForumObjects = $this->getForumObjects();
5375  $forumObj = $oForumObjects['forumObj'];
5376 
5377  if (!$this->user->isAnonymous() && in_array($this->requestAction, ['showdraft', 'editdraft'])) {
5378  if (!$this->access->checkAccess('add_reply', '', $ref_id)) {
5379  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5380  }
5381  if (!$this->checkDraftAccess($draft_id)) {
5382  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5383  }
5384 
5385  $user_alias = ilForumUtil::getPublicUserAlias(
5386  $oReplyEditForm->getInput('alias'),
5387  $this->objProperties->isAnonymized()
5388  );
5389 
5390  $update_draft = new ilForumPostDraft(
5391  $this->user->getId(),
5392  $this->objCurrentPost->getId(),
5393  $draft_id
5394  );
5395 
5396  $update_draft->setPostSubject($this->handleFormInput($oReplyEditForm->getInput('subject'), false));
5397  $update_draft->setPostMessage(ilRTE::_replaceMediaObjectImageSrc(
5398  $oReplyEditForm->getInput('message')
5399  ));
5400  $update_draft->setPostUserAlias($user_alias);
5401  $update_draft->setNotificationStatus($oReplyEditForm->getInput('notify') && !$this->user->isAnonymous());
5402  $update_draft->setUpdateUserId($this->user->getId());
5403  $update_draft->setPostAuthorId($this->user->getId());
5404  $update_draft->setPostDisplayUserId($this->isWritingWithPseudonymAllowed() ? 0 : $this->user->getId());
5405 
5406  $update_draft->updateDraft();
5407 
5409  $GLOBALS['ilAppEventHandler']->raise(
5410  'Modules/Forum',
5411  'updatedDraft',
5412  [
5413  'draftObj' => $update_draft,
5414  'obj_id' => $this->object->getId(),
5415  'is_file_upload_allowed' => $this->objProperties->isFileUploadAllowed()
5416  ]
5417  );
5418  }
5419 
5420  $uploadedObjects = ilObjMediaObject::_getMobsOfObject('frm~:html', $this->user->getId());
5421 
5422  foreach ($uploadedObjects as $mob) {
5423  ilObjMediaObject::_removeUsage($mob, 'frm~:html', $this->user->getId());
5424  ilObjMediaObject::_saveUsage($mob, 'frm~d:html', $update_draft->getDraftId());
5425  }
5427  $oReplyEditForm->getInput('message'),
5428  'frm~d:html',
5429  $update_draft->getDraftId()
5430  );
5431 
5432  $oFDForumDrafts = new ilFileDataForumDrafts($forumObj->getId(), $update_draft->getDraftId());
5433 
5434  $file2delete = $oReplyEditForm->getInput('del_file');
5435  if (is_array($file2delete) && count($file2delete)) {
5436  $oFDForumDrafts->unlinkFilesByMD5Filenames($file2delete);
5437  }
5438 
5439  if ($this->objProperties->isFileUploadAllowed()) {
5440  $file = $_FILES['userfile'];
5441  if (is_array($file) && !empty($file)) {
5442  $oFDForumDrafts->storeUploadedFiles();
5443  }
5444  }
5445 
5446  $frm_session_values = ilSession::get('frm');
5447  if (is_array($frm_session_values)) {
5448  $frm_session_values[$thr_pk]['openTreeNodes'][] = $this->objCurrentPost->getId();
5449  }
5450  ilSession::set('frm', $frm_session_values);
5451  $this->tpl->setOnScreenMessage('success', $this->lng->txt('save_draft_successfully'), true);
5452  $this->ctrl->clearParameters($this);
5453  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
5454  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
5455  $this->ctrl->setParameter($this, 'draft_id', $update_draft->getDraftId());
5456  }
5457  } else {
5458  $this->ctrl->clearParameters($this);
5459  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
5460  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
5461  $this->ctrl->setParameter($this, 'draft_id', $draft_id);
5462  $this->ctrl->setParameter($this, 'action', 'editdraft');
5463  $oReplyEditForm->setValuesByPost();
5464  $this->viewThreadObject();
5465  return;
5466  }
5467  $this->ctrl->clearParameters($this);
5468  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
5469  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
5470  $this->ctrl->redirect($this, 'viewThread');
5471  }
5472 
5473  protected function deleteMobsOfDraft(int $draft_id, string $message): void
5474  {
5475  // remove usage of deleted media objects
5476  $oldMediaObjects = ilObjMediaObject::_getMobsOfObject('frm~d:html', $draft_id);
5477  $curMediaObjects = ilRTE::_getMediaObjects($message);
5478  foreach ($oldMediaObjects as $oldMob) {
5479  $found = false;
5480  foreach ($curMediaObjects as $curMob) {
5481  if ($oldMob === $curMob) {
5482  $found = true;
5483  break;
5484  }
5485  }
5486  if (!$found && ilObjMediaObject::_exists($oldMob)) {
5487  ilObjMediaObject::_removeUsage($oldMob, 'frm~d:html', $draft_id);
5488  $mob_obj = new ilObjMediaObject($oldMob);
5489  $mob_obj->delete();
5490  }
5491  }
5492  }
5493 
5494  protected function deleteSelectedDraft(ilForumPostDraft $draft_obj = null): void
5495  {
5496  $ref_id = $this->retrieveRefId();
5497  $draft_id = $this->retrieveDraftId();
5498 
5499  if (
5500  !$this->access->checkAccess('add_reply', '', $ref_id) ||
5501  $this->user->isAnonymous() ||
5502  ($draft_obj instanceof ilForumPostDraft && $this->user->getId() !== $draft_obj->getPostAuthorId())) {
5503  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5504  }
5505 
5506  $post_id = $this->objCurrentPost->getId();
5507  if (!($draft_obj instanceof ilForumPostDraft)) {
5508  $draft_id_to_delete = $draft_id;
5509  $draft_obj = new ilForumPostDraft($this->user->getId(), $post_id, $draft_id_to_delete);
5510 
5511  if (!$draft_obj->getDraftId() || ($draft_obj->getDraftId() !== $draft_id_to_delete)) {
5512  $this->ctrl->clearParameters($this);
5513  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
5514  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
5515  $this->ctrl->redirect($this, 'viewThread');
5516  }
5517  }
5518 
5519  $this->deleteMobsOfDraft($draft_obj->getDraftId(), $draft_obj->getPostMessage());
5520 
5521  $objFileDataForumDrafts = new ilFileDataForumDrafts($this->object->getId());
5522  $objFileDataForumDrafts->delete([$draft_obj->getDraftId()]);
5523 
5525  $GLOBALS['ilAppEventHandler']->raise(
5526  'Modules/Forum',
5527  'deletedDraft',
5528  [
5529  'draftObj' => $draft_obj,
5530  'obj_id' => $this->object->getId(),
5531  'is_file_upload_allowed' => $this->objProperties->isFileUploadAllowed()
5532  ]
5533  );
5534  }
5535  $draft_obj->deleteDraft();
5536 
5537  $this->tpl->setOnScreenMessage('success', $this->lng->txt('delete_draft_successfully'), true);
5538  $this->ctrl->clearParameters($this);
5539  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
5540  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
5541  $this->ctrl->redirect($this, 'viewThread');
5542  }
5543 
5544  protected function autosaveDraftAsyncObject(): void
5545  {
5546  if (
5547  $this->requestAction !== 'ready_showreply' &&
5548  $this->access->checkAccess('read', '', $this->object->getRefId()) &&
5549  $this->access->checkAccess('add_reply', '', $this->object->getRefId())
5550  ) {
5551  $action = new ilForumAutoSaveAsyncDraftAction(
5552  $this->user,
5553  $this->getReplyEditForm(),
5554  $this->objProperties,
5555  $this->objCurrentTopic,
5556  $this->objCurrentPost,
5557  function (string $message): string {
5558  return $this->handleFormInput($message);
5559  },
5560  $this->retrieveDraftId(),
5561  ilObjForum::lookupForumIdByRefId($this->ref_id),
5562  ilUtil::stripSlashes($this->requestAction)
5563  );
5564 
5565  $this->http->saveResponse($this->http->response()->withBody(
5566  \ILIAS\Filesystem\Stream\Streams::ofString(json_encode(
5567  $action->executeAndGetResponseObject(),
5568  JSON_THROW_ON_ERROR
5569  ))
5570  ));
5571  }
5572 
5573  $this->http->sendResponse();
5574  $this->http->close();
5575  }
5576 
5577  protected function autosaveThreadDraftAsyncObject(): void
5578  {
5579  if (
5580  $this->requestAction !== 'ready_showreply' &&
5581  $this->access->checkAccess('read', '', $this->object->getRefId()) &&
5582  $this->access->checkAccess('add_thread', '', $this->object->getRefId())
5583  ) {
5584  $action = new ilForumAutoSaveAsyncDraftAction(
5585  $this->user,
5586  $this->buildThreadForm(),
5587  $this->objProperties,
5588  $this->objCurrentTopic,
5589  $this->objCurrentPost,
5590  function (string $message): string {
5591  return $this->handleFormInput($message, false);
5592  },
5593  $this->retrieveDraftId(),
5594  ilObjForum::lookupForumIdByRefId($this->ref_id),
5595  ilUtil::stripSlashes($this->requestAction)
5596  );
5597 
5598  $this->http->saveResponse($this->http->response()->withBody(
5599  \ILIAS\Filesystem\Stream\Streams::ofString(json_encode(
5600  $action->executeAndGetResponseObject(),
5601  JSON_THROW_ON_ERROR
5602  ))
5603  ));
5604  }
5605 
5606  $this->http->sendResponse();
5607  $this->http->close();
5608  }
5609 
5610  private function renderSplitButton(
5611  ilTemplate $tpl,
5612  string $action,
5613  bool $is_post,
5614  ilForumPost $node,
5615  int $pageIndex = 0,
5616  ilForumPostDraft $draft = null
5617  ): void {
5618  $draft_id = $this->retrieveDraftId();
5619 
5620  $actions = [];
5621  if ($is_post) {
5622  if (($this->objCurrentPost->getId() !== $node->getId() || (
5623  !in_array($action, ['showreply', 'showedit', 'censor', 'delete'], true) &&
5625  )) && ($this->is_moderator || $node->isActivated() || $node->isOwner($this->user->getId()))) {
5626  if ($this->is_moderator && !$this->objCurrentTopic->isClosed() && !$node->isActivated()) {
5627  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
5628  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
5629  $this->ctrl->setParameter($this, 'page', $pageIndex);
5630  $this->ctrl->setParameter(
5631  $this,
5632  'orderby',
5633  $this->getOrderByParam()
5634  );
5635  $primary_action = $this->ctrl->getLinkTarget(
5636  $this,
5637  'askForPostActivation',
5638  (string) $node->getId()
5639  );
5640  $primary_action_language_id = 'activate_post';
5641  $this->ctrl->clearParameters($this);
5642  }
5643  if (
5644  !$this->objCurrentTopic->isClosed() && $node->isActivated() && !$node->isCensored() &&
5645  $this->access->checkAccess('add_reply', '', $this->object->getRefId())
5646  ) {
5647  $this->ctrl->setParameter($this, 'action', 'showreply');
5648  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
5649  $this->ctrl->setParameter($this, 'page', $pageIndex);
5650  $this->ctrl->setParameter(
5651  $this,
5652  'orderby',
5653  $this->getOrderByParam()
5654  );
5655  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
5656  $primary_action = $this->ctrl->getLinkTarget(
5657  $this,
5658  'viewThread',
5659  'reply_' . $node->getId()
5660  );
5661  $primary_action_language_id = 'reply_to_postings';
5662  $this->ctrl->clearParameters($this);
5663  }
5664  if (
5665  !$this->objCurrentTopic->isClosed() &&
5666  !$node->isCensored() &&
5667  !$this->user->isAnonymous() &&
5668  ($node->isOwner($this->user->getId()) || $this->is_moderator)
5669  ) {
5670  $this->ctrl->setParameter($this, 'action', 'showedit');
5671  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
5672  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
5673  $this->ctrl->setParameter($this, 'page', $pageIndex);
5674  $this->ctrl->setParameter(
5675  $this,
5676  'orderby',
5677  $this->getOrderByParam()
5678  );
5679  $actions['edit'] = $this->ctrl->getLinkTarget($this, 'viewThread', (string) $node->getId());
5680  $this->ctrl->clearParameters($this);
5681  }
5682  if (!$this->user->isAnonymous()) {
5683  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
5684  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
5685  $this->ctrl->setParameter($this, 'page', $pageIndex);
5686  $this->ctrl->setParameter(
5687  $this,
5688  'orderby',
5689  $this->getOrderByParam()
5690  );
5691  $this->ctrl->setParameter($this, 'viewmode', $this->selectedSorting);
5692 
5693  $read_undread_txt = 'frm_mark_as_read';
5694  $read_undread_cmd = 'markPostRead';
5695  if ($node->isPostRead()) {
5696  $read_undread_txt = 'frm_mark_as_unread';
5697  $read_undread_cmd = 'markPostUnread';
5698  }
5699  $actions[$read_undread_txt] = $this->ctrl->getLinkTarget(
5700  $this,
5701  $read_undread_cmd,
5702  (string) $node->getId()
5703  );
5704 
5705  $this->ctrl->clearParameters($this);
5706  }
5707  if (!$node->isCensored()) {
5708  $this->ctrl->setParameterByClass(ilForumExportGUI::class, 'top_pk', $node->getForumId());
5709  $this->ctrl->setParameterByClass(ilForumExportGUI::class, 'thr_pk', $node->getThreadId());
5710 
5711 
5712  $this->ctrl->clearParameters($this);
5713  }
5714  if (
5715  !$this->objCurrentTopic->isClosed() &&
5716  !$this->user->isAnonymous() &&
5717  ($this->is_moderator || ($node->isOwner($this->user->getId()) && !$node->hasReplies()))
5718  ) {
5719  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
5720  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
5721  $this->ctrl->setParameter($this, 'page', $pageIndex);
5722  $this->ctrl->setParameter(
5723  $this,
5724  'orderby',
5725  $this->getOrderByParam()
5726  );
5727  $actions['delete'] = $this->ctrl->getFormAction($this, 'deletePosting');
5728  $this->ctrl->clearParameters($this);
5729  }
5730  if ($this->is_moderator && !$this->objCurrentTopic->isClosed()) {
5731  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
5732  $this->ctrl->setParameter($this, 'thr_pk', $node->getThreadId());
5733  $this->ctrl->setParameter($this, 'page', $pageIndex);
5734  $this->ctrl->setParameter(
5735  $this,
5736  'orderby',
5737  $this->getOrderByParam()
5738  );
5739  if ($node->isCensored()) {
5740  $this->ctrl->setParameter($this, 'action', 'viewThread');
5741  $actions['frm_revoke_censorship'] = $this->ctrl->getFormAction($this, 'revokeCensorship');
5742  } else {
5743  $actions['frm_censorship'] = $this->ctrl->getFormAction($this, 'addCensorship');
5744  }
5745  $this->ctrl->clearParameters($this);
5746  }
5747  }
5748  } elseif ($draft_id !== $draft->getDraftId() || !in_array($action, ['deletedraft', 'editdraft'])) {
5749  // get actions for drafts
5750  $this->ctrl->setParameter($this, 'action', 'publishdraft');
5751  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
5752  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
5753  $this->ctrl->setParameter($this, 'page', $pageIndex);
5754  $this->ctrl->setParameter($this, 'draft_id', $draft->getDraftId());
5755  $this->ctrl->setParameter(
5756  $this,
5757  'orderby',
5758  $this->getOrderByParam()
5759  );
5760  $primary_action = $this->ctrl->getLinkTarget($this, 'publishSelectedDraft', (string) $node->getId());
5761  $primary_action_language_id = 'publish';
5762  $this->ctrl->clearParameters($this);
5763 
5764  $this->ctrl->setParameter($this, 'action', 'editdraft');
5765  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
5766  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
5767  $this->ctrl->setParameter($this, 'draft_id', $draft->getDraftId());
5768  $this->ctrl->setParameter($this, 'page', $pageIndex);
5769  $this->ctrl->setParameter(
5770  $this,
5771  'orderby',
5772  $this->getOrderByParam()
5773  );
5774  $actions['edit'] = $this->ctrl->getLinkTarget($this, 'editDraft', 'draft_edit_' . $draft->getDraftId());
5775  $this->ctrl->clearParameters($this);
5776 
5777  $this->ctrl->setParameter($this, 'pos_pk', $node->getId());
5778  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
5779  $this->ctrl->setParameter($this, 'draft_id', $draft->getDraftId());
5780  $this->ctrl->setParameter($this, 'page', $pageIndex);
5781  $this->ctrl->setParameter(
5782  $this,
5783  'orderby',
5784  $this->getOrderByParam()
5785  );
5786  $actions['delete'] = $this->ctrl->getFormAction($this, 'deletePostingDraft');
5787  $this->ctrl->clearParameters($this);
5788 
5789  if ($draft_id !== 0 && $action === 'editdraft') {
5790  $actions = [];
5791  }
5792  }
5793 
5794  $tpl->setCurrentBlock('posts_row');
5795  if ($actions !== [] && !$this->objCurrentTopic->isClosed()) {
5796  $items = [];
5797  foreach ($actions as $lng_id => $url) {
5798  if ('frm_revoke_censorship' === $lng_id || 'frm_censorship' === $lng_id) {
5799  $modalTemplate = new ilTemplate('tpl.forums_censor_modal.html', true, true, 'Modules/Forum');
5800  $formID = str_replace('.', '_', uniqid('form', true));
5801  $modalTemplate->setVariable('FORM_ID', $formID);
5802 
5803  if ($node->isCensored()) {
5804  $modalTemplate->setVariable('BODY', $this->lng->txt('forums_info_censor2_post'));
5805  } else {
5806  $modalTemplate->setVariable('BODY', $this->lng->txt('forums_info_censor_post'));
5807  $modalTemplate->touchBlock('message');
5808  }
5809 
5810  $modalTemplate->setVariable('FORM_ACTION', $url);
5811 
5812  $content = $this->uiFactory->legacy($modalTemplate->get());
5813  $submitBtn = $this->uiFactory->button()->primary(
5814  $this->lng->txt('submit'),
5815  '#'
5816  )->withOnLoadCode(
5817  static function (string $id) use ($formID): string {
5818  return "$('#$id').click(function() { $('#$formID').submit(); return false; });";
5819  }
5820  );
5821  $modal = $this->uiFactory->modal()->roundtrip(
5822  $this->lng->txt($lng_id),
5823  [$content]
5824  )->withActionButtons([$submitBtn]);
5825  $items[] = $this->uiFactory->button()->shy($this->lng->txt($lng_id), '#')->withOnClick(
5826  $modal->getShowSignal()
5827  );
5828 
5829  $this->modalActionsContainer[] = $modal;
5830  continue;
5831  }
5832 
5833  if ('delete' === $lng_id) {
5834  $modal = $this->uiFactory->modal()->interruptive(
5835  $this->lng->txt($lng_id),
5836  str_contains($url, 'deletePostingDraft') ?
5837  $this->lng->txt('forums_info_delete_draft') :
5838  $this->lng->txt('forums_info_delete_post'),
5839  $url
5840  )->withActionButtonLabel(
5841  $this->lng->txt(str_contains($url, 'deletePostingDraft') ? 'deletePostingDraft' : 'deletePosting')
5842  );
5843 
5844  $items[] = $this->uiFactory->button()->shy($this->lng->txt($lng_id), '#')->withOnClick(
5845  $modal->getShowSignal()
5846  );
5847 
5848  $this->modalActionsContainer[] = $modal;
5849 
5850 
5851  continue;
5852  }
5853 
5854  $items[] = $this->uiFactory->button()->shy($this->lng->txt($lng_id), $url);
5855  }
5856 
5857  $dropdown = $this->uiFactory->dropdown()->standard($items);
5858  $render_action_buttons = [$dropdown];
5859  if (isset($primary_action, $primary_action_language_id)) {
5860  if ($primary_action_language_id === 'activate_post') {
5861  $action_button = $this->addActivationFormModal($node);
5862  } else {
5863  $action_button = $this->uiFactory->button()->standard(
5864  $this->lng->txt($primary_action_language_id),
5865  $primary_action
5866  );
5867  }
5868  $tpl->setVariable('MAIN_ACTION', $this->uiRenderer->render($action_button));
5869  }
5870  $tpl->setVariable('DROPDOWN_ACTIONS', $this->uiRenderer->render($render_action_buttons));
5871  }
5872  }
5873 
5874  public function checkDraftAccess(int $draftId): bool
5875  {
5876  $draft = ilForumPostDraft::newInstanceByDraftId($draftId);
5877  if (
5878  $this->user->isAnonymous() || !$this->access->checkAccess('add_reply', '', $this->object->getRefId()) ||
5879  $this->user->getId() !== $draft->getPostAuthorId()
5880  ) {
5881  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5882  }
5883 
5884  return true;
5885  }
5886 
5887  private function doHistoryCheck(int $draftId): void
5888  {
5889  if (!$this->checkDraftAccess($draftId)) {
5890  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5891  }
5892 
5894  return;
5895  }
5896 
5898  $draftsFromHistory = ilForumDraftsHistory::getInstancesByDraftId($draftId);
5899  if ($draftsFromHistory !== []) {
5900  $modal = ilModalGUI::getInstance();
5901  $modal->setHeading($this->lng->txt('restore_draft_from_autosave'));
5902  $modal->setId('frm_autosave_restore');
5903  $form_tpl = new ilTemplate('tpl.restore_thread_draft.html', true, true, 'Modules/Forum');
5904  $first_open = null;
5905 
5906  foreach ($draftsFromHistory as $history_instance) {
5907  $accordion = new ilAccordionGUI();
5908  $accordion->setId('acc_' . $history_instance->getHistoryId());
5909  $accordion->setBehaviour(ilAccordionGUI::ALL_CLOSED);
5910  if ($first_open === null) {
5911  $first_open = $history_instance->getHistoryId();
5912  $accordion->setBehaviour(ilAccordionGUI::FIRST_OPEN);
5913  }
5914 
5915  $form_tpl->setCurrentBlock('list_item');
5916  $message = ilRTE::_replaceMediaObjectImageSrc($history_instance->getPostMessage(), 1);
5917 
5918  $history_date = ilDatePresentation::formatDate(new ilDateTime(
5919  $history_instance->getDraftDate(),
5921  ));
5922  $this->ctrl->setParameter($this, 'history_id', $history_instance->getHistoryId());
5923  $header = $history_date . ': ' . $history_instance->getPostSubject();
5924 
5925  $accordion_tpl = new ilTemplate(
5926  'tpl.restore_thread_draft_accordion_content.html',
5927  true,
5928  true,
5929  'Modules/Forum'
5930  );
5931  $accordion_tpl->setVariable('MESSAGE', $message);
5932  $accordion_tpl->setVariable(
5933  'BUTTON',
5934  $this->uiRenderer->render(
5935  $this->uiFactory->button()->standard(
5936  $this->lng->txt('restore'),
5937  $this->ctrl->getLinkTarget($this, 'restoreFromHistory')
5938  )
5939  )
5940  );
5941  $accordion->addItem($header, $accordion_tpl->get());
5942 
5943  $form_tpl->setVariable('ACC_AUTO_SAVE', $accordion->getHTML());
5944  $form_tpl->parseCurrentBlock();
5945  }
5946 
5947  $form_tpl->setVariable('RESTORE_DATA_EXISTS', 'found_threat_history_to_restore');
5948  $modal->setBody($form_tpl->get());
5950  $this->modal_history = $modal->getHTML();
5951  } else {
5953  }
5954  }
5955 
5956  private function renderPostingForm(ilTemplate $tpl, ilForum $frm, ilForumPost $node, string $action): void
5957  {
5958  $ref_id = $this->retrieveRefId();
5959  $draft_id = $this->retrieveDraftId();
5960 
5961  if (
5962  $action === 'showedit' && (
5963  (!$this->is_moderator && !$node->isOwner($this->user->getId())) ||
5964  $this->user->isAnonymous() ||
5965  $node->isCensored()
5966  )
5967  ) {
5968  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5969  } elseif ($action === 'showreply' && !$this->access->checkAccess('add_reply', '', $ref_id)) {
5970  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
5971  }
5972 
5973  $tpl->setVariable('REPLY_ANKER', 'reply_' . $this->objCurrentPost->getId());
5974  $oEditReplyForm = $this->getReplyEditForm();
5975  $subject = '';
5976  if ($action !== 'editdraft') {
5977  switch ($this->objProperties->getSubjectSetting()) {
5978  case 'add_re_to_subject':
5979  $subject = $this->getModifiedReOnSubject();
5980  break;
5981 
5982  case 'preset_subject':
5983  $subject = $this->objCurrentPost->getSubject();
5984  break;
5985 
5986  case 'empty_subject':
5987  $subject = '';
5988  break;
5989  }
5990  }
5991 
5992  switch ($action) {
5993  case 'showreply':
5994  if ($this->ctrl->getCmd() === 'savePost' || $this->ctrl->getCmd() === 'saveAsDraft') {
5995  $oEditReplyForm->setValuesByPost();
5996  } elseif ($this->ctrl->getCmd() === 'quotePost') {
5997  $authorinfo = new ilForumAuthorInformation(
5998  $node->getPosAuthorId(),
5999  $node->getDisplayUserId(),
6000  (string) $node->getUserAlias(),
6001  (string) $node->getImportName()
6002  );
6003 
6004  $oEditReplyForm->setValuesByPost();
6005  $oEditReplyForm->getItemByPostVar('message')->setValue(
6007  $frm->prepareText(
6008  $node->getMessage(),
6009  1,
6010  $authorinfo->getAuthorName()
6011  ) . "\n" . $oEditReplyForm->getInput('message'),
6012  1
6013  )
6014  );
6015  } else {
6016  $oEditReplyForm->setValuesByArray([
6017  'draft_id' => $draft_id,
6018  'alias' => '',
6019  'subject' => $subject,
6020  'message' => '',
6021  'notify' => 0,
6022  'userfile' => '',
6023  'del_file' => []
6024  ]);
6025  }
6026 
6027  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
6028  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
6029 
6030  $jsTpl = new ilTemplate('tpl.forum_post_quoation_ajax_handler.js', true, true, 'Modules/Forum');
6031  $jsTpl->setVariable(
6032  'IL_FRM_QUOTE_CALLBACK_SRC',
6033  $this->ctrl->getLinkTarget($this, 'getQuotationHTMLAsynch', '', true)
6034  );
6035  $this->ctrl->clearParameters($this);
6036  $this->tpl->addOnLoadCode($jsTpl->get());
6037  break;
6038 
6039  case 'showedit':
6040  if ($this->ctrl->getCmd() === 'savePost') {
6041  $oEditReplyForm->setValuesByPost();
6042  } else {
6043  $oEditReplyForm->setValuesByArray([
6044  'alias' => '',
6045  'subject' => $this->objCurrentPost->getSubject(),
6047  $this->objCurrentPost->getMessage(),
6048  2
6049  ), 1),
6050  'notify' => $this->objCurrentPost->isNotificationEnabled() && !$this->user->isAnonymous(),
6051  'userfile' => '',
6052  'del_file' => [],
6053  'draft_id' => $draft_id
6054  ]);
6055  }
6056 
6057  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getParentId());
6058  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
6059  $jsTpl = new ilTemplate('tpl.forum_post_quoation_ajax_handler.js', true, true, 'Modules/Forum');
6060  $jsTpl->setVariable(
6061  'IL_FRM_QUOTE_CALLBACK_SRC',
6062  $this->ctrl->getLinkTarget($this, 'getQuotationHTMLAsynch', '', true)
6063  );
6064  $this->ctrl->clearParameters($this);
6065  $this->tpl->addOnLoadCode($jsTpl->get());
6066  break;
6067 
6068  case 'editdraft':
6069  if (in_array($this->ctrl->getCmd(), ['saveDraft', 'updateDraft', 'publishDraft'])) {
6070  $oEditReplyForm->setValuesByPost();
6071  } elseif ($draft_id > 0) {
6073  $draftObject = new ilForumPostDraft(
6074  $this->user->getId(),
6075  $this->objCurrentPost->getId(),
6076  $draft_id
6077  );
6078  $oEditReplyForm->setValuesByArray([
6079  'alias' => $draftObject->getPostUserAlias(),
6080  'subject' => $draftObject->getPostSubject(),
6082  $draftObject->getPostMessage(),
6083  2
6084  ), 1),
6085  'notify' => $draftObject->isNotificationEnabled() && !$this->user->isAnonymous(),
6086  'userfile' => '',
6087  'del_file' => [],
6088  'draft_id' => $draft_id
6089  ]);
6090  }
6091 
6092  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
6093  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
6094 
6095  $jsTpl = new ilTemplate('tpl.forum_post_quoation_ajax_handler.js', true, true, 'Modules/Forum');
6096  $jsTpl->setVariable(
6097  'IL_FRM_QUOTE_CALLBACK_SRC',
6098  $this->ctrl->getLinkTarget($this, 'getQuotationHTMLAsynch', '', true)
6099  );
6100  $this->ctrl->clearParameters($this);
6101  $this->tpl->addOnLoadCode($jsTpl->get());
6102  break;
6103  }
6104 
6105  $this->ctrl->setParameter($this, 'pos_pk', $this->objCurrentPost->getId());
6106  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentPost->getThreadId());
6107  $this->ctrl->setParameter($this, 'page', (int) ($this->httpRequest->getQueryParams()['page'] ?? 0));
6108  $this->ctrl->setParameter(
6109  $this,
6110  'orderby',
6111  $this->getOrderByParam()
6112  );
6113  $this->ctrl->setParameter(
6114  $this,
6115  'action',
6116  ilUtil::stripSlashes($this->requestAction)
6117  );
6118  if ($action !== 'editdraft') {
6119  $tpl->setVariable('FORM', $oEditReplyForm->getHTML());
6120  }
6121  $this->ctrl->clearParameters($this);
6122  }
6123 
6124  private function getResetLimitedViewInfo(): string
6125  {
6126  $this->ctrl->setParameter($this, 'thr_pk', $this->objCurrentTopic->getId());
6127 
6128  $buttons = [
6129  $this->uiFactory->button()->standard(
6130  $this->lng->txt('reset_limited_view_button'),
6131  $this->ctrl->getLinkTarget($this, 'resetLimitedView')
6132  )
6133  ];
6134 
6135  return $this->uiRenderer->render(
6136  $this->uiFactory
6137  ->messageBox()
6138  ->info($this->lng->txt('reset_limited_view_info'))
6139  ->withButtons($buttons)
6140  );
6141  }
6142 
6143  private function getOrderByParam(): string
6144  {
6145  return ilUtil::stripSlashes($this->http->wrapper()->query()->retrieve(
6146  'orderby',
6147  $this->refinery->byTrying([
6148  $this->refinery->kindlyTo()->string(),
6149  $this->refinery->always('')
6150  ])
6151  ));
6152  }
6153 }
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
static _getMediaObjects(string $a_text, int $a_direction=0)
Returns all media objects found in the passed string.
Class ilForumStatisticsTableGUI.
static _getRTEClassname()
parseCurrentBlock(string $part=ilGlobalTemplateInterface::DEFAULT_BLOCK)
setOffset(int $a_offset)
set dataset offset
renderPostContent(ilTemplate $tpl, ilForumPost $node, string $action, int $pageIndex, int $postIndex)
setDisplayConfirmPostActivation(bool $status=false)
buildThreadForm(bool $isDraft=false)
Class ilForumPostDraft.
setData(array $a_data)
ILIAS HTTP Services $http
getFirstPostNode(int $tree_id)
static get(string $a_var)
setFilenames(array $a_filenames)
initEditCustomForm(ilPropertyFormGUI $a_form)
isForumNotificationEnabled(int $user_id)
An entity that renders components to a string output.
Definition: Renderer.php:30
button(string $caption, string $cmd)
setPostSubject(string $post_subject)
getThreadEditingForm(int $a_thread_id)
ilObjectDataCache $ilObjDataCache
bool $display_confirm_post_activation
Class Forum core functions for forum.
static getInstancesByDraftId(int $draft_id)
initializeThreadOffsetAndLimit(ilForumThreadObjectTableGUI $tbl)
Class ilInfoScreenGUI.
static moveMediaObjects(string $post_message, string $source_type, int $source_id, string $target_type, int $target_id, int $direction=0)
ilForumProperties $objProperties
const IL_CAL_DATETIME
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static lookupForumIdByObjId(int $obj_id)
static _getIcon(int $obj_id=0, string $size="big", string $type="", bool $offline=false)
Get icon for repository item.
Class ilForumExplorerGUI.
ILIAS DI RBACServices $rbac
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
GUI class for the workflow of copying objects.
getEditTitleModal(ilForumTopic $topic)
const ROOT_FOLDER_ID
Definition: constants.php:32
static switchColor(int $a_num, string $a_css1, string $a_css2)
switches style sheets for each even $a_num (used for changing colors of different result rows) ...
ILIAS GlobalScreen Services $globalScreen
renderSortationControl(int $currentSorting)
setMessage(string $a_message)
static _goto($a_target, $a_thread=0, $a_posting=0)
ilNavigationHistory $ilNavigationHistory
prepareOutput(bool $show_sub_objects=true)
setMDB2WhereCondition(string $query_string, array $data_type, array $data_value)
Class ChatMainBarProvider .
readonly bool $in_page_editor_style_context
getThreadProperties(ilForumTopic $forum_topic)
static _setRichTextEditorUserState(int $a_state)
Sets the state of the rich text editor visibility for the current user.
doHistoryCheck(int $draftId)
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
markTopThreadInOverview(ilForumTopic $current_thread, Item $list_item)
static _getAllReferences(int $id)
get all reference ids for object ID
static getImagePath(string $img, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
Help GUI class.
initializeThreadSortation(ilForumThreadObjectTableGUI $tbl)
static initJS(ilGlobalTemplateInterface $a_main_tpl=null)
Psr Http Message ServerRequestInterface $httpRequest
ILIAS Style Content GUIService $content_style_gui
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ilObjForumListGUI.
This class represents a file wizard property in a property form.
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false)
ilForumTopic $objCurrentTopic
static _saveUsage(int $a_mob_id, string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
Save usage of mob within another container (e.g.
static lookupTitle(int $a_topic_id)
disableForumNotification(int $user_id)
get(string $part=self::DEFAULT_BLOCK)
Renders the given block and returns the html string.
Class ilForumDraftsTableGUI.
getStickyActionForThread(ilForumTopic $forum_topic, int $ref_id)
addDraftButtonIfDraftsExists(string $cmd)
$objId
Definition: xapitoken.php:57
setDbTable(string $dbTable)
setRepositoryMode(bool $a_repositorymode)
handleCensorship(bool $wasRevoked=false)
Class ilForumSettingsGUI.
ensureValidPageForCurrentPosting(array $subtree_nodes, array $pagedPostings, int $pageSize, ilForumPost $firstForumPost)
setVariable(string $variable, $value='')
Sets the given variable to the given value.
isOwner(int $a_user_id=0)
initHeaderAction(?string $sub_type=null, ?int $sub_id=null)
renderSplitButton(ilTemplate $tpl, string $action, bool $is_post, ilForumPost $node, int $pageIndex=0, ilForumPostDraft $draft=null)
static checkAccess(int $a_ref_id, bool $a_allow_only_read=true)
check access to learning progress
Class ilForumNotification.
setForumRefId(int $a_ref_id)
static prepareFormOutput($a_str, bool $a_strip=false)
static lookupForumIdByRefId(int $ref_id)
addActivationFormModal(ilForumPost $node)
prepareFormOutput(string $a_text)
buildMinimalThreadForm(bool $isDraft=false)
static lookupCreationDate(int $thread_id)
convertDate(string $date)
ilForumSettingsGUI $forum_settings_gui
static createDraftBackup(int $draft_id)
setId(string $a_val)
$ilErr
Definition: raiseError.php:17
getPostRootNode(bool $isModerator=false, bool $preventImplicitRead=false)
renderDraftContent(ilTemplate $tpl, string $action, ilForumPost $referencePosting, array $drafts)
Class ilForumTopicTableGUI.
Class ilForumDraftHistory.
setColumnSettings(ilColumnGUI $column_gui)
static _lookupObjId(int $ref_id)
getActionsForThreadOverview(int $ref_id, ilForumTopic $forum_topic)
static getInstance(int $a_obj_id=0)
global $DIC
Definition: feed.php:28
mergeThreads(int $source_id, int $target_id)
deleteSelectedDraft(ilForumPostDraft $draft_obj=null)
getCenterColumnHTML()
Get center column.
Export User Interface Class.
ilLanguage $lng
getHTML()
Get HTML.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
publishDraftObject(bool $use_replyform=true)
afterSave(ilObject $new_object)
ilForumPost $objCurrentPost
GUI class for public user profile presentation.
hideToolbar($a_flag=null)
static http()
Fetches the global http state from ILIAS.
__construct(VocabulariesInterface $vocabularies)
setVariable($variable, $value='')
Sets a variable value.
Definition: IT.php:546
updateCustom(ilPropertyFormGUI $form)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
ilGlobalTemplateInterface $tpl
createEmptyThread(bool $createFromDraft=false)
Refactored thread creation to method, refactoring to a separate class should be done in next refactor...
static _lookupTitle(int $obj_id)
setOrderDirection(string $a_order_direction)
$GLOBALS["DIC"]
Definition: wac.php:31
renderViewModeControl(int $currentViewMode)
static getPublicUserAlias(string $user_alias, bool $is_anonymized)
Class ilForumModeratorsGUI.
handleFormInput(string $a_text, bool $a_stripslashes=true)
static saveMediaObjects(string $post_message, string $target_type, int $target_id, int $direction=0)
Forum export to HTML and Print.
setChangeDate(?string $a_changedate)
Column user interface class.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getEditFormCustomValues(array &$a_values)
getLinkActionForThread(int $ref_id, string $title, string $cmd, int $thread_id=null)
updateVisits(int $ID)
prepareText(string $text, int $edit=0, string $quote_user='', string $type='')
static _lookupObjIdForForumId(int $a_for_id)
Class ilObjectGUI Basic methods of all Output classes.
ilObjForumGUI: ilPermissionGUI, ilForumExportGUI, ilInfoScreenGUI ilObjForumGUI: ilColumnGUI...
Common interface to all items.
Definition: Item.php:31
static _recordReadEvent(string $a_type, int $a_ref_id, int $obj_id, int $usr_id, bool $isCatchupWriteEvents=true, $a_ext_rc=null, $a_ext_time=null)
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
countUserArticles(int $a_user_id)
ilForumThreadSettingsSessionStorage $selected_post_storage
__construct($data, int $id=0, bool $call_by_reference=true, bool $prepare_output=true)
static getThreadDraftData(int $post_author_id, int $forum_id)
ilToolbarGUI $toolbar
static _lookupObjectId(int $ref_id)
ensureThreadBelongsToForum(int $objId, ilForumTopic $thread)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$url
Definition: ltiregstart.php:35
static getInstanceByType(string $type)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setBlockProperty(string $a_block_type, string $a_property, string $a_value)
This function is supposed to be used for block type specific properties, that should be passed to ilB...
getOpenCloseActionForThread(ilForumTopic $forum_topic, int $ref_id)
static _exists(int $id, bool $reference=false, ?string $type=null)
setRequired(bool $a_required)
ILIAS Style Content Object ObjectFacade $content_style_domain
static _getMobsOfObject(string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
withValue($value)
Get an input like this with another value displayed on the client side.
Definition: Group.php:58
Last visited history for repository items.
static _removeUsage(int $a_mob_id, string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
Remove usage of mob in another container.
unlinkFilesByMD5Filenames($hashed_filename_or_filenames)
setOrderField(string $a_order_field)
setTitle(string $a_title, string $a_icon="", string $a_icon_alt="")
checkPermissionBool(string $perm, string $cmd="", string $type="", ?int $ref_id=null)
enableForumNotification(int $user_id)
generateThread(ilForumTopic $thread, string $message, bool $notify, bool $notify_posts, bool $status=true, bool $withFirstVisibleEntry=true)
setCurrentBlock(string $part=ilGlobalTemplateInterface::DEFAULT_BLOCK)
static getInstance()
static _isModerator(int $a_ref_id, int $a_usr_id)
A news item can be created by different sources.
static getSortedDrafts(int $usrId, int $threadId, int $sorting=ilForumProperties::VIEW_DATE_ASC)
getRightColumnHTML()
Display right column.
getSafePostCommands()
This method must return a list of safe POST commands.
deleteMobsOfDraft(int $draft_id, string $message)
static initjQuery(ilGlobalTemplateInterface $a_tpl=null)
inits and adds the jQuery JS-File to the global or a passed template
countActiveUserArticles(int $a_user_id)
editThreadDraftObject(ilPropertyFormGUI $form=null)
static getFirstNewsIdForContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="")
Get first new id of news set related to a certain context.
static _getRichTextEditorUserState()
Gets the state of the rich text editor visibility for the current user.
This class represents a text area property in a property form.
const PRESENTATION_MODE_PRESENTATION
presentation mode for requesting
deletePost($postIdOrRecord, bool $raiseEvents=true)
setLimit(int $a_limit=0, int $a_default_limit=0)
createThread(ilForumPostDraft $draft, bool $createFromDraft=false)
Refactored thread creation to method, refactoring to a separate class should be done in next refactor...
postCensorship(ilObjForum $forum, string $message, int $pos_pk, int $cens=0)
toggleExplorerNodeState()
Should be called by an ilCtrl-enabled command class if a tree node toggle action should be processed...
ilPropertyFormGUI $replyEditForm
static lookupForumIdByTopicId(int $a_topic_id)
Class ilForumThreadFormGUI.
decorateWithAutosave(ilPropertyFormGUI $form)
$message
Definition: xapiexit.php:32
New PermissionGUI (extends from old ilPermission2GUI) RBAC related output.
delete(array $posting_ids_to_delete=null)
This describes a Standard Dropdown.
Definition: Standard.php:26
static getOverallRatingForObject(int $a_obj_id, string $a_obj_type, int $a_sub_obj_id=null, string $a_sub_obj_type=null, int $a_category_id=null)
Get overall rating for an object.
parseCurrentBlock(string $block_name=self::DEFAULT_BLOCK)
Parses the given block.
static newInstanceByDraftId(int $draft_id)
Class ilObjForum.
setForumId(int $a_obj_id)
static getDraftInstancesByUserId(int $user_id)
getUnsafeGetCommands()
This method must return a list of unsafe GET commands.
$post
Definition: ltitoken.php:49
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
eventsFormBuilder(?array $predefined_values=null)
addHeaderAction()
Add header action menu.
addItem(int $a_ref_id, string $a_link, string $a_type, string $a_title="", ?int $a_sub_obj_id=null, string $a_goto_link="")
Add an item to the stack.
Interface ilCtrlSecurityInterface provides ilCtrl security information.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
checkPermission(string $perm, string $cmd="", string $type="", ?int $ref_id=null)
static set(string $a_var, $a_val)
Set a value.
static getInstanceFromAjaxCall()
(Re-)Build instance from ajax call
checkDraftAccess(int $draftId)
isThreadNotificationEnabled(int $user_id, int $thread_id)
ilForumPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI ilForumPageGUI: ilPublicUserProfi...