19 declare(strict_types=1);
46 private string $replQuote1 =
'<blockquote class="ilForumQuote">';
64 $this->error = $DIC[
'ilErr'];
65 $this->
lng = $DIC->language();
66 $this->db = $DIC->database();
67 $this->
user = $DIC->user();
69 $this->
event = $DIC->event();
70 $this->ui_factory = $DIC->ui()->factory();
71 $this->ui_renderer = $DIC->ui()->renderer();
76 $this->
id = $a_obj_id;
81 $this->ref_id = $a_ref_id;
96 if ($dbTable ===
'') {
97 die($this->className .
'::setDbTable(): No database table given.');
110 $this->mdb2Query = $query_string;
111 $this->mdb2DataValue = $data_value;
112 $this->mdb2DataType = $data_type;
119 return $this->mdb2Query ?:
'';
124 return $this->mdb2DataValue ?: [];
129 return $this->mdb2DataType ?: [];
152 $query =
'SELECT * FROM frm_data WHERE ';
161 $res = $this->db->queryF($query, $data_type, $data_value);
162 $row = $this->db->fetchAssoc(
$res);
164 if (!is_array($row) || $row === []) {
176 $query =
'SELECT * FROM frm_threads WHERE ';
185 $sql_res = $this->db->queryF($query, $data_type, $data_value);
186 $result = $this->db->fetchAssoc($sql_res);
187 $result[
'thr_subject'] = trim((
string) ($result[
'thr_subject'] ??
''));
190 $thread_obj->assignData($result);
195 public function generatePost(
199 int $display_user_id,
203 string $subject =
'',
204 ?
string $alias =
null,
207 bool $send_activation_mail =
false 210 $objNewPost->setForumId($forum_id);
211 $objNewPost->setThreadId($thread_id);
212 $objNewPost->setSubject($subject);
213 $objNewPost->setMessage($message);
214 $objNewPost->setDisplayUserId($display_user_id);
215 $objNewPost->setUserAlias($alias);
216 $objNewPost->setPosAuthorId($author_id);
220 $is_moderator =
false;
221 if ($frm_settings->getMarkModeratorPosts() && self::_isModerator($this->
getForumRefId(), $author_id)) {
222 $is_moderator =
true;
224 $objNewPost->setIsAuthorModerator($is_moderator);
227 $objNewPost->setCreateDate(date(
'Y-m-d H:i:s'));
228 } elseif (strpos($date,
'-') > 0) {
229 $objNewPost->setCreateDate($date);
233 $objNewPost->setPostActivationDate($objNewPost->getCreateDate());
237 $objNewPost->setNotification($notify);
238 $objNewPost->setStatus($status);
239 $objNewPost->insert();
241 if ($parent_pos === 0) {
242 $this->
addPostTree($objNewPost->getThreadId(), $objNewPost->getId(), $objNewPost->getCreateDate());
245 $objNewPost->getId(),
247 $objNewPost->getThreadId(),
248 $objNewPost->getCreateDate()
252 $lastPost = $objNewPost->getForumId() .
'#' . $objNewPost->getThreadId() .
'#' . $objNewPost->getId();
254 $this->db->manipulateF(
255 'UPDATE frm_threads SET thr_num_posts = thr_num_posts + 1, thr_last_post = %s WHERE thr_pk = %s',
257 [$lastPost, $objNewPost->getThreadId()]
260 $this->db->manipulateF(
261 'UPDATE frm_data SET top_num_posts = top_num_posts + 1, top_last_post = %s WHERE top_pk = %s',
263 [$lastPost, $objNewPost->getForumId()]
268 $forum_obj->markPostRead($objNewPost->getPosAuthorId(), $objNewPost->getThreadId(), $objNewPost->getId());
270 if ($status && $parent_pos > 0) {
272 $news_item->setContext($forum_obj->getId(),
'frm', $objNewPost->getId(),
'pos');
274 $news_item->setTitle($objNewPost->getSubject());
279 if ($objNewPost->getMessage() !== strip_tags($objNewPost->getMessage())) {
280 $news_item->setContentHtml(
true);
283 $news_item->setUserId($display_user_id);
285 $news_item->create();
288 return $objNewPost->getId();
297 bool $withFirstVisibleEntry =
true 310 $this->db->manipulateF(
311 'UPDATE frm_data SET top_num_threads = top_num_threads + 1 WHERE top_pk = %s',
316 $rootNodeId = $this->generatePost(
331 if (!$withFirstVisibleEntry) {
335 return $this->generatePost(
359 if ($target_obj_id <= 0 || $src_forum->
getId() <= 0) {
360 return $errorMessages;
369 if (!$oldFrmData->getTopPk() || !$newFrmData->getTopPk()) {
370 return $errorMessages;
373 $num_moved_posts = 0;
374 $num_moved_threads = 0;
377 foreach ($thread_ids as $id) {
381 $numPosts = $objTmpThread->movePosts(
383 $oldFrmData->getTopPk(),
385 $newFrmData->getTopPk()
388 if (($last_post_string = ($objTmpThread->getLastPostString() ??
'')) !==
'') {
389 $last_post_string = explode(
'#', $last_post_string);
390 $last_post_string[0] = $newFrmData->getTopPk();
391 $last_post_string = implode(
'#', $last_post_string);
392 $objTmpThread->setLastPostString($last_post_string);
395 $num_visits += $objTmpThread->getVisits();
396 $num_moved_posts += $numPosts;
397 ++$num_moved_threads;
399 $objTmpThread->setForumId($newFrmData->getTopPk());
400 $objTmpThread->update();
402 $errorMessages[] = sprintf($this->
lng->txt(
'frm_move_invalid_file_type'), $objTmpThread->getSubject());
407 if (0 === max($num_moved_threads, $num_moved_posts, $num_visits)) {
408 return $errorMessages;
411 $this->db->setLimit(1, 0);
412 $res = $this->db->queryF(
413 'SELECT pos_thr_fk, pos_pk FROM frm_posts WHERE pos_top_fk = %s ORDER BY pos_date DESC',
415 [$oldFrmData->getTopPk()]
419 $row = $this->db->fetchObject(
$res);
421 $last_post_src = $oldFrmData->getTopPk() .
'#' . $row->pos_thr_fk .
'#' . $row->pos_pk;
424 $this->db->manipulateF(
426 'SET top_num_posts = top_num_posts - %s, top_num_threads = top_num_threads - %s, visits = visits - %s, ' .
427 'top_last_post = %s WHERE top_pk = %s',
428 [
'integer',
'integer',
'integer',
'text',
'integer'],
434 $oldFrmData->getTopPk()
438 $this->db->setLimit(1, 0);
439 $res = $this->db->queryF(
440 'SELECT pos_thr_fk, pos_pk FROM frm_posts WHERE pos_top_fk = %s ORDER BY pos_date DESC',
442 [$newFrmData->getTopPk()]
445 $last_post_dest =
'';
446 $row = $this->db->fetchObject(
$res);
448 $last_post_dest = $newFrmData->getTopPk() .
'#' . $row->pos_thr_fk .
'#' . $row->pos_pk;
451 $this->db->manipulateF(
452 'UPDATE frm_data SET top_num_posts = top_num_posts + %s, top_num_threads = top_num_threads + %s, ' .
453 'visits = visits + %s, top_last_post = %s WHERE top_pk = %s',
454 [
'integer',
'integer',
'integer',
'text',
'integer'],
455 [$num_moved_posts, $num_moved_threads, $num_visits, $last_post_dest, $newFrmData->getTopPk()]
459 'components/ILIAS/Forum',
462 'source_ref_id' => $src_forum->
getId(),
463 'target_ref_id' => $src_forum->
getId(),
464 'thread_ids' => $src_forum->
getId(),
465 'source_frm_obj_id' => $src_forum->
getId(),
466 'target_frm_obj_id' => $target_obj_id
470 return $errorMessages;
475 $cens_date = date(
'Y-m-d H:i:s');
477 $this->db->manipulateF(
479 SET pos_cens_com = %s, 484 [
'text',
'timestamp',
'integer',
'integer',
'integer'],
488 $this->
user->getId(),
502 $news_item->setContent(nl2br($this->
prepareText($message, 0)));
503 $news_item->setContentHtml(
false);
504 if ($message !== strip_tags($message)) {
505 $news_item->setContentHtml(
true);
508 $res = $this->db->queryF(
'SELECT pos_message FROM frm_posts WHERE pos_pk = %s', [
'integer'], [$pos_pk]);
509 $rec = $this->db->fetchAssoc(
$res);
512 $news_item->setContent(nl2br($this->
prepareText($rec[
'pos_message'], 0)));
513 $news_item->setContentHtml(
false);
514 if ($rec[
'pos_message'] !== strip_tags($rec[
'pos_message'])) {
515 $news_item->setContentHtml(
true);
518 $news_item->update();
522 'components/ILIAS/Forum',
537 $p_node = $postIdOrRecord;
538 if (is_numeric($postIdOrRecord)) {
544 $is_deleted_thread = (
$post->getParentId() == 0) ?
true :
false;
545 $num_visible_active_posts = 0;
546 if ($is_deleted_thread) {
548 SELECT COUNT(*) AS cnt 550 INNER JOIN frm_posts_tree ON pos_pk = pos_fk 551 WHERE frm_posts_tree.parent_pos != 0 552 AND pos_thr_fk = ' . $this->db->quote(
$post->getThreadId(),
'integer') .
' 553 AND pos_status = ' . $this->db->quote(1,
'integer');
554 $res = $this->db->query($query);
555 $row = $this->db->fetchAssoc(
$res);
556 $num_visible_active_posts = (
int) ($row[
'cnt'] ?? 0);
560 'components/ILIAS/Forum',
561 'beforePostDeletion',
566 'thread_deleted' => $is_deleted_thread,
567 'num_visible_active_posts' => $num_visible_active_posts
577 $affected_user_ids[] =
$post->getPosAuthorId();
581 $obj_history->deleteHistoryByPostIds($deleted_post_ids);
584 $obj_draft->deleteDraftsByPostIds($deleted_post_ids);
586 foreach ($deleted_post_ids as $post_id) {
590 $dead_pos = count($deleted_post_ids);
593 if ((
int)
$post->getParentId() === 0) {
594 $dead_thr =
$post->getThreadId();
596 $this->db->manipulateF(
'DELETE FROM frm_threads WHERE thr_pk = %s', [
'integer'], [$dead_thr]);
597 $this->db->manipulateF(
598 'UPDATE frm_data SET top_num_threads = top_num_threads - 1 WHERE top_frm_fk = %s',
603 $posset = $this->db->queryF(
'SELECT * FROM frm_posts WHERE pos_thr_fk = %s', [
'integer'], [$dead_thr]);
604 while ($posrec = $this->db->fetchAssoc($posset)) {
608 (
int) $posrec[
'pos_pk'],
613 $news_item->delete();
618 foreach ($mobs as $mob) {
627 $affected_user_ids[] = (
int) $posrec[
'pos_author_id'];
630 $this->db->manipulateF(
'DELETE FROM frm_posts WHERE pos_thr_fk = %s', [
'integer'], [
$post->getThreadId()]);
632 for ($i = 0; $i < $dead_pos; $i++) {
633 $this->db->manipulateF(
'DELETE FROM frm_posts WHERE pos_pk = %s', [
'integer'], [$deleted_post_ids[$i]]);
638 $deleted_post_ids[$i],
643 $news_item->delete();
648 foreach ($mobs as $mob) {
659 $this->db->manipulateF(
660 'UPDATE frm_threads SET thr_num_posts = thr_num_posts - %s WHERE thr_pk = %s',
661 [
'integer',
'integer'],
662 [$dead_pos,
$post->getTreeId()]
665 $res1 = $this->db->queryF(
666 'SELECT * FROM frm_posts WHERE pos_thr_fk = %s ORDER BY pos_date DESC',
672 if ($res1->numRows() > 0) {
675 while ($selData = $this->db->fetchAssoc($res1)) {
680 $lastPost_thr = $selData[
'pos_top_fk'] .
'#' . $selData[
'pos_thr_fk'] .
'#' . $selData[
'pos_pk'];
685 $this->db->manipulateF(
686 'UPDATE frm_threads SET thr_last_post = %s WHERE thr_pk = %s',
688 [$lastPost_thr,
$post->getTreeId()]
692 $this->db->manipulateF(
693 'UPDATE frm_data SET top_num_posts = top_num_posts - %s WHERE top_frm_fk = %s',
694 [
'integer',
'integer'],
695 [$dead_pos, $this->
id]
698 $res2 = $this->db->queryF(
699 'SELECT * FROM frm_posts, frm_data WHERE pos_top_fk = top_pk AND top_frm_fk = %s ORDER BY pos_date DESC',
705 if ($res2->numRows() > 0) {
708 while ($selData = $this->db->fetchAssoc($res2)) {
713 $lastPost_top = $selData[
'pos_top_fk'] .
'#' . $selData[
'pos_thr_fk'] .
'#' . $selData[
'pos_pk'];
718 $this->db->manipulateF(
719 'UPDATE frm_data SET top_last_post = %s WHERE top_frm_fk = %s',
721 [$lastPost_top, $this->
id]
726 'components/ILIAS/Forum',
731 'user_ids' => $affected_user_ids
745 $is_post_activation_enabled = $frm_props->isPostActivationEnabled();
749 $excluded_ids_condition =
'';
750 if (isset(
$params[
'excluded_ids']) && is_array(
$params[
'excluded_ids']) &&
$params[
'excluded_ids']) {
751 $excluded_ids_condition =
' AND ' . $this->db->in(
'thr_pk',
$params[
'excluded_ids'],
true,
'integer') .
' ';
754 if (!isset(
$params[
'order_column']) || !in_array(
755 strtolower(
$params[
'order_column']),
756 [
'lp_date',
'rating',
'thr_subject',
'num_posts',
'num_visit']
758 $params[
'order_column'] =
'post_date';
760 if (!isset(
$params[
'order_direction']) || !in_array(strtolower(
$params[
'order_direction']), [
'asc',
'desc'])) {
761 $params[
'order_direction'] =
'desc';
764 $cnt_active_pos_query =
'';
765 $cnt_join_type =
'LEFT';
766 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
767 $cnt_active_pos_query =
" AND (pos_status = {$this->db->quote(1, 'integer')} OR pos_author_id = {$this->db->quote($user_id, 'integer')}) ";
768 $cnt_join_type =
"INNER";
771 "SELECT COUNT(DISTINCT(thr_pk)) cnt 773 $cnt_join_type JOIN frm_posts 774 ON pos_thr_fk = thr_pk $cnt_active_pos_query 775 WHERE thr_top_fk = %s $excluded_ids_condition 777 $res = $this->db->queryF($query, [
'integer'], [$a_topic_id]);
778 $cntData = $this->db->fetchAssoc(
$res);
779 $cnt = (
int) $cntData[
'cnt'];
783 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
784 $active_query =
' AND (pos_status = %s OR pos_author_id = %s) ';
785 $having =
' HAVING num_posts > 0';
792 $optional_fields =
'';
793 if ($frm_props->isIsThreadRatingEnabled()) {
794 $optional_fields =
', avg_rating';
797 $additional_sort =
'';
799 if (
$params[
'order_column'] ===
'thr_subject') {
800 $dynamic_columns = [
', thr_subject ' .
$params[
'order_direction']];
801 } elseif (
$params[
'order_column'] ===
'num_posts') {
802 $dynamic_columns = [
', num_posts ' .
$params[
'order_direction']];
803 } elseif (
$params[
'order_column'] ===
'num_visit') {
804 $dynamic_columns = [
', visits ' .
$params[
'order_direction']];
806 $dynamic_columns = [
', post_date ' .
$params[
'order_direction']];
809 if ($frm_props->isIsThreadRatingEnabled()) {
810 $dynamic_columns[] =
' ,avg_rating ' .
$params[
'order_direction'];
812 if (
'rating' === strtolower(
$params[
'order_column'])) {
813 $dynamic_columns = array_reverse($dynamic_columns);
815 $additional_sort .= implode(
' ', $dynamic_columns);
818 if (!$this->
user->isAnonymous()) {
820 (CASE WHEN COUNT(DISTINCT(notification_id)) > 0 THEN 1 ELSE 0 END) usr_notification_is_enabled, 821 MAX(pos_date) post_date, 822 SUM(tree1.parent_pos != 0) num_posts, 823 SUM(tree1.parent_pos != 0) - SUM(tree1.parent_pos != 0 AND postread.post_id IS NOT NULL) num_unread_posts, ";
825 $query .=
" thr_pk, thr_top_fk, thr_subject, thr_author_id, thr_display_user_id, thr_usr_alias, thr_num_posts, thr_last_post, thr_date, thr_update, visits, frm_threads.import_name, is_sticky, is_closed 829 LEFT JOIN frm_notification 830 ON frm_notification.thread_id = thr_pk 831 AND frm_notification.user_id = %s 834 ON pos_thr_fk = thr_pk $active_query 835 LEFT JOIN frm_posts_tree tree1 836 ON tree1.pos_fk = frm_posts.pos_pk 837 LEFT JOIN frm_user_read postread 838 ON postread.post_id = pos_pk 839 AND postread.usr_id = %s";
841 $query .=
" WHERE thr_top_fk = %s 842 $excluded_ids_condition 843 GROUP BY thr_pk, thr_top_fk, thr_subject, thr_author_id, thr_display_user_id, thr_usr_alias, thr_num_posts, thr_last_post, thr_date, thr_update, visits, frm_threads.import_name, is_sticky, is_closed 846 ORDER BY is_sticky DESC $additional_sort, thr_date DESC";
849 $data_types[] =
'integer';
850 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
851 $data_types[] =
'integer';
852 $data_types[] =
'integer';
854 $data_types[] =
'integer';
855 $data_types[] =
'integer';
859 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
866 0 usr_notification_is_enabled, 867 MAX(pos_date) post_date, 868 COUNT(DISTINCT(tree1.pos_fk)) num_posts, 869 COUNT(DISTINCT(tree1.pos_fk)) num_unread_posts, 870 thr_pk, thr_top_fk, thr_subject, thr_author_id, thr_display_user_id, thr_usr_alias, thr_num_posts, thr_last_post, thr_date, thr_update, visits, frm_threads.import_name, is_sticky, is_closed 875 ON pos_thr_fk = thr_pk $active_query 876 LEFT JOIN frm_posts_tree tree1 877 ON tree1.pos_fk = frm_posts.pos_pk AND tree1.parent_pos != 0 880 $query .=
" WHERE thr_top_fk = %s 881 $excluded_ids_condition 882 GROUP BY thr_pk, thr_top_fk, thr_subject, thr_author_id, thr_display_user_id, thr_usr_alias, thr_num_posts, thr_last_post, thr_date, thr_update, visits, frm_threads.import_name, is_sticky, is_closed 885 ORDER BY is_sticky DESC $additional_sort, thr_date DESC";
887 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
888 $data_types[] =
'integer';
889 $data_types[] =
'integer';
891 $data_types[] =
'integer';
892 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
897 $data[] = $a_topic_id;
899 if ($limit || $offset) {
900 $this->db->setLimit($limit, $offset);
904 $res = $this->db->queryF($query, $data_types,
$data);
905 while ($row = $this->db->fetchAssoc(
$res)) {
907 $thread->assignData($row);
908 $threads[(
int) $row[
'thr_pk']] = $thread;
909 $threadIds[] = (
int) $row[
'thr_pk'];
912 $inner_last_active_post_condition =
'';
913 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
914 $inner_last_active_post_condition = sprintf(
915 ' AND (iposts.pos_status = %s OR (iposts.pos_status = %s AND iposts.pos_author_id = %s)) ',
916 $this->db->quote(1,
'integer'),
917 $this->db->quote(0,
'integer'),
918 $this->db->quote($this->
user->getId(),
'integer')
922 $post_res = $this->db->query(
926 SELECT pos_thr_fk, MAX(iposts.pos_date) i_pos_date 927 FROM frm_posts iposts 928 WHERE ' . $this->db->in(
'iposts.pos_thr_fk', $threadIds,
false,
'integer') .
' 929 ' . $inner_last_active_post_condition .
' 931 ) opost ON frm_posts.pos_thr_fk = opost.pos_thr_fk AND frm_posts.pos_date = opost.i_pos_date' 933 while ($post_row = $this->db->fetchAssoc($post_res)) {
934 $tmp_obj =
new ilForumPost((
int) $post_row[
'pos_pk'], (
bool)
$params[
'is_moderator'],
true);
935 $tmp_obj->setPosAuthorId((
int) $post_row[
'pos_author_id']);
936 $tmp_obj->setDisplayUserId((
int) $post_row[
'pos_display_user_id']);
937 $tmp_obj->setUserAlias((
string) $post_row[
'pos_usr_alias']);
938 $tmp_obj->setImportName((
string) $post_row[
'import_name']);
939 $tmp_obj->setId((
int) $post_row[
'pos_pk']);
940 $tmp_obj->setCreateDate((
string) $post_row[
'pos_date']);
942 $threads[(
int) $post_row[
'pos_thr_fk']]->setLastPostForThreadOverview($tmp_obj);
955 SUM(IF(f.pos_cens = %s, 1, 0)) cnt 957 INNER JOIN frm_posts_tree t ON f.pos_pk = t.pos_fk AND t.parent_pos != %s 958 INNER JOIN frm_threads th ON t.thr_fk = th.thr_pk 959 INNER JOIN frm_data d ON d.top_pk = f.pos_top_fk AND d.top_frm_fk = %s 960 WHERE f.pos_author_id = %s 963 if ($post_activation_required) {
964 $query .=
' AND f.pos_status = ' . $this->db->quote(1,
'integer');
967 $res = $this->db->queryF(
969 [
'integer',
'integer',
'integer',
'integer'],
972 $row = $this->db->fetchAssoc(
$res);
973 if (is_array($row)) {
974 return (
int) $row[
'cnt'];
991 u.login, u.lastname, u.firstname, f.pos_author_id, u.usr_id, 992 p.value public_profile, 993 SUM(IF(f.pos_cens = %s, 1, 0)) num_postings 995 INNER JOIN frm_posts_tree t ON f.pos_pk = t.pos_fk 996 INNER JOIN frm_threads th ON t.thr_fk = th.thr_pk 997 INNER JOIN usr_data u ON u.usr_id = f.pos_author_id 998 INNER JOIN frm_data d ON d.top_pk = f.pos_top_fk 999 LEFT JOIN usr_pref p ON p.usr_id = u.usr_id AND p.keyword = %s 1000 WHERE t.parent_pos != %s 1003 $data_types[] =
'integer';
1004 $data_types[] =
'text';
1005 $data_types[] =
'integer';
1007 $data[] =
'public_profile';
1010 if ($post_activation_required) {
1011 $query .=
' AND pos_status = %s';
1012 $data_types[] =
'integer';
1017 AND d.top_frm_fk = %s 1018 GROUP BY u.login, p.value,u.lastname, u.firstname, f.pos_author_id 1021 $data_types[] =
'integer';
1024 $res = $this->db->queryF($query, $data_types,
$data);
1025 while ($row = $this->db->fetchAssoc(
$res)) {
1027 !in_array($row[
'public_profile'], [
1028 PersonalProfileMode::PROFILE_ENABLED_LOGGED_IN_USERS,
1029 PersonalProfileMode::PROFILE_ENABLED_GLOBAL],
true)
1030 || ($this->
user->isAnonymous() && $row[
'public_profile'] !== PersonalProfileMode::PROFILE_ENABLED_GLOBAL)
1032 $row[
'lastname'] =
'';
1033 $row[
'firstname'] =
'';
1036 $row[
'usr_id'] = (
int) $row[
'usr_id'];
1037 $row[
'pos_author_id'] = (
int) $row[
'pos_author_id'];
1038 $row[
'num_postings'] = (
int) $row[
'num_postings'];
1040 $statistic[] = $row;
1048 $res = $this->db->queryF(
1049 'SELECT pos_fk FROM frm_posts_tree WHERE thr_fk = %s AND parent_pos = %s',
1050 [
'integer',
'integer'],
1054 $row = $this->db->fetchObject(
$res);
1056 return (
int) $row->pos_fk;
1077 $rbacreview = $DIC->rbac()->review();
1079 $role_arr = $rbacreview->getRolesOfRoleFolder($a_ref_id);
1080 foreach ($role_arr as $role_id) {
1082 return array_map(
'intval', $rbacreview->assignedUsers($role_id));
1091 if (!isset(self::$moderators_by_ref_id_map[$a_ref_id])) {
1092 self::$moderators_by_ref_id_map[$a_ref_id] = self::_getModerators($a_ref_id);
1095 return in_array($a_usr_id, self::$moderators_by_ref_id_map[$a_ref_id],
true);
1100 $res = $this->db->queryF(
1101 'SELECT * FROM frm_data 1102 INNER JOIN frm_posts ON pos_top_fk = top_pk 1103 INNER JOIN frm_posts_tree tree1 ON tree1.pos_fk = frm_posts.pos_pk AND tree1.parent_pos != 0 1104 WHERE top_frm_fk = %s 1105 AND pos_author_id = %s',
1106 [
'integer',
'integer'],
1110 return $res->numRows();
1115 $res = $this->db->queryF(
1116 'SELECT * FROM frm_data 1117 INNER JOIN frm_posts ON pos_top_fk = top_pk 1118 INNER JOIN frm_posts_tree tree1 ON tree1.pos_fk = frm_posts.pos_pk AND tree1.parent_pos != 0 1119 WHERE top_frm_fk = %s 1120 AND (pos_status = %s OR (pos_status = %s AND pos_author_id = %s)) 1121 AND pos_author_id = %s',
1122 [
'integer',
'integer',
'integer',
'integer',
'integer'],
1126 return $res->numRows();
1134 public function addPostTree(
int $a_tree_id,
int $a_node_id = -1,
string $a_date =
''): bool
1136 $a_date = $a_date ?: date(
'Y-m-d H:i:s');
1138 if ($a_node_id <= 0) {
1139 $a_node_id = $a_tree_id;
1142 $nextId = $this->db->nextId(
'frm_posts_tree');
1144 $this->db->manipulateF(
1146 INSERT INTO frm_posts_tree 1156 VALUES(%s, %s, %s, %s, %s, %s, %s, %s )',
1157 [
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'timestamp'],
1158 [$nextId, $a_tree_id, $a_node_id, 0, 1, 2, 1, $a_date]
1167 public function insertPostNode(
int $a_node_id,
int $a_parent_id,
int $tree_id,
string $a_date =
''): void
1169 $a_date = $a_date ?: date(
'Y-m-d H:i:s');
1172 $res = $this->db->queryF(
1173 'SELECT lft FROM frm_posts_tree WHERE pos_fk = %s AND thr_fk = %s',
1174 [
'integer',
'integer'],
1175 [$a_parent_id, $tree_id]
1177 $row = $this->db->fetchObject(
$res);
1179 $left = (
int) $row->lft;
1185 $this->db->manipulateF(
1187 UPDATE frm_posts_tree 1199 [
'integer',
'integer',
'integer'],
1200 [$left, $left, $tree_id]
1203 $depth = $this->
getPostDepth($a_parent_id, $tree_id) + 1;
1205 $nextId = $this->db->nextId(
'frm_posts_tree');
1206 $this->db->manipulateF(
1208 INSERT INTO frm_posts_tree 1218 VALUES(%s,%s,%s, %s, %s, %s,%s, %s)',
1219 [
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'timestamp'],
1235 if ($tree_id !== 0) {
1236 $res = $this->db->queryF(
1237 'SELECT depth FROM frm_posts_tree WHERE pos_fk = %s AND thr_fk = %s',
1238 [
'integer',
'integer'],
1239 [$a_node_id, $tree_id]
1242 $row = $this->db->fetchObject(
$res);
1244 return (
int) $row->depth;
1253 $res = $this->db->queryF(
1254 'SELECT * FROM frm_posts, frm_posts_tree WHERE pos_pk = pos_fk AND parent_pos = %s AND thr_fk = %s',
1255 [
'integer',
'integer'],
1259 if (($row = $this->db->fetchObject(
$res)) !==
null) {
1268 $res = $this->db->queryF(
1269 'SELECT * FROM frm_posts, frm_posts_tree WHERE pos_pk = pos_fk AND pos_pk = %s',
1274 if (($row = $this->db->fetchObject(
$res)) !==
null) {
1290 $tmp_user =
new ilObjUser((
int) $a_row->pos_display_user_id);
1291 $fullname = $tmp_user->getFullname();
1292 $loginname = $tmp_user->getLogin();
1295 if ($fullname ===
'') {
1296 $fullname = $this->
lng->txt(
'unknown');
1297 if ($a_row->import_name) {
1298 $fullname = $a_row->import_name;
1304 'pos_pk' => (
int) $a_row->pos_pk,
1305 'pos_thr_fk' => (
int) $a_row->pos_thr_fk,
1306 'child' => (
int) $a_row->pos_pk,
1307 'author' => (
int) $a_row->pos_display_user_id,
1308 'alias' => (string) $a_row->pos_usr_alias,
1309 'title' => $fullname,
1310 'loginname' => $loginname,
1311 'message' => (
string) $a_row->pos_message,
1312 'subject' => (string) $a_row->pos_subject,
1313 'pos_cens_com' => (
string) $a_row->pos_cens_com,
1314 'pos_cens' => (
int) $a_row->pos_cens,
1315 'date' => $a_row->fpt_date,
1316 'create_date' => $a_row->pos_date,
1317 'update' => $a_row->pos_update,
1318 'update_user' => (
int) $a_row->update_user,
1319 'tree' => (
int) $a_row->thr_fk,
1320 'parent' => (
int) $a_row->parent_pos,
1321 'lft' => (
int) $a_row->lft,
1322 'rgt' => (
int) $a_row->rgt,
1323 'depth' => (
int) $a_row->depth,
1324 'id' => (
int) $a_row->fpt_pk,
1325 'notify' => (
int) $a_row->notify,
1326 'import_name' => $a_row->import_name,
1327 'pos_status' => (
int) $a_row->pos_status
1336 $res = $this->db->queryF(
1337 'SELECT pos_fk FROM frm_posts_tree WHERE lft BETWEEN %s AND %s AND thr_fk = %s',
1343 while ($post_tree_data = $this->db->fetchAssoc(
$res)) {
1344 $post_ids[] = (
int) $post_tree_data[
'pos_fk'];
1355 $res = $this->db->queryF(
1356 'SELECT lft, rgt FROM frm_posts_tree WHERE thr_fk = %s AND pos_fk = %s AND parent_pos = %s',
1357 [
'integer',
'integer',
'integer'],
1358 [$a_node[
'tree'], $a_node[
'pos_pk'], $a_node[
'parent']]
1361 while ($row = $this->db->fetchObject(
$res)) {
1362 $a_node[
'lft'] = (
int) $row->lft;
1363 $a_node[
'rgt'] = (
int) $row->rgt;
1366 $diff = $a_node[
'rgt'] - $a_node[
'lft'] + 1;
1368 $res = $this->db->queryF(
1369 'SELECT pos_fk FROM frm_posts_tree WHERE lft BETWEEN %s AND %s AND thr_fk = %s',
1370 [
'integer',
'integer',
'integer'],
1371 [$a_node[
'lft'], $a_node[
'rgt'], $a_node[
'tree']]
1374 $deleted_post_ids = [];
1375 while ($treeData = $this->db->fetchAssoc(
$res)) {
1376 $deleted_post_ids[] = (
int) $treeData[
'pos_fk'];
1379 $this->db->manipulateF(
1380 'DELETE FROM frm_posts_tree WHERE lft BETWEEN %s AND %s AND thr_fk = %s',
1381 [
'integer',
'integer',
'integer'],
1382 [$a_node[
'lft'], $a_node[
'rgt'], $a_node[
'tree']]
1385 $this->db->manipulateF(
1387 UPDATE frm_posts_tree 1399 [
'integer',
'integer',
'integer',
'integer',
'integer'],
1400 [$a_node[
'lft'], $diff, $a_node[
'lft'], $diff, $a_node[
'tree']]
1403 return $deleted_post_ids;
1408 $checkTime = time() - (60 * 60);
1409 $session_key =
'frm_visit_' . $this->dbTable .
'_' . $ID;
1413 $query =
'UPDATE ' . $this->dbTable .
' SET visits = visits + 1 WHERE ';
1422 $this->db->manipulateF($query, $data_type, $data_value);
1427 public function prepareText(
string $text,
int $edit = 0,
string $quote_user =
'',
string $type =
''): string
1429 if ($type ===
'export') {
1430 $this->replQuote1 =
"<blockquote class=\"quote\"><hr size=\"1\" color=\"#000000\">";
1431 $this->replQuote2 =
"<hr size=\"1\" color=\"#000000\"/></blockquote>";
1436 if ($quote_user !==
'') {
1437 $lname =
'="' . $quote_user .
'"';
1440 $text =
"[quote$lname]" . $text .
"[/quote]";
1443 $startZ = substr_count($text,
"[quote");
1444 $endZ = substr_count($text,
"[/quote]");
1446 if ($startZ > 0 || $endZ > 0) {
1448 if ($startZ > $endZ) {
1449 $diff = $startZ - $endZ;
1451 for ($i = 0; $i < $diff; $i++) {
1452 if ($type ===
'export') {
1455 $text .=
"[/quote]";
1458 } elseif ($startZ < $endZ) {
1459 $diff = $endZ - $startZ;
1461 for ($i = 0; $i < $diff; $i++) {
1462 if ($type ===
'export') {
1463 $text = $this->txtQuote1 . $text;
1465 $text =
"[quote]" . $text;
1471 $text = preg_replace(
1472 '@\[(quote\s*?=\s*?"([^"]*?)"\s*?)\]@i',
1473 $this->replQuote1 .
'<div class="ilForumQuoteHead">' . $this->
lng->txt(
'quote') .
' ($2)</div>',
1477 $text = str_replace(
1478 [
"[quote]",
"[/quote]"],
1480 $this->replQuote1 .
'<div class="ilForumQuoteHead">' . $this->
lng->txt(
'quote') .
'</div>',
1489 if ($type !==
'export') {
1492 $text = $this->ui_renderer->render($this->ui_factory->legacy()->latexContent($text));
1498 $text = str_replace([
"{",
"}"], [
"{",
"}"], $text);
1509 foreach ($a_ids as $pos_id) {
1511 $files = $forumFiles->getFilesOfPost();
1512 foreach ($files as $file) {
1513 $forumFiles->unlinkFile($file[
'name']);
1525 $this->import_name = $a_import_name;
1532 $res = $this->db->queryF(
1534 SELECT frm_notification.thread_id FROM frm_data, frm_notification, frm_threads 1535 WHERE frm_notification.user_id = %s 1536 AND frm_notification.thread_id = frm_threads.thr_pk 1537 AND frm_threads.thr_top_fk = frm_data.top_pk 1538 AND frm_data.top_frm_fk = %s 1539 GROUP BY frm_notification.thread_id',
1540 [
'integer',
'integer'],
1541 [$user_id, $this->
id]
1544 if (
$res->numRows() > 0) {
1546 $thread_data_types = [];
1548 $query =
' DELETE FROM frm_notification WHERE user_id = %s AND thread_id IN (';
1550 $thread_data_types[] =
'integer';
1553 while ($row = $this->db->fetchAssoc(
$res)) {
1554 if ($counter < $res->numRows()) {
1556 $thread_data[] = $row[
'thread_id'];
1557 $thread_data_types[] =
'integer';
1560 if ($counter ===
$res->numRows()) {
1562 $thread_data[] = $row[
'thread_id'];
1563 $thread_data_types[] =
'integer';
1568 $this->db->manipulateF($query, $thread_data_types, $thread_data);
1572 $nextId = $this->db->nextId(
'frm_notification');
1573 $this->db->manipulateF(
1574 'INSERT INTO frm_notification (notification_id, user_id, frm_id) VALUES(%s, %s, %s)',
1575 [
'integer',
'integer',
'integer'],
1576 [$nextId, $user_id, $this->
id]
1585 $this->db->manipulateF(
1586 'DELETE FROM frm_notification WHERE user_id = %s AND frm_id = %s',
1587 [
'integer',
'integer'],
1588 [$user_id, $this->
id]
1596 $res = $this->db->queryF(
1597 'SELECT COUNT(*) cnt FROM frm_notification WHERE user_id = %s AND frm_id = %s',
1598 [
'integer',
'integer'],
1599 [$user_id, $this->
id]
1602 if ($row = $this->db->fetchAssoc(
$res)) {
1603 return (
int) $row[
'cnt'] > 0;
1611 $res = $this->db->queryF(
1612 'SELECT COUNT(*) cnt FROM frm_notification WHERE user_id = %s AND thread_id = %s',
1613 [
'integer',
'integer'],
1614 [$user_id, $thread_id]
1617 if ($row = $this->db->fetchAssoc(
$res)) {
1618 return (
int) $row[
'cnt'] > 0;
1631 $sort = match ($a_sort_mode) {
1632 self::SORT_DATE =>
'thr_date',
1633 default =>
'thr_subject',
1636 $res = $DIC->database()->queryF(
1637 'SELECT thr_pk, thr_subject FROM frm_threads INNER JOIN frm_data ON top_pk = thr_top_fk WHERE top_frm_fk = %s ORDER BY %s',
1638 [
'integer',
'text'],
1643 while ($row = $DIC->database()->fetchObject(
$res)) {
1644 $threads[(
int) $row->thr_pk] = $row->thr_subject;
1654 $res = $DIC->database()->queryF(
'SELECT top_frm_fk FROM frm_data WHERE top_pk = %s', [
'integer'], [$a_for_id]);
1655 if ($row = $DIC->database()->fetchAssoc(
$res)) {
1656 return (
int) $row[
'top_frm_fk'];
1668 if ($sourceThread->getForumId() !== $targetThread->getForumId()) {
1669 throw new ilException(
'not_allowed_to_merge_into_another_forum');
1673 if ($sourceThread->getCreateDate() > $targetThread->getCreateDate()) {
1674 $sourceThreadForMerge = $sourceThread;
1675 $targetThreadForMerge = $targetThread;
1677 $sourceThreadForMerge = $targetThread;
1678 $targetThreadForMerge = $sourceThread;
1681 $threadSubject = $targetThreadForMerge->getSubject();
1683 $targetWasClosedBeforeMerge = $targetThreadForMerge->isClosed();
1684 $sourceThreadForMerge->close();
1686 if (!$targetWasClosedBeforeMerge) {
1687 $targetThreadForMerge->close();
1690 $allSourcePostings = $sourceThreadForMerge->getAllPostIds();
1691 $sourceThreadRootNode = $sourceThreadForMerge->getPostRootNode();
1692 $targetThreadRootNode = $targetThreadForMerge->getPostRootNode();
1694 $sourceThreadRootArray = $this->
getPostNode($sourceThreadRootNode->getId());
1696 $ilAtomQuery = $this->db->buildAtomQuery();
1697 $ilAtomQuery->addTableLock(
'frm_posts');
1698 $ilAtomQuery->addTableLock(
'frm_posts_tree');
1699 $ilAtomQuery->addTableLock(
'frm_threads');
1700 $ilAtomQuery->addTableLock(
'frm_data');
1703 $targetThreadForMerge,
1704 $sourceThreadForMerge,
1705 $targetThreadRootNode,
1706 $sourceThreadRootNode,
1709 $targetRootNodeRgt = $targetThreadRootNode->getRgt();
1710 $targetRootNodeId = $targetThreadRootNode->getId();
1714 $targetThreadRootNode->getId(),
1715 ($targetThreadRootNode->getRgt() + $sourceThreadRootNode->getRgt() - 2)
1719 foreach ($allSourcePostings as $pos_pk) {
1722 if ($post_obj->getId() === $sourceThreadRootNode->getId()) {
1728 $tree->setPosFk($pos_pk);
1730 if ($post_obj->getParentId() === $sourceThreadRootNode->getId()) {
1731 $tree->setParentPos($targetRootNodeId);
1733 $tree->setParentPos($post_obj->getParentId());
1736 $tree->setLft(($post_obj->getLft() + $targetRootNodeRgt) - 2);
1737 $tree->setRgt(($post_obj->getRgt() + $targetRootNodeRgt) - 2);
1739 $tree->setDepth($post_obj->getDepth());
1740 $tree->setTargetThreadId($targetThreadForMerge->getId());
1741 $tree->setSourceThreadId($sourceThreadForMerge->getId());
1747 $sourceThreadForMerge->getId(),
1748 $targetThreadForMerge->getId(),
1749 [$sourceThreadRootNode->getId()]
1752 $ilAtomQuery->run();
1757 $lastPostString = $targetThreadForMerge->getLastPostString() ??
'';
1758 $exp = explode(
'#', $lastPostString);
1759 if (array_key_exists(2, $exp)) {
1761 $exp[2] = $targetThreadForMerge->getLastPost()->getId();
1762 $lastPostString = implode(
'#', $exp);
1764 $lastPostString =
null;
1769 $frm_topic_obj->setNumPosts($sourceThreadForMerge->getNumPosts() + $targetThreadForMerge->getNumPosts());
1770 $frm_topic_obj->setVisits($sourceThreadForMerge->getVisits() + $targetThreadForMerge->getVisits());
1771 $frm_topic_obj->setLastPostString($lastPostString);
1772 $frm_topic_obj->setSubject($threadSubject);
1773 $frm_topic_obj->setId($targetThreadForMerge->getId());
1774 $frm_topic_obj->updateMergedThread();
1776 if (!$targetWasClosedBeforeMerge) {
1777 $targetThreadForMerge->reopen();
1780 $this->
event->raise(
1781 'components/ILIAS/Forum',
1785 'source_thread_id' => $sourceThreadForMerge->getId(),
1786 'target_thread_id' => $targetThreadForMerge->getId()
1790 $this->
deletePost($sourceThreadRootArray,
false);
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...
addPostTree(int $a_tree_id, int $a_node_id=-1, string $a_date='')
getFirstPostNode(int $tree_id)
static get(string $a_var)
isForumNotificationEnabled(int $user_id)
getPostNode(int $post_id)
static mergeForumUserRead(int $merge_source_thread_id, int $merge_target_thread_id)
static array $moderators_by_ref_id_map
Personal profile publishing mode of a user.
getRootPostIdByThread(int $a_thread_id)
setCreateDate(?string $a_createdate)
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
setMDB2WhereCondition(string $query_string, array $data_type, array $data_value)
getUserStatistics(bool $post_activation_required)
disableForumNotification(int $user_id)
deletePostFiles(array $a_ids)
enableNotification(int $a_user_id)
getPostDepth(int $a_node_id, int $tree_id)
setDbTable(string $dbTable)
static mergePosts(int $sourceThreadId, int $targetThreadId, array $excludedPostIds=[])
ILIAS UI Renderer $ui_renderer
moveThreads(array $thread_ids, ilObjForum $src_forum, int $target_obj_id)
setForumRefId(int $a_ref_id)
convertDate(string $date)
static _deleteReadEntries(int $a_post_id)
static replaceLatexSpan(string $text)
Replace the latex delimiters used by the rich text editor Unfortunately these can't be processed by M...
Class ilForumDraftHistory.
static getInstance(int $a_obj_id=0)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
setImportName(?string $a_import_name)
mergeThreads(int $source_id, int $target_id)
insertPostNode(int $a_node_id, int $a_parent_id, int $tree_id, string $a_date='')
insert node under parent node
getNumberOfPublishedUserPostings(int $usr_id, bool $post_activation_required)
fetchPostNodeData(stdClass $a_row)
const int DEFAULT_PAGE_HITS
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
static getInstanceFromArray(array $record)
static updateTargetRootRgt(int $root_node_id, int $rgt)
static _lookupTitle(int $obj_id)
readonly ilAppEventHandler $event
prepareText(string $text, int $edit=0, string $quote_user='', string $type='')
static _lookupObjIdForForumId(int $a_for_id)
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
countUserArticles(int $a_user_id)
ILIAS UI Factory $ui_factory
static getEmptyInstance()
getSubPathIdsForNode(ilForumPost $post)
getAllThreads(int $a_topic_id, array $params=[], int $limit=0, int $offset=0)
enableForumNotification(int $user_id)
generateThread(ilForumTopic $thread, string $message, bool $notify, bool $notify_posts, bool $status=true, bool $withFirstVisibleEntry=true)
setPageHits(int $pageHits)
static _isModerator(int $a_ref_id, int $a_usr_id)
A news item can be created by different sources.
countActiveUserArticles(int $a_user_id)
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.
deletePost($postIdOrRecord, bool $raiseEvents=true)
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
postCensorship(ilObjForum $forum, string $message, int $pos_pk, int $cens=0)
static _getModerators(int $a_ref_id)
setImportName(string $a_import_name)
static getSortedThreadSubjects(int $a_obj_id, int $a_sort_mode=self::SORT_DATE)
setForumId(int $a_obj_id)
deletePostTree(array $a_node)
static mergeThreadNotifications($merge_source_thread_id, $merge_target_thread_id)
static set(string $a_var, $a_val)
Set a value.
isThreadNotificationEnabled(int $user_id, int $thread_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...