Passed
Push — master ( 2338dd...fbaf94 )
by Julito
09:45
created

getPostStatus()   C

Complexity

Conditions 12
Paths 289

Size

Total Lines 66
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 46
nc 289
nop 3
dl 0
loc 66
rs 5.0208
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Course;
6
use Chamilo\CoreBundle\Entity\GradebookLink;
7
use Chamilo\CoreBundle\Entity\User;
8
use Chamilo\CoreBundle\Framework\Container;
9
use Chamilo\CourseBundle\Entity\CForum;
10
use Chamilo\CourseBundle\Entity\CForumAttachment;
11
use Chamilo\CourseBundle\Entity\CForumCategory;
12
use Chamilo\CourseBundle\Entity\CForumNotification;
13
use Chamilo\CourseBundle\Entity\CForumPost;
14
use Chamilo\CourseBundle\Entity\CForumThread;
15
use Chamilo\CourseBundle\Entity\CGroup;
16
use Chamilo\CourseBundle\Entity\CLp;
17
use Chamilo\CourseBundle\Entity\CLpItem;
18
use ChamiloSession as Session;
19
use Doctrine\Common\Collections\Criteria;
20
use Symfony\Component\HttpFoundation\File\UploadedFile;
21
22
/**
23
 * These files are a complete rework of the forum. The database structure is
24
 * based on phpBB but all the code is rewritten. A lot of new functionalities
25
 * are added:
26
 * - forum categories and forums can be sorted up or down, locked or made invisible
27
 * - consistent and integrated forum administration
28
 * - forum options:     are students allowed to edit their post?
29
 *                         moderation of posts (approval)
30
 *                         reply only forums (students cannot create new threads)
31
 *                         multiple forums per group
32
 * - sticky messages
33
 * - new view option: nested view
34
 * - quoting a message.
35
 *
36
 * @todo convert into a class
37
 */
38
39
function handleForum($url)
40
{
41
    $id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : null;
42
43
    if (api_is_allowed_to_edit(false, true)) {
44
        //if is called from a learning path lp_id
45
        $lp_id = isset($_REQUEST['lp_id']) ? (int) $_REQUEST['lp_id'] : null;
46
        $content = $_REQUEST['content'] ?? '';
47
        $action = $_REQUEST['action'] ?? null;
48
        $repo = null;
49
        switch ($content) {
50
            case 'forumcategory':
51
                $repo = Container::getForumCategoryRepository();
52
                break;
53
            case 'forum':
54
                $repo = Container::getForumRepository();
55
                break;
56
            case 'thread':
57
                $repo = Container::getForumThreadRepository();
58
                break;
59
        }
60
61
        $resource = null;
62
        if ($repo && $id) {
63
            $resource = $repo->find($id);
64
        }
65
66
        switch ($action) {
67
            case 'add_forum':
68
                $formContent = forumForm(null, $lp_id);
69
70
                return $formContent;
71
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
72
            case 'edit_forum':
73
                $repo = Container::getForumRepository();
74
                $resource = $repo->find($id);
75
                $formContent = forumForm($resource, $lp_id);
76
77
                return $formContent;
78
                break;
79
            case 'add_category':
80
                $formContent = show_add_forumcategory_form([], $lp_id);
81
82
                return $formContent;
83
                break;
84
            case 'edit_category':
85
                $repo = Container::getForumCategoryRepository();
86
                $category = $repo->find($id);
87
                $formContent = editForumCategoryForm($category);
88
89
                return $formContent;
90
                break;
91
            case 'notify':
92
                if (0 != api_get_session_id() &&
93
                    false == api_is_allowed_to_session_edit(false, true)
94
                ) {
95
                    api_not_allowed();
96
                }
97
                $message = set_notification($content, $id);
98
                Display::addFlash(Display::return_message($message, 'confirm', false));
99
100
                header('Location: '.$url);
101
                exit;
102
                break;
103
            case 'lock':
104
            case 'unlock':
105
                if (null !== $resource) {
106
                    if ('lock' === $action) {
107
                        $locked = 1;
108
                        $message = get_lang('Locked: students can no longer post new messages in this forum category, forum or thread but they can still read the messages that were already posted');
109
                    } else {
110
                        $locked = 0;
111
                        $message = get_lang('Unlocked: learners can post new messages in this forum category, forum or thread');
112
                    }
113
114
                    $resource->setLocked($locked);
115
                    $repo->update($resource);
116
117
                    Display::addFlash(
118
                        Display::return_message($message, 'confirmation', false)
119
                    );
120
                }
121
122
                header('Location: '.$url);
123
                exit;
124
                break;
125
            case 'move':
126
                move_up_down($content, $_REQUEST['direction'] ?? '', $id);
127
                header('Location: '.$url);
128
                exit;
129
                break;
130
            case 'move_thread':
131
                $message = move_thread_form();
132
133
                return $message;
134
                break;
135
            case 'visible':
136
            case 'invisible':
137
                if (null !== $resource) {
138
                    if ('visible' === $action) {
139
                        $repo->setVisibilityPublished($resource);
140
                    } else {
141
                        $repo->setVisibilityPending($resource);
142
                    }
143
144
                    if ('visible' === $action) {
145
                        handle_mail_cue($content, $id);
146
                    }
147
148
                    Display::addFlash(
149
                        Display::return_message(get_lang('Updated'), 'confirmation', false)
150
                    );
151
                }
152
                header('Location: '.$url);
153
                exit;
154
                break;
155
            case 'delete_category':
156
                if ($resource) {
157
                    $repo->delete($resource);
158
159
                    Display::addFlash(
160
                        Display::return_message(get_lang('Forum category deleted'), 'confirmation', false)
161
                    );
162
                }
163
                header('Location: '.$url);
164
                exit;
165
                break;
166
            case 'delete_forum':
167
                if ($resource) {
168
                    $resource = Container::getForumRepository()->find($id);
169
                    $repo->delete($resource);
170
                    Display::addFlash(Display::return_message(get_lang('Forum deleted'), 'confirmation', false));
171
                }
172
173
                header('Location: '.$url);
174
                exit;
175
                break;
176
            case 'delete_thread':
177
                $locked = api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD);
178
                if ($resource && false === $locked) {
179
                    $repo->delete($resource);
180
                    SkillModel::deleteSkillsFromItem($id, ITEM_TYPE_FORUM_THREAD);
181
                    $link_info = GradebookUtils::isResourceInCourseGradebook(
182
                        api_get_course_id(),
183
                        5,
184
                        $id,
185
                        api_get_session_id()
186
                    );
187
188
                    if (false !== $link_info) {
189
                        $link_id = $link_info['id'];
190
                        GradebookUtils::remove_resource_from_course_gradebook($link_id);
191
                    }
192
                    Display::addFlash(Display::return_message(get_lang('Thread deleted'), 'confirmation', false));
193
                }
194
195
                header('Location: '.$url);
196
                exit;
197
                break;
198
        }
199
    }
200
}
201
202
/**
203
 * This function displays the form that is used to add a forum category.
204
 *
205
 * @param int $lp_id Learning path ID
206
 *
207
 * @return string
208
 *
209
 * @author Patrick Cool <[email protected]>, Ghent University
210
 * @author Juan Carlos Raña Trabado (return to lp_id)
211
 *
212
 * @version may 2011, Chamilo 1.8.8
213
 */
214
function show_add_forumcategory_form($lp_id)
215
{
216
    $form = new FormValidator(
217
        'forumcategory',
218
        'post',
219
        'index.php?'.api_get_cidreq().'&action=add_category'
220
    );
221
    // hidden field if from learning path
222
    $form->addHidden('lp_id', $lp_id);
223
    $form->addHidden('action', 'add_category');
224
    // Setting the form elements.
225
    $form->addHeader(get_lang('Add forum category'));
226
    $form->addText('forum_category_title', get_lang('Title'), true, ['autofocus']);
227
    $form->addHtmlEditor(
228
        'forum_category_comment',
229
        get_lang('Description'),
230
        false,
231
        false,
232
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
233
    );
234
235
    $extraField = new ExtraField('forum_category');
236
    $extraField->addElements(
237
        $form,
238
        null,
239
        [], //exclude
240
        false, // filter
241
        false, // tag as select
242
        [], //show only fields
243
        [], // order fields
244
        [] // extra data
245
    );
246
247
    $form->addButtonCreate(get_lang('Create category'), 'SubmitForumCategory');
248
249
    // Setting the rules.
250
    $form->addRule('forum_category_title', get_lang('Required field'), 'required');
251
252
    // The validation or display
253
    if ($form->validate()) {
254
        $check = Security::check_token('post');
255
        if ($check) {
256
            $values = $form->exportValues();
257
            store_forumcategory($values);
258
        }
259
        Security::clear_token();
260
    } else {
261
        $token = Security::get_token();
262
        $form->addElement('hidden', 'sec_token');
263
        $form->setConstants(['sec_token' => $token]);
264
265
        return $form->returnForm();
266
    }
267
}
268
269
function forumForm(CForum $forum = null, $lp_id)
270
{
271
    $_course = api_get_course_info();
272
    // The header for the form
273
    $form_title = get_lang('Add a forum');
274
    $action = 'add_forum';
275
    $id = 0;
276
    if ($forum) {
277
        $id = $forum->getIid();
278
        $action = 'edit_forum';
279
        $form_title = get_lang('Edit forum');
280
    }
281
282
    $form = new FormValidator('forumcategory', 'post', 'index.php?'.api_get_cidreq().'&action='.$action.'&id='.$id);
283
    $form->addHidden('action', $action);
284
    $form->addHeader($form_title);
285
286
    // We have a hidden field if we are editing.
287
    if ($forum) {
288
        $form->addHidden('forum_id', $id);
289
    }
290
    $lp_id = (int) $lp_id;
291
292
    // hidden field if from learning path
293
    $form->addHidden('lp_id', $lp_id);
294
295
    // The title of the forum
296
    $form->addText('forum_title', get_lang('Title'), true, ['autofocus']);
297
298
    // The comment of the forum.
299
    $form->addHtmlEditor(
300
        'forum_comment',
301
        get_lang('Description'),
302
        false,
303
        false,
304
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
305
    );
306
307
    // Dropdown list: Forum categories
308
    $forum_categories = get_forum_categories();
309
    $forum_categories_titles = [];
310
    foreach ($forum_categories as $value) {
311
        $forum_categories_titles[$value->getIid()] = $value->getCatTitle();
312
    }
313
    $form->addSelect(
314
        'forum_category',
315
        get_lang('Create in category'),
316
        $forum_categories_titles
317
    );
318
    $form->applyFilter('forum_category', 'html_filter');
319
320
    if (COURSE_VISIBILITY_OPEN_WORLD == $_course['visibility']) {
321
        // This is for horizontal
322
        $group = [];
323
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('Yes'), 1);
324
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('No'), 0);
325
        $form->addGroup($group, 'allow_anonymous_group', get_lang('Allow anonymous posts?'));
326
    }
327
328
    $form->addButtonAdvancedSettings('advanced_params');
329
    $form->addHtml('<div id="advanced_params_options" style="display:none">');
330
331
    $form->addDateTimePicker(
332
        'start_time',
333
        [
334
            get_lang('Public access (access authorized to any member of the course)ation date'),
335
            get_lang('Public access (access authorized to any member of the course)ation dateComment'),
336
        ],
337
        ['id' => 'start_time']
338
    );
339
340
    $form->addDateTimePicker(
341
        'end_time',
342
        [get_lang('Closing date'), get_lang('Closing dateComment')],
343
        ['id' => 'end_time']
344
    );
345
346
    $form->addRule(
347
        ['start_time', 'end_time'],
348
        get_lang('Start date must be before the end date'),
349
        'compare_datetime_text',
350
        '< allow_empty'
351
    );
352
353
    $group = [];
354
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('Yes'), 1);
355
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('No'), 0);
356
    $form->addGroup($group, 'moderated', get_lang('Moderated forum'));
357
358
    $group = [];
359
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('Yes'), 1);
360
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('No'), 0);
361
    $form->addGroup($group, 'students_can_edit_group', get_lang('Can learners edit their own posts?'));
362
363
    $group = [];
364
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Approval'), 1);
365
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Direct'), 0);
366
367
    $group = [];
368
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('Yes'), 1);
369
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('No'), 0);
370
371
    $group = [];
372
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('Yes'), 1);
373
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('No'), 0);
374
    $form->addGroup($group, 'allow_new_threads_group', get_lang('Allow users to start new threads'));
375
376
    $group = [];
377
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Flat'), 'flat');
378
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Threaded'), 'threaded');
379
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Nested'), 'nested');
380
    $form->addGroup($group, 'default_view_type_group', get_lang('Default view type'));
381
382
    // Drop down list: Groups
383
    $groups = GroupManager::get_group_list();
384
    $groups_titles[0] = get_lang('Not a group forum');
385
    foreach ($groups as $value) {
386
        $groups_titles[$value['iid']] = $value['name'];
387
    }
388
    $form->addSelect('group_forum', get_lang('For Group'), $groups_titles);
389
390
    // Public or private group forum
391
    $group = [];
392
    $group[] = $form->createElement(
393
        'radio',
394
        'public_private_group_forum',
395
        null,
396
        get_lang('Public access (access authorized to any member of the course)'),
397
        'public'
398
    );
399
    $group[] = $form->createElement(
400
        'radio',
401
        'public_private_group_forum',
402
        null,
403
        get_lang('Private access (access authorized to group members only)'),
404
        'private'
405
    );
406
    $form->addGroup(
407
        $group,
408
        'public_private_group_forum_group',
409
        get_lang(
410
            'Public access (access authorized to any member of the course)Private access (access authorized to group members only)GroupForum'
411
        )
412
    );
413
414
    // Forum image
415
    $form->addProgress();
416
417
    $form->addElement('html', '</div>');
418
419
    // The OK button
420
    if ($forum) {
421
        $form->addButtonUpdate(get_lang('Edit forum'), 'SubmitForum');
422
    } else {
423
        $form->addButtonCreate(get_lang('Create forum'), 'SubmitForum');
424
    }
425
426
    // setting the rules
427
    $form->addRule('forum_title', get_lang('Required field'), 'required');
428
    $form->addRule('forum_category', get_lang('Required field'), 'required');
429
430
    // Settings the defaults
431
    if (null === $forum) {
432
        $defaults['moderated']['moderated'] = 0;
433
        $defaults['allow_anonymous_group']['allow_anonymous'] = 0;
434
        $defaults['students_can_edit_group']['students_can_edit'] = 0;
435
        $defaults['approval_direct_group']['approval_direct'] = 0;
436
        $defaults['allow_attachments_group']['allow_attachments'] = 1;
437
        $defaults['allow_new_threads_group']['allow_new_threads'] = 1;
438
        $defaults['default_view_type_group']['default_view_type'] = api_get_setting('default_forum_view');
439
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = 'public';
440
        if (isset($_GET['forumcategory'])) {
441
            $defaults['forum_category'] = Security::remove_XSS($_GET['forumcategory']);
442
        }
443
    } else {
444
        // the default values when editing = the data in the table
445
        $defaults['forum_id'] = $forum->getIid();
446
        $defaults['forum_title'] = prepare4display($forum->getForumTitle());
447
        $defaults['forum_comment'] = prepare4display($forum->getForumComment());
448
        $defaults['start_time'] = api_get_local_time($forum->getStartTime());
449
        $defaults['end_time'] = api_get_local_time($forum->getEndTime());
450
        $defaults['moderated']['moderated'] = $forum->isModerated();
451
        $defaults['forum_category'] = $forum->getForumCategory()->getIid();
452
        $defaults['allow_anonymous_group']['allow_anonymous'] = $forum->getAllowAnonymous();
453
        $defaults['students_can_edit_group']['students_can_edit'] = $forum->getAllowEdit();
454
        $defaults['approval_direct_group']['approval_direct'] = $forum->getApprovalDirectPost();
455
        $defaults['allow_attachments_group']['allow_attachments'] = $forum->getAllowAttachments();
456
        $defaults['allow_new_threads_group']['allow_new_threads'] = $forum->getAllowNewThreads();
457
        $defaults['default_view_type_group']['default_view_type'] = $forum->getDefaultView();
458
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = $forum->getForumGroupPublicPrivate();
459
        $defaults['group_forum'] = $forum->getForumOfGroup();
460
    }
461
462
    $form->setDefaults($defaults);
463
    // Validation or display
464
    if ($form->validate()) {
465
        $check = Security::check_token('post');
466
        if ($check) {
467
            $values = $form->getSubmitValues();
468
            $forumId = store_forum($values, '', true);
469
            if ($forumId) {
470
                // SkillModel::saveSkills($form, ITEM_TYPE_FORUM, $forumId);
471
                if (isset($values['forum_id'])) {
472
                    Display::addFlash(Display::return_message(get_lang('The forum has been modified'), 'confirmation'));
473
                } else {
474
                    Display::addFlash(Display::return_message(get_lang('The forum has been added'), 'confirmation'));
475
                }
476
            }
477
            $url = api_get_path(WEB_CODE_PATH).'forum/index.php?'.api_get_cidreq();
478
            header('Location: '.$url);
479
            exit;
480
        }
481
        Security::clear_token();
482
    } else {
483
        $token = Security::get_token();
484
        $form->addElement('hidden', 'sec_token');
485
        $form->setConstants(['sec_token' => $token]);
486
487
        return $form->returnForm();
488
    }
489
}
490
491
/**
492
 * This function deletes the forum image if exists.
493
 *
494
 * @param int $forum_id forum id
495
 *
496
 * @return bool true if success
497
 *
498
 * @author Julio Montoya <[email protected]>
499
 *
500
 * @version february 2006, dokeos 1.8
501
 */
502
function delete_forum_image($forum_id)
503
{
504
    throw new Exception('delete_forum_image');
505
    /*$table_forums = Database::get_course_table(TABLE_FORUM);
506
    $course_id = api_get_course_int_id();
507
    $forum_id = (int) $forum_id;
508
509
    $sql = "SELECT forum_image FROM $table_forums
510
            WHERE forum_id = $forum_id AND c_id = $course_id";
511
    $result = Database::query($sql);
512
    $row = Database::fetch_array($result);
513
    if ('' != $row['forum_image']) {
514
        $file = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/forum/images/'.$row['forum_image'];
515
        if (file_exists($file)) {
516
            unlink($file);
517
        }
518
519
        return true;
520
    } else {
521
        return false;
522
    }*/
523
}
524
525
function editForumCategoryForm(CForumCategory $category)
526
{
527
    $categoryId = $category->getIid();
528
    $form = new FormValidator(
529
        'forumcategory',
530
        'post',
531
        'index.php?action=edit_category&'.api_get_cidreq().'&id='.$categoryId
532
    );
533
    // Setting the form elements.
534
    $form->addElement('header', '', get_lang('Edit forumCategory'));
535
536
    $form->addElement('hidden', 'action', 'edit_category');
537
    $form->addElement('hidden', 'forum_category_id');
538
    $form->addElement('text', 'forum_category_title', get_lang('Title'));
539
540
    $form->addElement(
541
        'html_editor',
542
        'forum_category_comment',
543
        get_lang('Comment'),
544
        null,
545
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
546
    );
547
548
    $extraField = new ExtraField('forum_category');
549
    $returnParams = $extraField->addElements(
550
        $form,
551
        $categoryId,
552
        [], //exclude
553
        false, // filter
554
        false, // tag as select
555
        [], //show only fields
556
        [], // order fields
557
        [] // extra data
558
    );
559
560
    $form->addButtonUpdate(get_lang('Edit category'), 'SubmitEdit forumCategory');
561
562
    // Setting the default values.
563
    $defaultvalues['forum_category_id'] = $categoryId;
564
    $defaultvalues['forum_category_title'] = $category->getCatTitle();
565
    $defaultvalues['forum_category_comment'] = $category->getCatComment();
566
    $form->setDefaults($defaultvalues);
567
568
    // Setting the rules.
569
    $form->addRule('forum_category_title', get_lang('Required field'), 'required');
570
571
    // Validation or display
572
    if ($form->validate()) {
573
        $check = Security::check_token('post');
574
        if ($check) {
575
            $values = $form->exportValues();
576
            store_forumcategory($values);
577
        }
578
        Security::clear_token();
579
    } else {
580
        $token = Security::get_token();
581
        $form->addElement('hidden', 'sec_token');
582
        $form->setConstants(['sec_token' => $token]);
583
584
        return $form->returnForm();
585
    }
586
}
587
588
/**
589
 * This function stores the forum category in the database.
590
 * The new category is added to the end.
591
 *
592
 * @param array $values
593
 * @param array $courseInfo
594
 * @param bool  $showMessage
595
 *
596
 * @return CForumCategory
597
 */
598
function store_forumcategory($values, $courseInfo = [], $showMessage = true)
599
{
600
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
601
    $course_id = $courseInfo['real_id'];
602
    // Find the max cat_order. The new forum category is added at the end => max cat_order + &
603
    /*$sql = "SELECT MAX(cat_order) as sort_max
604
            FROM $table_categories
605
            WHERE c_id = $course_id";
606
    $result = Database::query($sql);
607
    $row = Database::fetch_array($result);
608
    $new_max = $row['sort_max'] + 1;*/
609
    $new_max = 1;
610
    $session_id = api_get_session_id();
611
    $clean_cat_title = $values['forum_category_title'];
612
    $last_id = null;
613
    $repo = Container::getForumCategoryRepository();
614
615
    $message = '';
616
    if (isset($values['forum_category_id'])) {
617
        /** @var CForumCategory $category */
618
        $category = $repo->find($values['forum_category_id']);
619
        $category
620
            ->setCatComment($values['forum_category_comment'] ?? '')
621
            ->setCatTitle($values['forum_category_title'])
622
        ;
623
        $repo->update($category);
624
        $message = get_lang('The forum category has been modified');
625
626
        $logInfo = [
627
            'tool' => TOOL_FORUM,
628
            'action' => 'update-forumcategory',
629
            'action_details' => 'forumcategory',
630
            'info' => $clean_cat_title,
631
        ];
632
        Event::registerLog($logInfo);
633
634
        $values['item_id'] = $values['forum_category_id'];
635
    } else {
636
        $course = api_get_course_entity($course_id);
637
        $session = api_get_session_entity($session_id);
638
639
        $category = new CForumCategory();
640
        $category
641
            ->setCatTitle($clean_cat_title)
642
            ->setCatComment($values['forum_category_comment'] ?? '')
643
            ->setCatOrder($new_max)
644
            ->setParent($course)
645
            ->addCourseLink($course, $session)
646
        ;
647
        $repo->create($category);
648
649
        $last_id = $category->getIid();
650
        if ($last_id > 0) {
651
            $message = get_lang('The forum category has been added');
652
        }
653
654
        $logInfo = [
655
            'tool' => TOOL_FORUM,
656
            'action' => 'new-forumcategory',
657
            'action_details' => 'forumcategory',
658
            'info' => $clean_cat_title,
659
        ];
660
        Event::registerLog($logInfo);
661
662
        $values['item_id'] = $last_id;
663
    }
664
665
    $extraFieldValue = new ExtraFieldValue('forum_category');
666
    $extraFieldValue->saveFieldValues($values);
667
668
    if ($showMessage) {
669
        Display::addFlash(Display::return_message($message, 'confirmation'));
670
    }
671
672
    return $category;
673
}
674
675
/**
676
 * This function stores the forum in the database. The new forum is added to the end.
677
 *
678
 * @param array $values
679
 * @param array $courseInfo
680
 * @param bool  $returnId
681
 *
682
 * @return string language variable
683
 */
