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