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