684
function store_forum($values, $courseInfo = [], $returnId = false)
685
{
686
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
687
    $courseId = $courseInfo['real_id'];
688
    $session_id = api_get_session_id();
689
690
    // Find the max forum_order for the given category. The new forum is added at the end => max cat_order + &
691
    if (null === $values['forum_category']) {
692
        $new_max = null;
693
    } else {
694
        /*$sql = "SELECT MAX(forum_order) as sort_max
695
                FROM $table_forums
696
                WHERE
697
                    c_id = $courseId AND
698
                    forum_category='".Database::escape_string($values['forum_category'])."'";
699
        $result = Database::query($sql);
700
        $row = Database::fetch_array($result);
701
        $new_max = $row['sort_max'] + 1;*/
702
    }
703
704
    $new_max = 0;
705
706
    // Forum images
707
    $has_attachment = false;
708
    $image_moved = true;
709
    if (!empty($_FILES['picture']['name'])) {
710
        $upload_ok = process_uploaded_file($_FILES['picture']);
711
        $has_attachment = true;
712
    }
713
714
    // Remove existing picture if it was requested.
715
    if (!empty($_POST['remove_picture'])) {
716
        delete_forum_image($values['forum_id']);
717
    }
718
719
    $new_file_name = '';
720
    if (isset($upload_ok)) {
721
        if ($has_attachment) {
722
            throw new Exception('$has_attachment');
723
            /*$course_dir = $courseInfo['path'].'/upload/forum/images';
724
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
725
            $updir = $sys_course_path.$course_dir;
726
            // Try to add an extension to the file if it hasn't one.
727
            $new_file_name = add_ext_on_mime(
728
                Database::escape_string($_FILES['picture']['name']),
729
                $_FILES['picture']['type']
730
            );
731
            if (!filter_extension($new_file_name)) {
732
                //Display::addFlash(Display::return_message(get_lang('File upload failed: this file extension or file type is prohibited'), 'error'));
733
                $image_moved = false;
734
            } else {
735
                $file_extension = explode('.', $_FILES['picture']['name']);
736
                $file_extension = strtolower($file_extension[count($file_extension) - 1]);
737
                $new_file_name = uniqid('').'.'.$file_extension;
738
                $new_path = $updir.'/'.$new_file_name;
739
                $result = @move_uploaded_file($_FILES['picture']['tmp_name'], $new_path);
740
                // Storing the attachments if any
741
                if ($result) {
742
                    $image_moved = true;
743
                }
744
            }*/
745
        }
746
    }
747
748
    $repo = Container::getForumRepository();
749
750
    if (!isset($values['forum_id'])) {
751
        $forum = new CForum();
752
        $forum->setForumOrder($new_max ?? null);
753
    } else {
754
        /** @var CForum $forum */
755
        $forum = $repo->find($values['forum_id']);
756
    }
757
758
    $forumCategory = null;
759
    if (!empty($values['forum_category'])) {
760
        $repoForumCategory = Container::getForumCategoryRepository();
761
        $forumCategory = $repoForumCategory->find($values['forum_category']);
762
    }
763
764
    $lpId = $values['lp_id'] ?? 0;
765
    $lpRepo = Container::getLpRepository();
766
    $lp = null;
767
    if (!empty($lpId)) {
768
        /** @var CLp $lp */
769
        $lp = $lpRepo->find($lpId);
770
    }
771
772
    $forum
773
        ->setForumTitle($values['forum_title'])
774
        ->setForumComment($values['forum_comment'] ?? '')
775
        ->setForumCategory($forumCategory)
776
        ->setAllowAnonymous($values['allow_anonymous_group']['allow_anonymous'] ?? 0)
777
        ->setAllowEdit($values['students_can_edit_group']['students_can_edit'] ?? 0)
778
        ->setApprovalDirectPost((string) ($values['approval_direct_group']['approval_direct'] ?? '0'))
779
        ->setAllowAttachments($values['allow_attachments_group']['allow_attachments'] ?? 0)
780
        ->setAllowNewThreads((int) ($values['allow_new_threads_group']['allow_new_threads'] ?? 0))
781
        ->setDefaultView($values['default_view_type_group']['default_view_type'] ?? '')
782
        ->setForumOfGroup((string) ($values['group_forum'] ?? ''))
783
        ->setForumGroupPublicPrivate($values['public_private_group_forum_group']['public_private_group_forum'] ?? '')
784
        ->setModerated((bool) ($values['moderated']['moderated'] ?? false))
785
        ->setStartTime(!empty($values['start_time']) ? api_get_utc_datetime($values['start_time'], true, true) : null)
786
        ->setEndTime(!empty($values['end_time']) ? api_get_utc_datetime($values['end_time'], true, true) : null)
787
        ->setLp($lp)
788
    ;
789
790
    $course = api_get_course_entity($courseId);
791
    $session = api_get_session_entity($session_id);
792
793
    if (isset($values['forum_id'])) {
794
        // Update.
795
        $repo->update($forum);
796
797
        if (isset($upload_ok)) {
798
            if ($has_attachment) {
799
                //$params['forum_image'] = $new_file_name;
800
            }
801
        }
802
803
        if (isset($values['remove_picture']) && 1 == $values['remove_picture']) {
804
            /*$params['forum_image'] = '';
805
            delete_forum_image($values['forum_id']);*/
806
        }
807
808
        // Move groups from one group to another
809
        if (isset($values['group_forum']) && false) {
810
            $forumData = get_forums($values['forum_id']);
811
            $currentGroupId = $forumData['forum_of_group'];
812
        }
813
814
        $return_message = get_lang('The forum has been modified');
815
        $forumId = $forum->getIid();
816
817
        $logInfo = [
818
            'tool' => TOOL_FORUM,
819
            'tool_id' => $values['forum_id'],
820
            'action' => 'update-forum',
821
            'action_details' => 'forum',
822
            'info' => $values['forum_title'],
823
        ];
824
        Event::registerLog($logInfo);
825
    } else {
826
        if ($image_moved) {
827
            $new_file_name = isset($new_file_name) ? $new_file_name : '';
828
        }
829
        $forum
830
            ->setParent($forumCategory)
831
            ->addCourseLink($course, $session);
832
        $repo->create($forum);
833
834
        $forumId = $forum->getIid();
835
        if ($forumId > 0) {
836
            $courseCode = $courseInfo['code'];
837
            $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications');
838
839
            $status = STUDENT;
840
            if (!empty($session_id)) {
841
                $status = 0;
842
            }
843
            if (1 === $subscribe) {
844
                $userList = CourseManager::get_user_list_from_course_code(
845
                    $courseCode,
846
                    $session_id,
847
                    null,
848
                    null,
849
                    $status
850
                );
851
                foreach ($userList as $userInfo) {
852
                    set_notification('forum', $forumId, false, $userInfo, $courseInfo);
853
                }
854
            }
855
856
            $logInfo = [
857
                'tool' => TOOL_FORUM,
858
                'tool_id' => $forumId,
859
                'action' => 'new-forum',
860
                'action_details' => 'forum',
861
                'info' => $values['forum_title'],
862
            ];
863
            Event::registerLog($logInfo);
864
        }
865
        $return_message = get_lang('The forum has been added');
866
    }
867
868
    if ($returnId) {
869
        return $forumId;
870
    }
871
872
    return $return_message;
873
}
874
875
function deletePost(CForumPost $post)
876
{
877
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
878
    $em = Database::getManager();
879
    if ($post) {
880
        $em
881
            ->createQuery('
882
                UPDATE ChamiloCourseBundle:CForumPost p
883
                SET p.postParent = :parent_of_deleted_post
884
                WHERE
885
                    p.postParent = :post AND
886
                    p.thread = :thread_of_deleted_post AND
887
                    p.forum = :forum_of_deleted_post
888
            ')
889
            ->execute([
890
                'parent_of_deleted_post' => $post->getPostParent(),
891
                'post' => $post->getIid(),
892
                'thread_of_deleted_post' => $post->getThread() ? $post->getThread()->getIid() : 0,
893
                'forum_of_deleted_post' => $post->getForum(),
894
            ]);
895
896
        $attachments = $post->getAttachments();
897
        if (!empty($attachments)) {
898
            foreach ($attachments as $attachment) {
899
                $em->remove($attachment);
900
            }
901
        }
902
903
        $em->remove($post);
904
        $em->flush();
905
    }
906
907
    $last_post_of_thread = check_if_last_post_of_thread($_GET['thread']);
908
909
    if (is_array($last_post_of_thread)) {
910
        // Decreasing the number of replies for this thread and also changing the last post information.
911
        $sql = "UPDATE $table_threads
912
                SET
913
                    thread_replies = thread_replies - 1,
914
                    thread_last_post = ".(int) ($last_post_of_thread['iid']).",
915
                    thread_date='".Database::escape_string($last_post_of_thread['post_date'])."'
916
                WHERE iid = ".(int) ($_GET['thread']);
917
        Database::query($sql);
918
        Display::addFlash(Display::return_message(get_lang('Post has been deleted')));
919
    }
920
    if (!$last_post_of_thread) {
921
        // We deleted the very single post of the thread so we need to delete the entry in the thread table also.
922
        $sql = "DELETE FROM $table_threads
923
                WHERE iid = ".(int) ($_GET['thread']);
924
        Database::query($sql);
925
926
        Display::addFlash(Display::return_message(get_lang('Thread deleted')));
927
    }
928
}
929
930
/**
931
 * This function gets the all information of the last (=most recent) post of the thread
932
 * This can be done by sorting the posts that have the field thread_id=$thread_id and sort them by post_date.
933
 *
934
 * @param int $thread_id id of the thread we want to know the last post of
935
 *
936
 * @return array an array or bool if there is a last post found, false if there is
937
 *               no post entry linked to that thread => thread will be deleted
938
 *
939
 * @author Patrick Cool <[email protected]>, Ghent University
940
 *
941
 * @version february 2006, dokeos 1.8
942
 */
943
function check_if_last_post_of_thread($thread_id)
944
{
945
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
946
    $sql = "SELECT * FROM $table_posts
947
            WHERE thread_id = ".(int) $thread_id.'
948
            ORDER BY post_date DESC';
949
    $result = Database::query($sql);
950
    if (Database::num_rows($result) > 0) {
951
        return Database::fetch_array($result);
952
    }
953
954
    return false;
955
}
956
957
/**
958
 * @param string $content                   Type of content forum category, forum, thread, post
959
 * @param int    $id                        the id of the content we want to make invisible
960
 * @param int    $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
961
 * @param array  $additional_url_parameters
962
 *
963
 * @return string HTML
964
 */
965
function return_visible_invisible_icon(
966
    $content,
967
    $id,
968
    $current_visibility_status,
969
    $additional_url_parameters = []
970
) {
971
    $html = '';
972
    $id = (int) $id;
973
    $current_visibility_status = (int) $current_visibility_status;
974
975
    if (1 == $current_visibility_status) {
976
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
977
        if (is_array($additional_url_parameters)) {
978
            foreach ($additional_url_parameters as $key => $value) {
979
                $html .= $key.'='.$value.'&';
980
            }
981
        }
982
        $html .= 'action=invisible&content='.$content.'&id='.$id.'">'.
983
            Display::return_icon('visible.png', get_lang('MakeInvisible'), [], ICON_SIZE_SMALL).'</a>';
984
    }
985
    if (0 == $current_visibility_status) {
986
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
987
        if (is_array($additional_url_parameters)) {
988
            foreach ($additional_url_parameters as $key => $value) {
989
                $html .= $key.'='.$value.'&';
990
            }
991
        }
992
        $html .= 'action=visible&content='.$content.'&id='.$id.'">'.
993
            Display::return_icon('invisible.png', get_lang('Make Visible'), [], ICON_SIZE_SMALL).'</a>';
994
    }
995
996
    return $html;
997
}
998
999
/**
1000
 * @param $content
1001
 * @param $id
1002
 * @param $current_lock_status
1003
 * @param string $additional_url_parameters
1004
 *
1005
 * @return string
1006
 */
1007
function return_lock_unlock_icon($content, $id, $current_lock_status, $additional_url_parameters = '')
1008
{
1009
    $html = '';
1010
    $id = (int) $id;
1011
    //check if the forum is blocked due
1012
    if ('thread' === $content) {
1013
        if (api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD)) {
1014
            return $html.Display::return_icon(
1015
                    'lock_na.png',
1016
                    get_lang(
1017
                        'This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'
1018
                    ),
1019
                    [],
1020
                    ICON_SIZE_SMALL
1021
                );
1022
        }
1023
    }
1024
    if ('1' == $current_lock_status) {
1025
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1026
        if (is_array($additional_url_parameters)) {
1027
            foreach ($additional_url_parameters as $key => $value) {
1028
                $html .= $key.'='.$value.'&';
1029
            }
1030
        }
1031
        $html .= 'action=unlock&content='.$content.'&id='.$id.'">'.
1032
            Display::return_icon('lock.png', get_lang('Unlock'), [], ICON_SIZE_SMALL).'</a>';
1033
    }
1034
    if ('0' == $current_lock_status) {
1035
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1036
        if (is_array($additional_url_parameters)) {
1037
            foreach ($additional_url_parameters as $key => $value) {
1038
                $html .= $key.'='.$value.'&';
1039
            }
1040
        }
1041
        $html .= 'action=lock&content='.$content.'&id='.$id.'">'.
1042
            Display::return_icon('unlock.png', get_lang('Lock'), [], ICON_SIZE_SMALL).'</a>';
1043
    }
1044
1045
    return $html;
1046
}
1047
1048
/**
1049
 * This function takes care of the display of the up and down icon.
1050
 *
1051
 * @param string $content what is it that we want to make (in)visible: forum category, forum, thread, post
1052
 * @param int    $id      is the id of the item we want to display the icons for
1053
 * @param array  $list    is an array of all the items. All items in this list should have
1054
 *                        an up and down icon except for the first (no up icon) and the last (no down icon)
1055
 *                        The key of this $list array is the id of the item.
1056
 *
1057
 * @return string HTML
1058
 */
1059
function return_up_down_icon($content, $id, $list)
1060
{
1061
    $id = (int) $id;
1062
    $total_items = count($list);
1063
    $position = 0;
1064
    $internal_counter = 0;
1065
    $forumCategory = isset($_GET['forumcategory']) ? Security::remove_XSS($_GET['forumcategory']) : null;
1066
1067
    if (is_array($list)) {
1068
        foreach ($list as $item) {
1069
            $internal_counter++;
1070
            if ($id == $item->getIid()) {
1071
                $position = $internal_counter;
1072
            }
1073
        }
1074
    }
1075
1076
    if ($position > 1) {
1077
        $return_value = '<a
1078
                href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=up&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'"
1079
                title="'.get_lang('Move up').'">'.
1080
            Display::return_icon('up.png', get_lang('Move up'), [], ICON_SIZE_SMALL).'</a>';
1081
    } else {
1082
        $return_value = Display::url(
1083
            Display::return_icon('up_na.png', '-', [], ICON_SIZE_SMALL),
1084
            'javascript:void(0)'
1085
        );
1086
    }
1087
1088
    if ($position < $total_items) {
1089
        $return_value .= '<a
1090
            href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=down&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'"
1091
            title="'.get_lang('Move down').'" >'.
1092
            Display::return_icon('down.png', get_lang('Move down'), [], ICON_SIZE_SMALL).'</a>';
1093
    } else {
1094
        $return_value = Display::url(
1095
            Display::return_icon('down_na.png', '-', [], ICON_SIZE_SMALL),
1096
            'javascript:void(0)'
1097
        );
1098
    }
1099
1100
    return $return_value;
1101
}
1102
1103
/**
1104
 * This function moves a forum or a forum category up or down.
1105
 *
1106
 * @param string $content   is it that we want to make (in)visible: forum category, forum, thread, post
1107
 * @param string $direction we want to move it up or down
1108
 * @param int    $id        id of the content we want to make invisible
1109
 *
1110
 * @return string language variable
1111
 *
1112
 * @todo consider removing the table_item_property calls here but this can
1113
 * prevent unwanted side effects when a forum does not have an entry in
1114
 * the item_property table but does have one in the forum table.
1115
 *
1116
 * @author Patrick Cool <[email protected]>, Ghent University
1117
 *
1118
 * @version february 2006, dokeos 1.8
1119
 */
1120
function move_up_down($content, $direction, $id)
1121
{
1122
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1123
    $table_forums = Database::get_course_table(TABLE_FORUM);
1124
    $course_id = api_get_course_int_id();
1125
    $id = (int) $id;
1126
1127
    // Determine which field holds the sort order.
1128
    if ('forumcategory' === $content) {
1129
        $table = $table_categories;
1130
        $sort_column = 'cat_order';
1131
        $id_column = 'cat_id';
1132
        $sort_column = 'cat_order';
1133
    } elseif ('forum' === $content) {
1134
        $table = $table_forums;
1135
        $sort_column = 'forum_order';
1136
        $id_column = 'forum_id';
1137
        $sort_column = 'forum_order';
1138
        // We also need the forum_category of this forum.
1139
        $sql = "SELECT forum_category FROM $table_forums
1140
                WHERE forum_id = ".$id;
1141
        $result = Database::query($sql);
1142
        $row = Database::fetch_array($result);
1143
        $forum_category = $row['forum_category'];
1144
    } else {
1145
        return false;
1146
    }
1147
1148
    // Determine the need for sorting ascending or descending order.
1149
    if ('down' === $direction) {
1150
        $sort_direction = 'ASC';
1151
    } elseif ('up' === $direction) {
1152
        $sort_direction = 'DESC';
1153
    } else {
1154
        return false;
1155
    }
1156
1157
    // The SQL statement
1158
    if ('forumcategory' === $content) {
1159
        $sql = "SELECT *
1160
                FROM $table_categories forum_categories
1161
                WHERE
1162
                    forum_categories.c_id = $course_id
1163
                ORDER BY forum_categories.cat_order $sort_direction";
1164
    }
1165
    if ('forum' === $content) {
1166
        $sql = "SELECT *
1167
            FROM $table
1168
            WHERE
1169
                c_id = $course_id AND
1170
                forum_category='".Database::escape_string($forum_category)."'
1171
            ORDER BY forum_order $sort_direction";
1172
    }
1173
    // Finding the items that need to be switched.
1174
    $result = Database::query($sql);
1175
    $found = false;
1176
    $next_sort = '';
1177
    $this_sort = '';
1178
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1179
        if ($found) {
1180
            $next_id = $row[$id_column];
1181
            $next_sort = $row[$sort_column];
1182
            $found = false;
1183
        }
1184
        if ($id == $row[$id_column]) {
1185
            $this_id = $id;
1186
            $this_sort = $row[$sort_column];
1187
            $found = true;
1188
        }
1189
    }
1190
1191
    if ('forum' === $content && $next_sort) {
1192
        $repo = Container::getForumRepository();
1193
        /** @var CForum $forum */
1194
        $forum = $repo->find($id);
1195
        $forum->setForumOrder($next_sort);
1196
        $repo->update($forum);
1197
1198
        Display::addFlash(Display::return_message(get_lang('Updated')));
1199
    } else {
1200
        if ($next_sort) {
1201
            $repo = Container::getForumCategoryRepository();
1202
            /** @var CForumCategory $forum */
1203
            $category = $repo->find($id);
1204
            if ($category) {
1205
                $category->setCatOrder($next_sort);
1206
                $repo->update($category);
1207
1208
                Display::addFlash(Display::return_message(get_lang('Updated')));
1209
            }
1210
        }
1211
    }
1212
}
1213
1214
/**
1215
 * Retrieve all the information off the forum categories (or one specific) for the current course.
1216
 * The categories are sorted according to their sorting order (cat_order.
1217
 *
1218
 * @param int $courseId  Optional. The course ID
1219
 * @param int $sessionId Optional. The session ID
1220
 *
1221
 * @return CForumCategory[]
1222
 */
1223
function get_forum_categories($courseId = 0, $sessionId = 0)
1224
{
1225
    $repo = Container::getForumCategoryRepository();
1226
1227
    $course = api_get_course_entity($courseId);
1228
    $session = api_get_session_entity($sessionId);
1229
1230
    $qb = $repo->getResourcesByCourse($course, $session, null, $course->getResourceNode());
1231
1232
    return $qb->getQuery()->getResult();
1233
}
1234
1235
/**
1236
 * This function retrieves all the fora in a given forum category.
1237
 *
1238
 * @param int $categoryId the id of the forum category
1239
 * @param int $courseId   Optional. The course ID
1240
 *
1241
 * @return CForum[] containing all the information about the forums (regardless of their category)
1242
 *
1243
 * @author Patrick Cool <[email protected]>, Ghent University
1244
 *
1245
 * @version february 2006, dokeos 1.8
1246
 */
1247
function get_forums_in_category($categoryId, $courseId = 0)
1248
{
1249
    $repo = Container::getForumRepository();
1250
    $course = api_get_course_entity($courseId);
1251
1252
    $qb = $repo->getResourcesByCourse($course, null);
1253
    $qb
1254
        ->andWhere('resource.forumCategory = :catId')
1255
        ->setParameter('catId', $categoryId)
1256
        ->orderBy('resource.forumOrder')
1257
    ;
1258
1259
    return $qb->getQuery()->getResult();
1260
}
1261
1262
/**
1263
 * Retrieve all the forums (regardless of their category) or of only one.
1264
 * The forums are sorted according to the forum_order.
1265
 * Since it does not take the forum category into account there probably
1266
 * will be two or more forums that have forum_order=1, ...
1267
 *
1268
 * @param bool $includeGroupsForum
1269
 * @param int  $sessionId
1270
 *
1271
 * @return CForum[]
1272
 */
1273
function get_forums(
1274
    $courseId = '',
1275
    $includeGroupsForum = true,
1276
    $sessionId = 0
1277
) {
1278
    $repo = Container::getForumRepository();
1279
    $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
1280
    $course = api_get_course_entity($courseId);
1281
    $session = api_get_session_entity($sessionId);
1282
1283
    $qb = $repo->getResourcesByCourse($course, $session);
1284
1285
    /*$qb->andWhere('resource.forumCategory = :catId')
1286
        ->setParameter('catId', $cat_id);
1287
    */
1288
    return $qb->getQuery()->getResult();
1289
}
1290
1291
/**
1292
 * Retrieve all the threads of a given forum.
1293
 *
1294
 * @param int|null $courseId  Optional If is null then it is considered the current course
1295
 * @param int|null $sessionId Optional. If is null then it is considered the current session
1296
 *
1297
 * @return CForumThread[]
1298
 */
1299
function get_threads($forumId, $courseId = null, $sessionId = null)
1300
{
1301
    $repo = Container::getForumThreadRepository();
1302
    $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
1303
    $course = api_get_course_entity($courseId);
1304
    $session = api_get_session_entity($sessionId);
1305
1306
    $qb = $repo->getResourcesByCourse($course, $session);
1307
    $qb->andWhere('resource.forum = :forum')->setParameter('forum', $forumId);
1308
1309
    return $qb->getQuery()->getResult();
1310
}
1311
1312
/**
1313
 * Get a thread by Id and course id.
1314
 *
1315
 * @param int $threadId the thread Id
1316
 *
1317
 * @return array containing all the information about the thread
1318
 */
1319
function getThreadInfo($threadId)
1320
{
1321
    $repo = Database::getManager()->getRepository(CForumThread::class);
1322
    /** @var CForumThread $forumThread */
1323
    $forumThread = $repo->findOneBy(['iid' => $threadId]);
1324
1325
    $thread = [];
1326
    if ($forumThread) {
1327
        $thread['iid'] = $forumThread->getIid();
1328
        $thread['threadId'] = $forumThread->getIid();
1329
        $thread['threadTitle'] = $forumThread->getThreadTitle();
1330
        $thread['forumId'] = $forumThread->getForum() ? $forumThread->getForum()->getIid() : 0;
1331
        //$thread['sessionId'] = $forumThread->getSessionId();
1332
        $thread['threadSticky'] = $forumThread->getThreadSticky();
1333
        $thread['locked'] = $forumThread->getLocked();
1334
        $thread['threadTitleQualify'] = $forumThread->getThreadTitleQualify();
1335
        $thread['threadQualifyMax'] = $forumThread->getThreadQualifyMax();
1336
        $thread['threadCloseDate'] = $forumThread->getThreadCloseDate();
1337
        $thread['threadWeight'] = $forumThread->getThreadWeight();
1338
        $thread['threadPeerQualify'] = $forumThread->isThreadPeerQualify();
1339
    }
1340
1341
    return $thread;
1342
}
1343
1344
/**
1345
 * Retrieve all posts of a given thread.
1346
 *
1347
 * @param int    $threadId       The thread ID
1348
 * @param string $orderDirection Optional. The direction for sort the posts
1349
 * @param bool   $recursive      Optional. If the list is recursive
1350
 * @param int    $postId         Optional. The post ID for recursive list
1351
 * @param int    $depth          Optional. The depth to indicate the indent
1352
 *
1353
 * @todo move to a repository
1354
 *
1355
 * @return array containing all the information about the posts of a given thread
1356
 */
