1<?php
2/* Copyright (c) 1998-2012 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4/**
5* @author Michael Jansen <mjansen@databay.de>
6* @version $Id$
7*
8* @ingroup ModulesForum
9*/
10class ilForumPost
11{
12    private $id = 0;
13
14    private $forum_id = 0;
15
16    private $thread_id = 0;
17
18    private $display_user_id = 0;
19
20    private $user_alias = '';
21
22    private $subject = '';
23
24    private $message = '';
25
26    private $createdate = '0000-00-00 00:00:00';
27
28    private $changedate = '0000-00-00 00:00:00';
29
30    private $user_id_update = 0;
31
32    private $censored = 0;
33
34    private $censorship_comment = '';
35
36    private $censored_date = '0000-00-00 00:00:00';
37
38    private $notification = 0;
39
40    private $import_name = '';
41
42    private $status = 1;
43
44    private $tree_id = 0;
45
46    private $parent_id = 0;
47
48    private $lft = 0;
49
50    private $rgt = 0;
51
52    private $depth = 0;
53
54    /**
55     * @var ilForumTopic
56     */
57    private $objThread = null;
58
59    private $db = null;
60    private $lng = null;
61
62    /**
63     *  current user in a forum
64     * @var bool
65     */
66    private $is_moderator = false;
67
68    /**
69     * author_id of a post is a moderator
70     * @var int|null
71     */
72    private $is_author_moderator = null;
73
74    private $post_read = false;
75
76    private $pos_author_id = 0;
77
78    private $post_activation_date = null;
79
80    /**
81     * ilForumPost constructor.
82     * @param int  $a_id
83     * @param bool $a_is_moderator
84     * @param bool $preventImplicitRead
85     */
86    public function __construct($a_id = 0, $a_is_moderator = false, $preventImplicitRead = false)
87    {
88        global $DIC;
89
90        $this->db = $DIC->database();
91        $this->lng = $DIC->language();
92        $this->id = $a_id;
93
94        if (!$preventImplicitRead) {
95            $this->read();
96        }
97    }
98
99    public function __destruct()
100    {
101        unset($this->db);
102        unset($this->objThread);
103    }
104
105    public function insert()
106    {
107        if ($this->forum_id && $this->thread_id) {
108            $this->id = $this->db->nextId('frm_posts');
109
110            $this->db->insert('frm_posts', array(
111                'pos_pk' => array('integer', $this->id),
112                'pos_top_fk' => array('integer', $this->forum_id),
113                'pos_thr_fk' => array('integer', $this->thread_id),
114                'pos_display_user_id' => array('integer', $this->display_user_id),
115                'pos_usr_alias' => array('text', $this->user_alias),
116                'pos_subject' => array('text', $this->subject),
117                'pos_message' => array('clob', $this->message),
118                'pos_date' => array('timestamp', $this->createdate),
119                'pos_update' => array('timestamp', $this->createdate),
120                'update_user' => array('integer', $this->user_id_update),
121                'pos_cens' => array('integer', $this->censored),
122                'notify' => array('integer', (int) $this->notification),
123                'import_name' => array('text', (string) $this->import_name),
124                'pos_status' => array('integer', (int) $this->status),
125                'pos_author_id' => array('integer', (int) $this->pos_author_id),
126                'is_author_moderator' => array('integer', $this->is_author_moderator),
127                'pos_activation_date' => array('timestamp', $this->createdate)
128            ));
129
130            return true;
131        }
132
133        return false;
134    }
135
136    public function update()
137    {
138        if ($this->id) {
139            $this->db->update(
140                'frm_posts',
141                array(
142                    'pos_top_fk' => array('integer', $this->forum_id),
143                    'pos_thr_fk' => array('integer', $this->thread_id),
144                    'pos_subject' => array('text', $this->subject),
145                    'pos_message' => array('clob', $this->message),
146                    'pos_update' => array('timestamp', $this->changedate),
147                    'update_user' => array('integer', $this->user_id_update),
148                    'pos_cens' => array('integer', $this->censored),
149                    'pos_cens_date' => array('timestamp', $this->censored_date),
150                    'pos_cens_com' => array('text', $this->censorship_comment),
151                    'notify' => array('integer', (int) $this->notification),
152                    'pos_status' => array('integer', (int) $this->status)
153                ),
154                array(
155                    'pos_pk' => array('integer', (int) $this->id)
156                )
157            );
158
159            if ($this->objThread->getFirstPostId() == $this->id) {
160                $this->objThread->setSubject($this->subject);
161                $this->objThread->update();
162                $this->objThread->reload();
163            }
164
165            return true;
166        }
167
168        return false;
169    }
170
171    private function read()
172    {
173        if ($this->id) {
174            $res = $this->db->queryF(
175                '
176				SELECT * FROM frm_posts
177				INNER JOIN frm_posts_tree ON pos_fk = pos_pk
178				WHERE pos_pk = %s',
179                array('integer'),
180                array($this->id)
181            );
182            $row = $this->db->fetchObject($res);
183
184            if (is_object($row)) {
185                $this->id = $row->pos_pk;
186                $this->forum_id = $row->pos_top_fk;
187                $this->thread_id = $row->pos_thr_fk;
188                $this->display_user_id = $row->pos_display_user_id;
189                $this->user_alias = $row->pos_usr_alias;
190                $this->subject = $row->pos_subject;
191                $this->message = $row->pos_message;
192                $this->createdate = $row->pos_date;
193                $this->changedate = $row->pos_update;
194                $this->user_id_update = $row->update_user;
195                $this->censored = $row->pos_cens;
196                $this->censored_date = $row->pos_cens_date;
197                $this->censorship_comment = $row->pos_cens_com;
198                $this->notification = $row->notify;
199                $this->import_name = $row->import_name;
200                $this->status = $row->pos_status;
201                $this->tree_id = $row->fpt_pk;
202                $this->parent_id = $row->parent_pos;
203                $this->lft = $row->lft;
204                $this->rgt = $row->rgt;
205                $this->depth = $row->depth;
206                $this->pos_author_id = $row->pos_author_id;
207                $this->is_author_moderator = $row->is_author_moderator;
208                $this->post_activation_date = $row->pos_activation_date;
209
210                $this->objThread = new ilForumTopic($this->thread_id, $this->is_moderator);
211
212                return true;
213            }
214            $this->id = 0;
215            return false;
216        }
217
218        return false;
219    }
220
221    public function isAnyParentDeactivated()
222    {
223        if ($this->id) {
224            $res = $this->db->queryF(
225                '
226				SELECT * FROM frm_posts_tree
227				INNER JOIN frm_posts ON pos_pk = pos_fk
228				WHERE pos_status = %s
229				AND lft < %s AND rgt > %s
230				AND thr_fk = %s',
231                array('integer', 'integer', 'integer', 'integer'),
232                array('0', $this->lft, $this->rgt, $this->thread_id)
233            );
234
235            return $res->numRows();
236        }
237
238        return false;
239    }
240
241    public function reload()
242    {
243        return $this->read();
244    }
245
246    public function activatePost()
247    {
248        if ($this->id) {
249            $now = date("Y-m-d H:i:s");
250            $this->db->update(
251                'frm_posts',
252                array('pos_status' => array('integer', 1),
253                      'pos_activation_date' => array('timestamp', $now)),
254                array('pos_pk' => array('integer', $this->id))
255            );
256
257            $this->activateParentPosts();
258            $this->setPostActivationDate($now);
259            $this->setStatus(1);
260            return true;
261        }
262
263        return false;
264    }
265
266    public function activatePostAndChildPosts()
267    {
268        if ($this->id) {
269            $query = "SELECT pos_pk FROM frm_posts_tree treea "
270                   . "INNER JOIN frm_posts_tree treeb ON treeb.thr_fk = treea.thr_fk "
271                   . "AND treeb.lft BETWEEN treea.lft AND treea.rgt "
272                   . "INNER JOIN frm_posts ON pos_pk = treeb.pos_fk "
273                   . "WHERE treea.pos_fk = %s";
274            $result = $this->db->queryF(
275                $query,
276                array('integer'),
277                array($this->id)
278            );
279
280            $now = date("Y-m-d H:i:s");
281            while ($row = $this->db->fetchAssoc($result)) {
282                $this->db->update(
283                    'frm_posts',
284                    array('pos_status' => array('integer', 1),
285                          'pos_activation_date' => array('timestamp', $now)),
286                    array('pos_pk' => array('integer', $row['pos_pk']))
287                );
288            }
289
290            $this->activateParentPosts();
291
292            return true;
293        }
294
295        return false;
296    }
297
298    public function activateParentPosts()
299    {
300        if ($this->id) {
301            $query = "SELECT pos_pk FROM frm_posts "
302                   . "INNER JOIN frm_posts_tree ON pos_fk = pos_pk "
303                   . "WHERE lft < %s AND rgt > %s AND thr_fk = %s";
304            $result = $this->db->queryF(
305                $query,
306                array('integer', 'integer', 'integer'),
307                array($this->lft, $this->rgt, $this->thread_id)
308            );
309
310            $now = date("Y-m-d H:i:s");
311            while ($row = $this->db->fetchAssoc($result)) {
312                $this->db->update(
313                    'frm_posts',
314                    array('pos_status' => array('integer', 1),
315                          'pos_activation_date' => array('timestamp', $now)),
316                    array('pos_pk' => array('integer', $row['pos_pk']))
317                );
318            }
319
320            return true;
321        }
322
323        return false;
324    }
325
326    public function isPostRead()
327    {
328        return $this->getIsRead();
329    }
330
331    public function isRead($a_user_id = 0)
332    {
333        if ($a_user_id && $this->id) {
334            $res = $this->db->queryF(
335                '
336				SELECT * FROM frm_user_read
337			  	WHERE usr_id = %s
338			 	AND post_id = %s',
339                array('integer', 'integer'),
340                array($a_user_id, $this->id)
341            );
342
343            return $res->numRows() ? true : false;
344        }
345
346        return false;
347    }
348
349    public function hasReplies()
350    {
351        if ($this->id && $this->rgt && $this->lft) {
352            $res = $this->db->queryF(
353                '
354				SELECT * FROM frm_posts_tree
355		  	 	WHERE lft > %s AND rgt < %s
356		  	  	AND thr_fk = %s',
357                array('integer', 'integer', 'integer'),
358                array($this->lft, $this->rgt, $this->thread_id)
359            );
360
361            return $res->numRows() ? true : false;
362        }
363
364        return false;
365    }
366
367    public function isOwner($a_user_id = 0)
368    {
369        if ($this->pos_author_id && $a_user_id) {
370            if ((int) $this->pos_author_id == (int) $a_user_id) {
371                return true;
372            }
373            return false;
374        }
375        return false;
376    }
377
378    public function setId($a_id)
379    {
380        $this->id = $a_id;
381    }
382    public function getId()
383    {
384        return $this->id;
385    }
386    public function setForumId($a_forum_id)
387    {
388        $this->forum_id = $a_forum_id;
389    }
390    public function getForumId()
391    {
392        return $this->forum_id;
393    }
394    public function setThreadId($a_thread_id)
395    {
396        $this->thread_id = $a_thread_id;
397    }
398    public function getThreadId()
399    {
400        return $this->thread_id;
401    }
402    public function setDisplayUserId($a_user_id)
403    {
404        $this->display_user_id = $a_user_id;
405    }
406    public function getDisplayUserId()
407    {
408        return $this->display_user_id;
409    }
410    public function setUserAlias($a_user_alias)
411    {
412        $this->user_alias = $a_user_alias;
413    }
414    public function getUserAlias()
415    {
416        return $this->user_alias;
417    }
418    public function setSubject($a_subject)
419    {
420        $this->subject = $a_subject;
421    }
422    public function getSubject()
423    {
424        return $this->subject;
425    }
426    public function setMessage($a_message)
427    {
428        $this->message = $a_message;
429    }
430    public function getMessage()
431    {
432        return $this->message;
433    }
434    public function setCreateDate($a_createdate)
435    {
436        $this->createdate = $a_createdate;
437    }
438    public function getCreateDate()
439    {
440        return $this->createdate;
441    }
442    public function setChangeDate($a_changedate)
443    {
444        $this->changedate = $a_changedate;
445    }
446    public function getChangeDate()
447    {
448        return $this->changedate;
449    }
450    public function setUpdateUserId($a_user_id_update)
451    {
452        $this->user_id_update = $a_user_id_update;
453    }
454    public function getUpdateUserId()
455    {
456        return $this->user_id_update;
457    }
458    public function setCensorship($a_censorship)
459    {
460        $this->censored = $a_censorship;
461    }
462    public function isCensored()
463    {
464        return $this->censored == 1 ? true : false;
465    }
466    public function setCensorshipComment($a_comment)
467    {
468        $this->censorship_comment = $a_comment;
469    }
470    public function getCensorshipComment()
471    {
472        return $this->censorship_comment;
473    }
474    public function setNotification($a_notification)
475    {
476        $this->notification = $a_notification;
477    }
478    public function isNotificationEnabled()
479    {
480        return $this->notification == 1 ? true : false;
481    }
482    public function setImportName($a_import_name)
483    {
484        $this->import_name = $a_import_name;
485    }
486    public function getImportName()
487    {
488        return $this->import_name;
489    }
490    public function setStatus($a_status)
491    {
492        $this->status = $a_status;
493    }
494    public function isActivated()
495    {
496        return $this->status == 1 ? true : false;
497    }
498    public function setTreeId($a_tree_id)
499    {
500        $this->tree_id = $a_tree_id;
501    }
502    public function getTreeId()
503    {
504        return $this->tree_id;
505    }
506    public function setParentId($a_parent_id)
507    {
508        $this->parent_id = $a_parent_id;
509    }
510
511    public function setIsRead($a_is_read)
512    {
513        $this->post_read = $a_is_read;
514    }
515
516    public function getIsRead()
517    {
518        return $this->post_read;
519    }
520
521    public function getParentId()
522    {
523        return $this->parent_id;
524    }
525    public function setLft($a_lft)
526    {
527        $this->lft = $a_lft;
528    }
529    public function getLft()
530    {
531        return $this->lft;
532    }
533    public function setRgt($a_rgt)
534    {
535        $this->rgt = $a_rgt;
536    }
537    public function getRgt()
538    {
539        return $this->rgt;
540    }
541    public function setDepth($a_depth)
542    {
543        $this->depth = $a_depth;
544    }
545    public function getDepth()
546    {
547        return $this->depth;
548    }
549    public function setThread(ilForumTopic $thread)
550    {
551        $this->objThread = $thread;
552    }
553    public function getThread()
554    {
555        return $this->objThread;
556    }
557
558    /**
559     * @param int $pos_author_id
560     */
561    public function setPosAuthorId($pos_author_id)
562    {
563        $this->pos_author_id = $pos_author_id;
564    }
565
566    /**
567     * @return int
568     */
569    public function getPosAuthorId()
570    {
571        return $this->pos_author_id;
572    }
573    /**
574     * @return int|null
575     */
576    public function getIsAuthorModerator()
577    {
578        return $this->is_author_moderator;
579    }
580
581    /**
582     * @param int|null
583     */
584    public function setIsAuthorModerator($is_author_moderator)
585    {
586        $this->is_author_moderator = $is_author_moderator;
587    }
588
589    /**
590     * @return string
591     */
592    public function getCensoredDate()
593    {
594        return $this->censored_date;
595    }
596
597    /**
598     * @return string
599     */
600    public function getPostActivationDate()
601    {
602        return $this->post_activation_date;
603    }
604
605    /**
606     * @param string $post_activation_date
607     */
608    public function setPostActivationDate($post_activation_date)
609    {
610        $this->post_activation_date = $post_activation_date;
611    }
612
613    /**
614     * @param string $censored_date
615     */
616    public function setCensoredDate($censored_date)
617    {
618        $this->censored_date = $censored_date;
619    }
620
621    /**
622     * @param $row
623     */
624    public function assignData($row)
625    {
626        $this->setUserAlias($row['pos_usr_alias']);
627        $this->setSubject($row['pos_subject']);
628        $this->setCreateDate($row['pos_date']);
629        $this->setMessage($row['pos_message']);
630        $this->setForumId($row['pos_top_fk']);
631        $this->setThreadId($row['pos_thr_fk']);
632        $this->setChangeDate($row['pos_update']);
633        $this->setUpdateUserId($row['update_user']);
634        $this->setCensorship($row['pos_cens']);
635        $this->setCensoredDate($row['pos_cens_date']);
636        $this->setCensorshipComment($row['pos_cens_com']);
637        $this->setNotification($row['notify']);
638        $this->setImportName($row['import_name']);
639        $this->setStatus($row['pos_status']);
640        $this->setTreeId($row['fpt_pk']);
641        $this->setParentId($row['parent_pos']);
642        $this->setLft($row['lft']);
643        $this->setRgt($row['rgt']);
644        $this->setDepth($row['depth']);
645        $this->setIsRead($row['post_read']);
646        $this->setDisplayUserId($row['pos_display_user_id']);
647        $this->setPosAuthorId($row['pos_author_id']);
648        $this->setIsAuthorModerator($row['is_author_moderator']);
649    }
650
651    /**
652     * @param int $sourceThreadId
653     * @param int $targetThreadId
654     * @param int[] $excludedPostIds
655     */
656    public static function mergePosts(int $sourceThreadId, int $targetThreadId, array $excludedPostIds = [])
657    {
658        global $DIC;
659        $ilDB = $DIC->database();
660
661        $conditions = ['pos_thr_fk = ' . $ilDB->quote($sourceThreadId, 'integer')];
662        if ($excludedPostIds !== []) {
663            $conditions[] = $ilDB->in('pos_pk', $excludedPostIds, true, 'integer');
664        }
665
666        $ilDB->manipulateF(
667            'UPDATE frm_posts SET pos_thr_fk = %s WHERE ' . implode(' AND ', $conditions),
668            ['integer',],
669            [$targetThreadId,]
670        );
671    }
672}
673