1357
function getPosts(
1358
    CForum $forum,
1359
    $threadId,
1360
    $orderDirection = 'ASC',
1361
    $recursive = false,
1362
    $postId = null,
1363
    $depth = -1
1364
) {
1365
    $em = Database::getManager();
1366
1367
    if (api_is_allowed_to_edit(false, true)) {
1368
        $visibleCriteria = Criteria::expr()->neq('visible', 2);
1369
    } else {
1370
        $visibleCriteria = Criteria::expr()->eq('visible', 1);
1371
    }
1372
1373
    $criteria = Criteria::create();
1374
    $criteria
1375
        ->where(Criteria::expr()->eq('thread', $threadId))
1376
        //->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
1377
        ->andWhere($visibleCriteria)
1378
    ;
1379
1380
    $groupId = api_get_group_id();
1381
    $filterModerated = true;
1382
1383
    if (empty($groupId)) {
1384
        if (api_is_allowed_to_edit()) {
1385
            $filterModerated = false;
1386
        }
1387
    } else {
1388
        $groupEntity = api_get_group_entity($groupId);
1389
        if (GroupManager::isTutorOfGroup(api_get_user_id(), $groupEntity) ||
1390
            api_is_allowed_to_edit(false, true)
1391
        ) {
1392
            $filterModerated = false;
1393
        }
1394
    }
1395
1396
    if ($recursive) {
1397
        $criteria->andWhere(Criteria::expr()->eq('postParent', $postId));
1398
    }
1399
1400
    $qb = $em->getRepository(CForumPost::class)->createQueryBuilder('p');
1401
    $qb->select('p')
1402
        ->addCriteria($criteria)
1403
        ->addOrderBy('p.iid', $orderDirection);
1404
1405
    if ($filterModerated && 1 == $forum->isModerated()) {
1406
        if (!api_is_allowed_to_edit(false, true)) {
1407
            $userId = api_get_user_id();
1408
            $qb->andWhere(
1409
                'p.status = 1 OR
1410
                    (p.status = '.CForumPost::STATUS_WAITING_MODERATION." AND p.posterId = $userId) OR
1411
                    (p.status = ".CForumPost::STATUS_REJECTED." AND p.posterId = $userId) OR
1412
                    (p.status IS NULL AND p.posterId = $userId)
1413
                    "
1414
            );
1415
        }
1416
    }
1417
1418
    $posts = $qb->getQuery()->getResult();
1419
    $depth++;
1420
1421
    $list = [];
1422
    /** @var CForumPost $post */
1423
    foreach ($posts as $post) {
1424
        $postInfo = [
1425
            'iid' => $post->getIid(),
1426
            'post_id' => $post->getIid(),
1427
            'post_title' => $post->getPostTitle(),
1428
            'post_text' => $post->getPostText(),
1429
            'thread_id' => $post->getThread() ? $post->getThread()->getIid() : 0,
1430
            'forum_id' => $post->getForum()->getIid(),
1431
            //'poster_id' => $post->getPosterId(),
1432
            //'poster_name' => $post->getPosterName(),
1433
            'post_date' => $post->getPostDate(),
1434
            'post_notification' => $post->getPostNotification(),
1435
            'post_parent_id' => $post->getPostParent() ? $post->getPostParent()->getIid() : 0,
1436
            'visible' => $post->getVisible(),
1437
            'status' => $post->getStatus(),
1438
            'indent_cnt' => $depth,
1439
            'entity' => $post,
1440
        ];
1441
1442
        $list[] = $postInfo;
1443
1444
        if (!$recursive) {
1445
            continue;
1446
        }
1447
        $list = array_merge(
1448
            $list,
1449
            getPosts(
1450
                $forum,
1451
                $threadId,
1452
                $orderDirection,
1453
                $recursive,
1454
                $post->getIid(),
1455
                $depth
1456
            )
1457
        );
1458
    }
1459
1460
    return $list;
1461
}
1462
1463
/**
1464
 * This function retrieves forum thread users details.
1465
 *
1466
 * @param int $thread_id Thread ID
1467
 * @param   string  Course DB name (optional)
1468
 *
1469
 * @return Doctrine\DBAL\Driver\Statement|null array Array of type
1470
 *                                             ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
1471
 *
1472
 * @author Christian Fasanando <[email protected]>,
1473
 *
1474
 * @todo     this function need to be improved
1475
 *
1476
 * @version octubre 2008, dokeos 1.8
1477
 */
1478
function get_thread_users_details($thread_id)
1479
{
1480
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
1481
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
1482
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1483
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1484
1485
    $course_id = api_get_course_int_id();
1486
1487
    $is_western_name_order = api_is_western_name_order();
1488
    if ($is_western_name_order) {
1489
        $orderby = 'ORDER BY user.firstname, user.lastname ';
1490
    } else {
1491
        $orderby = 'ORDER BY user.lastname, user.firstname';
1492
    }
1493
1494
    if (api_get_session_id()) {
1495
        $session_info = api_get_session_info(api_get_session_id());
1496
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
1497
        //not showing coaches
1498
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
1499
                FROM $t_posts p, $t_users user, $t_session_rel_user session_rel_user_rel_course
1500
                WHERE
1501
                    p.poster_id = user.id AND
1502
                    user.id = session_rel_user_rel_course.user_id AND
1503
                    session_rel_user_rel_course.status<>'2' AND
1504
                    session_rel_user_rel_course.user_id NOT IN ($user_to_avoid) AND
1505
                    p.thread_id = ".(int) $thread_id.' AND
1506
                    session_id = '.api_get_session_id()." AND
1507
                    p.c_id = $course_id AND
1508
                    session_rel_user_rel_course.c_id = ".$course_id." $orderby ";
1509
    } else {
1510
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
1511
                FROM $t_posts p, $t_users user, $t_course_user course_user
1512
                WHERE
1513
                    p.poster_id = user.id
1514
                    AND user.id = course_user.user_id
1515
                    AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
1516
                    AND p.thread_id = '.(int) $thread_id."
1517
                    AND course_user.status NOT IN('1') AND
1518
                    p.c_id = $course_id AND
1519
                    course_user.c_id = ".$course_id." $orderby";
1520
    }
1521
1522
    return Database::query($sql);
1523
}
1524
1525
/**
1526
 * This function retrieves forum thread users qualify.
1527
 *
1528
 * @param int $thread_id Thread ID
1529
 * @param   string  Course DB name (optional)
1530
 *
1531
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
1532
 *
1533
 * @author Jhon Hinojosa
1534
 *
1535
 * @todo     this function need to be improved
1536
 */
1537
function get_thread_users_qualify($thread_id)
1538
{
1539
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
1540
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
1541
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
1542
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1543
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1544
1545
    $course_id = api_get_course_int_id();
1546
    $sessionId = api_get_session_id();
1547
1548
    $is_western_name_order = api_is_western_name_order();
1549
    if ($is_western_name_order) {
1550
        $orderby = 'ORDER BY user.firstname, user.lastname ';
1551
    } else {
1552
        $orderby = 'ORDER BY user.lastname, user.firstname';
1553
    }
1554
1555
    if ($sessionId) {
1556
        $session_info = api_get_session_info($sessionId);
1557
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
1558
        //not showing coaches
1559
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
1560
                FROM $t_posts post , $t_users user, $t_session_rel_user scu, $t_qualify qualify
1561
                WHERE poster_id = user.id
1562
                    AND post.poster_id = qualify.user_id
1563
                    AND user.id = scu.user_id
1564
                    AND scu.status<>'2'
1565
                    AND scu.user_id NOT IN ($user_to_avoid)
1566
                    AND qualify.thread_id = ".(int) $thread_id.'
1567
                    AND post.thread_id = '.(int) $thread_id."
1568
                    AND scu.session_id = $sessionId
1569
                    AND scu.c_id = ".$course_id." AND
1570
                    qualify.c_id = $course_id AND
1571
                    post.c_id = $course_id
1572
                $orderby ";
1573
    } else {
1574
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
1575
                FROM $t_posts post,
1576
                     $t_qualify qualify,
1577
                     $t_users user,
1578
                     $t_course_user course_user
1579
                WHERE
1580
                     post.poster_id = user.id
1581
                     AND post.poster_id = qualify.user_id
1582
                     AND user.id = course_user.user_id
1583
                     AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
1584
                     AND qualify.thread_id = '.(int) $thread_id.'
1585
                     AND post.thread_id = '.(int) $thread_id."
1586
                     AND course_user.status not in('1')
1587
                     AND course_user.c_id = $course_id
1588
                     AND qualify.c_id = $course_id
1589
                     AND post.c_id = $course_id
1590
                 $orderby ";
1591
    }
1592
1593
    return Database::query($sql);
1594
}
1595
1596
/**
1597
 * This function retrieves forum thread users not qualify.
1598
 *
1599
 * @param int $thread_id Thread ID
1600
 * @param   string  Course DB name (optional)
1601
 *
1602
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
1603
 *
1604
 * @author   Jhon Hinojosa<[email protected]>,
1605
 *
1606
 * @version oct 2008, dokeos 1.8
1607
 */
1608
function get_thread_users_not_qualify($thread_id)
1609
{
1610
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
1611
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
1612
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
1613
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1614
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1615
1616
    $is_western_name_order = api_is_western_name_order();
1617
    if ($is_western_name_order) {
1618
        $orderby = 'ORDER BY user.firstname, user.lastname ';
1619
    } else {
1620
        $orderby = 'ORDER BY user.lastname, user.firstname';
1621
    }
1622
1623
    $course_id = api_get_course_int_id();
1624
1625
    $sql1 = "SELECT user_id FROM  $t_qualify
1626
             WHERE thread_id = '".$thread_id."'";
1627
    $result1 = Database::query($sql1);
1628
    $cad = '';
1629
    while ($row = Database::fetch_array($result1)) {
1630
        $cad .= $row['user_id'].',';
1631
    }
1632
    if ('' == $cad) {
1633
        $cad = '0';
1634
    } else {
1635
        $cad = substr($cad, 0, strlen($cad) - 1);
1636
    }
1637
1638
    if (api_get_session_id()) {
1639
        $session_info = api_get_session_info(api_get_session_id());
1640
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
1641
        //not showing coaches
1642
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
1643
                FROM $t_posts post , $t_users user, $t_session_rel_user session_rel_user_rel_course
1644
                WHERE poster_id = user.id
1645
                    AND user.id NOT IN (".$cad.")
1646
                    AND user.id = session_rel_user_rel_course.user_id
1647
                    AND session_rel_user_rel_course.status<>'2'
1648
                    AND session_rel_user_rel_course.user_id NOT IN ($user_to_avoid)
1649
                    AND post.thread_id = ".(int) $thread_id.'
1650
                    AND session_id = '.api_get_session_id()."
1651
                    AND session_rel_user_rel_course.c_id = $course_id AND post.c_id = $course_id $orderby ";
1652
    } else {
1653
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
1654
                FROM $t_posts post, $t_users user,$t_course_user course_user
1655
                WHERE post.poster_id = user.id
1656
                AND user.id NOT IN (".$cad.')
1657
                AND user.id = course_user.user_id
1658
                AND course_user.relation_type<>'.COURSE_RELATION_TYPE_RRHH.'
1659
                AND post.thread_id = '.(int) $thread_id."
1660
                AND course_user.status not in('1')
1661
                AND course_user.c_id = $course_id AND post.c_id = $course_id  $orderby";
1662
    }
1663
1664
    return Database::query($sql);
1665
}
1666
1667
/**
1668
 * This function counts the number of forums inside a given category.
1669
 *
1670
 * @param int $cat_id the id of the forum category
1671
 *
1672
 * @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return
1673
 *       the number of visible forums, $countinvisible=1 would return the number of visible and invisible forums
1674
 *
1675
 * @return int the number of forums inside the given category
1676
 *
1677
 * @author Patrick Cool <[email protected]>, Ghent University
1678
 *
1679
 * @version february 2006, dokeos 1.8
1680
 */
1681
function count_number_of_forums_in_category($cat_id)
1682
{
1683
    $table_forums = Database::get_course_table(TABLE_FORUM);
1684
    $course_id = api_get_course_int_id();
1685
    $cat_id = (int) $cat_id;
1686
    $sql = "SELECT count(*) AS number_of_forums
1687
            FROM $table_forums
1688
            WHERE forum_category = $cat_id";
1689
    $result = Database::query($sql);
1690
    $row = Database::fetch_array($result);
1691
1692
    return $row['number_of_forums'];
1693
}
1694
1695
/**
1696
 * This function update a thread.
1697
 *
1698
 * @param array $values - The form Values
1699
 */
1700
function updateThread($values)
1701
{
1702
    if (!api_is_allowed_to_edit()) {
1703
        return '';
1704
    }
1705
1706
    $logInfo = [
1707
        'tool' => TOOL_FORUM,
1708
        'tool_id' => $values['forum_id'],
1709
        'tool_id_detail' => $values['thread_id'],
1710
        'action' => 'edit-thread',
1711
        'action_details' => 'thread',
1712
        'info' => $values['thread_title'],
1713
    ];
1714
    Event::registerLog($logInfo);
1715
1716
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
1717
    $courseId = api_get_course_int_id();
1718
    $courseCode = api_get_course_id();
1719
    $sessionId = api_get_session_id();
1720
1721
    // Simple update + set gradebook values to null
1722
    $params = [
1723
        'thread_title' => $values['thread_title'],
1724
        'thread_sticky' => $values['thread_sticky'] ?? 0,
1725
    ];
1726
    $where = ['iid = ?' => [$values['thread_id']]];
1727
    Database::update($threadTable, $params, $where);
1728
1729
    $id = $values['thread_id'];
1730
    $linkInfo = GradebookUtils::isResourceInCourseGradebook(
1731
        $courseCode,
1732
        LINK_FORUM_THREAD,
1733
        $id,
1734
        $sessionId
1735
    );
1736
1737
    $gradebookLink = null;
1738
    $em = Database::getManager();
1739
    if (!empty($linkInfo) && isset($linkInfo['id'])) {
1740
        $gradebookLink = $em->getRepository(GradebookLink::class)->find($linkInfo['id']);
1741
    }
1742
1743
    // values 1 or 0
1744
    $check = isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : false;
1745
    if ($check) {
1746
        $title = Security::remove_XSS(stripslashes($values['calification_notebook_title']));
1747
        $value = isset($values['numeric_calification']) ? (int) ($values['numeric_calification']) : 0;
1748
        $weight = isset($values['weight_calification']) ? (float) ($values['weight_calification']) : 0;
1749
        $description = '';
1750
        // Update title
1751
        $params = [
1752
            'thread_title_qualify' => $values['calification_notebook_title'],
1753
            'thread_qualify_max' => api_float_val($values['numeric_calification']),
1754
            'thread_weight' => api_float_val($values['weight_calification']),
1755
            'thread_peer_qualify' => $values['thread_peer_qualify'],
1756
        ];
1757
        $where = ['iid = ?' => [$values['thread_id']]];
1758
        Database::update($threadTable, $params, $where);
1759
1760
        if (!$linkInfo) {
1761
            GradebookUtils::add_resource_to_course_gradebook(
1762
                $values['category_id'],
1763
                $courseCode,
1764
                LINK_FORUM_THREAD,
1765
                $id,
1766
                $title,
1767
                $weight,
1768
                $value,
1769
                $description,
1770
                1,
1771
                $sessionId
1772
            );
1773
        } else {
1774
            if ($gradebookLink) {
1775
                $gradebookLink->setWeight($weight);
1776
                $em->persist($gradebookLink);
1777
                $em->flush();
1778
            }
1779
        }
1780
    } else {
1781
        $params = [
1782
            'thread_title_qualify' => '',
1783
            'thread_qualify_max' => 0,
1784
            'thread_weight' => 0,
1785
            'thread_peer_qualify' => 0,
1786
        ];
1787
        $where = ['iid = ?' => [$values['thread_id']]];
1788
        Database::update($threadTable, $params, $where);
1789
1790
        if (!empty($linkInfo)) {
1791
            if ($gradebookLink) {
1792
                $em->remove($gradebookLink);
1793
                $em->flush();
1794
            }
1795
        }
1796
    }
1797
1798
    $message = get_lang('The post has been modified').'<br />';
1799
    Display::addFlash(Display::return_message($message, 'confirmation', false));
1800
}
1801
1802
function saveThread(
1803
    CForum $forum,
1804
    array $values,
1805
    array $courseInfo = [],
1806
    $showMessage = true,
1807
    $userId = 0,
1808
    $sessionId = 0
1809
): ?CForumThread {
1810
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
1811
    $userId = $userId ?: api_get_user_id();
1812
    $course_id = $courseInfo['real_id'];
1813
    $courseCode = $courseInfo['code'];
1814
    $sessionId = $sessionId ?: api_get_session_id();
1815
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1816
1817
    $post_date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
1818
    $visible = true;
1819
    if ('1' == $forum->getApprovalDirectPost() && !api_is_allowed_to_edit(null, true)) {
1820
        $visible = false; // The post has not been approved yet.
1821
    }
1822
    $clean_post_title = $values['post_title'];
1823
1824
    $user = api_get_user_entity(api_get_user_id());
1825
    $course = api_get_course_entity($course_id);
1826
    $session = api_get_session_entity($sessionId);
1827
1828
    // We first store an entry in the forum_thread table because the thread_id is used in the forum_post table.
1829
    $thread = new CForumThread();
1830
    $thread
1831
        ->setThreadTitle($clean_post_title)
1832
        ->setForum($forum)
1833
        ->setUser($user)
1834
        ->setThreadDate($post_date)
1835
        ->setThreadSticky((bool) ($values['thread_sticky'] ?? false))
1836
        ->setThreadTitleQualify($values['calification_notebook_title'] ?? '')
1837
        ->setThreadQualifyMax(api_float_val($values['numeric_calification'] ?? 0))
1838
        ->setThreadWeight(api_float_val($values['weight_calification'] ?? 0))
1839
        ->setThreadPeerQualify(isset($values['thread_peer_qualify']) ? (bool) $values['thread_peer_qualify'] : false)
1840
        ->setParent($forum)
1841
        ->addCourseLink($course, $session)
1842
    ;
1843
    $em = Database::getManager();
1844
    $itemId = isset($values['lp_item_id']) ? (int) $values['lp_item_id'] : 0;
1845
    if (!empty($itemId)) {
1846
        $item = $em->getRepository(CLpItem::class)->find($itemId);
1847
        $thread->setItem($item);
1848
    }
1849
1850
    $repo = Container::getForumThreadRepository();
1851
    $repo->create($thread);
1852
1853
    if (!$thread->getIid()) {
1854
        return null;
1855
    }
1856
1857
    // Add option gradebook qualify.
1858
    if (isset($values['thread_qualify_gradebook']) &&
1859
        1 == $values['thread_qualify_gradebook']
1860
    ) {
1861
        // Add function gradebook.
1862
        $resourcename = stripslashes($values['calification_notebook_title']);
1863
        GradebookUtils::add_resource_to_course_gradebook(
1864
            $values['category_id'],
1865
            $courseCode,
1866
            5,
1867
            $thread->getIid(),
1868
            $resourcename,
1869
            $values['weight_calification'],
1870
            $values['numeric_calification'],
1871
            '',
1872
            0,
1873
            $sessionId
1874
        );
1875
    }
1876
1877
    $logInfo = [
1878
        'tool' => TOOL_FORUM,
1879
        'tool_id' => $values['forum_id'],
1880
        'tool_id_detail' => $thread->getIid(),
1881
        'action' => 'new-thread',
1882
        'info' => $clean_post_title,
1883
    ];
1884
    Event::registerLog($logInfo);
1885
1886
    // We now store the content in the table_post table.
1887
    $post = new CForumPost();
1888
    $post
1889
        ->setPostTitle($clean_post_title)
1890
        ->setPostText($values['post_text'])
1891
        ->setThread($thread)
1892
        ->setForum($forum)
1893
        ->setUser(api_get_user_entity($userId))
1894
        ->setPostDate($post_date)
1895
        ->setPostNotification(isset($values['post_notification']) ? (bool) $values['post_notification'] : false)
1896
        ->setVisible($visible)
1897
        ->setStatus(CForumPost::STATUS_VALIDATED)
1898
        ->setParent($thread)
1899
        ->addCourseLink($course, $session)
1900
    ;
1901
1902
    if ($forum->isModerated()) {
1903
        $post->setStatus(
1904
            api_is_course_admin() ? CForumPost::STATUS_VALIDATED : CForumPost::STATUS_WAITING_MODERATION
1905
        );
1906
    }
1907
1908
    $repo = Container::getForumPostRepository();
1909
    $repo->create($post);
1910
    $thread->setThreadLastPost($post);
1911
    $em = Database::getManager();
1912
    $em->persist($thread);
1913
    $em->flush();
1914
1915
    $postId = $post->getIid();
1916
1917
    $logInfo = [
1918
        'tool' => TOOL_FORUM,
1919
        'tool_id' => $values['forum_id'],
1920
        'tool_id_detail' => $thread->getIid(),
1921
        'action' => 'new-post',
1922
        'info' => $clean_post_title,
1923
    ];
1924
    Event::registerLog($logInfo);
1925
1926
    // Now we have to update the thread table to fill the thread_last_post
1927
    // field (so that we know when the thread has been updated for the last time).
1928
    $sql = "UPDATE $table_threads
1929
            SET thread_last_post = '".$postId."'
1930
            WHERE
1931
                iid = '".$thread->getIid()."'";
1932
    Database::query($sql);
1933
1934
    $message = '';
1935
    if ($showMessage) {
1936
        Display::addFlash(Display::return_message(get_lang('The new thread has been added'), 'success', false));
1937
    }
1938
1939
    // Overwrite default message.
1940
    if ($forum->isModerated() &&
1941
        !api_is_allowed_to_edit(null, true)
1942
    ) {
1943
        if ($showMessage) {
1944
            Display::addFlash(Display::return_message(get_lang('Your message has to be approved before people can view it.'), 'success', false));
1945
        }
1946
    }
1947
1948
    add_forum_attachment_file(
1949
        null,
1950
        $post
1951
    );
1952
1953
    if ('1' == $forum->getApprovalDirectPost() &&
1954
        !api_is_allowed_to_edit(null, true)
1955
    ) {
1956
        $message .= get_lang('Your message has to be approved before people can view it.').'<br />';
1957
        $message .= get_lang('You can now return to the').
1958
            ' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
1959
            get_lang('Forum').'</a><br />';
1960
    } else {
1961
        $message .= get_lang('You can now return to the').
1962
            ' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
1963
            get_lang('Forum').'</a><br />';
1964
        $message .= get_lang('You can now return to the').
1965
            ' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&thread='.$thread->getIid().'">'.
1966
            get_lang('Message').'</a>';
1967
    }
1968
    $reply_info['new_post_id'] = $postId;
1969
    $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
1970
1971
    if (1 == $my_post_notification) {
1972
        set_notification('thread', $thread->getIid(), true);
1973
    }
1974
1975
    send_notification_mails(
1976
        $forum,
1977
        $thread,
1978
        $reply_info
1979
    );
1980
1981
    Session::erase('formelements');
1982
    Session::erase('origin');
1983
    Session::erase('breadcrumbs');
1984
    Session::erase('addedresource');
1985
    Session::erase('addedresourceid');
1986
1987
    if ($showMessage) {
1988
        Display::addFlash(Display::return_message($message, 'success', false));
1989
    }
1990
1991
    return $thread;
1992
}
1993
1994
/**
1995
 * This function displays the form that is used to add a post. This can be a new thread or a reply.
1996
 *
1997
 * @param string $action
1998
 *                            is the parameter that determines if we are
1999
 *                            2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete
2000
 *                            thread (if enabled)
2001
 *                            3. replymessage: Replying to a message ($action =replymessage) => I-frame with the
2002
 *                            complete thread (if enabled)
2003
 *                            (I first thought to put and I-frame with the message only)
2004
 *                            4. quote: Quoting a message ($action= quotemessage) => I-frame with the complete thread
2005
 *                            (if enabled). The message will be in the reply. (I first thought not to put an I-frame
2006
 *                            here)
2007
 * @param array  $form_values
2008
 * @param bool   $showPreview
2009
 *
2010
 * @return FormValidator
2011
 */
2012
function show_add_post_form(CForum $forum, CForumThread $thread, CForumPost $post = null, $action, $form_values, $showPreview = true)
2013
{
2014
    $_user = api_get_user_info();
2015
    $action = isset($action) ? Security::remove_XSS($action) : '';
2016
    $threadId = $thread->getIid();
2017
    $forumId = $forum->getIid();
2018
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
2019
    $postId = $post ? $post->getIid() : 0;
2020
2021
    $url = api_get_self().'?'.http_build_query(
2022
        [
2023
            'action' => $action,
2024
            'forum' => $forumId,
2025
            'thread' => $threadId,
2026
            'post' => $postId,
2027
        ]
2028
    ).'&'.api_get_cidreq();
2029
2030
    $form = new FormValidator(
2031
        'thread',
2032
        'post',
2033
        $url
2034
    );
2035
    $form->setConstants(['forum' => '5']);
2036
2037
    // Setting the form elements.
2038
    $form->addElement('hidden', 'forum_id', $forumId);
2039
    $form->addElement('hidden', 'thread_id', $threadId);
2040
    $form->addElement('hidden', 'action', $action);
2041
2042
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2043
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2044
        $form->addElement('text', 'poster_name', get_lang('Name'));
2045
        $form->applyFilter('poster_name', 'html_filter');
2046
    }
2047
2048
    $form->addElement('text', 'post_title', get_lang('Title'));
2049
    $form->addHtmlEditor(
2050
        'post_text',
2051
        get_lang('Text'),
2052
        true,
2053
        false,
2054
        api_is_allowed_to_edit(null, true) ? [
2055
            'ToolbarSet' => 'Forum',
2056
            'Width' => '100%',
2057
            'Height' => '300',
2058
        ] : [
2059
            'ToolbarSet' => 'ForumStudent',
2060
            'Width' => '100%',
2061
            'Height' => '300',
2062
            'UserStatus' => 'student',
2063
        ]
2064
    );
2065
    $form->addRule('post_text', get_lang('Required field'), 'required');
2066
2067
    if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2068
        $extraFields = new ExtraField('forum_post');
2069
        $extraFields->addElements(
2070
            $form,
2071
            null,
2072
            [], //exclude
2073
            false, // filter
2074
            false, // tag as select
2075
            ['ask_for_revision'], //show only fields
2076
            [], // order fields
2077
            [] // extra data);
2078
        );
2079
    }
2080
2081
    $iframe = null;
2082
    if ($showPreview) {
2083
        if ('newthread' !== $action && !empty($threadId)) {
2084
            $iframe = '<iframe style="border: 1px solid black"
2085
            src="iframe_thread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId.'#'.$postId.'" width="100%"></iframe>';
2086
        }
2087
        if (!empty($iframe)) {
2088
            $form->addElement('label', get_lang('Thread'), $iframe);
2089
        }
2090
    }
2091
2092
    if (in_array($action, ['quote', 'replymessage'])) {
2093
        $form->addFile('user_upload[]', get_lang('Attachment'));
2094
        $form->addButton(
2095
            'add_attachment',
2096
            get_lang('Add attachment'),
2097
            'paperclip',
2098
            'default',
2099
            'default',
2100
            null,
2101
            ['id' => 'reply-add-attachment']
2102
        );
2103
    } else {
2104
        $form->addFile('user_upload', get_lang('Attachment'));
2105
    }
2106
2107
    if ($giveRevision) {
2108
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
2109
        $form->addHidden('give_revision', 1);
2110
        if (false === $hide) {
2111
            $extraField = new ExtraField('forum_post');
2112
            $extraField->addElements(
2113
                $form,
2114
                null,
2115
                [], //exclude
2116
                false, // filter
2117
                false, // tag as select
2118
                ['revision_language'], //show only fields
2119
                [], // order fields
2120
                [] // extra data
2121
            );
2122
        } else {
2123
            $form->addHidden('extra_revision_language', 1);
2124
        }
2125
    }
2126
2127
    // Setting the class and text of the form title and submit button.
2128
    if ('quote' === $action) {
2129
        $form->addButtonCreate(get_lang('Quote this message'), 'SubmitPost');
2130
    } elseif ('replythread' === $action) {
2131
        $form->addButtonCreate(get_lang('Reply to this thread'), 'SubmitPost');
2132
    } elseif ('replymessage' === $action) {
2133
        $form->addButtonCreate(get_lang('Reply to this message'), 'SubmitPost');
2134
    }
2135
2136
    $defaults['thread_peer_qualify'] = 0;
2137
    if (!empty($form_values)) {
2138
        $defaults['post_title'] = prepare4display($form_values['post_title']);
2139
        $defaults['post_text'] = prepare4display($form_values['post_text']);
2140
        $defaults['post_notification'] = (int) $form_values['post_notification'];
2141
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
2142
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
2143
    }
2144
2145
    // If we are quoting a message we have to retrieve the information of the post we are quoting so that
2146
    // we can add this as default to the textarea.
2147
    // We also need to put the parent_id of the post in a hidden form when
2148
    if (('quote' === $action || 'replymessage' === $action || $giveRevision) && !empty($postId)) {
2149
        // we are quoting or replying to a message (<> reply to a thread !!!)
2150
        $form->addHidden('post_parent_id', $post->getIid());
2151
        // If we are replying or are quoting then we display a default title.
2152
        $posterName = UserManager::formatUserFullName($post->getUser());
2153
        $defaults['post_title'] = get_lang('Re:').api_html_entity_decode($post->getPostTitle(), ENT_QUOTES);
2154
        // When we are quoting a message then we have to put that message into the wysiwyg editor.
2155
        // Note: The style has to be hardcoded here because using class="quote" didn't work.
2156
        if ('quote' === $action) {
2157
            $defaults['post_text'] = '<div>&nbsp;</div>
2158
                <div style="margin: 5px;">
2159
                    <div style="font-size: 90%; font-style: italic;">'.
2160
                get_lang('Quoting').' '.$posterName.':</div>
2161
                        <div style="color: #006600; font-size: 90%;  font-style: italic; background-color: #FAFAFA; border: #D1D7DC 1px solid; padding: 3px;">'.
2162
                prepare4display($post->getPostText()).'
2163
                        </div>
2164
                    </div>
2165
                <div>&nbsp;</div>
2166
                <div>&nbsp;</div>
2167
            ';
2168
        }
2169
        if ($giveRevision) {
2170
            $defaults['post_text'] = prepare4display($post->getPostText());
2171
        }
2172
    }
2173
2174
    $form->setDefaults(isset($defaults) ? $defaults : []);
2175
2176
    // The course admin can make a thread sticky (=appears with special icon and always on top).
2177
    $form->addRule('post_title', get_lang('Required field'), 'required');
2178
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2179
        $form->addRule(
2180
            'poster_name',
2181
            get_lang('Required field'),
2182
            'required'
2183
        );
2184
    }
2185
2186
    // Validation or display
2187
    if ($form->validate()) {
2188
        $check = Security::check_token('post');
2189
        if ($check) {
2190
            $values = $form->getSubmitValues();
2191
            if (isset($values['thread_qualify_gradebook']) &&
2192
                '1' == $values['thread_qualify_gradebook'] &&
2193
                empty($values['weight_calification'])
2194
            ) {
2195
                Display::addFlash(
2196
                    Display::return_message(
2197
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
2198
                        'error',
2199
                        false
2200
                    )
2201
                );
2202
2203
                return false;
2204
            }
2205
2206
            $postId = 0;
2207
            $threadId = 0;
2208
2209
            switch ($action) {
2210
                case 'quote':
2211
                case 'replythread':
2212
                case 'replymessage':
2213
                    $postId = store_reply($forum, $thread, $values);
2214
2215
                    break;
2216
            }
2217
2218
            if ($postId) {
2219
                if (isset($values['give_revision']) && 1 == $values['give_revision']) {
2220
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2221
                    $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
2222
                    $params = [
2223
                        'item_id' => $postId,
2224
                        'extra_revision_language' => $revisionLanguage,
2225
                    ];
2226
2227
                    $extraFieldValues->saveFieldValues(
2228
                        $params,
2229
                        false,
2230
                        false,
2231
                        ['revision_language']
2232
                    );
2233
                }
2234
2235
                if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2236
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2237
                    $params = [
2238
                        'item_id' => $postId,
2239
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
2240
                    ];
2241
                    $extraFieldValues->saveFieldValues(
2242
                        $params,
2243
                        false,
2244
                        false,
2245
                        ['ask_for_revision']
2246
                    );
2247
                }
2248
            }
2249
2250
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
2251
                [
2252
                    'forum' => $forumId,
2253
                    'thread' => $thread->getIid(),
2254
                ]
2255
            );
2256
2257
            Security::clear_token();
2258
            header('Location: '.$url);
2259
            exit;
2260
        }
2261
    } else {
2262
        $token = Security::get_token();
2263
        $form->addElement('hidden', 'sec_token');
2264
        $form->setConstants(['sec_token' => $token]);
2265
2266
        // Delete from $_SESSION forum attachment from other posts
2267
        // and keep only attachments for new post
2268
        //clearAttachedFiles(FORUM_NEW_POST);
2269
        // Get forum attachment ajax table to add it to form
2270
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
2271
        $ajaxHtml = $attachmentAjaxTable;
2272
        $form->addElement('html', $ajaxHtml);
2273
2274
        return $form;
2275
    }
2276
}
2277
2278
function newThread(CForum $forum, $form_values = '', $showPreview = true)
2279
{
2280
    $_user = api_get_user_info();
2281
    $forumId = $forum->getIid();
2282
    $my_post = isset($_GET['post']) ? (int) $_GET['post'] : '';
2283
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
2284
    $action = 'new_thread';
2285
2286
    $url = api_get_self().'?'.http_build_query(
2287
            [
2288
                'action' => $action,
2289
                'forum' => $forumId,
2290
                'post' => $my_post,
2291
            ]
2292
        ).'&'.api_get_cidreq();
2293
2294
    $form = new FormValidator(
2295
        'thread',
2296
        'post',
2297
        $url
2298
    );
2299
2300
    // Setting the form elements.
2301
    $form->addElement('hidden', 'forum_id', $forumId);
2302
    $form->addElement('hidden', 'thread_id', 0);
2303
    $form->addElement('hidden', 'action', $action);
2304
2305
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2306
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2307
        $form->addElement('text', 'poster_name', get_lang('Name'));
2308
        $form->applyFilter('poster_name', 'html_filter');
2309
    }
2310
2311
    $form->addElement('text', 'post_title', get_lang('Title'));
2312
    $form->addHtmlEditor(
2313
        'post_text',
2314
        get_lang('Text'),
2315
        true,
2316
        false,
2317
        api_is_allowed_to_edit(null, true) ? [
2318
            'ToolbarSet' => 'Forum',
2319
            'Width' => '100%',
2320
            'Height' => '300',
2321
        ] : [
2322
            'ToolbarSet' => 'ForumStudent',
2323
            'Width' => '100%',
2324
            'Height' => '300',
2325
            'UserStatus' => 'student',
2326
        ]
2327
    );
2328
    $form->addRule('post_text', get_lang('Required field'), 'required');
2329
2330
    $extraFields = new ExtraField('forum_post');
2331
    $extraFields->addElements(
2332
        $form,
2333
        null,
2334
        [], //exclude
2335
        false, // filter
2336
        false, // tag as select
2337
        ['ask_for_revision'], //show only fields
2338
        [], // order fields
2339
        [] // extra data);
2340
    );
2341
2342
    if (Gradebook::is_active() &&
2343
        (api_is_course_admin() || api_is_session_general_coach() || api_is_course_tutor())
2344
    ) {
2345
        $form->addElement('advanced_settings', 'advanced_params', get_lang('Advanced settings'));
2346
        $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
2347
2348
        // Thread qualify
2349
        if (Gradebook::is_active()) {
2350
            //Loading gradebook select
2351
            GradebookUtils::load_gradebook_select_in_tool($form);
2352
            $form->addCheckBox(
2353
                'thread_qualify_gradebook',
2354
                '',
2355
                get_lang('Grade this thread'),
2356
                ['onclick' => 'javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}']
2357
            );
2358
        } else {
2359
            $form->addElement('hidden', 'thread_qualify_gradebook', false);
2360
        }
2361
2362
        $form->addElement('html', '<div id="options_field" style="display:none">');
2363
        $form->addElement('text', 'numeric_calification', get_lang('Maximum score'));
2364
        $form->applyFilter('numeric_calification', 'html_filter');
2365
        $form->addElement('text', 'calification_notebook_title', get_lang('Column header in Competences Report'));
2366
        $form->applyFilter('calification_notebook_title', 'html_filter');
2367
2368
        $form->addElement(
2369
            'text',
2370
            'weight_calification',
2371
            get_lang('Weight in Report'),
2372
            ['value' => '0.00', 'onfocus' => 'javascript: this.select();']
2373
        );
2374
        $form->applyFilter('weight_calification', 'html_filter');
2375
2376
        $group = [];
2377
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('Yes'), 1);
2378
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('No'), 0);
2379
        $form->addGroup(
2380
            $group,
2381
            '',
2382
            [
2383
                get_lang('Thread scored by peers'),
2384
                get_lang('Thread scored by peersComment'),
2385
            ]
2386
        );
2387
        $form->addElement('html', '</div>');
2388
        $form->addElement('html', '</div>');
2389
    }
2390
2391
    SkillModel::addSkillsToForm($form, ITEM_TYPE_FORUM_THREAD, 0);
2392
    $form->addElement('checkbox', 'thread_sticky', '', get_lang('This is a sticky message (appears always on top and has a special sticky icon)'));
2393
2394
    $form->addFile('user_upload', get_lang('Attachment'));
2395
2396
    if ($giveRevision) {
2397
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
2398
        $form->addHidden('give_revision', 1);
2399
        if (false === $hide) {
2400
            $extraField = new ExtraField('forum_post');
2401
            $extraField->addElements(
2402
                $form,
2403
                null,
2404
                [], //exclude
2405
                false, // filter
2406
                false, // tag as select
2407
                ['revision_language'], //show only fields
2408
                [], // order fields
2409
                [] // extra data
2410
            );
2411
        } else {
2412
            $form->addHidden('extra_revision_language', 1);
2413
        }
2414
    }
2415
    $form->addButtonCreate(get_lang('Create thread'), 'SubmitPost');
2416
2417
    $defaults['thread_peer_qualify'] = 0;
2418
    if (!empty($form_values)) {
2419
        $defaults['post_title'] = prepare4display($form_values['post_title']);
2420
        $defaults['post_text'] = prepare4display($form_values['post_text']);
2421
        $defaults['post_notification'] = (int) $form_values['post_notification'];
2422
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
2423
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
2424
    }
2425
2426
    $form->setDefaults(isset($defaults) ? $defaults : []);
2427
2428
    // The course admin can make a thread sticky (=appears with special icon and always on top).
2429
    $form->addRule('post_title', get_lang('Required field'), 'required');
2430
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2431
        $form->addRule(
2432
            'poster_name',
2433
            get_lang('Required field'),
2434
            'required'
2435
        );
2436
    }
2437
2438
    // Validation or display
2439
    if ($form->validate()) {
2440
        $check = Security::check_token('post');
2441
        if ($check) {
2442
            $values = $form->getSubmitValues();
2443
            if (isset($values['thread_qualify_gradebook']) &&
2444
                '1' == $values['thread_qualify_gradebook'] &&
2445
                empty($values['weight_calification'])
2446
            ) {
2447
                Display::addFlash(
2448
                    Display::return_message(
2449
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
2450
                        'error',
2451
                        false
2452
                    )
2453
                );
2454
2455
                return false;
2456
            }
2457
2458
            $newThread = saveThread($forum, $values);
2459
            if ($newThread) {
2460
                SkillModel::saveSkills($form, ITEM_TYPE_FORUM_THREAD, $newThread->getIid());
2461
                $post = $newThread->getThreadLastPost();
2462
2463
                if ($post) {
2464
                    $postId = $post->getIid();
2465
2466
                    if (isset($values['give_revision']) && 1 == $values['give_revision']) {
2467
                        $extraFieldValues = new ExtraFieldValue('forum_post');
2468
                        $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
2469
2470
                        $params = [
2471
                            'item_id' => $postId,
2472
                            'extra_revision_language' => $revisionLanguage,
2473
                        ];
2474
2475
                        $extraFieldValues->saveFieldValues(
2476
                            $params,
2477
                            false,
2478
                            false,
2479
                            ['revision_language']
2480
                        );
2481
                    }
2482
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2483
                    $params = [
2484
                        'item_id' => $postId,
2485
                        'extra_ask_for_revision' => $values['extra_ask_for_revision'] ?? '',
2486
                    ];
2487
                    $extraFieldValues->saveFieldValues(
2488
                        $params,
2489
                        false,
2490
                        false,
2491
                        ['ask_for_revision']
2492
                    );
2493
                }
2494
            }
2495
2496
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
2497
                [
2498
                    'forum' => $forumId,
2499
                    'thread' => $newThread->getIid(),
2500
                ]
2501
            );
2502
2503
            Security::clear_token();
2504
            header('Location: '.$url);
2505
            exit;
2506
        }
2507
    } else {
2508
        $token = Security::get_token();
2509
        $form->addElement('hidden', 'sec_token');
2510
        $form->setConstants(['sec_token' => $token]);
2511
2512
        // Delete from $_SESSION forum attachment from other posts
2513
        // and keep only attachments for new post
2514
        //clearAttachedFiles(FORUM_NEW_POST);
2515
        // Get forum attachment ajax table to add it to form
2516
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
2517
        $ajaxHtml = $attachmentAjaxTable;
2518
        $form->addElement('html', $ajaxHtml);
2519
2520
        return $form;
2521
    }
2522
}
2523
2524
/**
2525
 * @param CForumThread $threadInfo
2526
 * @param int          $user_id
2527
 * @param int          $thread_id
2528
 * @param int          $thread_qualify
2529
 * @param int          $qualify_time
2530
 * @param int          $session_id
2531
 *
2532
 * @return string
2533
 *
2534
 * @author Isaac Flores <[email protected]>, U.N.A.S University
2535
 *
2536
 * @version October 2008, dokeos  1.8.6
2537
 */
2538
function saveThreadScore(
2539
    CForumThread $threadEntity,
2540
    $user_id,
2541
    $thread_id,
2542
    $thread_qualify,
2543
    $qualify_time,
2544
    $session_id
2545
) {
2546
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2547
2548
    $course_id = api_get_course_int_id();
2549
    $session_id = (int) $session_id;
2550
    $thread_id = (int) $thread_id;
2551
    $user_id = (int) $user_id;
2552
    $thread_qualify = (float) $thread_qualify;
2553
    $currentUserId = api_get_user_id();
2554
    $qualify_time = Database::escape_string($qualify_time);
2555
2556
    $max = $threadEntity->getThreadQualifyMax();
2557
    if ($thread_qualify <= $max) {
2558
        if ($threadEntity->isThreadPeerQualify()) {
2559
            $sql = "SELECT COUNT(*) FROM $table_threads_qualify
2560
                    WHERE
2561
                        user_id = $user_id AND
2562
                        qualify_user_id = $currentUserId AND
2563
                        thread_id = ".$thread_id;
2564
        } else {
2565
            $sql = "SELECT COUNT(*) FROM $table_threads_qualify
2566
                    WHERE
2567
                        user_id = $user_id AND
2568
                        thread_id = ".$thread_id;
2569
        }
2570
2571
        $result = Database::query($sql);
2572
        $row = Database::fetch_array($result);
2573
2574
        if (0 == $row[0]) {
2575
            $sql = "INSERT INTO $table_threads_qualify (c_id, user_id, thread_id,qualify,qualify_user_id,qualify_time,session_id)
2576
                    VALUES (".$course_id.", '".$user_id."','".$thread_id."',".$thread_qualify.", '".$currentUserId."','".$qualify_time."','".$session_id."')";
2577
            Database::query($sql);
2578
2579
            return 'insert';
2580
        } else {
2581
            saveThreadScoreHistory(
2582
                '1',
2583
                $course_id,
2584
                $user_id,
2585
                $thread_id
2586
            );
2587
2588
            // Update
2589
            $sql = "UPDATE $table_threads_qualify
2590
                    SET
2591
                        qualify = '".$thread_qualify."',
2592
                        qualify_time = '".$qualify_time."'
2593
                    WHERE
2594
                        user_id=".$user_id.' AND
2595
                        thread_id='.$thread_id." AND
2596
                        qualify_user_id = $currentUserId
2597
                    ";
2598
            Database::query($sql);
2599
2600
            return 'update';
2601
        }
2602
    }
2603
2604
    return '';
2605
}
2606
2607
/**
2608
 * This function shows qualify.
2609
 *
2610
 * @param string $option    contains the information of option to run
2611
 * @param int    $user_id   contains the information the current user id
2612
 * @param int    $thread_id contains the information the current thread id
2613
 *
2614
 * @return int qualify
2615
 *             <code> $option=1 obtained the qualification of the current thread</code>
2616
 *
2617
 * @author Isaac Flores <[email protected]>, U.N.A.S University
2618
 *
2619
 * @version October 2008, dokeos  1.8.6
2620
 */
2621
function showQualify($option, $user_id, $thread_id)
2622
{
2623
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2624
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2625
2626
    $course_id = api_get_course_int_id();
2627
    $user_id = (int) $user_id;
2628
    $thread_id = (int) $thread_id;
2629
2630
    if (empty($user_id) || empty($thread_id)) {
2631
        return 0;
2632
    }
2633
2634
    $sql = '';
2635
    switch ($option) {
2636
        case 1:
2637
            $sql = "SELECT qualify FROM $table_threads_qualify
2638
                    WHERE
2639
                        c_id = $course_id AND
2640
                        user_id=".$user_id.' AND
2641
                        thread_id='.$thread_id;
2642
2643
            break;
2644
        case 2:
2645
            $sql = "SELECT thread_qualify_max FROM $table_threads
2646
                    WHERE c_id = $course_id AND iid=".$thread_id;
2647
2648
            break;
2649
    }
2650
2651
    if (!empty($sql)) {
2652
        $rs = Database::query($sql);
2653
        $row = Database::fetch_array($rs);
2654
        if ($row) {
2655
            return $row[0];
2656
        }
2657
    }
2658
2659
    return 0;
2660
}
2661
2662
/**
2663
 * This function gets qualify historical.
2664
 *
2665
 * @param int  $user_id   contains the information the current user id
2666
 * @param int  $thread_id contains the information the current thread id
2667
 * @param bool $opt       contains the information of option to run
2668
 *
2669
 * @return array
2670
 *
2671
 * @author Christian Fasanando <[email protected]>,
2672
 * @author Isaac Flores <[email protected]>,
2673
 *
2674
 * @version October 2008, dokeos  1.8.6
2675
 */
2676
function getThreadScoreHistory($user_id, $thread_id, $opt)
2677
{
2678
    $user_id = (int) $user_id;
2679
    $thread_id = (int) $thread_id;
2680
2681
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
2682
    $course_id = api_get_course_int_id();
2683
2684
    if ('false' == $opt) {
2685
        $sql = "SELECT * FROM $table_threads_qualify_log
2686
                WHERE
2687
                    c_id = $course_id AND
2688
                    thread_id='".$thread_id."' AND
2689
                    user_id='".$user_id."'
2690
                ORDER BY qualify_time";
2691
    } else {
2692
        $sql = "SELECT * FROM $table_threads_qualify_log
2693
                WHERE
2694
                    c_id = $course_id AND
2695
                    thread_id='".$thread_id."' AND
2696
                    user_id='".$user_id."'
2697
                ORDER BY qualify_time DESC";
2698
    }
2699
    $rs = Database::query($sql);
2700
    $log = [];
2701
    while ($row = Database::fetch_array($rs, 'ASSOC')) {
2702
        $log[] = $row;
2703
    }
2704
2705
    return $log;
2706
}
2707
2708
/**
2709
 * This function stores qualify historical.
2710
 *
2711
 * @param bool contains the information of option to run
2712
 * @param string contains the information the current course id
2713
 * @param int contains the information the current forum id
2714
 * @param int contains the information the current user id
2715
 * @param int contains the information the current thread id
2716
 * @param int contains the information the current qualify
2717
 * @param string $option
2718
 * @param int    $course_id
2719
 * @param int    $user_id
2720
 * @param int    $thread_id
2721
 *
2722
 * @author Isaac Flores <[email protected]>, U.N.A.S University
2723
 *
2724
 * @version October 2008, dokeos  1.8.6
2725
 */
2726
function saveThreadScoreHistory(
2727
    $option,
2728
    $course_id,
2729
    $user_id,
2730
    $thread_id
2731
) {
2732
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2733
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
2734
2735
    $thread_id = (int) $thread_id;
2736
    $course_id = (int) $course_id;
2737
    $user_id = (int) $user_id;
2738
    $qualify_user_id = api_get_user_id();
2739
2740
    if (1 == $option) {
2741
        // Extract information of thread_qualify.
2742
        $sql = "SELECT qualify, qualify_time
2743
                FROM $table_threads_qualify
2744
                WHERE
2745
                    c_id = $course_id AND
2746
                    user_id = ".$user_id.' AND
2747
                    thread_id = '.$thread_id." AND
2748
                    qualify_user_id = $qualify_user_id
2749
                ";
2750
        $rs = Database::query($sql);
2751
        $row = Database::fetch_array($rs);
2752
2753
        // Insert thread_historical.
2754
        $sql = "INSERT INTO $table_threads_qualify_log (c_id, user_id, thread_id, qualify, qualify_user_id,qualify_time,session_id)
2755
                VALUES(".$course_id.", '".$user_id."','".$thread_id."',".(float) $row[0].", '".$qualify_user_id."','".$row[1]."','')";
2756
        Database::query($sql);
2757
    }
2758
}
2759
2760
/**
2761
 * This function shows current thread qualify .
2762
 *
2763
 * @param int $threadId
2764
 * @param int $sessionId
2765
 * @param int $userId
2766
 *
2767
 * @return array or null if is empty
2768
 *
2769
 * @author Isaac Flores <[email protected]>, U.N.A.S University
2770
 *
2771
 * @version December 2008, dokeos  1.8.6
2772
 */
2773
function current_qualify_of_thread($threadId, $sessionId, $userId)
2774
{
2775
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2776
2777
    $course_id = api_get_course_int_id();
2778
    $currentUserId = api_get_user_id();
2779
    $sessionId = (int) $sessionId;
2780
    $threadId = (int) $threadId;
2781
2782
    $sql = "SELECT qualify FROM $table_threads_qualify
2783
            WHERE
2784
                c_id = $course_id AND
2785
                thread_id = $threadId AND
2786
                session_id = $sessionId AND
2787
                qualify_user_id = $currentUserId AND
2788
                user_id = $userId
2789
            ";
2790
    $res = Database::query($sql);
2791
    $row = Database::fetch_array($res, 'ASSOC');
2792
2793
    if ($row) {
2794
        return $row['qualify'];
2795
    }
2796
2797
    return 0;
2798
}
2799
2800
/**
2801
 * This function stores a reply in the forum_post table.
2802
 * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date).
2803
 *
2804
 * @param array $values
2805
 * @param int   $courseId Optional
2806
 * @param int   $userId   Optional
2807
 *
2808
 * @return int post id
2809
 */
2810
function store_reply(CForum $forum, CForumThread $thread, $values, $courseId = 0, $userId = 0)
2811
{
2812
    $courseId = !empty($courseId) ? $courseId : api_get_course_int_id();
2813
    $post_date = api_get_utc_datetime();
2814
    $userId = $userId ?: api_get_user_id();
2815
2816
    if (1 == $forum->getAllowAnonymous()) {
2817
        if (api_is_anonymous() && empty($userId)) {
2818
            $userId = api_get_anonymous_id();
2819
        }
2820
    }
2821
2822
    if (empty($userId)) {
2823
        return false;
2824
    }
2825
2826
    $visible = 1;
2827
    if ('1' == $forum->getApprovalDirectPost() &&
2828
        !api_is_allowed_to_edit(null, true)
2829
    ) {
2830
        $visible = 0;
2831
    }
2832
2833
    $upload_ok = 1;
2834
    $new_post_id = 0;
2835
2836
    if ($upload_ok) {
2837
        $course = api_get_course_entity($courseId);
2838
        $session = api_get_session_entity();
2839
2840
        $repo = Container::getForumPostRepository();
2841
        $post = new CForumPost();
2842
        $post
2843
            ->setPostTitle($values['post_title'])
2844
            ->setPostText(isset($values['post_text']) ?: null)
2845
            ->setThread($thread)
2846
            ->setForum($forum)
2847
            ->setUser(api_get_user_entity($userId))
2848
            ->setPostNotification(isset($values['post_notification']) ? (bool) $values['post_notification'] : false)
2849
            ->setVisible($visible)
2850
            ->setPostDate(api_get_utc_datetime(null, false, true))
2851
            ->setParent($thread)
2852
            ->addCourseLink($course, $session)
2853
        ;
2854
2855
        if (isset($values['post_parent_id']) && !empty($values['post_parent_id'])) {
2856
            $parent = $repo->find($values['post_parent_id']);
2857
            $post->setPostParent($parent);
2858
        }
2859
        $repo->create($post);
2860
2861
        $new_post_id = $post->getIid();
2862
        if ($new_post_id) {
2863
            $values['new_post_id'] = $new_post_id;
2864
            $message = get_lang('The reply has been added');
2865
2866
            if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
2867
                foreach ($_POST['file_ids'] as $key => $id) {
2868
                    editAttachedFile(
2869
                        [
2870
                            'comment' => $_POST['file_comments'][$key],
2871
                            'post_id' => $new_post_id,
2872
                        ],
2873
                        $id
2874
                    );
2875
                }
2876
            }
2877
2878
            // Update the thread.
2879
            updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
2880
2881
            if ('1' == $forum->getApprovalDirectPost() &&
2882
                !api_is_allowed_to_edit(null, true)
2883
            ) {
2884
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
2885
            }
2886
2887
            if ($forum->isModerated() &&
2888
                !api_is_allowed_to_edit(null, true)
2889
            ) {
2890
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
2891
            }
2892
2893
            // Setting the notification correctly.
2894
            $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
2895
            if (1 == $my_post_notification) {
2896
                set_notification('thread', $values['thread_id'], true);
2897
            }
2898
2899
            send_notification_mails(
2900
                $forum,
2901
                $thread,
2902
                $values
2903
            );
2904
            add_forum_attachment_file('', $post);
2905
2906
            $logInfo = [
2907
                'tool' => TOOL_FORUM,
2908
                'tool_id' => $values['forum_id'],
2909
                'tool_id_detail' => $values['thread_id'],
2910
                'action' => 'new-post',
2911
                'action_details' => $values['action'],
2912
                'info' => $values['post_title'],
2913
            ];
2914
            Event::registerLog($logInfo);
2915
        }
2916
2917
        Session::erase('formelements');
2918
        Session::erase('origin');
2919
        Session::erase('breadcrumbs');
2920
        Session::erase('addedresource');
2921
        Session::erase('addedresourceid');
2922
2923
        Display::addFlash(Display::return_message($message, 'confirmation', false));
2924
    } else {
2925
        Display::addFlash(
2926
            Display::return_message(
2927
                get_lang('No file was uploaded.').' '.get_lang('Please select a file before pressing the upload button.'),
2928
                'error'
2929
            )
2930
        );
2931
    }
2932
2933
    return $new_post_id;
2934
}
2935
2936
/**
2937
 * This function displays the form that is used to edit a post. This can be a new thread or a reply.
2938
 *
2939
 * @param CForumPost   $post        contains all the information about the current post
2940
 * @param CForumThread $thread      contains all the information about the current thread
2941
 * @param CForum       $forum       contains all info about the current forum (to check if attachments are allowed)
2942
 * @param array        $form_values contains the default values to fill the form
2943
 *
2944
 * @author Patrick Cool <[email protected]>, Ghent University
2945
 *
2946
 * @version february 2006, dokeos 1.8
2947
 */
2948
function show_edit_post_form(
2949
    $post,
2950
    $thread,
2951
    $forum,
2952
    $form_values,
2953
    $id_attach = 0
2954
) {
2955
    // Initialize the object.
2956
    $form = new FormValidator(
2957
        'edit_post',
2958
        'post',
2959
        api_get_self().'?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&post='.(int) ($_GET['post'])
2960
    );
2961
    $form->addElement('header', get_lang('Edit a post'));
2962
    // Setting the form elements.
2963
    $form->addElement('hidden', 'post_id', $post->getIid());
2964
    $form->addElement('hidden', 'thread_id', $thread->getIid());
2965
    $form->addElement('hidden', 'id_attach', $id_attach);
2966
2967
    if (null === $post->getPostParent()) {
2968
        $form->addElement('hidden', 'is_first_post_of_thread', '1');
2969
    }
2970
2971
    $form->addElement('text', 'post_title', get_lang('Title'));
2972
    $form->applyFilter('post_title', 'html_filter');
2973
    $form->addElement(
2974
        'html_editor',
2975
        'post_text',
2976
        get_lang('Text'),
2977
        null,
2978
        api_is_allowed_to_edit(null, true) ? [
2979
            'ToolbarSet' => 'Forum',
2980
            'Width' => '100%',
2981
            'Height' => '400',
2982
        ] : [
2983
            'ToolbarSet' => 'ForumStudent',
2984
            'Width' => '100%',
2985
            'Height' => '400',
2986
            'UserStatus' => 'student',
2987
        ]
2988
    );
2989
    $form->addRule('post_text', get_lang('Required field'), 'required');
2990
2991
    $extraFields = new ExtraField('forum_post');
2992
    $extraFields->addElements($form, $post->getIid());
2993
2994
    $form->addButtonAdvancedSettings('advanced_params');
2995
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
2996
2997
    if ($forum->isModerated() && api_is_allowed_to_edit(null, true)) {
2998
        $group = [];
2999
        $group[] = $form->createElement(
3000
            'radio',
3001
            'status',
3002
            null,
3003
            get_lang('Validated'),
3004
            1
3005
        );
3006
        $group[] = $form->createElement(
3007
            'radio',
3008
            'status',
3009
            null,
3010
            get_lang('Waiting for moderation'),
3011
            2
3012
        );
3013
        $group[] = $form->createElement(
3014
            'radio',
3015
            'status',
3016
            null,
3017
            get_lang('Rejected'),
3018
            3
3019
        );
3020
        $form->addGroup($group, 'status', get_lang('Status'));
3021
    }
3022
3023
    $defaults['status']['status'] = $post->getStatus();
3024
3025
    $form->addElement(
3026
        'checkbox',
3027
        'post_notification',
3028
        '',
3029
        get_lang('Notify me by e-mail when somebody replies')
3030
    );
3031
3032
    if (api_is_allowed_to_edit(null, true) && null === $post->getPostParent()) {
3033
        // The sticky checkbox only appears when it is the first post of a thread.
3034
        $form->addElement(
3035
            'checkbox',
3036
            'thread_sticky',
3037
            '',
3038
            get_lang('This is a sticky message (appears always on top and has a special sticky icon)')
3039
        );
3040
        if (1 == $thread->getThreadSticky()) {
3041
            $defaults['thread_sticky'] = true;
3042
        }
3043
    }
3044
3045
    $form->addElement('html', '</div>');
3046
3047
    $form->addFile('user_upload[]', get_lang('Attachment'));
3048
    $form->addButton(
3049
        'add_attachment',
3050
        get_lang('Add attachment'),
3051
        'paperclip',
3052
        'default',
3053
        'default',
3054
        null,
3055
        ['id' => 'reply-add-attachment']
3056
    );
3057
3058
    $form->addButtonUpdate(get_lang('Edit'), 'SubmitPost');
3059
3060
    // Setting the default values for the form elements.
3061
    $defaults['post_title'] = $post->getPostTitle();
3062
    $defaults['post_text'] = $post->getPostText();
3063
3064
    if (1 == $post->getPostNotification()) {
3065
        $defaults['post_notification'] = true;
3066
    }
3067
3068
    if (!empty($form_values)) {
3069
        $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
3070
        $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
3071
    }
3072
3073
    $form->setDefaults($defaults);
3074
3075
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3076
    $form->addRule('post_title', get_lang('Required field'), 'required');
3077
3078
    // Validation or display
3079
    if ($form->validate()) {
3080
        $values = $form->exportValues();
3081
        $values['item_id'] = $post->getIid();
3082
        $extraFieldValues = new ExtraFieldValue('forum_post');
3083
        $extraFieldValues->saveFieldValues($values);
3084
3085
        store_edit_post($forum, $values);
3086
    } else {
3087
        // Delete from $_SESSION forum attachment from other posts
3088
        clearAttachedFiles($post->getIid());
3089
        // Get forum attachment ajax table to add it to form
3090
        $fileData = getAttachmentsAjaxTable($post->getIid(), $forum->getIid());
3091
        $form->addElement('html', $fileData);
3092
        $form->display();
3093
    }
3094
}
3095
3096
/**
3097
 * This function stores the edit of a post in the forum_post table.
3098
 *
3099
 * @author Patrick Cool <[email protected]>, Ghent University
3100
 *
3101
 * @version february 2006, dokeos 1.8
3102
 */
3103
function store_edit_post(CForum $forum, $values)
3104
{
3105
    $logInfo = [
3106
        'tool' => TOOL_FORUM,
3107
        'tool_id' => $_GET['forum'],
3108
        'tool_id_detail' => $values['thread_id'],
3109
        'action' => 'edit-post',
3110
        'action_details' => 'post',
3111
        'info' => $values['post_title'],
3112
    ];
3113
    Event::registerLog($logInfo);
3114
3115
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
3116
3117
    //check if this post is the first of the thread
3118
    // First we check if the change affects the thread and if so we commit
3119
    // the changes (sticky and post_title=thread_title are relevant).
3120
    $posts = getPosts($forum, $values['thread_id']);
3121
    $first_post = null;
3122
    if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
3123
        $first_post = $posts[0];
3124
    }
3125
3126
    if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
3127
        // Simple edit
3128
        $params = [
3129
            'thread_title' => $values['post_title'],
3130
            'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
3131
        ];
3132
        $where = ['iid = ?' => [$values['thread_id']]];
3133
        Database::update($threadTable, $params, $where);
3134
    }
3135
3136
    $status = '';
3137
    $updateStatus = false;
3138
    if ($forum->isModerated()) {
3139
        if (api_is_allowed_to_edit(null, true)) {
3140
            $status = $values['status']['status'];
3141
            $updateStatus = true;
3142
        } else {
3143
            $status = CForumPost::STATUS_WAITING_MODERATION;
3144
            $updateStatus = true;
3145
        }
3146
    }
3147
3148
    $postId = $values['post_id'];
3149
    $repo = Container::getForumPostRepository();
3150
    /** @var CForumPost $post */
3151
    $post = $repo->find($postId);
3152
    if ($post) {
3153
        $post
3154
            ->setPostTitle($values['post_title'])
3155
            ->setPostText($values['post_text'])
3156
            ->setPostNotification(isset($values['post_notification']))
3157
        ;
3158
3159
        if ($updateStatus) {
3160
            $post->setStatus($status);
3161
        }
3162
        $repo->update($post);
3163
    }
3164
3165
    // Update attached files
3166
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3167
        foreach ($_POST['file_ids'] as $key => $id) {
3168
            editAttachedFile(
3169
                [
3170
                    'comment' => $_POST['file_comments'][$key],
3171
                    'post_id' => $values['post_id'],
3172
                ],
3173
                $id
3174
            );
3175
        }
3176
    }
3177
3178
    if (!empty($values['remove_attach'])) {
3179
        throw new Exception('remove_attach');
3180
    }
3181
3182
    if (empty($values['id_attach'])) {
3183
        add_forum_attachment_file(
3184
            isset($values['file_comment']) ? $values['file_comment'] : null,
3185
            $post
3186
        );
3187
    }
3188
3189
    $message = get_lang('The post has been modified').'<br />';
3190
    $message .= get_lang('You can now return to the').
3191
        ' <a href="viewforum.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&">'.
3192
        get_lang('Forum').'</a><br />';
3193
    $message .= get_lang('You can now return to the').
3194
        ' <a
3195
            href="viewthread.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.$values['thread_id'].'&post='.Security::remove_XSS($_GET['post']).'">'.
3196
        get_lang('Message').'</a>';
3197
3198
    Session::erase('formelements');
3199
    Session::erase('origin');
3200
    Session::erase('breadcrumbs');
3201
    Session::erase('addedresource');
3202
    Session::erase('addedresourceid');
3203
3204
    echo Display::return_message($message, 'confirmation', false);
3205
}
3206
3207
function displayUserLink(User $user)
3208
{
3209
    return '<a href="'.$user->getProfileUrl().'">'.
3210
        Security::remove_XSS(UserManager::formatUserFullName($user)).'</a>';
3211
}
3212
3213
function displayUserImage(User $user)
3214
{
3215
    $url = Container::getIllustrationRepository()->getIllustrationUrl($user, '', ICON_SIZE_BIG);
3216
3217
    return '<div class="thumbnail"><img src="'.$url.'?w=100"/></div>';
3218
}
3219
3220
/**
3221
 * The relies counter gets increased every time somebody replies to the thread.
3222
 *
3223
 * @author Patrick Cool <[email protected]>, Ghent University
3224
 *
3225
 * @version february 2006, dokeos 1.8
3226
 *
3227
 * @param int    $threadId
3228
 * @param string $lastPostId
3229
 * @param string $post_date
3230
 */
3231
function updateThreadInfo($threadId, $lastPostId, $post_date)
3232
{
3233
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3234
    $threadId = (int) $threadId;
3235
    $lastPostId = (int) $lastPostId;
3236
3237
    $sql = "UPDATE $table_threads SET
3238
            thread_replies = thread_replies+1,
3239
            thread_last_post = '".$lastPostId."',
3240
            thread_date = '".Database::escape_string($post_date)."'
3241
            WHERE
3242
                iid ='".$threadId."'"; // this needs to be cleaned first
3243
    Database::query($sql);
3244
}
3245
3246
function approvePost(CForumPost $post, $action)
3247
{
3248
    if ('invisible' === $action) {
3249
        $visibility = 0;
3250
    }
3251
3252
    if ('visible' === $action) {
3253
        $visibility = 1;
3254
        handle_mail_cue('post', $post->getIid());
3255
    }
3256
3257
    $post->setVisible($visibility);
3258
    Database::getManager()->persist($post);
3259
    Database::getManager()->flush();
3260
3261
    Display::addFlash(Display::return_message(get_lang('The visibility has been changed')));
3262
}
3263
3264
/**
3265
 * This function retrieves all the unapproved messages for a given forum
3266
 * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see
3267
 * this).
3268
 *
3269
 * @param int $forum_id forum where we want to know the unapproved messages of
3270
 *
3271
 * @return array returns
3272
 *
3273
 * @author Patrick Cool <[email protected]>, Ghent University
3274
 *
3275
 * @version february 2006, dokeos 1.8
3276
 */
3277
function get_unaproved_messages($forum_id)
3278
{
3279
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3280
    $course_id = api_get_course_int_id();
3281
3282
    $return_array = [];
3283
    $sql = "SELECT DISTINCT thread_id FROM $table_posts
3284
            WHERE
3285
                c_id = $course_id AND
3286
                forum_id='".Database::escape_string($forum_id)."' AND
3287
                visible='0' ";
3288
    $result = Database::query($sql);
3289
    while ($row = Database::fetch_array($result)) {
3290
        $return_array[] = $row['thread_id'];
3291
    }
3292
3293
    return $return_array;
3294
}
3295
3296
/**
3297
 * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
3298
 * was added to a given thread.
3299
 */
3300
function send_notification_mails(CForum $forum, CForumThread $thread, $reply_info)
3301
{
3302
    $courseEntity = api_get_course_entity();
3303
    $courseId = $courseEntity->getId();
3304
3305
    $sessionId = api_get_session_id();
3306
    $sessionEntity = api_get_session_entity($sessionId);
3307
3308
    $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
3309
3310
    // First we need to check if
3311
    // 1. the forum category is visible
3312
    // 2. the forum is visible
3313
    // 3. the thread is visible
3314
    // 4. the reply is visible (=when there is)
3315
3316
    $current_forum_category = null;
3317
    if ($forum->getForumCategory()) {
3318
        $current_forum_category = $forum->getForumCategory();
3319
    }
3320
3321
    $send_mails = false;
3322
    if ($thread->isVisible($courseEntity, $sessionEntity) &&
3323
        $forum->isVisible($courseEntity, $sessionEntity) &&
3324
        ($current_forum_category && $forum->getForumCategory()->isVisible($courseEntity, $sessionEntity)) &&
3325
        '1' != $forum->getApprovalDirectPost()
3326
    ) {
3327
        $send_mails = true;
3328
    }
3329
3330
    // The forum category, the forum, the thread and the reply are visible to the user
3331
    if ($send_mails && !empty($forum)) {
3332
        $postId = isset($reply_info['new_post_id']) ? $reply_info['new_post_id'] : 0;
3333
        send_notifications($forum, $thread, $postId);
3334
    } else {
3335
        $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
3336
        if ($forum) {
3337
            $sql = "SELECT * FROM $table_notification
3338
                    WHERE
3339
                        c_id = ".$courseId." AND
3340
                        (
3341
                            forum_id = '".$forum->getIid()."' OR
3342
                            thread_id = '".$thread->getIid()."'
3343
                        ) ";
3344
            $result = Database::query($sql);
3345
            $user_id = api_get_user_id();
3346
            while ($row = Database::fetch_array($result)) {
3347
                $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
3348
                        VALUES (".$courseId.", '".$thread->getIid()."', '".(int) ($reply_info['new_post_id'])."', '$user_id' )";
3349
                Database::query($sql);
3350
            }
3351
        }
3352
    }
3353
}
3354
3355
/**
3356
 * This function is called whenever something is made visible because there might
3357
 * be new posts and the user might have indicated that (s)he wanted to be
3358
 * informed about the new posts by mail.
3359
 *
3360
 * @param string $content Content type (post, thread, forum, forum_category)
3361
 * @param int    $id      Item DB ID of the corresponding content type
3362
 *
3363
 * @return string language variable
3364
 *
3365
 * @author Patrick Cool <[email protected]>, Ghent University
3366
 *
3367
 * @version february 2006, dokeos 1.8
3368
 */
3369
function handle_mail_cue($content, $id)
3370
{
3371
    $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
3372
    $table_forums = Database::get_course_table(TABLE_FORUM);
3373
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3374
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3375
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
3376
3377
    $course_id = api_get_course_int_id();
3378
    $id = (int) $id;
3379
3380
    /* If the post is made visible we only have to send mails to the people
3381
     who indicated that they wanted to be informed for that thread.*/
3382
    if ('post' === $content) {
3383
        // Getting the information about the post (need the thread_id).
3384
        /** @var CForumPost $post */
3385
        $post = Container::getForumPostRepository()->find($id);
3386
        $thread_id = $post->getThread()->getIid();
3387
3388
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
3389
        $sql = "SELECT users.firstname, users.lastname, users.id as user_id, users.email
3390
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
3391
                WHERE
3392
                    posts.c_id = $course_id AND
3393
                    mailcue.c_id = $course_id AND
3394
                    posts.thread_id = $thread_id AND
3395
                    posts.post_notification = '1' AND
3396
                    mailcue.thread_id = $thread_id AND
3397
                    users.id = posts.poster_id AND
3398
                    users.active = 1
3399
                GROUP BY users.email";
3400
3401
        $result = Database::query($sql);
3402
        $forum = Container::getForumRepository()->find($post->getForum()->getIid());
3403
3404
        while ($row = Database::fetch_array($result)) {
3405
            send_mail($row, $forum, $post->getThread(), $post);
3406
        }
3407
    } elseif ('thread' === $content) {
3408
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
3409
        $sql = "SELECT users.firstname, users.lastname, users.id as user_id, users.email, posts.forum_id
3410
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
3411
                WHERE
3412
                    posts.c_id = $course_id AND
3413
                    mailcue.c_id = $course_id AND
3414
                    posts.thread_id = $id AND
3415
                    posts.post_notification = '1' AND
3416
                    mailcue.thread_id = $id AND
3417
                    users.id = posts.poster_id AND
3418
                    users.active = 1
3419
                GROUP BY users.email";
3420
        $result = Database::query($sql);
3421
        while ($row = Database::fetch_array($result)) {
3422
            $forum = Container::getForumRepository()->find($row['forum_id']);
3423
            $thread = Container::getForumThreadRepository()->find($id);
3424
            send_mail($row, $forum, $thread);
3425
        }
3426
3427
        // Deleting the relevant entries from the mailcue.
3428
        $sql = "DELETE FROM $table_mailcue
3429
                WHERE c_id = $course_id AND thread_id = $id";
3430
        Database::query($sql);
3431
    } elseif ('forum' === $content) {
3432
        $sql = "SELECT iid FROM $table_threads
3433
                WHERE c_id = $course_id AND forum_id = $id";
3434
        $result = Database::query($sql);
3435
        while ($row = Database::fetch_array($result)) {
3436
            handle_mail_cue('thread', $row['iid']);
3437
        }
3438
    } elseif ('forum_category' === $content) {
3439
        $sql = "SELECT iid FROM $table_forums
3440
                WHERE c_id = $course_id AND forum_category = $id";
3441
        $result = Database::query($sql);
3442
        while ($row = Database::fetch_array($result)) {
3443
            handle_mail_cue('forum', $row['iid']);
3444
        }
3445
    } else {
3446
        return get_lang('Error');
3447
    }
3448
}
3449
3450
/**
3451
 * This function sends the mails for the mail notification.
3452
 */
3453
function send_mail($userInfo, CForum $forum, CForumThread $thread, CForumPost $postInfo = null)
3454
{
3455
    if (empty($userInfo) || empty($forum) || empty($thread)) {
3456
        return false;
3457
    }
3458
3459
    $_course = api_get_course_info();
3460
    $user_id = api_get_user_id();
3461
    $forumId = $forum->getIid();
3462
    $threadId = $thread->getIid();
3463
3464
    $thread_link = api_get_path(WEB_CODE_PATH).
3465
        'forum/viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId;
3466
3467
    $email_body = get_lang('Dear').' '.
3468
        api_get_person_name($userInfo['firstname'], $userInfo['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
3469
    $email_body .= get_lang('New Post in the forum').
3470
        ': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
3471
3472
    $courseId = api_get_configuration_value('global_forums_course_id');
3473
    $subject = get_lang('New Post in the forum').' - '.
3474
        $_course['official_code'].': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
3475
3476
    $courseInfoTitle = get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
3477
    if (!empty($courseId) && $_course['real_id'] == $courseId) {
3478
        $subject = get_lang('New Post in the forum').': '.
3479
            $forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
3480
        $courseInfoTitle = " <br />\n";
3481
    }
3482
    $email_body .= $courseInfoTitle;
3483
3484
    if (!empty($postInfo)) {
3485
        $text = cut(strip_tags($postInfo->getPostText()), 100);
3486
        if (!empty($text)) {
3487
            $email_body .= get_lang('Message').": <br />\n ";
3488
            $email_body .= $text;
3489
            $email_body .= "<br /><br />\n";
3490
        }
3491
    }
3492
3493
    $email_body .= get_lang('You stated that you wanted to be informed by e-mail whenever somebody replies on the thread')."<br />\n";
3494
3495
    if (!empty($thread_link)) {
3496
        $email_body .= get_lang('The thread can be found here').' : <br /><a href="'.$thread_link.'">'.$thread_link."</a>\n";
3497
    }
3498
3499
    if ($userInfo['user_id'] != $user_id) {
3500
        MessageManager::send_message(
3501
            $userInfo['user_id'],
3502
            $subject,
3503
            $email_body,
3504
            [],
3505
            [],
3506
            null,
3507
            null,
3508
            null,
3509
            null,
3510
            $user_id
3511
        );
3512
    }
3513
}
3514
3515
/**
3516
 * This function displays the form for moving a thread to a different (already existing) forum.
3517
 *
3518
 * @author Patrick Cool <[email protected]>, Ghent University
3519
 *
3520
 * @version february 2006, dokeos 1.8
3521
 */
3522
function move_thread_form()
3523
{
3524
    $form = new FormValidator(
3525
        'movepost',
3526
        'post',
3527
        api_get_self().'?forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
3528
    );
3529
    $form->addHeader(get_lang('Move Thread'));
3530
    // Invisible form: the thread_id
3531
    $form->addHidden('thread_id', (int) ($_GET['thread']));
3532
    $forum_categories = get_forum_categories();
3533
3534
    $htmlcontent = '<div class="row">
3535
        <div class="label">
3536
            <span class="form_required">*</span>'.get_lang('Move to').'
3537
        </div>
3538
        <div class="formw">';
3539
    $htmlcontent .= '<select name="forum">';
3540
    foreach ($forum_categories as $category) {
3541
        $htmlcontent .= '<optgroup label="'.$category->getCatTitle().'">';
3542
        $forums = $category->getForums();
3543
        foreach ($forums as $forum) {
3544
            $htmlcontent .= '<option value="'.$forum->getIid().'">'.$forum->getForumTitle().'</option>';
3545
        }
3546
        $htmlcontent .= '</optgroup>';
3547
    }
3548
    $htmlcontent .= '</select>';
3549
    $htmlcontent .= '   </div>
3550
                    </div>';
3551
3552
    $form->addElement('html', $htmlcontent);
3553
3554
    // The OK button
3555
    $form->addButtonSave(get_lang('Move Thread'), 'SubmitForum');
3556
3557
    // Validation or display
3558
    if ($form->validate()) {
3559
        $values = $form->exportValues();
3560
        if (isset($_POST['forum'])) {
3561
            store_move_thread($values);
3562
            Display::addFlash(Display::return_message(get_lang('Moved')));
3563
        }
3564
    } else {
3565
        return $form->returnForm();
3566
    }
3567
}
3568
3569
/**
3570
 * This function displays the form for moving a post message to a different (already existing) or a new thread.
3571
 *
3572
 * @author Patrick Cool <[email protected]>, Ghent University
3573
 *
3574
 * @version february 2006, dokeos 1.8
3575
 */
3576
function move_post_form()
3577
{
3578
    $form = new FormValidator(
3579
        'movepost',
3580
        'post',
3581
        api_get_self().'?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&post='.Security::remove_XSS($_GET['post']).'&action='.Security::remove_XSS($_GET['action']).'&post='.Security::remove_XSS($_GET['post'])
3582
    );
3583
    // The header for the form
3584
    $form->addElement('header', '', get_lang('Move post'));
3585
3586
    // Invisible form: the post_id
3587
    $form->addElement('hidden', 'post_id', (int) ($_GET['post']));
3588
3589
    // Dropdown list: Threads of this forum
3590
    $threads = get_threads($_GET['forum']);
3591
    $threads_list[0] = get_lang('A new thread');
3592
    foreach ($threads as $thread) {
3593
        $threads_list[$thread->getIid()] = $thread->getThreadTitle();
3594
    }
3595
    $form->addSelect('thread', get_lang('Move toThread'), $threads_list);
3596
    $form->applyFilter('thread', 'html_filter');
3597
3598
    // The OK button
3599
    $form->addButtonSave(get_lang('Move post'), 'submit');
3600
3601
    // Setting the rules
3602
    $form->addRule('thread', get_lang('Required field'), 'required');
3603
3604
    return $form;
3605
}
3606
3607
/**
3608
 * @param array $values
3609
 *
3610
 * @return string HTML language variable
3611
 *
3612
 * @author Patrick Cool <[email protected]>, Ghent University
3613
 *
3614
 * @version february 2006, dokeos 1.8
3615
 */
3616
function store_move_post($values)
3617
{
3618
    $_course = api_get_course_info();
3619
    $course_id = api_get_course_int_id();
3620
3621
    $table_forums = Database::get_course_table(TABLE_FORUM);
3622
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3623
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3624
3625
    $user = api_get_user_entity(api_get_user_id());
3626
    $course = api_get_course_entity($course_id);
3627
    $session = api_get_session_entity();
3628
3629
    if ('0' == $values['thread']) {
3630
        $repoPost = Container::getForumPostRepository();
3631
3632
        /** @var CForumPost $post */
3633
        $post = $repoPost->find($values['post_id']);
3634
        $forumId = $post->getForum()->getIid();
3635
        $threadId = $post->getThread()->getIid();
3636
3637
        $thread = new CForumThread();
3638
        $thread
3639
            ->setThreadTitle($post->getPostTitle())
3640
            ->setForum($post->getForum())
3641
            ->setUser($post->getUser())
3642
            ->setThreadLastPost($post)
3643
            ->setThreadDate($post->getPostDate())
3644
            ->setParent($post->getForum())
3645
            ->addCourseLink(
3646
                $user,
3647
                $course,
3648
                $session
3649
            );
3650
3651
        $repo = Container::getForumThreadRepository();
3652
        $repo->create($thread);
3653
        $new_thread_id = $thread->getIid();
3654
3655
        // Moving the post to the newly created thread.
3656
        $sql = "UPDATE $table_posts SET thread_id='".$new_thread_id."', post_parent_id = NULL
3657
                WHERE c_id = $course_id AND iid ='".(int) ($values['post_id'])."'";
3658
        Database::query($sql);
3659
3660
        // Resetting the parent_id of the thread to 0 for all those who had this moved post as parent.
3661
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
3662
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
3663
        Database::query($sql);
3664
3665
        // Updating updating the number of threads in the forum.
3666
        $sql = "UPDATE $table_forums SET forum_threads=forum_threads+1
3667
                WHERE c_id = $course_id AND iid ='".$forumId."'";
3668
        Database::query($sql);
3669
3670
        // Resetting the last post of the old thread and decreasing the number of replies and the thread.
3671
        $sql = "SELECT * FROM $table_posts
3672
                WHERE c_id = $course_id AND thread_id='".$threadId."'
3673
                ORDER BY iid DESC";
3674
        $result = Database::query($sql);
3675
        $row = Database::fetch_array($result);
3676
        $sql = "UPDATE $table_threads SET
3677
                    thread_last_post='".$row['iid']."',
3678
                    thread_replies=thread_replies-1
3679
                WHERE
3680
                    c_id = $course_id AND
3681
                    iid ='".$threadId."'";
3682
        Database::query($sql);
3683
    } else {
3684
        // Moving to the chosen thread.
3685
        $sql = 'SELECT thread_id FROM '.$table_posts."
3686
                WHERE c_id = $course_id AND iid = '".$values['post_id']."' ";
3687
        $result = Database::query($sql);
3688
        $row = Database::fetch_array($result);
3689
3690
        $original_thread_id = $row['thread_id'];
3691
        $sql = 'SELECT thread_last_post FROM '.$table_threads."
3692
                WHERE c_id = $course_id AND iid = '".$original_thread_id."' ";
3693
3694
        $result = Database::query($sql);
3695
        $row = Database::fetch_array($result);
3696
        $thread_is_last_post = $row['thread_last_post'];
3697
        // If is this thread, update the thread_last_post with the last one.
3698
3699
        if ($thread_is_last_post == $values['post_id']) {
3700
            $sql = 'SELECT iid as post_id FROM '.$table_posts."
3701
                    WHERE
3702
                        c_id = $course_id AND
3703
                        thread_id = '".$original_thread_id."' AND
3704
                        iid <> '".$values['post_id']."'
3705
                    ORDER BY post_date DESC LIMIT 1";
3706
            $result = Database::query($sql);
3707
3708
            $row = Database::fetch_array($result);
3709
            $thread_new_last_post = $row['post_id'];
3710
3711
            $sql = 'UPDATE '.$table_threads."
3712
                    SET thread_last_post = '".$thread_new_last_post."'
3713
                    WHERE c_id = $course_id AND iid = '".$original_thread_id."' ";
3714
            Database::query($sql);
3715
        }
3716
3717
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies-1
3718
                WHERE c_id = $course_id AND iid ='".$original_thread_id."'";
3719
        Database::query($sql);
3720
3721
        // moving to the chosen thread
3722
        $sql = "UPDATE $table_posts SET thread_id='".(int) ($_POST['thread'])."', post_parent_id = NULL
3723
                WHERE c_id = $course_id AND iid ='".(int) ($values['post_id'])."'";
3724
        Database::query($sql);
3725
3726
        // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
3727
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
3728
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
3729
        Database::query($sql);
3730
3731
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies+1
3732
                WHERE c_id = $course_id AND iid ='".(int) ($_POST['thread'])."'";
3733
        Database::query($sql);
3734
    }
3735
3736
    return get_lang('Thread moved');
3737
}
3738
3739
/**
3740
 * @param array $values
3741
 *
3742
 * @return string HTML language variable
3743
 *
3744
 * @author Patrick Cool <[email protected]>, Ghent University
3745
 *
3746
 * @version february 2006, dokeos 1.8
3747
 */
3748
function store_move_thread($values)
3749
{
3750
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3751
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3752
3753
    $courseId = api_get_course_int_id();
3754
    $sessionId = api_get_session_id();
3755
3756
    $forumId = (int) ($_POST['forum']);
3757
    $threadId = (int) ($_POST['thread_id']);
3758
    //$forumInfo = get_forums($forumId);
3759
3760
    // Change the thread table: Setting the forum_id to the new forum.
3761
    $sql = "UPDATE $table_threads SET forum_id = $forumId
3762
            WHERE c_id = $courseId AND iid = $threadId";
3763
    Database::query($sql);
3764
3765
    // Changing all the posts of the thread: setting the forum_id to the new forum.
3766
    $sql = "UPDATE $table_posts SET forum_id = $forumId
3767
            WHERE c_id = $courseId AND thread_id= $threadId";
3768
    Database::query($sql);
3769
3770
    // Fix group id, if forum is moved to a different group
3771
    /*if (!empty($forumInfo['to_group_id'])) {
3772
        $groupId = $forumInfo['to_group_id'];
3773
        $item = api_get_item_property_info(
3774
            $courseId,
3775
            TABLE_FORUM_THREAD,
3776
            $threadId,
3777
            $sessionId,
3778
            $groupId
3779
        );
3780
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3781
        $sessionCondition = api_get_session_condition($sessionId);
3782
3783
        if (!empty($item)) {
3784
            if ($item['to_group_id'] != $groupId) {
3785
                $sql = "UPDATE $table
3786
                    SET to_group_id = $groupId
3787
                    WHERE
3788
                      tool = '".TABLE_FORUM_THREAD."' AND
3789
                      c_id = $courseId AND
3790
                      ref = ".$item['ref']."
3791
                      $sessionCondition
3792
                ";
3793
                Database::query($sql);
3794
            }
3795
        } else {
3796
            $sql = "UPDATE $table
3797
                    SET to_group_id = $groupId
3798
                    WHERE
3799
                      tool = '".TABLE_FORUM_THREAD."' AND
3800
                      c_id = $courseId AND
3801
                      ref = ".$threadId."
3802
                      $sessionCondition
3803
            ";
3804
            Database::query($sql);
3805
        }
3806
    }*/
3807
3808
    return get_lang('Thread moved');
3809
}
3810
3811
/**
3812
 * Prepares a string for displaying by highlighting the search results inside, if any.
3813
 *
3814
 * @param string $input the input string
3815
 *
3816
 * @return string the same string with highlighted hits inside
3817
 *
3818
 * @author Patrick Cool <[email protected]>, Ghent University, February 2006 - the initial version.
3819
 * @author Ivan Tcholakov, March 2011 - adaptation for Chamilo LMS.
3820
 */
3821
function prepare4display($input)
3822
{
3823
    static $highlightcolors = ['yellow', '#33CC33', '#3399CC', '#9999FF', '#33CC33'];
3824
    static $search;
3825
3826
    if (!isset($search)) {
3827
        if (isset($_POST['search_term'])) {
3828
            $search = $_POST['search_term']; // No html at all.
3829
        } elseif (isset($_GET['search'])) {
3830
            $search = $_GET['search'];
3831
        } else {
3832
            $search = '';
3833
        }
3834
    }
3835
3836
    if (!empty($search)) {
3837
        if (strstr($search, '+')) {
3838
            $search_terms = explode('+', $search);
3839
        } else {
3840
            $search_terms[] = trim($search);
3841
        }
3842
        $counter = 0;
3843
        foreach ($search_terms as $key => $search_term) {
3844
            $input = api_preg_replace(
3845
                '/'.preg_quote(trim($search_term), '/').'/i',
3846
                '<span style="background-color: '.$highlightcolors[$counter].'">$0</span>',
3847
                $input
3848
            );
3849
            $counter++;
3850
        }
3851
    }
3852
3853
    // TODO: Security should be implemented outside this function.
3854
    // Change this to COURSEMANAGERLOWSECURITY or COURSEMANAGER to lower filtering and allow more styles
3855
    // (see comments of Security::remove_XSS() method to learn about other levels).
3856
3857
    return Security::remove_XSS($input, STUDENT, true);
3858
}
3859
3860
/**
3861
 * Display the search form for the forum and display the search results.
3862
 *
3863
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
3864
 *
3865
 * @version march 2008, dokeos 1.8.5
3866
 */
3867
function forum_search()
3868
{
3869
    $form = new FormValidator(
3870
        'forumsearch',
3871
        'post',
3872
        'forumsearch.php?'.api_get_cidreq()
3873
    );
3874
3875
    // Setting the form elements.
3876
    $form->addElement('header', '', get_lang('Search in the Forum'));
3877
    $form->addElement('text', 'search_term', get_lang('Search term'), ['autofocus']);
3878
    $form->applyFilter('search_term', 'html_filter');
3879
    $form->addElement('static', 'search_information', '', get_lang('Search in the ForumInformation'));
3880
    $form->addButtonSearch(get_lang('Search'));
3881
3882
    // Setting the rules.
3883
    $form->addRule('search_term', get_lang('Required field'), 'required');
3884
    $form->addRule('search_term', get_lang('Too short'), 'minlength', 3);
3885
3886
    // Validation or display.
3887
    if ($form->validate()) {
3888
        $values = $form->exportValues();
3889
        $form->setDefaults($values);
3890
        $form->display();
3891
        // Display the search results.
3892
        display_forum_search_results($values['search_term']);
3893
    } else {
3894
        $form->display();
3895
    }
3896
}
3897
3898
/**
3899
 * Display the search results.
3900
 *
3901
 * @param string $search_term
3902
 *
3903
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
3904
 *
3905
 * @version march 2008, dokeos 1.8.5
3906
 */
3907
function display_forum_search_results($search_term)
3908
{
3909
    /*$table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3910
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3911
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
3912
    $session_id = api_get_session_id();
3913
    $course_id = api_get_course_int_id();
3914
3915
    // Defining the search strings as an array.
3916
    if (strstr($search_term, '+')) {
3917
        $search_terms = explode('+', $search_term);
3918
    } else {
3919
        $search_terms[] = $search_term;
3920
    }
3921
3922
    // Search restriction.
3923
    foreach ($search_terms as $value) {
3924
        $search_restriction[] = "
3925
        (
3926
            posts.post_title LIKE '%".Database::escape_string(trim($value))."%' OR
3927
            posts.post_text LIKE '%".Database::escape_string(trim($value))."%'
3928
        )";
3929
    }
3930
3931
    $sessionCondition = api_get_session_condition(
3932
        $session_id,
3933
        true,
3934
        false,
3935
        'item_property.session_id'
3936
    );
3937
3938
    $sql = "SELECT posts.*
3939
            FROM $table_posts posts
3940
            INNER JOIN $table_threads threads
3941
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
3942
            INNER JOIN $table_item_property item_property
3943
            ON (item_property.ref = threads.thread_id AND item_property.c_id = threads.c_id)
3944
            WHERE
3945
                posts.c_id = $course_id AND
3946
                item_property.c_id = $course_id AND
3947
                item_property.visibility = 1
3948
                $sessionCondition AND
3949
                posts.visible = 1 AND
3950
                item_property.tool = '".TOOL_FORUM_THREAD."' AND
3951
                ".implode(' AND ', $search_restriction).'
3952
            GROUP BY posts.post_id';
3953
3954
    // Getting all the information of the forum categories.
3955
    $forum_categories_list = get_forum_categories();
3956
3957
    // Getting all the information of the forums.
3958
    $forum_list = get_forums();
3959
3960
    $result = Database::query($sql);
3961
    $search_results = [];
3962
    while ($row = Database::fetch_array($result, 'ASSOC')) {
3963
        $forumId = $row['forum_id'];
3964
        $forumData = get_forums($forumId);
3965
        $category = isset($forum_categories_list[$forumData['forum_category']]) ? $forum_categories_list[$forumData['forum_category']] : null;
3966
        $display_result = false;
3967
3968
//          We only show it when
3969
//          1. forum category is visible
3970
//          2. forum is visible
3971
//          3. thread is visible (to do)
3972
//          4. post is visible
3973
3974
        if (!api_is_allowed_to_edit(null, true)) {
3975
            if (!empty($category)) {
3976
                if ('1' == $category['visibility'] && '1' == $forumData['visibility']) {
3977
                    $display_result = true;
3978
                }
3979
            } else {
3980
                if ('1' == $forumData['visible']) {
3981
                    $display_result = true;
3982
                }
3983
            }
3984
        } else {
3985
            $display_result = true;
3986
        }
3987
3988
        if ($display_result) {
3989
            $categoryName = !empty($category) ? $category['cat_title'] : '';
3990
            $search_results_item = '<li><a href="viewforumcategory.php?'.api_get_cidreq().'&forumcategory='.$forumData['forum_category'].'&search='.urlencode($search_term).'">'.
3991
                prepare4display($categoryName).'</a> &gt; ';
3992
            $search_results_item .= '<a href="viewforum.php?'.api_get_cidreq().'&forum='.$forumId.'&search='.urlencode($search_term).'">'.
3993
                prepare4display($forum_list[$row['forum_id']]['forum_title']).'</a> &gt; ';
3994
            $search_results_item .= '<a href="viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$row['thread_id'].'&search='.urlencode($search_term).'">'.
3995
                prepare4display($row['post_title']).'</a>';
3996
            $search_results_item .= '<br />';
3997
            if (api_strlen($row['post_title']) > 200) {
3998
                $search_results_item .= prepare4display(api_substr(strip_tags($row['post_title']), 0, 200)).'...';
3999
            } else {
4000
                $search_results_item .= prepare4display($row['post_title']);
4001
            }
4002
            $search_results_item .= '</li>';
4003
            $search_results[] = $search_results_item;
4004
        }
4005
    }
4006
    echo '<legend>'.count($search_results).' '.get_lang('Search in the ForumResults').'</legend>';
4007
    echo '<ol>';
4008
    if ($search_results) {
4009
        echo implode($search_results);
4010
    }
4011
    echo '</ol>';*/
4012
}
4013
4014
/**
4015
 * Return the link to the forum search page.
4016
 *
4017
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4018
 *
4019
 * @version April 2008, dokeos 1.8.5
4020
 */
4021
function search_link()
4022
{
4023
    // @todo implement search
4024
4025
    return '';
4026
4027
    $return = '';
0 ignored issues
show
Unused Code introduced by
$return = '' is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
4028
    $origin = api_get_origin();
4029
    if ('learnpath' != $origin) {
4030
        $return = '<a href="forumsearch.php?'.api_get_cidreq().'&action=search"> ';
4031
        $return .= Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
4032
4033
        if (!empty($_GET['search'])) {
4034
            $return .= ': '.Security::remove_XSS($_GET['search']).' ';
4035
            $url = api_get_self().'?';
4036
            $url_parameter = [];
4037
            foreach ($_GET as $key => $value) {
4038
                if ('search' != $key) {
4039
                    $url_parameter[] = Security::remove_XSS($key).'='.Security::remove_XSS($value);
4040
                }
4041
            }
4042
            $url .= implode('&', $url_parameter);
4043
            $return .= '<a href="'.$url.'">'.Display::return_icon('delete.gif', get_lang('Clean search results')).'</a>';
4044
        }
4045
    }
4046
4047
    return $return;
4048
}
4049
4050
/**
4051
 * This function adds an attachment file into a forum.
4052
 *
4053
 * @param string     $file_comment a comment about file
4054
 * @param CForumPost $post         from forum_post table
4055
 *
4056
 * @return false|null
4057
 */
4058
function add_forum_attachment_file($file_comment, CForumPost $post)
4059
{
4060
    $request = Container::getRequest();
4061
    if (false === $request->files->has('user_upload')) {
4062
        return false;
4063
    }
4064
4065
    $file = $request->files->get('user_upload');
4066
    if (empty($file)) {
4067
        return false;
4068
    }
4069
4070
    $files = [];
4071
    if ($file instanceof UploadedFile) {
4072
        $files[] = $file;
4073
    } else {
4074
        $files = $file;
4075
    }
4076
4077
    /** @var UploadedFile $attachment */
4078
    foreach ($files as $file) {
4079
        $valid = process_uploaded_file($file);
4080
4081
        if (!$valid) {
4082
            continue;
4083
        }
4084
4085
        // Try to add an extension to the file if it hasn't one.
4086
        $new_file_name = add_ext_on_mime(
4087
            stripslashes($file->getPathname()),
4088
            $file->getType()
4089
        );
4090
4091
        // User's file name
4092
        $file_name = $file->getClientOriginalName();
4093
4094
        if (!filter_extension($new_file_name)) {
4095
            Display::addFlash(
4096
                Display::return_message(
4097
                    get_lang('File upload failed: this file extension or file type is prohibited'),
4098
                    'error'
4099
                )
4100
            );
4101
4102
            return;
4103
        }
4104
4105
        $safe_file_comment = Database::escape_string($file_comment);
4106
4107
        $user = api_get_user_entity(api_get_user_id());
4108
        $course = api_get_course_entity(api_get_course_int_id());
4109
        $session = api_get_session_entity(api_get_session_id());
4110
4111
        $attachment = (new CForumAttachment())
4112
            ->setCId(api_get_course_int_id())
4113
            ->setComment($safe_file_comment)
4114
            ->setFilename($file_name)
4115
            ->setPath($file_name)
4116
            ->setPost($post)
4117
            ->setSize($file->getSize())
4118
            ->setParent($post)
4119
            ->addCourseLink(
4120
                $course,
4121
                $session
4122
            );
4123
4124
        $repo = Container::getForumAttachmentRepository();
4125
        $repo->create($attachment);
4126
        $repo->addFile($attachment, $file);
4127
        $repo->update($attachment);
4128
    }
4129
}
4130
4131
/**
4132
 * This function edits an attachment file into a forum.
4133
 *
4134
 * @param string $file_comment a comment about file
4135
 * @param int    $post_id
4136
 * @param int    $id_attach    attachment file Id
4137
 */
4138
function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
4139
{
4140
    throw new Exception('edit_forum_attachment_file');
4141
    /*
4142
    $_course = api_get_course_info();
4143
    $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
4144
    $course_id = api_get_course_int_id();
4145
4146
    $filesData = [];
4147
4148
    if (!is_array($_FILES['user_upload']['name'])) {
4149
        $filesData[] = $_FILES['user_upload'];
4150
    } else {
4151
        $fileCount = count($_FILES['user_upload']['name']);
4152
        $fileKeys = array_keys($_FILES['user_upload']);
4153
4154
        for ($i = 0; $i < $fileCount; $i++) {
4155
            foreach ($fileKeys as $key) {
4156
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
4157
            }
4158
        }
4159
    }
4160
4161
    foreach ($filesData as $attachment) {
4162
        if (empty($attachment['name'])) {
4163
            continue;
4164
        }
4165
4166
        $upload_ok = process_uploaded_file($attachment);
4167
4168
        if (!$upload_ok) {
4169
            continue;
4170
        }
4171
4172
        $course_dir = $_course['path'].'/upload/forum';
4173
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
4174
        $updir = $sys_course_path.$course_dir;
4175
4176
        // Try to add an extension to the file if it hasn't one.
4177
        $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
4178
        // User's file name
4179
        $file_name = $attachment['name'];
4180
4181
        if (!filter_extension($new_file_name)) {
4182
            Display::addFlash(
4183
                Display::return_message(
4184
                    get_lang('File upload failed: this file extension or file type is prohibited'),
4185
                    'error'
4186
                )
4187
            );
4188
        } else {
4189
            $new_file_name = uniqid('');
4190
            $new_path = $updir.'/'.$new_file_name;
4191
            $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
4192
            $safe_file_comment = Database::escape_string($file_comment);
4193
            $safe_file_name = Database::escape_string($file_name);
4194
            $safe_new_file_name = Database::escape_string($new_file_name);
4195
            $safe_post_id = (int) $post_id;
4196
            $safe_id_attach = (int) $id_attach;
4197
            // Storing the attachments if any.
4198
            if ($result) {
4199
                $sql = "UPDATE $table_forum_attachment
4200
                        SET
4201
                            filename = '$safe_file_name',
4202
                            comment = '$safe_file_comment',
4203
                            path = '$safe_new_file_name',
4204
                            post_id = '$safe_post_id',
4205
                            size ='".$attachment['size']."'
4206
                        WHERE c_id = $course_id AND id = '$safe_id_attach'";
4207
                Database::query($sql);
4208
                api_item_property_update(
4209
                    $_course,
4210
                    TOOL_FORUM_ATTACH,
4211
                    $safe_id_attach,
4212
                    'ForumAttachmentUpdated',
4213
                    api_get_user_id()
4214
                );
4215
            }
4216
        }
4217
    }*/
4218
}
4219
4220
/**
4221
 * Show a list with all the attachments according to the post's id.
4222
 *
4223
 * @param int $postId
4224
 *
4225
 * @return array with the post info
4226
 *
4227
 * @author Julio Montoya
4228
 *
4229
 * @version avril 2008, dokeos 1.8.5
4230
 */
4231
function get_attachment($postId)
4232
{
4233
    $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
4234
    $course_id = api_get_course_int_id();
4235
    $row = [];
4236
    $postId = (int) $postId;
4237
4238
    if (empty($postId)) {
4239
        return [];
4240
    }
4241
4242
    $sql = "SELECT iid, path, filename, comment
4243
            FROM $table
4244
            WHERE c_id = $course_id AND post_id = $postId";
4245
    $result = Database::query($sql);
4246
    if (0 != Database::num_rows($result)) {
4247
        $row = Database::fetch_array($result);
4248
    }
4249
4250
    return $row;
4251
}
4252
4253
/**
4254
 * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
4255
 *
4256
 * @param int $postId
4257
 * @param int $attachmentId
4258
 *
4259
 * @return bool
4260
 */
4261
function delete_attachment($postId, $attachmentId)
4262
{
4263
    $repo = Container::getForumPostRepository();
4264
    $em = Database::getManager();
4265
    /** @var CForumPost $post */
4266
    $post = $repo->find($postId);
4267
    if ($post) {
4268
        $repoAttachment = Container::getForumAttachmentRepository();
4269
        $attachment = $repoAttachment->find($attachmentId);
4270
        if ($attachment) {
4271
            $post->removeAttachment($attachment);
4272
            $em->remove($attachment);
4273
        }
4274
        $repo->update($post);
4275
4276
        Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
4277
    }
4278
4279
    return true;
4280
}
4281
4282
/**
4283
 * This function gets all the forum information of the all the forum of the group.
4284
 *
4285
 * @param array $groupInfo the id of the group we need the fora of (see forum.forum_of_group)
4286
 *
4287
 * @return CForum[]
4288
 *
4289
 * @todo this is basically the same code as the get_forums function. Consider merging the two.
4290
 */
4291
function get_forums_of_group(CGroup $group)
4292
{
4293
    $course = api_get_course_entity();
4294
    $session = api_get_session_entity();
4295
    $repo = Container::getForumRepository();
4296
    $qb = $repo->getResourcesByCourse($course, $session, $group);
4297
4298
    return $qb->getQuery()->getResult();
4299
}
4300
4301
/**
4302
 * This function stores which users have to be notified of which forums or threads.
4303
 *
4304
 * @param string $content    does the user want to be notified about a forum or about a thread
4305
 * @param int    $id         the id of the forum or thread
4306
 * @param bool   $addOnly
4307
 * @param array  $userInfo
4308
 * @param array  $courseInfo
4309
 *
4310
 * @return string language variable
4311
 *
4312
 * @author  Patrick Cool <[email protected]>, Ghent University, Belgium
4313
 * @author  Julio Montoya
4314
 *
4315
 * @since   May 2008 v1.8.5
4316
 */
4317
function set_notification($content, $id, $addOnly = false, $userInfo = [], $courseInfo = [])
4318
{
4319
    $userInfo = empty($userInfo) ? api_get_user_info() : $userInfo;
4320
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
4321
    $id = (int) $id;
4322
4323
    if (empty($userInfo) || empty($courseInfo) || empty($id) || empty($content)) {
4324
        return false;
4325
    }
4326
4327
    // Database table definition
4328
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4329
    $course_id = $courseInfo['real_id'];
4330
4331
    // Which database field do we have to store the id in?
4332
    $field = 'thread_id';
4333
    if ('forum' === $content) {
4334
        $field = 'forum_id';
4335
    }
4336
4337
    $userId = $userInfo['user_id'];
4338
4339
    // First we check if the notification is already set for this.
4340
    $sql = "SELECT * FROM $table_notification
4341
            WHERE
4342
                c_id = $course_id AND
4343
                $field = $id AND
4344
                user_id = $userId ";
4345
    $result = Database::query($sql);
4346
    $total = Database::num_rows($result);
4347
4348
    // If the user did not indicate that (s)he wanted to be notified already
4349
    // then we store the notification request (to prevent double notification requests).
4350
    if ($total <= 0) {
4351
        $notification = new CForumNotification();
4352
        $notification
4353
            ->setCId($course_id)
4354
            ->setUserId($userId)
4355
        ;
4356
4357
        if ('forum' === $content) {
4358
            $notification->setForumId($id);
4359
        } else {
4360
            $notification->setThreadId($id);
4361
        }
4362
4363
        $em = Database::getManager();
4364
        $em->persist($notification);
4365
        $em->flush();
4366
4367
        Session::erase('forum_notification');
4368
        getNotificationsPerUser(0, true);
4369
4370
        return get_lang('You will be notified of new posts by e-mail.');
4371
    } else {
4372
        if (!$addOnly) {
4373
            $sql = "DELETE FROM $table_notification
4374
                    WHERE
4375
                        c_id = $course_id AND
4376
                        $field = $id AND
4377
                        user_id = $userId ";
4378
            Database::query($sql);
4379
            Session::erase('forum_notification');
4380
            getNotificationsPerUser(0, true);
4381
4382
            return get_lang('You will no longer be notified of new posts by email');
4383
        }
4384
    }
4385
}
4386
4387
/**
4388
 * This function retrieves all the email adresses of the users who wanted to be notified
4389
 * about a new post in a certain forum or thread.
4390
 *
4391
 * @param string $content does the user want to be notified about a forum or about a thread
4392
 * @param int    $id      the id of the forum or thread
4393
 *
4394
 * @return array returns
4395
 *
4396
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4397
 * @author Julio Montoya
4398
 *
4399
 * @version May 2008, dokeos 1.8.5
4400
 *
4401
 * @since May 2008, dokeos 1.8.5
4402
 */
4403
function get_notifications($content, $id)
4404
{
4405
    // Database table definition
4406
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4407
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4408
    $course_id = api_get_course_int_id();
4409
4410
    // Which database field contains the notification?
4411
    $field = 'thread_id';
4412
    if ('forum' === $content) {
4413
        $field = 'forum_id';
4414
    }
4415
4416
    $id = (int) $id;
4417
4418
    $sql = "SELECT user.id as user_id, user.firstname, user.lastname, user.email, user.id user
4419
            FROM $table_users user, $table_notification notification
4420
            WHERE
4421
                notification.c_id = $course_id AND user.active = 1 AND
4422
                user.id = notification.user_id AND
4423
                notification.$field = $id ";
4424
4425
    $result = Database::query($sql);
4426
    $return = [];
4427
4428
    while ($row = Database::fetch_array($result)) {
4429
        $return['user'.$row['user_id']] = ['email' => $row['email'], 'user_id' => $row['user_id']];
4430
    }
4431
4432
    return $return;
4433
}
4434
4435
/**
4436
 * Get all the users who need to receive a notification of a new post (those subscribed to
4437
 * the forum or the thread).
4438
 *
4439
 * @param int $post_id the id of the post
4440
 *
4441
 * @return false|null
4442
 *
4443
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4444
 *
4445
 * @version May 2008, dokeos 1.8.5
4446
 *
4447
 * @since May 2008, dokeos 1.8.5
4448
 */
4449
function send_notifications(CForum $forum, CForumThread $thread, $post_id = 0)
4450
{
4451
    if (!$forum) {
4452
        return false;
4453
    }
4454
4455
    // Users who subscribed to the forum
4456
    $users_to_be_notified_by_forum = get_notifications('forum', $forum->getIid());
4457
4458
    // User who subscribed to the thread
4459
    $users_to_be_notified_by_thread = [];
4460
    if (!$thread) {
4461
        $users_to_be_notified_by_thread = get_notifications('thread', $thread->getIid());
4462
    }
4463
4464
    $postInfo = null;
4465
    if (!empty($post_id)) {
4466
        $postInfo = Container::getForumPostRepository()->find($post_id);
4467
    }
4468
4469
    // Merging the two
4470
    $users_to_be_notified = array_merge($users_to_be_notified_by_forum, $users_to_be_notified_by_thread);
4471
4472
    if (is_array($users_to_be_notified)) {
4473
        foreach ($users_to_be_notified as $value) {
4474
            $userInfo = api_get_user_info($value['user_id']);
4475
            send_mail($userInfo, $forum, $thread, $postInfo);
4476
        }
4477
    }
4478
}
4479
4480
/**
4481
 * Get all the notification subscriptions of the user
4482
 * = which forums and which threads does the user wants to be informed of when a new
4483
 * post is added to this thread.
4484
 *
4485
 * @param int  $user_id the user_id of a user (default = 0 => the current user)
4486
 * @param bool $force   force get the notification subscriptions (even if the information is already in the session
4487
 *
4488
 * @return array
4489
 *
4490
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4491
 *
4492
 * @version May 2008, dokeos 1.8.5
4493
 *
4494
 * @since May 2008, dokeos 1.8.5
4495
 */
4496
function getNotificationsPerUser($user_id = 0, $force = false, $course_id = 0)
4497
{
4498
    // Database table definition
4499
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4500
    $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
4501
    if (empty($course_id) || -1 == $course_id) {
4502
        return null;
4503
    }
4504
4505
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
4506
4507
    if (!isset($_SESSION['forum_notification']) ||
4508
        $_SESSION['forum_notification']['course'] != $course_id ||
4509
        true == $force
4510
    ) {
4511
        $_SESSION['forum_notification']['course'] = $course_id;
4512
        $sql = "SELECT * FROM $table_notification
4513
                WHERE c_id = $course_id AND user_id='".$user_id."'";
4514
4515
        $result = Database::query($sql);
4516
        while ($row = Database::fetch_array($result)) {
4517
            if (null !== $row['forum_id']) {
4518
                $_SESSION['forum_notification']['forum'][] = $row['forum_id'];
4519
            }
4520
            if (null !== $row['thread_id']) {
4521
                $_SESSION['forum_notification']['thread'][] = $row['thread_id'];
4522
            }
4523
        }
4524
    }
4525
}
4526
4527
/**
4528
 * This function counts the number of post inside a thread.
4529
 *
4530
 * @param int $thread_id
4531
 *
4532
 * @return int the number of post inside a thread
4533
 *
4534
 * @author Jhon Hinojosa <[email protected]>,
4535
 *
4536
 * @version octubre 2008, dokeos 1.8
4537
 */
4538
function count_number_of_post_in_thread($thread_id)
4539
{
4540
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4541
    $course_id = api_get_course_int_id();
4542
    if (empty($course_id)) {
4543
        return 0;
4544
    }
4545
    $sql = "SELECT count(*) count FROM $table_posts
4546
            WHERE
4547
                c_id = $course_id AND
4548
                thread_id='".(int) $thread_id."' ";
4549
    $result = Database::query($sql);
4550
4551
    $count = 0;
4552
    if (Database::num_rows($result) > 0) {
4553
        $row = Database::fetch_array($result);
4554
        $count = $row['count'];
4555
    }
4556
4557
    return $count;
4558
}
4559
4560
/**
4561
 * This function counts the number of post inside a thread user.
4562
 *
4563
 * @param int $thread_id
4564
 * @param int $user_id
4565
 *
4566
 * @return int the number of post inside a thread user
4567
 */
4568
function count_number_of_post_for_user_thread($thread_id, $user_id)
4569
{
4570
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4571
    $sql = "SELECT count(iid) as count
4572
            FROM $table_posts
4573
            WHERE
4574
                  thread_id=".(int) $thread_id.' AND
4575
                  poster_id = '.(int) $user_id.' AND
4576
                  visible = 1 ';
4577
    $result = Database::query($sql);
4578
    $count = 0;
4579
    if (Database::num_rows($result) > 0) {
4580
        $count = Database::fetch_array($result);
4581
        $count = $count['count'];
4582
    }
4583
4584
    return $count;
4585
}
4586
4587
/**
4588
 * This function retrieves information of statistical.
4589
 *
4590
 * @param int $thread_id
4591
 * @param int $user_id
4592
 * @param int $course_id
4593
 *
4594
 * @return array the information of statistical
4595
 *
4596
 * @author Jhon Hinojosa <[email protected]>,
4597
 *
4598
 * @version oct 2008, dokeos 1.8
4599
 */
4600
function get_statistical_information($thread_id, $user_id, $course_id)
4601
{
4602
    $result = [];
4603
    $courseInfo = api_get_course_info_by_id($course_id);
4604
    $result['user_course'] = CourseManager::get_users_count_in_course($courseInfo['code']);
4605
    $result['post'] = count_number_of_post_in_thread($thread_id);
4606
    $result['user_post'] = count_number_of_post_for_user_thread($thread_id, $user_id);
4607
4608
    return $result;
4609
}
4610
4611
/**
4612
 * This function return the posts inside a thread from a given user.
4613
 *
4614
 * @param int $thread_id
4615
 * @param int $user_id
4616
 *
4617
 * @return array posts inside a thread
4618
 *
4619
 * @author  Jhon Hinojosa <[email protected]>,
4620
 *
4621
 * @version oct 2008, dokeos 1.8
4622
 */
4623
function get_thread_user_post(Course $course, $thread_id, $user_id)
4624
{
4625
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4626
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4627
    $thread_id = (int) $thread_id;
4628
    $user_id = (int) $user_id;
4629
    $course_id = $course->getId();
4630
4631
    if (empty($course_id)) {
4632
        $course_id = api_get_course_int_id();
4633
    }
4634
    $sql = "SELECT *, user.id as user_id FROM $table_posts posts
4635
            LEFT JOIN $table_users user
4636
            ON posts.poster_id = user.id
4637
            WHERE
4638
                posts.c_id = $course_id AND
4639
                posts.thread_id='$thread_id' AND
4640
                posts.poster_id='$user_id'
4641
            ORDER BY posts.iid ASC";
4642
4643
    $result = Database::query($sql);
4644
    $post_list = [];
4645
    while ($row = Database::fetch_array($result)) {
4646
        $row['status'] = '1';
4647
        $post_list[] = $row;
4648
        $sql = "SELECT * FROM $table_posts posts
4649
                LEFT JOIN $table_users users
4650
                ON (posts.poster_id=users.id)
4651
                WHERE
4652
                    posts.c_id = $course_id AND
4653
                    posts.thread_id='$thread_id'
4654
                    AND posts.post_parent_id='".$row['iid']."'
4655
                ORDER BY posts.iid ASC";
4656
        $result2 = Database::query($sql);
4657
        while ($row2 = Database::fetch_array($result2)) {
4658
            $row2['status'] = '0';
4659
            $post_list[] = $row2;
4660
        }
4661
    }
4662
4663
    return $post_list;
4664
}
4665
4666
/**
4667
 * This function get the name of an thread by id.
4668
 *
4669
 * @param int $thread_id
4670
 *
4671
 * @return string
4672
 *
4673
 * @author Christian Fasanando
4674
 * @author Julio Montoya <[email protected]> Adding security
4675
 */
4676
function get_name_thread_by_id($thread_id)
4677
{
4678
    $t_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
4679
    $course_id = api_get_course_int_id();
4680
    $sql = "SELECT thread_title
4681
            FROM $t_forum_thread
4682
            WHERE c_id = $course_id AND iid = '".(int) $thread_id."' ";
4683
    $result = Database::query($sql);
4684
    $row = Database::fetch_array($result);
4685
4686
    return $row[0];
4687
}
4688
4689
/**
4690
 * This function gets all the post written by an user.
4691
 *
4692
 * @param int $user_id
4693
 *
4694
 * @return string
4695
 */
4696
function get_all_post_from_user($user_id, $courseId)
4697
{
4698
    $j = 0;
4699
    $forums = get_forums($courseId);
4700
    krsort($forums);
4701
    $forum_results = '';
4702
4703
    foreach ($forums as $forum) {
4704
        $forumId = $forum->getIid();
4705
4706
        /*if (0 == $forum['visibility']) {
4707
            continue;
4708
        }*/
4709
        if ($j <= 4) {
4710
            $threads = get_threads($forumId);
4711
4712
            if ($threads) {
4713
                $i = 0;
4714
                $hand_forums = '';
4715
                $post_counter = 0;
4716
                foreach ($threads as $thread) {
4717
                    /*if (0 == $thread['visibility']) {
4718
                        continue;
4719
                    }*/
4720
                    if ($i <= 4) {
4721
                        $post_list = get_thread_user_post_limit(
4722
                            $courseId,
4723
                            $thread->getIid(),
4724
                            $user_id,
4725
                            1
4726
                        );
4727
                        $post_counter = count($post_list);
4728
                        if (is_array($post_list) && count($post_list) > 0) {
4729
                            $hand_forums .= '<div id="social-thread">';
4730
                            $hand_forums .= Display::return_icon(
4731
                                'thread.png',
4732
                                get_lang('Thread'),
4733
                                '',
4734
                                ICON_SIZE_MEDIUM
4735
                            );
4736
                            $hand_forums .= '&nbsp;'.Security::remove_XSS($thread->getThreadTitle(), STUDENT);
4737
                            $hand_forums .= '</div>';
4738
4739
                            foreach ($post_list as $posts) {
4740
                                $hand_forums .= '<div id="social-post">';
4741
                                $hand_forums .= '<strong>'.Security::remove_XSS($posts['post_title'], STUDENT).'</strong>';
4742
                                $hand_forums .= '<br / >';
4743
                                $hand_forums .= Security::remove_XSS($posts['post_text'], STUDENT);
4744
                                $hand_forums .= '</div>';
4745
                                $hand_forums .= '<br / >';
4746
                            }
4747
                        }
4748
                    }
4749
                    $i++;
4750
                }
4751
                $forum_results .= '<div id="social-forum">';
4752
                $forum_results .= '<div class="clear"></div><br />';
4753
                $forum_results .= '<div id="social-forum-title">'.
4754
                    Display::return_icon('forum.gif', get_lang('Forum')).'&nbsp;'.Security::remove_XSS($forum->getForumTitle(), STUDENT).
4755
                    '<div style="float:right;margin-top:-35px">
4756
                        <a href="../forum/viewforum.php?'.api_get_cidreq_params($courseId).'&forum='.$forum->getIid().' " >'.
4757
                    get_lang('See forum').'
4758
                        </a>
4759
                     </div></div>';
4760
                $forum_results .= '<br / >';
4761
                if ($post_counter > 0) {
4762
                    $forum_results .= $hand_forums;
4763
                }
4764
                $forum_results .= '</div>';
4765
            }
4766
            $j++;
4767
        }
4768
    }
4769
4770
    return $forum_results;
4771
}
4772
4773
/**
4774
 * @param int $thread_id
4775
 * @param int $user_id
4776
 * @param int $limit
4777
 *
4778
 * @return array
4779
 */
4780
function get_thread_user_post_limit($courseId, $thread_id, $user_id, $limit = 10)
4781
{
4782
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4783
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4784
4785
    $courseId = (int) $courseId;
4786
    $limit = (int) $limit;
4787
4788
    $sql = "SELECT * FROM $table_posts posts
4789
            LEFT JOIN $table_users users
4790
                ON posts.poster_id=users.id
4791
            WHERE
4792
                posts.c_id = $courseId AND
4793
                posts.thread_id='".Database::escape_string($thread_id)."' AND
4794
                posts.poster_id='".Database::escape_string($user_id)."'
4795
            ORDER BY posts.post_id DESC LIMIT $limit ";
4796
    $result = Database::query($sql);
4797
    $post_list = [];
4798
    while ($row = Database::fetch_array($result)) {
4799
        $row['status'] = '1';
4800
        $post_list[] = $row;
4801
    }
4802
4803
    return $post_list;
4804
}
4805
4806
/**
4807
 * @param string $userId
4808
 * @param array  $courseInfo
4809
 * @param int    $sessionId
4810
 *
4811
 * @return array
4812
 */
4813
function getForumCreatedByUser($userId, $courseInfo, $sessionId)
4814
{
4815
    if (empty($userId) || empty($courseInfo)) {
4816
        return [];
4817
    }
4818
4819
    $courseId = $courseInfo['real_id'];
4820
4821
    $repo = Container::getForumRepository();
4822
4823
    $courseEntity = api_get_course_entity($courseId);
4824
    $sessionEntity = api_get_session_entity($sessionId);
4825
4826
    $qb = $repo->getResourcesByCourse($courseEntity, $sessionEntity);
4827
4828
    $qb->andWhere('node.creator = :creator');
4829
    $qb->setParameter('creator', $userId);
4830
    $items = $qb->getQuery()->getResult();
4831
4832
    $forumList = [];
4833
    if (!empty($items)) {
4834
        /** @var CForum $forum */
4835
        foreach ($items as $forum) {
4836
            $forumList[] = [
4837
                $forum->getForumTitle(),
4838
                api_get_local_time($forum->getResourceNode()->getCreatedAt()),
4839
                api_get_local_time($forum->getResourceNode()->getUpdatedAt()),
4840
            ];
4841
        }
4842
    }
4843
4844
    return $forumList;
4845
}
4846
4847
/**
4848
 * This function builds an array of all the posts in a given thread
4849
 * where the key of the array is the post_id
4850
 * It also adds an element children to the array which itself is an array
4851
 * that contains all the id's of the first-level children.
4852
 *
4853
 * @return array containing all the information on the posts of a thread
4854
 *
4855
 * @author Patrick Cool <[email protected]>, Ghent University
4856
 */
4857
function calculate_children($rows)
4858
{
4859
    $sorted_rows = [0 => []];
4860
    if (!empty($rows)) {
4861
        foreach ($rows as $row) {
4862
            $rows_with_children[$row['post_id']] = $row;
4863
            $rows_with_children[$row['post_parent_id']]['children'][] = $row['post_id'];
4864
        }
4865
4866
        $rows = $rows_with_children;
4867
        forumRecursiveSort($rows, $sorted_rows);
4868
        unset($sorted_rows[0]);
4869
    }
4870
4871
    return $sorted_rows;
4872
}
4873
4874
/**
4875
 * @param $rows
4876
 * @param $threads
4877
 * @param int $seed
4878
 * @param int $indent
4879
 */
4880
function forumRecursiveSort($rows, &$threads, $seed = 0, $indent = 0)
4881
{
4882
    if ($seed > 0) {
4883
        $threads[$rows[$seed]['post_id']] = $rows[$seed];
4884
        $threads[$rows[$seed]['post_id']]['indent_cnt'] = $indent;
4885
        $indent++;
4886
    }
4887
4888
    if (isset($rows[$seed]['children'])) {
4889
        foreach ($rows[$seed]['children'] as $child) {
4890
            forumRecursiveSort($rows, $threads, $child, $indent);
4891
        }
4892
    }
4893
}
4894
4895
/**
4896
 * Update forum attachment data, used to update comment and post ID.
4897
 *
4898
 * @param array $array    (field => value) to update forum attachment row
4899
 * @param int   $id       ID to find row to update
4900
 * @param int   $courseId course ID to find row to update
4901
 *
4902
 * @return int number of affected rows
4903
 */
4904
function editAttachedFile($array, $id, $courseId = null)
4905
{
4906
    // Init variables
4907
    $setString = '';
4908
    $id = (int) $id;
4909
    $courseId = (int) $courseId;
4910
    if (empty($courseId)) {
4911
        // $courseId can be null, use api method
4912
        $courseId = api_get_course_int_id();
4913
    }
4914
    /*
4915
     * Check if Attachment ID and Course ID are greater than zero
4916
     * and array of field values is not empty
4917
     */
4918
    if ($id > 0 && $courseId > 0 && !empty($array) && is_array($array)) {
4919
        foreach ($array as $key => &$item) {
4920
            $item = Database::escape_string($item);
4921
            $setString .= $key.' = "'.$item.'", ';
4922
        }
4923
        // Delete last comma
4924
        $setString = substr($setString, 0, strlen($setString) - 2);
4925
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
4926
        $sql = "UPDATE $forumAttachmentTable
4927
                SET $setString WHERE c_id = $courseId AND id = $id";
4928
        $result = Database::query($sql);
4929
        if (false !== $result) {
4930
            $affectedRows = Database::affected_rows($result);
4931
            if ($affectedRows > 0) {
4932
                /*
4933
                 * If exist in $_SESSION variable, then delete them from it
4934
                 * because they would be deprecated
4935
                 */
4936
                if (!empty($_SESSION['forum']['upload_file'][$courseId][$id])) {
4937
                    unset($_SESSION['forum']['upload_file'][$courseId][$id]);
4938
                }
4939
            }
4940
4941
            return $affectedRows;
4942
        }
4943
    }
4944
4945
    return 0;
4946
}
4947
4948
/**
4949
 * Return a table where the attachments will be set.
4950
 *
4951
 * @param int $postId Forum Post ID
4952
 *
4953
 * @return string The Forum Attachments Ajax Table
4954
 */
4955
function getAttachmentsAjaxTable($postId = 0)
4956
{
4957
    $postId = (int) $postId;
4958
    $courseId = api_get_course_int_id();
4959
    $attachIds = getAttachmentIdsByPostId($postId, $courseId);
4960
    $fileDataContent = '';
4961
    // Update comment to show if form did not pass validation
4962
    if (!empty($_REQUEST['file_ids']) && is_array($_REQUEST['file_ids'])) {
4963
        // 'file_ids is the name from forum attachment ajax form
4964
        foreach ($_REQUEST['file_ids'] as $key => $attachId) {
4965
            if (!empty($_SESSION['forum']['upload_file'][$courseId][$attachId]) &&
4966
                is_array($_SESSION['forum']['upload_file'][$courseId][$attachId])
4967
            ) {
4968
                // If exist forum attachment then update into $_SESSION data
4969
                $_SESSION['forum']['upload_file'][$courseId][$attachId]['comment'] = $_POST['file_comments'][$key];
4970
            }
4971
        }
4972
    }
4973
4974
    // Get data to fill into attachment files table
4975
    if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
4976
        is_array($_SESSION['forum']['upload_file'][$courseId])
4977
    ) {
4978
        $uploadedFiles = $_SESSION['forum']['upload_file'][$courseId];
4979
        foreach ($uploadedFiles as $k => $uploadedFile) {
4980
            if (!empty($uploadedFile) && in_array($uploadedFile['id'], $attachIds)) {
4981
                // Buil html table including an input with attachmentID
4982
                $fileDataContent .= '<tr id="'.$uploadedFile['id'].'" ><td>'.$uploadedFile['name'].'</td><td>'.$uploadedFile['size'].'</td><td>&nbsp;'.$uploadedFile['result'].
4983
                    ' </td><td> <input style="width:90%;" type="text" value="'.$uploadedFile['comment'].'" name="file_comments[]"> </td><td>'.
4984
                    $uploadedFile['delete'].'</td>'.
4985
                    '<input type="hidden" value="'.$uploadedFile['id'].'" name="file_ids[]">'.'</tr>';
4986
            } else {
4987
                /*
4988
                 * If attachment data is empty, then delete it from $_SESSION
4989
                 * because could generate and empty row into html table
4990
                 */
4991
                unset($_SESSION['forum']['upload_file'][$courseId][$k]);
4992
            }
4993
        }
4994
    }
4995
    $style = empty($fileDataContent) ? 'display: none;' : '';
4996
    // Forum attachment Ajax table
4997
    return '
4998
    <div class="control-group " style="'.$style.'">
4999
        <label class="control-label">'.get_lang('Attachments list').'</label>
5000
        <div class="controls">
5001
            <table id="attachmentFileList" class="files data_table span10">
5002
                <tr>
5003
                    <th>'.get_lang('Filename').'</th>
5004
                    <th>'.get_lang('Size').'</th>
5005
                    <th>'.get_lang('Status').'</th>
5006
                    <th>'.get_lang('Comment').'</th>
5007
                    <th>'.get_lang('Delete').'</th>
5008
                </tr>
5009
                '.$fileDataContent.'
5010
            </table>
5011
        </div>
5012
    </div>';
5013
}
5014
5015
/**
5016
 * Return an array of prepared attachment data to build forum attachment table
5017
 * Also, save this array into $_SESSION to do available the attachment data.
5018
 *
5019
 * @param int $forumId
5020
 * @param int $threadId
5021
 * @param int $postId
5022
 * @param int $attachId
5023
 * @param int $courseId
5024
 *
5025
 * @return array
5026
 */
5027
function getAttachedFiles(
5028
    $forumId,
5029
    $threadId,
5030
    $postId = 0,
5031
    $attachId = 0,
5032
    $courseId = 0
5033
) {
5034
    $forumId = (int) $forumId;
5035
    $courseId = (int) $courseId;
5036
    $attachId = (int) $attachId;
5037
    $postId = (int) $postId;
5038
    $threadId = (int) $threadId;
5039
5040
    if (empty($courseId)) {
5041
        // $courseId can be null, use api method
5042
        $courseId = api_get_course_int_id();
5043
    }
5044
    if (empty($forumId)) {
5045
        if (!empty($_REQUEST['forum'])) {
5046
            $forumId = (int) $_REQUEST['forum'];
5047
        } else {
5048
            // if forum ID is empty, cannot generate delete url
5049
5050
            return [];
5051
        }
5052
    }
5053
    // Check if exist at least one of them to filter forum attachment select query
5054
    if (empty($postId) && empty($attachId)) {
5055
        return [];
5056
    }
5057
5058
    if (empty($postId)) {
5059
        $filter = "AND iid = $attachId";
5060
    } elseif (empty($attachId)) {
5061
        $filter = "AND post_id = $postId";
5062
    } else {
5063
        $filter = "AND post_id = $postId AND iid = $attachId";
5064
    }
5065
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5066
    $sql = "SELECT iid
5067
            FROM $forumAttachmentTable
5068
            WHERE c_id = $courseId $filter";
5069
    $result = Database::query($sql);
5070
    $json = [];
5071
    if (Database::num_rows($result) > 0) {
5072
        $repo = Container::getForumAttachmentRepository();
5073
        while ($row = Database::fetch_array($result, 'ASSOC')) {
5074
            /** @var CForumAttachment $attachment */
5075
            $attachment = $repo->find($row['iid']);
5076
            $downloadUrl = $repo->getResourceFileDownloadUrl($attachment);
5077
5078
            // name contains an URL to download attachment file and its filename
5079
            $json['name'] = Display::url(
5080
                api_htmlentities($attachment->getFilename()),
5081
                $downloadUrl,
5082
                ['target' => '_blank', 'class' => 'attachFilename']
5083
            );
5084
            $json['id'] = $row['iid'];
5085
            $json['comment'] = $attachment->getComment();
5086
            // Format file size
5087
            $json['size'] = format_file_size($attachment->getSize());
5088
            // Check if $row is consistent
5089
            if ($attachment) {
5090
                // Set result as success and bring delete URL
5091
                $json['result'] = Display::return_icon('accept.png', get_lang('Uploaded.'));
5092
                $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&action=delete_attach&forum='.$forumId.'&thread='.$threadId.'&id_attach='.$row['iid'];
5093
                $json['delete'] = Display::url(
5094
                    Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL),
5095
                    $url,
5096
                    ['class' => 'deleteLink']
5097
                );
5098
            } else {
5099
                // If not, set an exclamation result
5100
                $json['result'] = Display::return_icon('exclamation.png', get_lang('Error'));
5101
            }
5102
            // Store array data into $_SESSION
5103
            $_SESSION['forum']['upload_file'][$courseId][$json['id']] = $json;
5104
        }
5105
    }
5106
5107
    return $json;
5108
}
5109
5110
/**
5111
 * Clear forum attachment data stored in $_SESSION,
5112
 * If is not defined post, it will clear all forum attachment data from course.
5113
 *
5114
 * @param int $postId   -1 : Clear all attachments from course stored in $_SESSION
5115
 *                      0 : Clear attachments from course, except from temporal post "0"
5116
 *                      but without delete them from file system and database
5117
 *                      Other values : Clear attachments from course except specified post
5118
 *                      and delete them from file system and database
5119
 * @param int $courseId : Course ID, if it is null, will use api_get_course_int_id()
5120
 *
5121
 * @return array
5122
 */
5123
function clearAttachedFiles($postId = 0, $courseId = 0)
5124
{
5125
    // Init variables
5126
    $courseId = (int) $courseId;
5127
    $postId = (int) $postId;
5128
    $array = [];
5129
    if (empty($courseId)) {
5130
        // $courseId can be null, use api method
5131
        $courseId = api_get_course_int_id();
5132
    }
5133
    if (-1 === $postId) {
5134
        // If post ID is -1 then delete course's attachment data from $_SESSION
5135
        if (!empty($_SESSION['forum']['upload_file'][$courseId])) {
5136
            $array = array_keys($_SESSION['forum']['upload_file'][$courseId]);
5137
            unset($_SESSION['forum']['upload_file'][$courseId]);
5138
        }
5139
    } else {
5140
        $attachIds = getAttachmentIdsByPostId($postId, $courseId);
5141
        if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
5142
            is_array($_SESSION['forum']['upload_file'][$courseId])) {
5143
            foreach ($_SESSION['forum']['upload_file'][$courseId] as $attachId => $attach) {
5144
                if (!in_array($attachId, $attachIds)) {
5145
                    // If attach ID is not into specified post, delete attachment
5146
                    // Save deleted attachment ID
5147
                    $array[] = $attachId;
5148
                    if (0 !== $postId) {
5149
                        // Post 0 is temporal, delete them from file system and DB
5150
                        delete_attachment(0, $attachId);
5151
                    }
5152
                    // Delete attachment data from $_SESSION
5153
                    unset($_SESSION['forum']['upload_file'][$courseId][$attachId]);
5154
                }
5155
            }
5156
        }
5157
    }
5158
5159
    return $array;
5160
}
5161
5162
/**
5163
 * Returns an array of forum attachment ids into a course and forum post.
5164
 *
5165
 * @param int $postId
5166
 * @param int $courseId
5167
 *
5168
 * @return array
5169
 */
5170
function getAttachmentIdsByPostId($postId, $courseId = 0)
5171
{
5172
    $array = [];
5173
    $courseId = (int) $courseId;
5174
    $postId = (int) $postId;
5175
    if (empty($courseId)) {
5176
        // $courseId can be null, use api method
5177
        $courseId = api_get_course_int_id();
5178
    }
5179
    if ($courseId > 0) {
5180
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5181
        $sql = "SELECT iid FROM $forumAttachmentTable
5182
                WHERE c_id = $courseId AND post_id = $postId";
5183
        $result = Database::query($sql);
5184
        if (false !== $result && Database::num_rows($result) > 0) {
5185
            while ($row = Database::fetch_array($result, 'ASSOC')) {
5186
                $array[] = $row['iid'];
5187
            }
5188
        }
5189
    }
5190
5191
    return $array;
5192
}
5193
5194
function getPostStatus(CForum $forum, array $row, bool $addWrapper = true): string
5195
{
5196
    $statusIcon = '';
5197
    if ($forum->isModerated()) {
5198
        if ($addWrapper) {
5199
            $statusIcon = '<br /><br /><span id="status_post_'.$row['iid'].'">';
5200
        }
5201
        $row['status'] = empty($row['status']) ? 2 : $row['status'];
5202
5203
        $addUrl = false;
5204
        $showStatus = false;
5205
        if (api_is_allowed_to_edit(false, true)) {
5206
            $addUrl = true;
5207
        } else {
5208
            if ($row['user_id'] == api_get_user_id()) {
5209
                $showStatus = true;
5210
            }
5211
        }
5212
5213
        $label = '';
5214
        $icon = '';
5215
        $buttonType = '';
5216
        switch ($row['status']) {
5217
            case CForumPost::STATUS_VALIDATED:
5218
                $label = get_lang('Validated');
5219
                $icon = 'check-circle';
5220
                $buttonType = 'success';
5221
5222
                break;
5223
            case CForumPost::STATUS_WAITING_MODERATION:
5224
                $label = get_lang('Waiting for moderation');
5225
                $icon = 'alert';
5226
                $buttonType = 'warning';
5227
5228
                break;
5229
            case CForumPost::STATUS_REJECTED:
5230
                $label = get_lang('Rejected');
5231
                $icon = 'minus-circle';
5232
                $buttonType = 'danger';
5233
5234
                break;
5235
        }
5236
5237
        if ($addUrl) {
5238
            $statusIcon .= Display::toolbarButton(
5239
                $label.'&nbsp;',
5240
                'javascript:void(0)',
5241
                $icon,
5242
                $buttonType,
5243
                ['class' => 'change_post_status']
5244
            );
5245
        } else {
5246
            if ($showStatus) {
5247
                $statusIcon .= Display::label(
5248
                    Display::returnFontAwesomeIcon($icon).$label,
5249
                    $buttonType
5250
                );
5251
            }
5252
        }
5253
5254
        if ($addWrapper) {
5255
            $statusIcon .= '</span>';
5256
        }
5257
    }
5258
5259
    return $statusIcon;
5260
}
5261
5262
/**
5263
 * @param CForum $forum
5264
 * @param int    $threadId
5265
 * @param int    $status
5266
 */
5267
function getCountPostsWithStatus($status, $forum, $threadId = null)
5268
{
5269
    $em = Database::getManager();
5270
    $criteria = Criteria::create();
5271
    $criteria
5272
        ->where(Criteria::expr()->eq('status', $status))
5273
        //->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
5274
        ->andWhere(Criteria::expr()->eq('visible', 1))
5275
    ;
5276
5277
    if (!empty($threadId)) {
5278
        $criteria->andWhere(Criteria::expr()->eq('thread', $threadId));
5279
    }
5280
5281
    $qb = $em->getRepository(CForumPost::class)->createQueryBuilder('p');
5282
    $qb->select('count(p.iid)')
5283
        ->addCriteria($criteria);
5284
5285
    return $qb->getQuery()->getSingleScalarResult();
5286
}
5287
5288
/**
5289
 * @param CForum     $forum
5290
 * @param CForumPost $post
5291
 *
5292
 * @return bool
5293
 */
5294
function postIsEditableByStudent($forum, $post)
5295
{
5296
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
5297
        return true;
5298
    }
5299
5300
    if (1 == $forum->isModerated()) {
5301
        if (null === $post->getStatus()) {
5302
            return true;
5303
        } else {
5304
            return in_array(
5305
                $post->getStatus(),
5306
                [
5307
                    CForumPost::STATUS_WAITING_MODERATION,
5308
                    CForumPost::STATUS_REJECTED,
5309
                ]
5310
            );
5311
        }
5312
    }
5313
5314
    return true;
5315
}
5316
5317
/**
5318
 * @return bool
5319
 */
5320
function savePostRevision(CForumPost $post)
5321
{
5322
    $userId = api_get_user_id();
5323
5324
    if ($post->getUser()->getId() != $userId) {
5325
        return false;
5326
    }
5327
5328
    $status = (int) !postNeedsRevision($post);
5329
    $extraFieldValue = new ExtraFieldValue('forum_post');
5330
    $params = [
5331
        'item_id' => $post->getIid(),
5332
        'extra_ask_for_revision' => ['extra_ask_for_revision' => $status],
5333
    ];
5334
    if (empty($status)) {
5335
        unset($params['extra_ask_for_revision']);
5336
    }
5337
    $extraFieldValue->saveFieldValues(
5338
        $params,
5339
        true,
5340
        false,
5341
        ['ask_for_revision']
5342
    );
5343
}
5344
5345
/**
5346
 * @param int $postId
5347
 *
5348
 * @return string
5349
 */
5350
function getPostRevision($postId)
5351
{
5352
    $extraFieldValue = new ExtraFieldValue('forum_post');
5353
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
5354
        $postId,
5355
        'revision_language'
5356
    );
5357
    $revision = '';
5358
    if ($value && isset($value['value'])) {
5359
        $revision = $value['value'];
5360
    }
5361
5362
    return $revision;
5363
}
5364
5365
function postNeedsRevision(CForumPost $post): bool
5366
{
5367
    $postId = $post->getIid();
5368
    $extraFieldValue = new ExtraFieldValue('forum_post');
5369
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
5370
        $postId,
5371
        'ask_for_revision'
5372
    );
5373
    $hasRevision = false;
5374
    if ($value && isset($value['value'])) {
5375
        return 1 == $value['value'];
5376
    }
5377
5378
    return $hasRevision;
5379
}
5380
5381
/**
5382
 * @param array $threadInfo
5383
 *
5384
 * @return string
5385
 */
5386
function getAskRevisionButton(CForumPost $post, $threadInfo)
5387
{
5388
    if (false === api_get_configuration_value('allow_forum_post_revisions')) {
5389
        return '';
5390
    }
5391
5392
    $postId = $post->getIid();
5393
5394
    $status = 'btn-default';
5395
    if (postNeedsRevision($post)) {
5396
        $status = 'btn-success';
5397
    }
5398
5399
    return Display::url(
5400
        get_lang('Ask for a revision'),
5401
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
5402
        api_get_cidreq().'&action=ask_revision&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
5403
        ['class' => "btn $status", 'title' => get_lang('Ask for a revision')]
5404
    );
5405
}
5406
5407
/**
5408
 * @param int   $postId
5409
 * @param array $threadInfo
5410
 *
5411
 * @return string
5412
 */
5413
function giveRevisionButton($postId, $threadInfo)
5414
{
5415
    $postId = (int) $postId;
5416
5417
    return Display::toolbarButton(
5418
        get_lang('Give revision'),
5419
        api_get_path(WEB_CODE_PATH).'forum/reply.php?'.api_get_cidreq().'&'.http_build_query(
5420
            [
5421
                'forum' => $threadInfo['forum_id'],
5422
                'thread' => $threadInfo['thread_id'],
5423
                'post' => $postId,
5424
                'action' => 'replymessage',
5425
                'give_revision' => 1,
5426
            ]
5427
        ),
5428
        'reply',
5429
        'primary',
5430
        ['id' => "reply-to-post-{$postId}"]
5431
    );
5432
}
5433
5434
/**
5435
 * @param int   $postId
5436
 * @param array $threadInfo
5437
 *
5438
 * @return string
5439
 */
5440
function getReportButton($postId, $threadInfo)
5441
{
5442
    $postId = (int) $postId;
5443
5444
    return Display::url(
5445
        Display::returnFontAwesomeIcon('flag'),
5446
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
5447
        api_get_cidreq().'&action=report&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
5448
        ['class' => 'btn btn-danger', 'title' => get_lang('Report')]
5449
    );
5450
}
5451
5452
/**
5453
 * @return bool
5454
 */
5455
function reportAvailable()
5456
{
5457
    $extraFieldValue = new ExtraFieldValue('course');
5458
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
5459
        api_get_course_int_id(),
5460
        'allow_forum_report_button'
5461
    );
5462
    $allowReport = false;
5463
    if ($value && isset($value['value']) && 1 == $value['value']) {
5464
        $allowReport = true;
5465
    }
5466
5467
    return $allowReport;
5468
}
5469
5470
/**
5471
 * @return array
5472
 */
5473
function getReportRecipients()
5474
{
5475
    $extraFieldValue = new ExtraFieldValue('course');
5476
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
5477
        api_get_course_int_id(),
5478
        'forum_report_recipients'
5479
    );
5480
    $users = [];
5481
    if ($value && isset($value['value'])) {
5482
        $usersType = explode(';', $value['value']);
5483
5484
        foreach ($usersType as $type) {
5485
            switch ($type) {
5486
                case 'teachers':
5487
                    $teachers = CourseManager::get_teacher_list_from_course_code(api_get_course_id());
5488
                    if (!empty($teachers)) {
5489
                        $users = array_merge($users, array_column($teachers, 'user_id'));
5490
                    }
5491
5492
                break;
5493
                case 'admins':
5494
                    $admins = UserManager::get_all_administrators();
5495
                    if (!empty($admins)) {
5496
                        $users = array_merge($users, array_column($admins, 'user_id'));
5497
                    }
5498
5499
                    break;
5500
                case 'community_managers':
5501
                    $managers = api_get_configuration_value('community_managers_user_list');
5502
                    if (!empty($managers) && isset($managers['users'])) {
5503
                        $users = array_merge($users, $managers['users']);
5504
                    }
5505
5506
                    break;
5507
            }
5508
        }
5509
5510
        $users = array_unique(array_filter($users));
5511
    }
5512
5513
    return $users;
5514
}
5515
5516
/**
5517
 * @param array $forumInfo
5518
 * @param array $threadInfo
5519
 *
5520
 * @return bool
5521
 */
5522
function reportPost(CForumPost $post, $forumInfo, $threadInfo)
5523
{
5524
    if (!reportAvailable()) {
5525
        return false;
5526
    }
5527
5528
    if (empty($forumInfo) || empty($threadInfo)) {
5529
        return false;
5530
    }
5531
5532
    $postId = $post->getIid();
5533
5534
    $currentUser = api_get_user_info();
5535
    $users = getReportRecipients();
5536
    if (!empty($users)) {
5537
        $url = api_get_path(WEB_CODE_PATH).
5538
            'forum/viewthread.php?forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'].'&'.api_get_cidreq().'&post_id='.$postId.'#post_id_'.$postId;
5539
        $postLink = Display::url(
5540
            $post->getPostTitle(),
5541
            $url
5542
        );
5543
        $subject = get_lang('Post reported');
5544
        $content = sprintf(
5545
            get_lang('User %s has reported the message %s in the forum %s'),
5546
            $currentUser['complete_name'],
5547
            $postLink,
5548
            $forumInfo['forum_title']
5549
        );
5550
        foreach ($users as $userId) {
5551
            MessageManager::send_message_simple($userId, $subject, $content);
5552
        }
5553
    }
5554
}
5555