Passed
Push — master ( 254001...bfc3ee )
by Julito
14:11
created

approvePost()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 4
nop 2
dl 0
loc 16
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\GradebookLink;
6
use Chamilo\CoreBundle\Framework\Container;
7
use Chamilo\CourseBundle\Entity\CForumAttachment;
8
use Chamilo\CourseBundle\Entity\CForumCategory;
9
use Chamilo\CourseBundle\Entity\CForumForum;
10
use Chamilo\CourseBundle\Entity\CForumNotification;
11
use Chamilo\CourseBundle\Entity\CForumPost;
12
use Chamilo\CourseBundle\Entity\CForumThread;
13
use ChamiloSession as Session;
14
use Doctrine\Common\Collections\Criteria;
15
use Symfony\Component\HttpFoundation\File\UploadedFile;
16
17
/*
18
 * These files are a complete rework of the forum. The database structure is
19
 * based on phpBB but all the code is rewritten. A lot of new functionalities
20
 * are added:
21
 * - forum categories and forums can be sorted up or down, locked or made invisible
22
 * - consistent and integrated forum administration
23
 * - forum options:     are students allowed to edit their post?
24
 *                         moderation of posts (approval)
25
 *                         reply only forums (students cannot create new threads)
26
 *                         multiple forums per group
27
 * - sticky messages
28
 * - new view option: nested view
29
 * - quoting a message.
30
 *
31
 * @package chamilo.forum
32
 *
33
 * @todo convert into a class
34
 */
35
define('FORUM_NEW_POST', 0);
36
getNotificationsPerUser();
37
38
$htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
39
$htmlHeadXtra[] = '<script>
40
41
function check_unzip() {
42
    if (document.upload.unzip.checked){
43
        document.upload.if_exists[0].disabled=true;
44
        document.upload.if_exists[1].checked=true;
45
        document.upload.if_exists[2].disabled=true;
46
    } else {
47
        document.upload.if_exists[0].checked=true;
48
        document.upload.if_exists[0].disabled=false;
49
        document.upload.if_exists[2].disabled=false;
50
    }
51
}
52
function setFocus() {
53
    $("#title_file").focus();
54
}
55
</script>';
56
// The next javascript script is to manage ajax upload file
57
$htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
58
59
// Recover Thread ID, will be used to generate delete attachment URL to do ajax
60
$threadId = isset($_REQUEST['thread']) ? (int) ($_REQUEST['thread']) : 0;
61
$forumId = isset($_REQUEST['forum']) ? (int) ($_REQUEST['forum']) : 0;
62
63
$ajaxUrl = api_get_path(WEB_AJAX_PATH).'forum.ajax.php?'.api_get_cidreq();
64
// The next javascript script is to delete file by ajax
65
$htmlHeadXtra[] = '<script>
66
$(function () {
67
    $(document).on("click", ".deleteLink", function(e) {
68
        e.preventDefault();
69
        e.stopPropagation();
70
        var l = $(this);
71
        var id = l.closest("tr").attr("id");
72
        var filename = l.closest("tr").find(".attachFilename").html();
73
        if (confirm("'.get_lang('Are you sure to delete').'", filename)) {
74
            $.ajax({
75
                type: "POST",
76
                url: "'.$ajaxUrl.'&a=delete_file&attachId=" + id +"&thread='.$threadId.'&forum='.$forumId.'",
77
                dataType: "json",
78
                success: function(data) {
79
                    if (data.error == false) {
80
                        l.closest("tr").remove();
81
                        if ($(".files td").length < 1) {
82
                            $(".files").closest(".control-group").hide();
83
                        }
84
                    }
85
                }
86
            })
87
        }
88
    });
89
});
90
</script>';
91
92
function handleForum($url)
93
{
94
    $id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : null;
95
96
    if (api_is_allowed_to_edit(false, true)) {
97
        //if is called from a learning path lp_id
98
        $lp_id = isset($_REQUEST['lp_id']) ? (int) $_REQUEST['lp_id'] : null;
99
        $content = isset($_REQUEST['content']) ? $_REQUEST['content'] : '';
100
        $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null;
101
102
        $repo = null;
103
104
        switch ($content) {
105
            case 'forumcategory':
106
                $repo = Container::getForumCategoryRepository();
107
                break;
108
            case 'forum':
109
                $repo = Container::getForumRepository();
110
                break;
111
            case 'thread':
112
                $repo = Container::getForumThreadRepository();
113
                break;
114
        }
115
116
        if ($repo && $id) {
117
            $resource = $repo->find($id);
118
        }
119
120
        switch ($action) {
121
            case 'add_forum':
122
                $formContent = forumForm(null, $lp_id);
123
124
                return $formContent;
125
                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...
126
            case 'edit_forum':
127
                $repo = Container::getForumRepository();
128
                $resource = $repo->find($id);
129
                $formContent = forumForm($resource, $lp_id);
130
131
                return $formContent;
132
                break;
133
            case 'add_category':
134
                $formContent = show_add_forumcategory_form([], $lp_id);
135
136
                return $formContent;
137
                break;
138
            case 'edit_category':
139
                $repo = Container::getForumCategoryRepository();
140
                $category = $repo->find($id);
141
                $formContent = editForumCategoryForm($category);
142
143
                return $formContent;
144
                break;
145
            case 'notify':
146
                if (0 != api_get_session_id() &&
147
                    false == api_is_allowed_to_session_edit(false, true)
148
                ) {
149
                    api_not_allowed();
150
                }
151
                $message = set_notification($content, $id);
152
                Display::addFlash(Display::return_message($message, 'confirm', false));
153
154
                header('Location: '.$url);
155
                exit;
156
                break;
157
            case 'lock':
158
            case 'unlock':
159
                if ($resource) {
160
                    if ('lock' === $action) {
161
                        $locked = 1;
162
                        $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');
163
                    } else {
164
                        $locked = 0;
165
                        $message = get_lang('Unlocked: learners can post new messages in this forum category, forum or thread');
166
                    }
167
168
                    $resource->setLocked($locked);
169
                    $repo->getEntityManager()->persist($resource);
170
                    $repo->getEntityManager()->flush();
171
172
                    Display::addFlash(
173
                        Display::return_message($message, 'confirmation', false)
174
                    );
175
                }
176
177
                header('Location: '.$url);
178
                exit;
179
                break;
180
            case 'move':
181
                move_up_down($content, $_REQUEST['direction'] ?? '', $id);
182
                header('Location: '.$url);
183
                exit;
184
                break;
185
            case 'move_thread':
186
                $message = move_thread_form();
187
188
                return $message;
189
                break;
190
            case 'visible':
191
            case 'invisible':
192
                if ('visible' === $action) {
193
                    $repo->setVisibilityPublished($resource);
194
                } else {
195
                    $repo->setVisibilityPending($resource);
196
                }
197
198
                if ('visible' === $action) {
199
                    handle_mail_cue($content, $id);
200
                }
201
202
                Display::addFlash(
203
                    Display::return_message(get_lang('Updated'), 'confirmation', false)
204
                );
205
                header('Location: '.$url);
206
                exit;
207
                break;
208
            case 'delete':
209
                $locked = api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD);
210
                if ($resource && false === $locked) {
211
                    $repo->delete($resource);
212
213
                    if ('thread' === $content) {
214
                        $return_message = get_lang('Thread deleted');
215
                        Skill::deleteSkillsFromItem($id, ITEM_TYPE_FORUM_THREAD);
216
                    }
217
218
                    $link_info = GradebookUtils::isResourceInCourseGradebook(
219
                        api_get_course_id(),
220
                        5,
221
                        $id,
222
                        api_get_session_id()
223
                    );
224
225
                    if (false !== $link_info) {
226
                        $link_id = $link_info['id'];
227
                        GradebookUtils::remove_resource_from_course_gradebook($link_id);
228
                    }
229
                }
230
231
                Display::addFlash(Display::return_message(get_lang('Forum category deleted'), 'confirmation', false));
232
                header('Location: '.$url);
233
                exit;
234
                break;
235
        }
236
    }
237
}
238
239
/**
240
 * This function displays the form that is used to add a forum category.
241
 *
242
 * @param int $lp_id Learning path ID
243
 *
244
 * @return string
245
 *
246
 * @author Patrick Cool <[email protected]>, Ghent University
247
 * @author Juan Carlos Raña Trabado (return to lp_id)
248
 *
249
 * @version may 2011, Chamilo 1.8.8
250
 */
251
function show_add_forumcategory_form($lp_id)
252
{
253
    $form = new FormValidator(
254
        'forumcategory',
255
        'post',
256
        'index.php?'.api_get_cidreq().'&action=add_category'
257
    );
258
    // hidden field if from learning path
259
    $form->addElement('hidden', 'lp_id', $lp_id);
260
    $form->addElement('hidden', 'action', 'add_category');
261
    // Setting the form elements.
262
    $form->addElement('header', get_lang('Add forum category'));
263
    $form->addElement('text', 'forum_category_title', get_lang('Title'), ['autofocus']);
264
    $form->addElement(
265
        'html_editor',
266
        'forum_category_comment',
267
        get_lang('Description'),
268
        null,
269
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
270
    );
271
272
    $extraField = new ExtraField('forum_category');
273
    $extraField->addElements(
274
        $form,
275
        null,
276
        [], //exclude
277
        false, // filter
278
        false, // tag as select
279
        [], //show only fields
280
        [], // order fields
281
        [] // extra data
282
    );
283
284
    $form->addButtonCreate(get_lang('Create category'), 'SubmitForumCategory');
285
286
    // Setting the rules.
287
    $form->addRule('forum_category_title', get_lang('Required field'), 'required');
288
289
    // The validation or display
290
    if ($form->validate()) {
291
        $check = Security::check_token('post');
292
        if ($check) {
293
            $values = $form->exportValues();
294
            store_forumcategory($values);
295
        }
296
        Security::clear_token();
297
    } else {
298
        $token = Security::get_token();
299
        $form->addElement('hidden', 'sec_token');
300
        $form->setConstants(['sec_token' => $token]);
301
302
        return $form->returnForm();
303
    }
304
}
305
306
function forumForm(CForumForum $forum = null, $lp_id)
307
{
308
    $_course = api_get_course_info();
309
    // The header for the form
310
    $form_title = get_lang('Add a forum');
311
    $action = 'add_forum';
312
    $id = 0;
313
    if ($forum) {
314
        $id = $forum->getIid();
315
        $action = 'edit_forum';
316
        $form_title = get_lang('Edit forum');
317
    }
318
319
    $form = new FormValidator('forumcategory', 'post', 'index.php?'.api_get_cidreq().'&action='.$action.'&id='.$id);
320
    $form->addHidden('action', $action);
321
    $form->addHeader($form_title);
322
323
    // We have a hidden field if we are editing.
324
    if ($forum) {
325
        $form->addElement('hidden', 'forum_id', $id);
326
    }
327
    $lp_id = (int) $lp_id;
328
329
    // hidden field if from learning path
330
    $form->addElement('hidden', 'lp_id', $lp_id);
331
332
    // The title of the forum
333
    $form->addElement('text', 'forum_title', get_lang('Title'), ['autofocus']);
334
335
    // The comment of the forum.
336
    $form->addElement(
337
        'html_editor',
338
        'forum_comment',
339
        get_lang('Description'),
340
        null,
341
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
342
    );
343
344
    // Dropdown list: Forum categories
345
    $forum_categories = get_forum_categories();
346
    $forum_categories_titles = [];
347
    foreach ($forum_categories as $value) {
348
        $forum_categories_titles[$value->getCatId()] = $value->getCatTitle();
349
    }
350
    $form->addElement(
351
        'select',
352
        'forum_category',
353
        get_lang('Create in category'),
354
        $forum_categories_titles
355
    );
356
    $form->applyFilter('forum_category', 'html_filter');
357
358
    if (COURSE_VISIBILITY_OPEN_WORLD == $_course['visibility']) {
359
        // This is for horizontal
360
        $group = [];
361
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('Yes'), 1);
362
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('No'), 0);
363
        $form->addGroup($group, 'allow_anonymous_group', get_lang('Allow anonymous posts?'));
364
    }
365
366
    $form->addButtonAdvancedSettings('advanced_params');
367
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
368
369
    $form->addDateTimePicker(
370
        'start_time',
371
        [get_lang('Public access (access authorized to any member of the course)ation date'), get_lang('Public access (access authorized to any member of the course)ation dateComment')],
372
        ['id' => 'start_time']
373
    );
374
375
    $form->addDateTimePicker(
376
        'end_time',
377
        [get_lang('Closing date'), get_lang('Closing dateComment')],
378
        ['id' => 'end_time']
379
    );
380
381
    $form->addRule(
382
        ['start_time', 'end_time'],
383
        get_lang('Start date must be before the end date'),
384
        'compare_datetime_text',
385
        '< allow_empty'
386
    );
387
388
    $group = [];
389
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('Yes'), 1);
390
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('No'), 0);
391
    $form->addGroup($group, 'moderated', get_lang('Moderated forum'));
392
393
    $group = [];
394
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('Yes'), 1);
395
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('No'), 0);
396
    $form->addGroup($group, 'students_can_edit_group', get_lang('Can learners edit their own posts?'));
397
398
    $group = [];
399
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Approval'), 1);
400
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Direct'), 0);
401
402
    $group = [];
403
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('Yes'), 1);
404
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('No'), 0);
405
406
    $group = [];
407
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('Yes'), 1);
408
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('No'), 0);
409
    $form->addGroup($group, 'allow_new_threads_group', get_lang('Allow users to start new threads'));
410
411
    $group = [];
412
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Flat'), 'flat');
413
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Threaded'), 'threaded');
414
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Nested'), 'nested');
415
    $form->addGroup($group, 'default_view_type_group', get_lang('Default view type'));
416
417
    // Drop down list: Groups
418
    $groups = GroupManager::get_group_list();
419
    $groups_titles[0] = get_lang('Not a group forum');
420
    foreach ($groups as $key => $value) {
421
        $groups_titles[$value['id']] = $value['name'];
422
    }
423
    $form->addElement('select', 'group_forum', get_lang('For Group'), $groups_titles);
424
425
    // Public or private group forum
426
    $group = [];
427
    $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Public access (access authorized to any member of the course)'), 'public');
428
    $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Private access (access authorized to group members only)'), 'private');
429
    $form->addGroup($group, 'public_private_group_forum_group', get_lang('Public access (access authorized to any member of the course)Private access (access authorized to group members only)GroupForum'));
430
431
    // Forum image
432
    $form->addProgress();
433
    /*
434
    if ($forum) {
435
        $baseImagePath = api_get_course_path().'/upload/forum/images/'.$inputvalues['forum_image'];
436
        $image_path = api_get_path(WEB_COURSE_PATH).$baseImagePath;
437
        $sysImagePath = api_get_path(SYS_COURSE_PATH).$baseImagePath;
438
439
        if (file_exists($sysImagePath)) {
440
            $show_preview_image = Display::img(
441
                $image_path,
442
                null,
443
                ['class' => 'img-responsive']
444
            );
445
            $form->addElement('label', get_lang('Preview image'), $show_preview_image);
446
            $form->addElement('checkbox', 'remove_picture', null, get_lang('Remove picture'));
447
        }
448
    }
449
    $forum_image = isset($inputvalues['forum_image']) ? $inputvalues['forum_image'] : '';
450
    $form->addElement('file', 'picture', ('' != $forum_image ? get_lang('Update Image') : get_lang('Add image')));
451
    $form->addRule(
452
        'picture',
453
        get_lang('Only PNG, JPG or GIF images allowed'),
454
        'filetype',
455
        ['jpg', 'jpeg', 'png', 'gif']
456
    );*/
457
458
    //$forumId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
459
    //$skillList = Skill::addSkillsToForm($form, ITEM_TYPE_FORUM, $forumId);
460
461
    $form->addElement('html', '</div>');
462
463
    // The OK button
464
    if ($forum) {
465
        $form->addButtonUpdate(get_lang('Edit forum'), 'SubmitForum');
466
    } else {
467
        $form->addButtonCreate(get_lang('Create forum'), 'SubmitForum');
468
    }
469
470
    // setting the rules
471
    $form->addRule('forum_title', get_lang('Required field'), 'required');
472
    $form->addRule('forum_category', get_lang('Required field'), 'required');
473
474
    $defaultSettingAllowNewThreads = api_get_default_tool_setting('forum', 'allow_new_threads', 0);
475
476
    // Settings the defaults
477
    if (null === $forum) {
478
        $defaults['moderated']['moderated'] = 0;
479
        $defaults['allow_anonymous_group']['allow_anonymous'] = 0;
480
        $defaults['students_can_edit_group']['students_can_edit'] = 0;
481
        $defaults['approval_direct_group']['approval_direct'] = 0;
482
        $defaults['allow_attachments_group']['allow_attachments'] = 1;
483
        $defaults['allow_new_threads_group']['allow_new_threads'] = $defaultSettingAllowNewThreads;
484
        $defaults['default_view_type_group']['default_view_type'] = api_get_setting('default_forum_view');
485
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = 'public';
486
        if (isset($_GET['forumcategory'])) {
487
            $defaults['forum_category'] = Security::remove_XSS($_GET['forumcategory']);
488
        }
489
    } else {
490
        // the default values when editing = the data in the table
491
        $defaults['forum_id'] = $forum->getIid();
492
        $defaults['forum_title'] = prepare4display($forum->getForumTitle());
493
        $defaults['forum_comment'] = prepare4display($forum->getForumComment());
494
        $defaults['start_time'] = api_get_local_time($forum->getStartTime());
495
        $defaults['end_time'] = api_get_local_time($forum->getEndTime());
496
        $defaults['moderated']['moderated'] = $forum->isModerated();
497
        $defaults['forum_category'] = $forum->getForumCategory()->getIid();
498
        $defaults['allow_anonymous_group']['allow_anonymous'] = $forum->getAllowAnonymous();
499
        $defaults['students_can_edit_group']['students_can_edit'] = $forum->getAllowEdit();
500
        $defaults['approval_direct_group']['approval_direct'] = $forum->getApprovalDirectPost();
501
        $defaults['allow_attachments_group']['allow_attachments'] = $forum->getAllowAttachments();
502
        $defaults['allow_new_threads_group']['allow_new_threads'] = $forum->getAllowNewThreads();
503
        $defaults['default_view_type_group']['default_view_type'] = $forum->getDefaultView();
504
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = $forum->getForumGroupPublicPrivate();
505
        $defaults['group_forum'] = $forum->getForumOfGroup();
506
    }
507
508
    $form->setDefaults($defaults);
509
    // Validation or display
510
    if ($form->validate()) {
511
        $check = Security::check_token('post');
512
        if ($check) {
513
            $values = $form->getSubmitValues();
514
            $forumId = store_forum($values, '', true);
515
            if ($forumId) {
516
                // Skill::saveSkills($form, ITEM_TYPE_FORUM, $forumId);
517
                if (isset($values['forum_id'])) {
518
                    Display::addFlash(Display::return_message(get_lang('The forum has been modified'), 'confirmation'));
519
                } else {
520
                    Display::addFlash(Display::return_message(get_lang('The forum has been added'), 'confirmation'));
521
                }
522
            }
523
            $url = api_get_path(WEB_CODE_PATH).'forum/index.php?'.api_get_cidreq();
524
            header('Location: '.$url);
525
            exit;
526
        }
527
        Security::clear_token();
528
    } else {
529
        $token = Security::get_token();
530
        $form->addElement('hidden', 'sec_token');
531
        $form->setConstants(['sec_token' => $token]);
532
533
        return $form->returnForm();
534
    }
535
}
536
537
/**
538
 * This function deletes the forum image if exists.
539
 *
540
 * @param int $forum_id forum id
541
 *
542
 * @return bool true if success
543
 *
544
 * @author Julio Montoya <[email protected]>
545
 *
546
 * @version february 2006, dokeos 1.8
547
 */
548
function delete_forum_image($forum_id)
549
{
550
    throw new Exception('delete_forum_image');
551
    /*$table_forums = Database::get_course_table(TABLE_FORUM);
552
    $course_id = api_get_course_int_id();
553
    $forum_id = (int) $forum_id;
554
555
    $sql = "SELECT forum_image FROM $table_forums
556
            WHERE forum_id = $forum_id AND c_id = $course_id";
557
    $result = Database::query($sql);
558
    $row = Database::fetch_array($result);
559
    if ('' != $row['forum_image']) {
560
        $file = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/forum/images/'.$row['forum_image'];
561
        if (file_exists($file)) {
562
            unlink($file);
563
        }
564
565
        return true;
566
    } else {
567
        return false;
568
    }*/
569
}
570
571
function editForumCategoryForm(CForumCategory $category)
572
{
573
    $categoryId = $category->getIid();
574
    $form = new FormValidator(
575
        'forumcategory',
576
        'post',
577
        'index.php?action=edit_category&'.api_get_cidreq().'&id='.$categoryId
578
    );
579
    // Setting the form elements.
580
    $form->addElement('header', '', get_lang('Edit forumCategory'));
581
582
    $form->addElement('hidden', 'action', 'edit_category');
583
    $form->addElement('hidden', 'forum_category_id');
584
    $form->addElement('text', 'forum_category_title', get_lang('Title'));
585
586
    $form->addElement(
587
        'html_editor',
588
        'forum_category_comment',
589
        get_lang('Comment'),
590
        null,
591
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
592
    );
593
594
    $extraField = new ExtraField('forum_category');
595
    $returnParams = $extraField->addElements(
596
        $form,
597
        $categoryId,
598
        [], //exclude
599
        false, // filter
600
        false, // tag as select
601
        [], //show only fields
602
        [], // order fields
603
        [] // extra data
604
    );
605
606
    $form->addButtonUpdate(get_lang('Edit category'), 'SubmitEdit forumCategory');
607
608
    // Setting the default values.
609
    $defaultvalues['forum_category_id'] = $categoryId;
610
    $defaultvalues['forum_category_title'] = $category->getCatTitle();
611
    $defaultvalues['forum_category_comment'] = $category->getCatComment();
612
    $form->setDefaults($defaultvalues);
613
614
    // Setting the rules.
615
    $form->addRule('forum_category_title', get_lang('Required field'), 'required');
616
617
    // Validation or display
618
    if ($form->validate()) {
619
        $check = Security::check_token('post');
620
        if ($check) {
621
            $values = $form->exportValues();
622
            store_forumcategory($values);
623
        }
624
        Security::clear_token();
625
    } else {
626
        $token = Security::get_token();
627
        $form->addElement('hidden', 'sec_token');
628
        $form->setConstants(['sec_token' => $token]);
629
630
        return $form->returnForm();
631
    }
632
}
633
634
/**
635
 * This function stores the forum category in the database.
636
 * The new category is added to the end.
637
 *
638
 * @param array $values
639
 * @param array $courseInfo
640
 * @param bool  $showMessage
641
 */
642
function store_forumcategory($values, $courseInfo = [], $showMessage = true)
643
{
644
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
645
    $course_id = $courseInfo['real_id'];
646
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
647
648
    // Find the max cat_order. The new forum category is added at the end => max cat_order + &
649
    $sql = "SELECT MAX(cat_order) as sort_max
650
            FROM $table_categories
651
            WHERE c_id = $course_id";
652
    $result = Database::query($sql);
653
    $row = Database::fetch_array($result);
654
    $new_max = $row['sort_max'] + 1;
655
    $session_id = api_get_session_id();
656
    $clean_cat_title = $values['forum_category_title'];
657
    $last_id = null;
658
    $repo = Container::getForumCategoryRepository();
659
660
    if (isset($values['forum_category_id'])) {
661
        /** @var CForumCategory $category */
662
        $category = $repo->find($values['forum_category_id']);
663
        $category
664
            ->setCatComment(isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '')
665
            ->setCatTitle($values['forum_category_title'])
666
        ;
667
668
        $repo->getEntityManager()->persist($category);
669
        $repo->getEntityManager()->flush();
670
        $message = get_lang('The forum category has been modified');
671
672
        $logInfo = [
673
            'tool' => TOOL_FORUM,
674
            'action' => 'update-forumcategory',
675
            'action_details' => 'forumcategory',
676
            'info' => $clean_cat_title,
677
        ];
678
        Event::registerLog($logInfo);
679
680
        $values['item_id'] = $values['forum_category_id'];
681
    } else {
682
        $course = api_get_course_entity($course_id);
683
        $session = api_get_session_entity($session_id);
684
685
        $category = new CForumCategory();
686
        $category
687
            ->setCatTitle($clean_cat_title)
688
            ->setCatComment(isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '')
689
            ->setCatOrder($new_max)
690
            ->setCId($course_id)
691
            ->setSessionId($session_id)
692
            ->setParent($course)
693
            ->addCourseLink($course, $session)
694
        ;
695
        $repo->getEntityManager()->persist($category);
696
        $repo->getEntityManager()->flush();
697
698
        $last_id = $category->getIid();
699
        if ($last_id > 0) {
700
            $sql = "UPDATE $table_categories SET cat_id = $last_id WHERE iid = $last_id";
701
            Database::query($sql);
702
            $message = get_lang('The forum category has been added');
703
        }
704
705
        $logInfo = [
706
            'tool' => TOOL_FORUM,
707
            'action' => 'new-forumcategory',
708
            'action_details' => 'forumcategory',
709
            'info' => $clean_cat_title,
710
        ];
711
        Event::registerLog($logInfo);
712
713
        $values['item_id'] = $last_id;
714
    }
715
716
    $extraFieldValue = new ExtraFieldValue('forum_category');
717
    $extraFieldValue->saveFieldValues($values);
718
719
    if ($showMessage) {
720
        Display::addFlash(Display::return_message($message, 'confirmation'));
721
    }
722
723
    return $last_id;
724
}
725
726
/**
727
 * This function stores the forum in the database. The new forum is added to the end.
728
 *
729
 * @param array $values
730
 * @param array $courseInfo
731
 * @param bool  $returnId
732
 *
733
 * @return string language variable
734
 */
735
function store_forum($values, $courseInfo = [], $returnId = false)
736
{
737
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
738
    $courseId = $courseInfo['real_id'];
739
    $session_id = api_get_session_id();
740
    $table_forums = Database::get_course_table(TABLE_FORUM);
741
742
    // Find the max forum_order for the given category. The new forum is added at the end => max cat_order + &
743
    if (null === $values['forum_category']) {
744
        $new_max = null;
745
    } else {
746
        $sql = "SELECT MAX(forum_order) as sort_max
747
                FROM $table_forums
748
                WHERE
749
                    c_id = $courseId AND
750
                    forum_category='".Database::escape_string($values['forum_category'])."'";
751
        $result = Database::query($sql);
752
        $row = Database::fetch_array($result);
753
        $new_max = $row['sort_max'] + 1;
754
    }
755
756
    // Forum images
757
    $has_attachment = false;
758
    $image_moved = true;
759
    if (!empty($_FILES['picture']['name'])) {
760
        $upload_ok = process_uploaded_file($_FILES['picture']);
761
        $has_attachment = true;
762
    }
763
764
    // Remove existing picture if it was requested.
765
    if (!empty($_POST['remove_picture'])) {
766
        delete_forum_image($values['forum_id']);
767
    }
768
769
    $new_file_name = '';
770
    if (isset($upload_ok)) {
771
        if ($has_attachment) {
772
            throw new Exception('$has_attachment');
773
            /*$course_dir = $courseInfo['path'].'/upload/forum/images';
774
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
775
            $updir = $sys_course_path.$course_dir;
776
            // Try to add an extension to the file if it hasn't one.
777
            $new_file_name = add_ext_on_mime(
778
                Database::escape_string($_FILES['picture']['name']),
779
                $_FILES['picture']['type']
780
            );
781
            if (!filter_extension($new_file_name)) {
782
                //Display::addFlash(Display::return_message(get_lang('File upload failed: this file extension or file type is prohibited'), 'error'));
783
                $image_moved = false;
784
            } else {
785
                $file_extension = explode('.', $_FILES['picture']['name']);
786
                $file_extension = strtolower($file_extension[count($file_extension) - 1]);
787
                $new_file_name = uniqid('').'.'.$file_extension;
788
                $new_path = $updir.'/'.$new_file_name;
789
                $result = @move_uploaded_file($_FILES['picture']['tmp_name'], $new_path);
790
                // Storing the attachments if any
791
                if ($result) {
792
                    $image_moved = true;
793
                }
794
            }*/
795
        }
796
    }
797
798
    $repo = Container::getForumRepository();
799
800
    if (!isset($values['forum_id'])) {
801
        $forum = new CForumForum();
802
        $forum
803
            ->setCId($courseId)
804
            ->setSessionId($session_id)
805
            ->setForumOrder(isset($new_max) ? $new_max : null)
806
        ;
807
    } else {
808
        $forum = $repo->find($values['forum_id']);
809
    }
810
811
    $forumCategory = null;
812
    if (!empty($values['forum_category'])) {
813
        $repoForumCategory = Container::getForumCategoryRepository();
814
        $forumCategory = $repoForumCategory->find($values['forum_category']);
815
    }
816
    //'forum_image' => $new_file_name,
817
    $forum
818
        ->setForumTitle($values['forum_title'])
819
        ->setForumComment($values['forum_comment'] ?? null)
820
        ->setForumCategory($forumCategory)
821
        ->setAllowAnonymous($values['allow_anonymous_group']['allow_anonymous'] ?? null)
822
        ->setAllowEdit($values['students_can_edit_group']['students_can_edit'] ?? null)
823
        ->setApprovalDirectPost($values['approval_direct_group']['approval_direct'] ?? null)
824
        ->setAllowAttachments($values['allow_attachments_group']['allow_attachments'] ?? null)
825
        ->setAllowNewThreads($values['allow_new_threads_group']['allow_new_threads'] ?? null)
826
        ->setDefaultView($values['default_view_type_group']['default_view_type'] ?? null)
827
        ->setForumOfGroup($values['group_forum'] ?? null)
828
        ->setForumGroupPublicPrivate($values['public_private_group_forum_group']['public_private_group_forum'] ?? '')
829
        ->setModerated($values['moderated']['moderated'] ?? null)
830
        ->setStartTime(!empty($values['start_time']) ? api_get_utc_datetime($values['start_time'], true, true) : null)
831
        ->setEndTime(!empty($values['end_time']) ? api_get_utc_datetime($values['end_time'], true, true) : null)
832
        ->setSessionId($session_id)
833
        ->setLpId($values['lp_id'] ?? 0)
834
    ;
835
836
    $course = api_get_course_entity($courseId);
837
    $session = api_get_session_entity($session_id);
838
839
    if (isset($values['forum_id'])) {
840
        // Edit
841
        $repo->getEntityManager()->persist($forum);
842
        $repo->getEntityManager()->flush();
843
844
        if (isset($upload_ok)) {
845
            if ($has_attachment) {
846
                //$params['forum_image'] = $new_file_name;
847
            }
848
        }
849
850
        if (isset($values['remove_picture']) && 1 == $values['remove_picture']) {
851
            /*$params['forum_image'] = '';
852
            delete_forum_image($values['forum_id']);*/
853
        }
854
855
        // Move groups from one group to another
856
        if (isset($values['group_forum']) && false) {
857
            $forumData = get_forums($values['forum_id']);
858
            $currentGroupId = $forumData['forum_of_group'];
859
            if ($currentGroupId != $values['group_forum']) {
860
                $threads = get_threads($values['forum_id']);
861
                $toGroupId = 'NULL';
862
                if (!empty($values['group_forum'])) {
863
                    $toGroupId = $values['group_forum'];
864
                }
865
                $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
866
                foreach ($threads as $thread) {
867
                    /*$sql = "UPDATE $tableItemProperty
868
                            SET to_group_id = $toGroupId
869
                            WHERE
870
                                tool = '".TOOL_FORUM_THREAD."' AND
871
                                ref = ".$thread['thread_id'].' AND
872
                                c_id = '.$courseId;
873
                    Database::query($sql);
874
875
                    $posts = getPosts(
876
                        $forumData,
877
                        $thread['thread_id']
878
                    );*/
879
880
                    /*foreach ($posts as $post) {
881
                        $postId = $post['post_id'];
882
                        $attachMentList = getAllAttachment($postId);
883
                        if (!empty($attachMentList)) {
884
                            foreach ($attachMentList as $attachMent) {
885
                                $sql = "UPDATE $tableItemProperty
886
                                        SET to_group_id = $toGroupId
887
                                        WHERE
888
                                            tool = '".TOOL_FORUM_ATTACH."' AND
889
                                            ref = ".$attachMent['iid'].' AND
890
                                            c_id = '.$courseId;
891
                                Database::query($sql);
892
                            }
893
                        }
894
895
                        $sql = "UPDATE $tableItemProperty
896
                                SET to_group_id = $toGroupId
897
                                WHERE
898
                                    tool = '".TOOL_FORUM_POST."' AND
899
                                    ref = $postId AND
900
                                    c_id = $courseId";
901
                        Database::query($sql);
902
                    }*/
903
                }
904
            }
905
        }
906
907
        /*
908
        api_item_property_update(
909
            $courseInfo,
910
            TOOL_FORUM,
911
            Database::escape_string($values['forum_id']),
912
            'ForumUpdated',
913
            api_get_user_id(),
914
            $groupInfo
915
        );*/
916
917
        $return_message = get_lang('The forum has been modified');
918
        $forumId = $forum->getIid();
919
920
        $logInfo = [
921
            'tool' => TOOL_FORUM,
922
            'tool_id' => $values['forum_id'],
923
            'action' => 'update-forum',
924
            'action_details' => 'forum',
925
            'info' => $values['forum_title'],
926
        ];
927
        Event::registerLog($logInfo);
928
    } else {
929
        if ($image_moved) {
930
            $new_file_name = isset($new_file_name) ? $new_file_name : '';
931
        }
932
        $forum
933
            ->setParent($course)
934
            ->addCourseLink($course, $session);
935
        $repo->getEntityManager()->persist($forum);
936
        $repo->getEntityManager()->flush();
937
938
        $forumId = $forum->getIid();
939
        if ($forumId > 0) {
940
            $courseCode = $courseInfo['code'];
941
            $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications');
942
943
            $status = STUDENT;
944
            if (!empty($session_id)) {
945
                $status = 0;
946
            }
947
            if (1 === $subscribe) {
948
                $userList = CourseManager::get_user_list_from_course_code(
949
                    $courseCode,
950
                    $session_id,
951
                    null,
952
                    null,
953
                    $status
954
                );
955
                foreach ($userList as $userInfo) {
956
                    set_notification('forum', $forumId, false, $userInfo, $courseInfo);
957
                }
958
            }
959
960
            /*api_item_property_update(
961
                $courseInfo,
962
                TOOL_FORUM,
963
                $forumId,
964
                'ForumAdded',
965
                api_get_user_id(),
966
                $groupInfo
967
            );
968
969
            api_set_default_visibility(
970
                $forumId,
971
                TOOL_FORUM,
972
                $group_id,
973
                $courseInfo
974
            );*/
975
976
            $logInfo = [
977
                'tool' => TOOL_FORUM,
978
                'tool_id' => $forumId,
979
                'action' => 'new-forum',
980
                'action_details' => 'forum',
981
                'info' => $values['forum_title'],
982
            ];
983
            Event::registerLog($logInfo);
984
        }
985
        $return_message = get_lang('The forum has been added');
986
    }
987
988
    if ($returnId) {
989
        return $forumId;
990
    }
991
992
    return $return_message;
993
}
994
995
function deletePost(CForumPost $post)
996
{
997
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
998
    $course_id = api_get_course_int_id();
999
    $em = Database::getManager();
1000
    if ($post) {
1001
        $em
1002
            ->createQuery('
1003
                UPDATE ChamiloCourseBundle:CForumPost p
1004
                SET p.postParentId = :parent_of_deleted_post
1005
                WHERE
1006
                    p.cId = :course AND
1007
                    p.postParentId = :post AND
1008
                    p.thread = :thread_of_deleted_post AND
1009
                    p.forum = :forum_of_deleted_post
1010
            ')
1011
            ->execute([
1012
                'parent_of_deleted_post' => $post->getPostParentId(),
1013
                'course' => $course_id,
1014
                'post' => $post->getIid(),
1015
                'thread_of_deleted_post' => $post->getThread() ? $post->getThread()->getIid() : 0,
1016
                'forum_of_deleted_post' => $post->getForum(),
1017
            ]);
1018
1019
        $attachments = $post->getAttachments();
1020
        if (!empty($attachments)) {
1021
            foreach ($attachments as $attachment) {
1022
                $em->remove($attachment);
1023
            }
1024
        }
1025
1026
        $em->remove($post);
1027
        $em->flush();
1028
    }
1029
1030
    $last_post_of_thread = check_if_last_post_of_thread($_GET['thread']);
1031
1032
    if (is_array($last_post_of_thread)) {
1033
        // Decreasing the number of replies for this thread and also changing the last post information.
1034
        $sql = "UPDATE $table_threads
1035
                SET
1036
                    thread_replies = thread_replies - 1,
1037
                    thread_last_post = ".(int) ($last_post_of_thread['iid']).",
1038
                    thread_date='".Database::escape_string($last_post_of_thread['post_date'])."'
1039
                WHERE c_id = $course_id AND iid = ".(int) ($_GET['thread']);
1040
        Database::query($sql);
1041
        Display::addFlash(Display::return_message(get_lang('Post has been deleted')));
1042
    }
1043
    if (!$last_post_of_thread) {
1044
        // We deleted the very single post of the thread so we need to delete the entry in the thread table also.
1045
        $sql = "DELETE FROM $table_threads
1046
                WHERE c_id = $course_id AND iid = ".(int) ($_GET['thread']);
1047
        Database::query($sql);
1048
1049
        Display::addFlash(Display::return_message(get_lang('Special Post Deleted')));
1050
    }
1051
}
1052
1053
/**
1054
 * This function gets the all information of the last (=most recent) post of the thread
1055
 * This can be done by sorting the posts that have the field thread_id=$thread_id and sort them by post_date.
1056
 *
1057
 * @param int $thread_id id of the thread we want to know the last post of
1058
 *
1059
 * @return array an array or bool if there is a last post found, false if there is
1060
 *               no post entry linked to that thread => thread will be deleted
1061
 *
1062
 * @author Patrick Cool <[email protected]>, Ghent University
1063
 *
1064
 * @version february 2006, dokeos 1.8
1065
 */
1066
function check_if_last_post_of_thread($thread_id)
1067
{
1068
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1069
    $course_id = api_get_course_int_id();
1070
    $sql = "SELECT * FROM $table_posts
1071
            WHERE thread_id = ".(int) $thread_id.'
1072
            ORDER BY post_date DESC';
1073
    $result = Database::query($sql);
1074
    if (Database::num_rows($result) > 0) {
1075
        return Database::fetch_array($result);
1076
    }
1077
1078
    return false;
1079
}
1080
1081
/**
1082
 * @param string $content                   Type of content forum category, forum, thread, post
1083
 * @param int    $id                        the id of the content we want to make invisible
1084
 * @param int    $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
1085
 * @param array  $additional_url_parameters
1086
 *
1087
 * @return string HTML
1088
 */
1089
function return_visible_invisible_icon(
1090
    $content,
1091
    $id,
1092
    $current_visibility_status,
1093
    $additional_url_parameters = []
1094
) {
1095
    $html = '';
1096
    $id = (int) $id;
1097
    $current_visibility_status = (int) $current_visibility_status;
1098
1099
    if (1 == $current_visibility_status) {
1100
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1101
        if (is_array($additional_url_parameters)) {
1102
            foreach ($additional_url_parameters as $key => $value) {
1103
                $html .= $key.'='.$value.'&';
1104
            }
1105
        }
1106
        $html .= 'action=invisible&content='.$content.'&id='.$id.'">'.
1107
            Display::return_icon('visible.png', get_lang('MakeInvisible'), [], ICON_SIZE_SMALL).'</a>';
1108
    }
1109
    if (0 == $current_visibility_status) {
1110
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1111
        if (is_array($additional_url_parameters)) {
1112
            foreach ($additional_url_parameters as $key => $value) {
1113
                $html .= $key.'='.$value.'&';
1114
            }
1115
        }
1116
        $html .= 'action=visible&content='.$content.'&id='.$id.'">'.
1117
            Display::return_icon('invisible.png', get_lang('Make Visible'), [], ICON_SIZE_SMALL).'</a>';
1118
    }
1119
1120
    return $html;
1121
}
1122
1123
/**
1124
 * @param $content
1125
 * @param $id
1126
 * @param $current_lock_status
1127
 * @param string $additional_url_parameters
1128
 *
1129
 * @return string
1130
 */
1131
function return_lock_unlock_icon($content, $id, $current_lock_status, $additional_url_parameters = '')
1132
{
1133
    $html = '';
1134
    $id = (int) $id;
1135
    //check if the forum is blocked due
1136
    if ('thread' == $content) {
1137
        if (api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD)) {
1138
            return $html.Display::return_icon(
1139
                'lock_na.png',
1140
                get_lang('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.'),
1141
                [],
1142
                ICON_SIZE_SMALL
1143
            );
1144
        }
1145
    }
1146
    if ('1' == $current_lock_status) {
1147
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1148
        if (is_array($additional_url_parameters)) {
1149
            foreach ($additional_url_parameters as $key => $value) {
1150
                $html .= $key.'='.$value.'&';
1151
            }
1152
        }
1153
        $html .= 'action=unlock&content='.$content.'&id='.$id.'">'.
1154
            Display::return_icon('lock.png', get_lang('Unlock'), [], ICON_SIZE_SMALL).'</a>';
1155
    }
1156
    if ('0' == $current_lock_status) {
1157
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1158
        if (is_array($additional_url_parameters)) {
1159
            foreach ($additional_url_parameters as $key => $value) {
1160
                $html .= $key.'='.$value.'&';
1161
            }
1162
        }
1163
        $html .= 'action=lock&content='.$content.'&id='.$id.'">'.
1164
            Display::return_icon('unlock.png', get_lang('Lock'), [], ICON_SIZE_SMALL).'</a>';
1165
    }
1166
1167
    return $html;
1168
}
1169
1170
/**
1171
 * This function takes care of the display of the up and down icon.
1172
 *
1173
 * @param string $content what is it that we want to make (in)visible: forum category, forum, thread, post
1174
 * @param int    $id      is the id of the item we want to display the icons for
1175
 * @param array  $list    is an array of all the items. All items in this list should have
1176
 *                        an up and down icon except for the first (no up icon) and the last (no down icon)
1177
 *                        The key of this $list array is the id of the item.
1178
 *
1179
 * @return string HTML
1180
 */
1181
function return_up_down_icon($content, $id, $list)
1182
{
1183
    $id = (int) $id;
1184
    $total_items = count($list);
1185
    $position = 0;
1186
    $internal_counter = 0;
1187
    $forumCategory = isset($_GET['forumcategory']) ? Security::remove_XSS($_GET['forumcategory']) : null;
1188
1189
    if (is_array($list)) {
1190
        foreach ($list as $item) {
1191
            $internal_counter++;
1192
            if ($id == $item->getIid()) {
1193
                $position = $internal_counter;
1194
            }
1195
        }
1196
    }
1197
1198
    if ($position > 1) {
1199
        $return_value = '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=up&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('Move up').'">'.
1200
            Display::return_icon('up.png', get_lang('Move up'), [], ICON_SIZE_SMALL).'</a>';
1201
    } else {
1202
        $return_value = Display::return_icon('up_na.png', '-', [], ICON_SIZE_SMALL);
1203
    }
1204
1205
    if ($position < $total_items) {
1206
        $return_value .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=down&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('Move down').'" >'.
1207
            Display::return_icon('down.png', get_lang('Move down'), [], ICON_SIZE_SMALL).'</a>';
1208
    } else {
1209
        $return_value .= Display::return_icon('down_na.png', '-', [], ICON_SIZE_SMALL);
1210
    }
1211
1212
    return $return_value;
1213
}
1214
1215
/**
1216
 * This function moves a forum or a forum category up or down.
1217
 *
1218
 * @param string $content   is it that we want to make (in)visible: forum category, forum, thread, post
1219
 * @param string $direction we want to move it up or down
1220
 * @param int    $id        id of the content we want to make invisible
1221
 *
1222
 * @return string language variable
1223
 *
1224
 * @todo consider removing the table_item_property calls here but this can
1225
 * prevent unwanted side effects when a forum does not have an entry in
1226
 * the item_property table but does have one in the forum table.
1227
 *
1228
 * @author Patrick Cool <[email protected]>, Ghent University
1229
 *
1230
 * @version february 2006, dokeos 1.8
1231
 */
1232
function move_up_down($content, $direction, $id)
1233
{
1234
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1235
    $table_forums = Database::get_course_table(TABLE_FORUM);
1236
    $course_id = api_get_course_int_id();
1237
    $id = (int) $id;
1238
1239
    // Determine which field holds the sort order.
1240
    if ('forumcategory' === $content) {
1241
        $table = $table_categories;
1242
        $sort_column = 'cat_order';
1243
        $id_column = 'cat_id';
1244
        $sort_column = 'cat_order';
1245
    } elseif ('forum' === $content) {
1246
        $table = $table_forums;
1247
        $sort_column = 'forum_order';
1248
        $id_column = 'forum_id';
1249
        $sort_column = 'forum_order';
1250
        // We also need the forum_category of this forum.
1251
        $sql = "SELECT forum_category FROM $table_forums
1252
                WHERE c_id = $course_id AND forum_id = ".$id;
1253
        $result = Database::query($sql);
1254
        $row = Database::fetch_array($result);
1255
        $forum_category = $row['forum_category'];
1256
    } else {
1257
        return false;
1258
    }
1259
1260
    // Determine the need for sorting ascending or descending order.
1261
    if ('down' === $direction) {
1262
        $sort_direction = 'ASC';
1263
    } elseif ('up' === $direction) {
1264
        $sort_direction = 'DESC';
1265
    } else {
1266
        return false;
1267
    }
1268
1269
    // The SQL statement
1270
    if ('forumcategory' === $content) {
1271
        $sql = "SELECT *
1272
                FROM $table_categories forum_categories
1273
                WHERE
1274
                    forum_categories.c_id = $course_id
1275
                ORDER BY forum_categories.cat_order $sort_direction";
1276
    }
1277
    if ('forum' === $content) {
1278
        $sql = "SELECT *
1279
            FROM $table
1280
            WHERE
1281
                c_id = $course_id AND
1282
                forum_category='".Database::escape_string($forum_category)."'
1283
            ORDER BY forum_order $sort_direction";
1284
    }
1285
    // Finding the items that need to be switched.
1286
    $result = Database::query($sql);
1287
    $found = false;
1288
    $next_sort = '';
1289
    $this_sort = '';
1290
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1291
        //var_dump($content, $row, $id_column, $sort_column);
1292
        if ($found) {
1293
            $next_id = $row[$id_column];
1294
            $next_sort = $row[$sort_column];
1295
            $found = false;
1296
        }
1297
        if ($id == $row[$id_column]) {
1298
            $this_id = $id;
1299
            $this_sort = $row[$sort_column];
1300
            $found = true;
1301
        }
1302
    }
1303
1304
    if ('forum' === $content && $next_sort) {
1305
        $repo = Container::getForumRepository();
1306
        /** @var CForumForum $forum */
1307
        $forum = $repo->find($id);
1308
        $forum->setForumOrder($next_sort);
1309
        $repo->getEntityManager()->persist($forum);
1310
        $repo->getEntityManager()->flush();
1311
1312
        Display::addFlash(Display::return_message(get_lang('Updated')));
1313
    } else {
1314
        if ($next_sort) {
1315
            $repo = Container::getForumCategoryRepository();
1316
            /** @var CForumCategory $forum */
1317
            $category = $repo->find($id);
1318
            if ($category) {
1319
                $category->setCatOrder($next_sort);
1320
                $repo->getEntityManager()->persist($category);
1321
                $repo->getEntityManager()->flush();
1322
1323
                Display::addFlash(Display::return_message(get_lang('Updated')));
1324
            }
1325
        }
1326
    }
1327
}
1328
1329
/**
1330
 * Retrieve all the information off the forum categories (or one specific) for the current course.
1331
 * The categories are sorted according to their sorting order (cat_order.
1332
 *
1333
 * @param int $courseId  Optional. The course ID
1334
 * @param int $sessionId Optional. The session ID
1335
 *
1336
 * @return CForumCategory[]
1337
 */
1338
function get_forum_categories($courseId = 0, $sessionId = 0)
1339
{
1340
    $repo = Container::getForumCategoryRepository();
1341
1342
    $course = api_get_course_entity($courseId);
1343
    $session = api_get_session_entity($sessionId);
1344
1345
    $qb = $repo->getResources(api_get_user_entity(api_get_user_id()), $course->getResourceNode(), $course, $session);
1346
1347
    return $qb->getQuery()->getResult();
1348
}
1349
1350
/**
1351
 * This function retrieves all the fora in a given forum category.
1352
 *
1353
 * @param int $categoryId the id of the forum category
1354
 * @param int $courseId   Optional. The course ID
1355
 *
1356
 * @return CForumForum[] containing all the information about the forums (regardless of their category)
1357
 *
1358
 * @author Patrick Cool <[email protected]>, Ghent University
1359
 *
1360
 * @version february 2006, dokeos 1.8
1361
 */
1362
function get_forums_in_category($categoryId, $courseId = 0)
1363
{
1364
    $repo = Container::getForumRepository();
1365
    $course = api_get_course_entity($courseId);
1366
1367
    $qb = $repo->getResourcesByCourse($course, null);
1368
    $qb
1369
        ->andWhere('resource.forumCategory = :catId')
1370
        ->setParameter('catId', $categoryId)
1371
        ->orderBy('resource.forumOrder')
1372
    ;
1373
1374
    return $qb->getQuery()->getResult();
1375
}
1376
1377
/**
1378
 * Retrieve all the forums (regardless of their category) or of only one.
1379
 * The forums are sorted according to the forum_order.
1380
 * Since it does not take the forum category into account there probably
1381
 * will be two or more forums that have forum_order=1, ...
1382
 *
1383
 * @param bool $includeGroupsForum
1384
 * @param int  $sessionId
1385
 *
1386
 * @return CForumForum[]
1387
 */
1388
function get_forums(
1389
    $courseId = '',
1390
    $includeGroupsForum = true,
1391
    $sessionId = 0
1392
) {
1393
    $repo = Container::getForumRepository();
1394
    $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
1395
    $course = api_get_course_entity($courseId);
1396
    $session = api_get_session_entity($sessionId);
1397
1398
    $qb = $repo->getResourcesByCourse($course, $session);
1399
1400
    /*$qb->andWhere('resource.forumCategory = :catId')
1401
        ->setParameter('catId', $cat_id);
1402
    */
1403
    return $qb->getQuery()->getResult();
1404
1405
    $id = (int) $id;
0 ignored issues
show
Unused Code introduced by
$id = (int)$id 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...
1406
    $course_info = api_get_course_info($course_code);
1407
1408
    $table_forums = Database::get_course_table(TABLE_FORUM);
1409
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1410
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1411
1412
    // Condition for the session
1413
    $session_id = (int) $sessionId ?: api_get_session_id();
1414
    $sessionIdLink = 0 === $session_id ? '' : ' AND threads.session_id = item_properties.session_id';
1415
1416
    $condition_session = api_get_session_condition(
1417
        $session_id,
1418
        true,
1419
        false,
1420
        'item_properties.session_id'
1421
    );
1422
1423
    $course_id = $course_info['real_id'];
1424
1425
    $forum_list = [];
1426
    $includeGroupsForumSelect = '';
1427
    if (!$includeGroupsForum) {
1428
        $includeGroupsForumSelect = ' AND (forum_of_group = 0 OR forum_of_group IS NULL) ';
1429
    }
1430
1431
    $allowToEdit = api_is_allowed_to_edit();
1432
1433
    if (empty($id)) {
1434
        // Student
1435
        // Select all the forum information of all forums (that are visible to students).
1436
        $sql = "SELECT item_properties.*, forum.*
1437
                FROM $table_forums forum
1438
                INNER JOIN $table_item_property item_properties
1439
                ON (
1440
                    forum.forum_id = item_properties.ref AND
1441
                    forum.c_id = item_properties.c_id
1442
                )
1443
                WHERE
1444
                    item_properties.visibility = 1 AND
1445
                    item_properties.tool = '".TOOL_FORUM."'
1446
                    $condition_session AND
1447
                    forum.c_id = $course_id AND
1448
                    item_properties.c_id = $course_id
1449
                    $includeGroupsForumSelect
1450
                ORDER BY forum.forum_order ASC";
1451
1452
        // Select the number of threads of the forums (only the threads that are visible).
1453
        $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1454
                FROM $table_threads threads
1455
                INNER JOIN $table_item_property item_properties
1456
                ON (
1457
                    threads.thread_id = item_properties.ref AND
1458
                    threads.c_id = item_properties.c_id
1459
                    $sessionIdLink
1460
                )
1461
                WHERE
1462
                    item_properties.visibility=1 AND
1463
                    item_properties.tool='".TOOL_FORUM_THREAD."' AND
1464
                    threads.c_id = $course_id AND
1465
                    item_properties.c_id = $course_id
1466
                GROUP BY threads.forum_id";
1467
1468
        // Course Admin
1469
        if ($allowToEdit) {
1470
            // Select all the forum information of all forums (that are not deleted).
1471
            $sql = "SELECT item_properties.*, forum.*
1472
                    FROM $table_forums forum
1473
                    INNER JOIN $table_item_property item_properties
1474
                    ON (
1475
                        forum.forum_id = item_properties.ref AND
1476
                        forum.c_id = item_properties.c_id
1477
                    )
1478
                    WHERE
1479
                        item_properties.visibility <> 2 AND
1480
                        item_properties.tool = '".TOOL_FORUM."'
1481
                        $condition_session AND
1482
                        forum.c_id = $course_id AND
1483
                        item_properties.c_id = $course_id
1484
                        $includeGroupsForumSelect
1485
                    ORDER BY forum_order ASC";
1486
1487
            // Select the number of threads of the forums (only the threads that are not deleted).
1488
            $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1489
                    FROM $table_threads threads
1490
                    INNER JOIN $table_item_property item_properties
1491
                    ON (
1492
                        threads.thread_id = item_properties.ref AND
1493
                        threads.c_id = item_properties.c_id
1494
                        $sessionIdLink
1495
                    )
1496
                    WHERE
1497
                        item_properties.visibility<>2 AND
1498
                        item_properties.tool='".TOOL_FORUM_THREAD."' AND
1499
                        threads.c_id = $course_id AND
1500
                        item_properties.c_id = $course_id
1501
                    GROUP BY threads.forum_id";
1502
        }
1503
    } else {
1504
        // GETTING ONE SPECIFIC FORUM
1505
        /* We could do the splitup into student and course admin also but we want
1506
        to have as much as information about a certain forum as possible
1507
        so we do not take too much information into account. This function
1508
         (or this section of the function) is namely used to fill the forms
1509
        when editing a forum (and for the moment it is the only place where
1510
        we use this part of the function) */
1511
1512
        // Select all the forum information of the given forum (that is not deleted).
1513
        $sql = "SELECT * FROM $table_item_property item_properties
1514
                INNER JOIN $table_forums forum
1515
                ON (forum.forum_id = item_properties.ref AND forum.c_id = item_properties.c_id)
1516
                WHERE
1517
                    forum.forum_id = $id AND
1518
                    forum.c_id = $course_id AND
1519
                    item_properties.visibility != 2 AND
1520
                    item_properties.tool = '".TOOL_FORUM."'
1521
                ORDER BY forum_order ASC";
1522
1523
        // Select the number of threads of the forum.
1524
        $sql2 = "SELECT count(*) AS number_of_threads, forum_id
1525
                FROM $table_threads
1526
                WHERE
1527
                    forum_id = $id
1528
                GROUP BY forum_id";
1529
    }
1530
1531
    // Handling all the forum information.
1532
    $result = Database::query($sql);
1533
    while ($row = Database::fetch_assoc($result)) {
1534
        if (empty($id)) {
1535
            $forum_list[$row['forum_id']] = $row;
1536
        } else {
1537
            $forum_list = $row;
1538
        }
1539
    }
1540
1541
    // Handling the thread count information.
1542
    $result2 = Database::query($sql2);
1543
    while ($row2 = Database::fetch_array($result2)) {
1544
        if (empty($id)) {
1545
            $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
1546
        } else {
1547
            $forum_list['number_of_threads'] = $row2['number_of_threads'];
1548
        }
1549
    }
1550
1551
    /* Finding the last post information
1552
    (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)*/
1553
    if (empty($id)) {
1554
        if (is_array($forum_list)) {
1555
            foreach ($forum_list as $key => $value) {
1556
                $lastPost = get_last_post_information(
1557
                    $key,
1558
                    $allowToEdit,
1559
                    $course_id
1560
                );
1561
1562
                if ($lastPost) {
1563
                    $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
1564
                    $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
1565
                    $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
1566
                    $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
1567
                    $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
1568
                    $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
1569
                    $forum_list[$key]['last_post_title'] = $lastPost['last_post_title'];
1570
                    $forum_list[$key]['last_post_text'] = $lastPost['last_post_text'];
1571
                }
1572
            }
1573
        } else {
1574
            $forum_list = [];
1575
        }
1576
    } else {
1577
        $lastPost = get_last_post_information(
1578
            $id,
1579
            $allowToEdit,
1580
            $course_id
1581
        );
1582
        if ($lastPost) {
1583
            $forum_list['last_post_id'] = $lastPost['last_post_id'];
1584
            $forum_list['last_poster_id'] = $lastPost['last_poster_id'];
1585
            $forum_list['last_post_date'] = $lastPost['last_post_date'];
1586
            $forum_list['last_poster_name'] = $lastPost['last_poster_name'];
1587
            $forum_list['last_poster_lastname'] = $lastPost['last_poster_lastname'];
1588
            $forum_list['last_poster_firstname'] = $lastPost['last_poster_firstname'];
1589
            $forum_list['last_post_title'] = $lastPost['last_post_title'];
1590
            $forum_list['last_post_text'] = $lastPost['last_post_text'];
1591
        }
1592
    }
1593
1594
    return $forum_list;
1595
}
1596
1597
/**
1598
 * @param int  $course_id
1599
 * @param int  $thread_id
1600
 * @param int  $forum_id
1601
 * @param bool $show_visible
1602
 *
1603
 * @return array|bool
1604
 */
1605
function get_last_post_by_thread($course_id, $thread_id, $forum_id, $show_visible = true)
1606
{
1607
    if (empty($thread_id) || empty($forum_id) || empty($course_id)) {
1608
        return false;
1609
    }
1610
1611
    $thread_id = (int) $thread_id;
1612
    $forum_id = (int) $forum_id;
1613
    $course_id = (int) $course_id;
1614
1615
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1616
    $sql = "SELECT * FROM $table_posts
1617
            WHERE
1618
                c_id = $course_id AND
1619
                thread_id = $thread_id AND
1620
                forum_id = $forum_id";
1621
1622
    if (false == $show_visible) {
1623
        $sql .= ' AND visible = 1 ';
1624
    }
1625
1626
    $sql .= ' ORDER BY iid DESC LIMIT 1';
1627
    $result = Database::query($sql);
1628
    if (Database::num_rows($result)) {
1629
        return Database::fetch_array($result, 'ASSOC');
1630
    } else {
1631
        return false;
1632
    }
1633
}
1634
1635
/**
1636
 * This function gets all the last post information of a certain forum.
1637
 *
1638
 * @param int    $forum_id        the id of the forum we want to know the last post information of
1639
 * @param bool   $show_invisibles
1640
 * @param string $course_id       course db name
1641
 * @param int    $sessionId       Optional. The session id
1642
 *
1643
 * @return array containing all the information about the last post
1644
 *               (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname,
1645
 *               last_poster_firstname)
1646
 *
1647
 * @author Patrick Cool <[email protected]>, Ghent University
1648
 *
1649
 * @version february 2006, dokeos 1.8
1650
 */
1651
function get_last_post_information($forum_id, $show_invisibles = false, $course_id = null, $sessionId = 0)
1652
{
1653
    if (!isset($course_id)) {
1654
        $course_id = api_get_course_int_id();
1655
    } else {
1656
        $course_id = (int) $course_id;
1657
    }
1658
    $sessionId = $sessionId ? (int) $sessionId : api_get_session_id();
1659
1660
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1661
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1662
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
1663
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1664
1665
    $forum_id = (int) $forum_id;
1666
    $return_array = [];
1667
1668
    // First get the threads to make sure there is no inconsistency in the
1669
    // database between forum and thread
1670
    $sql = "SELECT iid as thread_id FROM $table_threads
1671
            WHERE
1672
                forum_id = $forum_id AND
1673
                c_id = $course_id AND
1674
                session_id = $sessionId";
1675
    $result = Database::query($sql);
1676
    if (0 == Database::num_rows($result)) {
1677
        // If there are no threads in this forum, then there are no posts
1678
        return [];
1679
    }
1680
    $threads = [];
1681
    while ($row = Database::fetch_row($result)) {
1682
        $threads[] = $row[0];
1683
    }
1684
    $threadsList = implode(',', $threads);
1685
    // Now get the posts that are linked to these threads
1686
    $sql = "SELECT
1687
                post.iid as post_id,
1688
                post.forum_id,
1689
                post.poster_id,
1690
                post.poster_name,
1691
                post.post_date,
1692
                users.lastname,
1693
                users.firstname,
1694
                post.visible,
1695
                thread_properties.visibility AS thread_visibility,
1696
                forum_properties.visibility AS forum_visibility,
1697
                post.post_title,
1698
                post.post_text
1699
            FROM
1700
                $table_posts post,
1701
                $table_users users,
1702
                $table_item_property thread_properties,
1703
                $table_item_property forum_properties
1704
            WHERE
1705
                post.forum_id = $forum_id AND
1706
                post.thread_id IN ($threadsList) AND
1707
                post.poster_id = users.id AND
1708
                 post.thread_id = thread_properties.ref AND thread_properties.tool='".TOOL_FORUM_THREAD."'
1709
                AND post.forum_id=forum_properties.ref
1710
                AND forum_properties.tool='".TOOL_FORUM."'
1711
                AND post.c_id = $course_id AND
1712
                thread_properties.c_id = $course_id AND
1713
                forum_properties.c_id = $course_id
1714
            ORDER BY post.post_id DESC";
1715
    $result = Database::query($sql);
1716
1717
    if ($show_invisibles) {
1718
        $row = Database::fetch_array($result);
1719
        $return_array['last_post_id'] = $row['post_id'];
1720
        $return_array['last_poster_id'] = $row['poster_id'];
1721
        $return_array['last_post_date'] = $row['post_date'];
1722
        $return_array['last_poster_name'] = $row['poster_name'];
1723
        $return_array['last_poster_lastname'] = $row['lastname'];
1724
        $return_array['last_poster_firstname'] = $row['firstname'];
1725
        $return_array['last_post_title'] = $row['post_title'];
1726
        $return_array['last_post_text'] = $row['post_text'];
1727
1728
        return $return_array;
1729
    } else {
1730
        // We have to loop through the results to find the first one that is
1731
        // actually visible to students (forum_category, forum, thread AND post are visible).
1732
        while ($row = Database::fetch_array($result)) {
1733
            if ('1' == $row['visible'] && '1' == $row['thread_visibility'] && '1' == $row['forum_visibility']) {
1734
                $return_array['last_post_id'] = $row['post_id'];
1735
                $return_array['last_poster_id'] = $row['poster_id'];
1736
                $return_array['last_post_date'] = $row['post_date'];
1737
                $return_array['last_poster_name'] = $row['poster_name'];
1738
                $return_array['last_poster_lastname'] = $row['lastname'];
1739
                $return_array['last_poster_firstname'] = $row['firstname'];
1740
                $return_array['last_post_title'] = $row['post_title'];
1741
                $return_array['last_post_text'] = $row['post_text'];
1742
1743
                return $return_array;
1744
            }
1745
        }
1746
    }
1747
}
1748
1749
/**
1750
 * Retrieve all the threads of a given forum.
1751
 *
1752
 * @param int|null $courseId  Optional If is null then it is considered the current course
1753
 * @param int|null $sessionId Optional. If is null then it is considered the current session
1754
 *
1755
 * @return CForumThread[]
1756
 */
1757
function get_threads($forumId, $courseId = null, $sessionId = null)
1758
{
1759
    $repo = Container::getForumThreadRepository();
1760
    $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
1761
    $course = api_get_course_entity($courseId);
1762
    $session = api_get_session_entity($sessionId);
1763
1764
    $qb = $repo->getResourcesByCourse($course, $session);
1765
1766
    $qb->andWhere('resource.forum = :forum')->setParameter('forum', $forumId);
1767
1768
    return $qb->getQuery()->getResult();
1769
1770
    $groupId = api_get_group_id();
0 ignored issues
show
Unused Code introduced by
$groupId = api_get_group_id() 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...
1771
    $sessionId = null !== $sessionId ? (int) $sessionId : api_get_session_id();
1772
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1773
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1774
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
1775
1776
    $courseId = null !== $courseId ? (int) $courseId : api_get_course_int_id();
1777
    $groupInfo = GroupManager::get_group_properties($groupId);
1778
    $groupCondition = '';
1779
1780
    if (!empty($groupInfo)) {
1781
        $groupIid = $groupInfo['iid'];
1782
        $groupCondition = " AND item_properties.to_group_id = '$groupIid' ";
1783
    }
1784
1785
    $sessionCondition = api_get_session_condition(
1786
        $sessionId,
1787
        true,
1788
        false,
1789
        'item_properties.session_id'
1790
    );
1791
1792
    // important note:  it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
1793
    // because we also have thread.* in it. This is because thread has a field locked and post also has the same field
1794
    // since we are merging these we would have the post.locked value but in fact we want the thread.locked value
1795
    // This is why it is added to the end of the field selection
1796
    $sql = "SELECT DISTINCT
1797
                item_properties.*,
1798
                users.firstname,
1799
                users.lastname,
1800
                users.user_id,
1801
                thread.locked as locked,
1802
                thread.*
1803
            FROM $table_threads thread
1804
            INNER JOIN $table_item_property item_properties
1805
            ON
1806
                thread.thread_id = item_properties.ref AND
1807
                item_properties.c_id = thread.c_id AND
1808
                item_properties.tool = '".TABLE_FORUM_THREAD."'
1809
                $groupCondition
1810
                $sessionCondition
1811
            LEFT JOIN $table_users users
1812
                ON thread.thread_poster_id = users.user_id
1813
            WHERE
1814
                item_properties.visibility='1' AND
1815
                thread.forum_id = ".(int) $forum_id." AND
1816
                thread.c_id = $courseId
1817
            ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1818
1819
    if (api_is_allowed_to_edit()) {
1820
        $sql = "SELECT DISTINCT
1821
                    item_properties.*,
1822
                    users.firstname,
1823
                    users.lastname,
1824
                    users.user_id,
1825
                    thread.locked as locked,
1826
                    thread.*
1827
                FROM $table_threads thread
1828
                INNER JOIN $table_item_property item_properties
1829
                ON
1830
                    thread.thread_id = item_properties.ref AND
1831
                    item_properties.c_id = thread.c_id AND
1832
                    item_properties.tool = '".TABLE_FORUM_THREAD."'
1833
                    $groupCondition
1834
                    $sessionCondition
1835
                LEFT JOIN $table_users users
1836
                    ON thread.thread_poster_id=users.user_id
1837
                WHERE
1838
                    item_properties.visibility<>2 AND
1839
                    thread.forum_id = ".(int) $forum_id." AND
1840
                    thread.c_id = $courseId
1841
                ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1842
    }
1843
    $result = Database::query($sql);
1844
    $list = [];
1845
    $alreadyAdded = [];
1846
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1847
        if (in_array($row['thread_id'], $alreadyAdded)) {
1848
            continue;
1849
        }
1850
        $list[] = $row;
1851
        $alreadyAdded[] = $row['thread_id'];
1852
    }
1853
1854
    return $list;
1855
}
1856
1857
/**
1858
 * Get a thread by Id and course id.
1859
 *
1860
 * @param int $threadId the thread Id
1861
 * @param int $cId      the course id
1862
 *
1863
 * @return array containing all the information about the thread
1864
 */
1865
function getThreadInfo($threadId, $cId)
1866
{
1867
    $repo = Database::getManager()->getRepository(CForumThread::class);
1868
    /** @var CForumThread $forumThread */
1869
    $forumThread = $repo->findOneBy(['iid' => $threadId, 'cId' => $cId]);
1870
1871
    $thread = [];
1872
    if ($forumThread) {
1873
        $thread['iid'] = $forumThread->getIid();
1874
        $thread['threadId'] = $forumThread->getIid();
1875
        $thread['threadTitle'] = $forumThread->getThreadTitle();
1876
        $thread['forumId'] = $forumThread->getForum() ? $forumThread->getForum()->getIid() : 0;
1877
        $thread['sessionId'] = $forumThread->getSessionId();
1878
        $thread['threadSticky'] = $forumThread->getThreadSticky();
1879
        $thread['locked'] = $forumThread->getLocked();
1880
        $thread['threadTitleQualify'] = $forumThread->getThreadTitleQualify();
1881
        $thread['threadQualifyMax'] = $forumThread->getThreadQualifyMax();
1882
        $thread['threadCloseDate'] = $forumThread->getThreadCloseDate();
1883
        $thread['threadWeight'] = $forumThread->getThreadWeight();
1884
        $thread['threadPeerQualify'] = $forumThread->isThreadPeerQualify();
1885
    }
1886
1887
    return $thread;
1888
}
1889
1890
/**
1891
 * Retrieve all posts of a given thread.
1892
 *
1893
 * @param int    $threadId       The thread ID
1894
 * @param string $orderDirection Optional. The direction for sort the posts
1895
 * @param bool   $recursive      Optional. If the list is recursive
1896
 * @param int    $postId         Optional. The post ID for recursive list
1897
 * @param int    $depth          Optional. The depth to indicate the indent
1898
 *
1899
 * @todo move to a repository
1900
 *
1901
 * @return array containing all the information about the posts of a given thread
1902
 */
1903
function getPosts(
1904
    CForumForum $forum,
1905
    $threadId,
1906
    $orderDirection = 'ASC',
1907
    $recursive = false,
1908
    $postId = null,
1909
    $depth = -1
1910
) {
1911
    $em = Database::getManager();
1912
1913
    if (api_is_allowed_to_edit(false, true)) {
1914
        $visibleCriteria = Criteria::expr()->neq('visible', 2);
1915
    } else {
1916
        $visibleCriteria = Criteria::expr()->eq('visible', 1);
1917
    }
1918
1919
    $criteria = Criteria::create();
1920
    $criteria
1921
        ->where(Criteria::expr()->eq('thread', $threadId))
1922
        ->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
1923
        ->andWhere($visibleCriteria)
1924
    ;
1925
1926
    $groupId = api_get_group_id();
1927
    $groupInfo = GroupManager::get_group_properties($groupId);
1928
    $filterModerated = true;
1929
1930
    if (empty($groupId)) {
1931
        if (api_is_allowed_to_edit()) {
1932
            $filterModerated = false;
1933
        }
1934
    } else {
1935
        if (GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo) ||
1936
            api_is_allowed_to_edit(false, true)
1937
        ) {
1938
            $filterModerated = false;
1939
        }
1940
    }
1941
1942
    if ($recursive) {
1943
        $criteria->andWhere(Criteria::expr()->eq('postParentId', $postId));
1944
    }
1945
1946
    $qb = $em->getRepository(CForumPost::class)->createQueryBuilder('p');
1947
    $qb->select('p')
1948
        ->addCriteria($criteria)
1949
        ->addOrderBy('p.iid', $orderDirection);
1950
1951
    if ($filterModerated && 1 == $forum->isModerated()) {
1952
        if (!api_is_allowed_to_edit(false, true)) {
1953
            $userId = api_get_user_id();
1954
            $qb->andWhere(
1955
                'p.status = 1 OR
1956
                    (p.status = '.CForumPost::STATUS_WAITING_MODERATION." AND p.posterId = $userId) OR
1957
                    (p.status = ".CForumPost::STATUS_REJECTED." AND p.posterId = $userId) OR
1958
                    (p.status IS NULL AND p.posterId = $userId)
1959
                    "
1960
            );
1961
        }
1962
    }
1963
1964
    $posts = $qb->getQuery()->getResult();
1965
    $depth++;
1966
1967
    $list = [];
1968
    /** @var CForumPost $post */
1969
    foreach ($posts as $post) {
1970
        $postInfo = [
1971
            'iid' => $post->getIid(),
1972
            'c_id' => $post->getCId(),
1973
            'post_id' => $post->getIid(),
1974
            'post_title' => $post->getPostTitle(),
1975
            'post_text' => $post->getPostText(),
1976
            'thread_id' => $post->getThread() ? $post->getThread()->getIid() : 0,
1977
            'forum_id' => $post->getForum()->getIid(),
1978
            'poster_id' => $post->getPosterId(),
1979
            'poster_name' => $post->getPosterName(),
1980
            'post_date' => $post->getPostDate(),
1981
            'post_notification' => $post->getPostNotification(),
1982
            'post_parent_id' => $post->getPostParentId(),
1983
            'visible' => $post->getVisible(),
1984
            'status' => $post->getStatus(),
1985
            'indent_cnt' => $depth,
1986
            'entity' => $post,
1987
        ];
1988
1989
        $posterId = $post->getPosterId();
1990
        if (!empty($posterId)) {
1991
            $user = api_get_user_entity($posterId);
1992
            if ($user) {
1993
                $postInfo['user_id'] = $user->getId();
1994
                $postInfo['username'] = $user->getUsername();
1995
                $postInfo['username_canonical'] = $user->getUsernameCanonical();
1996
                $postInfo['lastname'] = $user->getLastname();
1997
                $postInfo['firstname'] = $user->getFirstname();
1998
                $postInfo['complete_name'] = UserManager::formatUserFullName($user);
1999
            }
2000
        }
2001
2002
        $list[] = $postInfo;
2003
2004
        if (!$recursive) {
2005
            continue;
2006
        }
2007
        $list = array_merge(
2008
            $list,
2009
            getPosts(
2010
                $forum,
2011
                $threadId,
2012
                $orderDirection,
2013
                $recursive,
2014
                $post->getIid(),
2015
                $depth
2016
            )
2017
        );
2018
    }
2019
2020
    return $list;
2021
}
2022
2023
/**
2024
 * This function retrieves forum thread users details.
2025
 *
2026
 * @param int $thread_id Thread ID
2027
 * @param   string  Course DB name (optional)
2028
 *
2029
 * @return Doctrine\DBAL\Driver\Statement|null array Array of type
2030
 *                                             ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2031
 *
2032
 * @author Christian Fasanando <[email protected]>,
2033
 *
2034
 * @todo     this function need to be improved
2035
 *
2036
 * @version octubre 2008, dokeos 1.8
2037
 */
2038
function get_thread_users_details($thread_id)
2039
{
2040
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2041
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2042
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2043
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2044
2045
    $course_id = api_get_course_int_id();
2046
2047
    $is_western_name_order = api_is_western_name_order();
2048
    if ($is_western_name_order) {
2049
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2050
    } else {
2051
        $orderby = 'ORDER BY user.lastname, user.firstname';
2052
    }
2053
2054
    if (api_get_session_id()) {
2055
        $session_info = api_get_session_info(api_get_session_id());
2056
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2057
        //not showing coaches
2058
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2059
                FROM $t_posts p, $t_users user, $t_session_rel_user session_rel_user_rel_course
2060
                WHERE
2061
                    p.poster_id = user.id AND
2062
                    user.id = session_rel_user_rel_course.user_id AND
2063
                    session_rel_user_rel_course.status<>'2' AND
2064
                    session_rel_user_rel_course.user_id NOT IN ($user_to_avoid) AND
2065
                    p.thread_id = ".(int) $thread_id.' AND
2066
                    session_id = '.api_get_session_id()." AND
2067
                    p.c_id = $course_id AND
2068
                    session_rel_user_rel_course.c_id = ".$course_id." $orderby ";
2069
    } else {
2070
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2071
                FROM $t_posts p, $t_users user, $t_course_user course_user
2072
                WHERE
2073
                    p.poster_id = user.id
2074
                    AND user.id = course_user.user_id
2075
                    AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
2076
                    AND p.thread_id = '.(int) $thread_id."
2077
                    AND course_user.status NOT IN('1') AND
2078
                    p.c_id = $course_id AND
2079
                    course_user.c_id = ".$course_id." $orderby";
2080
    }
2081
2082
    return Database::query($sql);
2083
}
2084
2085
/**
2086
 * This function retrieves forum thread users qualify.
2087
 *
2088
 * @param int $thread_id Thread ID
2089
 * @param   string  Course DB name (optional)
2090
 *
2091
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2092
 *
2093
 * @author Jhon Hinojosa
2094
 *
2095
 * @todo     this function need to be improved
2096
 */
2097
function get_thread_users_qualify($thread_id)
2098
{
2099
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2100
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2101
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2102
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2103
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2104
2105
    $course_id = api_get_course_int_id();
2106
    $sessionId = api_get_session_id();
2107
2108
    $is_western_name_order = api_is_western_name_order();
2109
    if ($is_western_name_order) {
2110
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2111
    } else {
2112
        $orderby = 'ORDER BY user.lastname, user.firstname';
2113
    }
2114
2115
    if ($sessionId) {
2116
        $session_info = api_get_session_info($sessionId);
2117
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2118
        //not showing coaches
2119
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2120
                FROM $t_posts post , $t_users user, $t_session_rel_user scu, $t_qualify qualify
2121
                WHERE poster_id = user.id
2122
                    AND post.poster_id = qualify.user_id
2123
                    AND user.id = scu.user_id
2124
                    AND scu.status<>'2'
2125
                    AND scu.user_id NOT IN ($user_to_avoid)
2126
                    AND qualify.thread_id = ".(int) $thread_id.'
2127
                    AND post.thread_id = '.(int) $thread_id."
2128
                    AND scu.session_id = $sessionId
2129
                    AND scu.c_id = ".$course_id." AND
2130
                    qualify.c_id = $course_id AND
2131
                    post.c_id = $course_id
2132
                $orderby ";
2133
    } else {
2134
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2135
                FROM $t_posts post,
2136
                     $t_qualify qualify,
2137
                     $t_users user,
2138
                     $t_course_user course_user
2139
                WHERE
2140
                     post.poster_id = user.id
2141
                     AND post.poster_id = qualify.user_id
2142
                     AND user.id = course_user.user_id
2143
                     AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
2144
                     AND qualify.thread_id = '.(int) $thread_id.'
2145
                     AND post.thread_id = '.(int) $thread_id."
2146
                     AND course_user.status not in('1')
2147
                     AND course_user.c_id = $course_id
2148
                     AND qualify.c_id = $course_id
2149
                     AND post.c_id = $course_id
2150
                 $orderby ";
2151
    }
2152
2153
    return Database::query($sql);
2154
}
2155
2156
/**
2157
 * This function retrieves forum thread users not qualify.
2158
 *
2159
 * @param int $thread_id Thread ID
2160
 * @param   string  Course DB name (optional)
2161
 *
2162
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2163
 *
2164
 * @author   Jhon Hinojosa<[email protected]>,
2165
 *
2166
 * @version oct 2008, dokeos 1.8
2167
 */
2168
function get_thread_users_not_qualify($thread_id)
2169
{
2170
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2171
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2172
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2173
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2174
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2175
2176
    $is_western_name_order = api_is_western_name_order();
2177
    if ($is_western_name_order) {
2178
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2179
    } else {
2180
        $orderby = 'ORDER BY user.lastname, user.firstname';
2181
    }
2182
2183
    $course_id = api_get_course_int_id();
2184
2185
    $sql1 = "SELECT user_id FROM  $t_qualify
2186
             WHERE c_id = $course_id AND thread_id = '".$thread_id."'";
2187
    $result1 = Database::query($sql1);
2188
    $cad = '';
2189
    while ($row = Database::fetch_array($result1)) {
2190
        $cad .= $row['user_id'].',';
2191
    }
2192
    if ('' == $cad) {
2193
        $cad = '0';
2194
    } else {
2195
        $cad = substr($cad, 0, strlen($cad) - 1);
2196
    }
2197
2198
    if (api_get_session_id()) {
2199
        $session_info = api_get_session_info(api_get_session_id());
2200
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2201
        //not showing coaches
2202
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2203
                FROM $t_posts post , $t_users user, $t_session_rel_user session_rel_user_rel_course
2204
                WHERE poster_id = user.id
2205
                    AND user.id NOT IN (".$cad.")
2206
                    AND user.id = session_rel_user_rel_course.user_id
2207
                    AND session_rel_user_rel_course.status<>'2'
2208
                    AND session_rel_user_rel_course.user_id NOT IN ($user_to_avoid)
2209
                    AND post.thread_id = ".(int) $thread_id.'
2210
                    AND session_id = '.api_get_session_id()."
2211
                    AND session_rel_user_rel_course.c_id = $course_id AND post.c_id = $course_id $orderby ";
2212
    } else {
2213
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2214
                FROM $t_posts post, $t_users user,$t_course_user course_user
2215
                WHERE post.poster_id = user.id
2216
                AND user.id NOT IN (".$cad.')
2217
                AND user.id = course_user.user_id
2218
                AND course_user.relation_type<>'.COURSE_RELATION_TYPE_RRHH.'
2219
                AND post.thread_id = '.(int) $thread_id."
2220
                AND course_user.status not in('1')
2221
                AND course_user.c_id = $course_id AND post.c_id = $course_id  $orderby";
2222
    }
2223
2224
    return Database::query($sql);
2225
}
2226
2227
/**
2228
 * This function retrieves all the information of a given forumcategory id.
2229
 *
2230
 * @param int $cat_id that indicates the forum
2231
 *
2232
 * @return array returns if there are category or bool returns if there aren't category
2233
 *
2234
 * @author Patrick Cool <[email protected]>, Ghent University
2235
 *
2236
 * @version february 2006, dokeos 1.8
2237
 */
2238
function get_forumcategory_information($cat_id)
2239
{
2240
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
2241
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2242
2243
    $course_id = api_get_course_int_id();
2244
    $sql = "SELECT *
2245
            FROM $table_categories forumcategories
2246
            INNER JOIN $table_item_property item_properties
2247
            ON (forumcategories.c_id = item_properties.c_id)
2248
            WHERE
2249
                forumcategories.c_id = $course_id AND
2250
                item_properties.c_id = $course_id AND
2251
                item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
2252
                item_properties.ref='".Database::escape_string($cat_id)."' AND
2253
                forumcategories.cat_id='".Database::escape_string($cat_id)."'";
2254
    $result = Database::query($sql);
2255
2256
    return Database::fetch_array($result);
2257
}
2258
2259
/**
2260
 * This function counts the number of forums inside a given category.
2261
 *
2262
 * @param int $cat_id the id of the forum category
2263
 *
2264
 * @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return
2265
 *       the number of visible forums, $countinvisible=1 would return the number of visible and invisible forums
2266
 *
2267
 * @return int the number of forums inside the given category
2268
 *
2269
 * @author Patrick Cool <[email protected]>, Ghent University
2270
 *
2271
 * @version february 2006, dokeos 1.8
2272
 */
2273
function count_number_of_forums_in_category($cat_id)
2274
{
2275
    $table_forums = Database::get_course_table(TABLE_FORUM);
2276
    $course_id = api_get_course_int_id();
2277
    $cat_id = (int) $cat_id;
2278
    $sql = "SELECT count(*) AS number_of_forums
2279
            FROM $table_forums
2280
            WHERE c_id = $course_id AND forum_category = $cat_id";
2281
    $result = Database::query($sql);
2282
    $row = Database::fetch_array($result);
2283
2284
    return $row['number_of_forums'];
2285
}
2286
2287
/**
2288
 * This function update a thread.
2289
 *
2290
 * @param array $values - The form Values
2291
 */
2292
function updateThread($values)
2293
{
2294
    if (!api_is_allowed_to_edit()) {
2295
        return '';
2296
    }
2297
2298
    $logInfo = [
2299
        'tool' => TOOL_FORUM,
2300
        'tool_id' => $values['forum_id'],
2301
        'tool_id_detail' => $values['thread_id'],
2302
        'action' => 'edit-thread',
2303
        'action_details' => 'thread',
2304
        'info' => $values['thread_title'],
2305
    ];
2306
    Event::registerLog($logInfo);
2307
2308
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
2309
    $courseId = api_get_course_int_id();
2310
    $courseCode = api_get_course_id();
2311
    $sessionId = api_get_session_id();
2312
2313
    // Simple update + set gradebook values to null
2314
    $params = [
2315
        'thread_title' => $values['thread_title'],
2316
        'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
2317
    ];
2318
    $where = ['c_id = ? AND iid = ?' => [$courseId, $values['thread_id']]];
2319
    Database::update($threadTable, $params, $where);
2320
2321
    $id = $values['thread_id'];
2322
    $linkInfo = GradebookUtils::isResourceInCourseGradebook(
2323
        $courseCode,
2324
        LINK_FORUM_THREAD,
2325
        $id,
2326
        $sessionId
2327
    );
2328
2329
    $gradebookLink = null;
2330
    $em = Database::getManager();
2331
    if (!empty($linkInfo) && isset($linkInfo['id'])) {
2332
        $gradebookLink = $em->getRepository(GradebookLink::class)->find($linkInfo['id']);
2333
    }
2334
2335
    // values 1 or 0
2336
    $check = isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : false;
2337
    if ($check) {
2338
        $title = Security::remove_XSS(stripslashes($values['calification_notebook_title']));
2339
        $value = isset($values['numeric_calification']) ? (int) ($values['numeric_calification']) : 0;
2340
        $weight = isset($values['weight_calification']) ? (float) ($values['weight_calification']) : 0;
2341
        $description = '';
2342
        // Update title
2343
        $params = [
2344
            'thread_title_qualify' => $values['calification_notebook_title'],
2345
            'thread_qualify_max' => api_float_val($values['numeric_calification']),
2346
            'thread_weight' => api_float_val($values['weight_calification']),
2347
            'thread_peer_qualify' => $values['thread_peer_qualify'],
2348
        ];
2349
        $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2350
        Database::update($threadTable, $params, $where);
2351
2352
        if (!$linkInfo) {
2353
            GradebookUtils::add_resource_to_course_gradebook(
2354
                $values['category_id'],
2355
                $courseCode,
2356
                LINK_FORUM_THREAD,
2357
                $id,
2358
                $title,
2359
                $weight,
2360
                $value,
2361
                $description,
2362
                1,
2363
                $sessionId
2364
            );
2365
        } else {
2366
            if ($gradebookLink) {
2367
                $gradebookLink->setWeight($weight);
2368
                $em->persist($gradebookLink);
2369
                $em->flush();
2370
            }
2371
        }
2372
    } else {
2373
        $params = [
2374
            'thread_title_qualify' => '',
2375
            'thread_qualify_max' => 0,
2376
            'thread_weight' => 0,
2377
            'thread_peer_qualify' => 0,
2378
        ];
2379
        $where = ['c_id = ? AND iid = ?' => [$courseId, $values['thread_id']]];
2380
        Database::update($threadTable, $params, $where);
2381
2382
        if (!empty($linkInfo)) {
2383
            if ($gradebookLink) {
2384
                $em->remove($gradebookLink);
2385
                $em->flush();
2386
            }
2387
        }
2388
    }
2389
2390
    $message = get_lang('The post has been modified').'<br />';
2391
    Display::addFlash(Display::return_message($message, 'confirmation', false));
2392
}
2393
2394
/**
2395
 * This function stores a new thread. This is done through an entry in the forum_thread table AND
2396
 * in the forum_post table because. The threads are also stored in the item_property table. (forum posts are not (yet)).
2397
 *
2398
 * @param bool $showMessage
2399
 * @param int  $userId      Optional. The user ID
2400
 * @param int  $sessionId
2401
 *
2402
 * @return CForumThread
2403
 *
2404
 * @author Patrick Cool <[email protected]>, Ghent University
2405
 *
2406
 * @version february 2006, dokeos 1.8
2407
 */
2408
function store_thread(
2409
    CForumForum $forum,
2410
    array $values,
2411
    array $courseInfo = [],
2412
    $showMessage = true,
2413
    $userId = 0,
2414
    $sessionId = 0
2415
) {
2416
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
2417
    $userId = $userId ?: api_get_user_id();
2418
    $course_id = $courseInfo['real_id'];
2419
    $courseCode = $courseInfo['code'];
2420
    $sessionId = $sessionId ?: api_get_session_id();
2421
2422
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2423
2424
    $post_date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
2425
    $visible = 1;
2426
    if ('1' == $forum->getApprovalDirectPost() && !api_is_allowed_to_edit(null, true)) {
2427
        $visible = 0; // The post has not been approved yet.
2428
    }
2429
    $clean_post_title = $values['post_title'];
2430
2431
    $user = api_get_user_entity(api_get_user_id());
2432
    $course = api_get_course_entity($course_id);
2433
    $session = api_get_session_entity($sessionId);
2434
2435
    // We first store an entry in the forum_thread table because the thread_id is used in the forum_post table.
2436
    $thread = new CForumThread();
2437
    $thread
2438
        ->setCId($course_id)
2439
        ->setThreadTitle($clean_post_title)
2440
        ->setForum($forum)
2441
        ->setThreadPosterId($userId)
2442
        ->setThreadPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2443
        ->setThreadDate($post_date)
2444
        ->setThreadSticky(isset($values['thread_sticky']) ? $values['thread_sticky'] : 0)
2445
        ->setThreadTitleQualify(
2446
            isset($values['calification_notebook_title']) ? $values['calification_notebook_title'] : null
2447
        )
2448
        ->setThreadQualifyMax(isset($values['numeric_calification']) ? (int) $values['numeric_calification'] : 0)
2449
        ->setThreadWeight(isset($values['weight_calification']) ? (int) $values['weight_calification'] : 0)
2450
        ->setThreadPeerQualify(isset($values['thread_peer_qualify']) ? (bool) $values['thread_peer_qualify'] : false)
2451
        ->setSessionId($sessionId)
2452
        ->setLpItemId(isset($values['lp_item_id']) ? (int) $values['lp_item_id'] : 0)
2453
        ->setParent($forum)
2454
        ->addCourseLink(
2455
            $course,
2456
            $session
2457
        )
2458
    ;
2459
2460
    $repo = Container::getForumThreadRepository();
2461
    $em = $repo->getEntityManager();
2462
    $em->persist($thread);
2463
    $em->flush();
2464
2465
    if (!$thread->getIid()) {
2466
        return null;
2467
    }
2468
2469
    // Add option gradebook qualify.
2470
    if (isset($values['thread_qualify_gradebook']) &&
2471
        1 == $values['thread_qualify_gradebook']
2472
    ) {
2473
        // Add function gradebook.
2474
        $resourcename = stripslashes($values['calification_notebook_title']);
2475
        GradebookUtils::add_resource_to_course_gradebook(
2476
            $values['category_id'],
2477
            $courseCode,
2478
            5,
2479
            $thread->getIid(),
2480
            $resourcename,
2481
            $values['weight_calification'],
2482
            $values['numeric_calification'],
2483
            '',
2484
            0,
2485
            $sessionId
2486
        );
2487
    }
2488
2489
    /*api_item_property_update(
2490
        $courseInfo,
2491
        TOOL_FORUM_THREAD,
2492
        $thread->getIid(),
2493
        'ForumThreadAdded',
2494
        $userId,
2495
        $groupInfo,
2496
        null,
2497
        null,
2498
        null,
2499
        $sessionId
2500
    );*/
2501
2502
    // If the forum properties tell that the posts have to be approved
2503
    // we have to put the whole thread invisible,
2504
    // because otherwise the students will see the thread and not the post
2505
    // in the thread.
2506
    // We also have to change $visible because the post itself has to be
2507
    // visible in this case (otherwise the teacher would have
2508
    // to make the thread visible AND the post.
2509
    // Default behaviour
2510
    /*api_set_default_visibility(
2511
        $thread->getIid(),
2512
        TOOL_FORUM_THREAD,
2513
        $groupId,
2514
        $courseInfo,
2515
        $sessionId,
2516
        $userId
2517
    );*/
2518
2519
    if (0 == $visible) {
2520
        /*api_item_property_update(
2521
            $courseInfo,
2522
            TOOL_FORUM_THREAD,
2523
            $thread->getIid(),
2524
            'invisible',
2525
            $userId,
2526
            $groupInfo
2527
        );*/
2528
        $visible = 1;
2529
    }
2530
2531
    $logInfo = [
2532
        'tool' => TOOL_FORUM,
2533
        'tool_id' => $values['forum_id'],
2534
        'tool_id_detail' => $thread->getIid(),
2535
        'action' => 'new-thread',
2536
        'info' => $clean_post_title,
2537
    ];
2538
    Event::registerLog($logInfo);
2539
2540
    // We now store the content in the table_post table.
2541
    $post = new CForumPost();
2542
    $post
2543
        ->setCId($course_id)
2544
        ->setPostTitle($clean_post_title)
2545
        ->setPostText($values['post_text'])
2546
        ->setThread($thread)
2547
        ->setForum($forum)
2548
        ->setPosterId($userId)
2549
        ->setPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2550
        ->setPostDate($post_date)
2551
        ->setPostNotification(isset($values['post_notification']) ? (int) $values['post_notification'] : null)
2552
        ->setVisible($visible)
2553
        ->setStatus(CForumPost::STATUS_VALIDATED)
2554
        ->setParent($thread)
2555
        ->addCourseLink(
2556
            $course,
2557
            $session
2558
        )
2559
    ;
2560
2561
    if ($forum->isModerated()) {
2562
        $post->setStatus(
2563
            api_is_course_admin() ? CForumPost::STATUS_VALIDATED : CForumPost::STATUS_WAITING_MODERATION
2564
        );
2565
    }
2566
2567
    $repo = Container::getForumPostRepository();
2568
    $em = $repo->getEntityManager();
2569
    $em->persist($post);
2570
    $em->flush();
2571
2572
    $postId = $post->getIid();
2573
    $thread->setThreadLastPost($postId);
2574
    $em->persist($thread);
2575
    $em->flush();
2576
2577
    $logInfo = [
2578
        'tool' => TOOL_FORUM,
2579
        'tool_id' => $values['forum_id'],
2580
        'tool_id_detail' => $thread->getIid(),
2581
        'action' => 'new-post',
2582
        'info' => $clean_post_title,
2583
    ];
2584
    Event::registerLog($logInfo);
2585
2586
    // Now we have to update the thread table to fill the thread_last_post
2587
    // field (so that we know when the thread has been updated for the last time).
2588
    $sql = "UPDATE $table_threads
2589
            SET thread_last_post = '".$postId."'
2590
            WHERE
2591
                c_id = $course_id AND
2592
                iid = '".$thread->getIid()."'";
2593
    Database::query($sql);
2594
    $message = get_lang('The new thread has been added');
2595
2596
    // Overwrite default message.
2597
    if ($forum->isModerated() &&
2598
        !api_is_allowed_to_edit(null, true)
2599
    ) {
2600
        $message = get_lang('Your message has to be approved before people can view it.');
2601
    }
2602
2603
    add_forum_attachment_file(
2604
        null,
2605
        $post
2606
    );
2607
2608
    if ('1' == $forum->getApprovalDirectPost() &&
2609
        !api_is_allowed_to_edit(null, true)
2610
    ) {
2611
        $message .= get_lang('Your message has to be approved before people can view it.').'<br />';
2612
        $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2613
            get_lang('Forum').'</a><br />';
2614
    } else {
2615
        $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2616
            get_lang('Forum').'</a><br />';
2617
        $message .= get_lang('You can now return to the').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&thread='.$thread->getIid().'">'.
2618
            get_lang('Message').'</a>';
2619
    }
2620
    $reply_info['new_post_id'] = $postId;
2621
    $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
2622
2623
    if (1 == $my_post_notification) {
2624
        set_notification('thread', $thread->getIid(), true);
2625
    }
2626
2627
    send_notification_mails(
2628
        $forum,
2629
        $thread,
2630
        $reply_info,
2631
        $courseInfo['code']
2632
    );
2633
2634
    Session::erase('formelements');
2635
    Session::erase('origin');
2636
    Session::erase('breadcrumbs');
2637
    Session::erase('addedresource');
2638
    Session::erase('addedresourceid');
2639
2640
    if ($showMessage) {
2641
        Display::addFlash(Display::return_message($message, 'success', false));
2642
    }
2643
2644
    return $thread;
2645
}
2646
2647
/**
2648
 * This function displays the form that is used to add a post. This can be a new thread or a reply.
2649
 *
2650
 * @param string $action
2651
 *                            is the parameter that determines if we are
2652
 *                            2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete thread (if enabled)
2653
 *                            3. replymessage: Replying to a message ($action =replymessage) => I-frame with the complete thread (if enabled)
2654
 *                            (I first thought to put and I-frame with the message only)
2655
 *                            4. quote: Quoting a message ($action= quotemessage) => I-frame with the complete thread (if enabled).
2656
 *                            The message will be in the reply. (I first thought not to put an I-frame here)
2657
 * @param array  $form_values
2658
 * @param bool   $showPreview
2659
 *
2660
 * @return FormValidator
2661
 */
2662
function show_add_post_form(CForumForum $forum, CForumThread $thread, CForumPost $post = null, $action, $form_values, $showPreview = true)
2663
{
2664
    $_user = api_get_user_info();
2665
    $action = isset($action) ? Security::remove_XSS($action) : '';
2666
    $threadId = $thread->getIid();
2667
    $forumId = $forum->getIid();
2668
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
2669
    $postId = $post ? $post->getIid() : 0;
2670
2671
    $url = api_get_self().'?'.http_build_query(
2672
        [
2673
            'action' => $action,
2674
            'forum' => $forumId,
2675
            'thread' => $threadId,
2676
            'post' => $postId,
2677
        ]
2678
    ).'&'.api_get_cidreq();
2679
2680
    $form = new FormValidator(
2681
        'thread',
2682
        'post',
2683
        $url
2684
    );
2685
    $form->setConstants(['forum' => '5']);
2686
2687
    // Setting the form elements.
2688
    $form->addElement('hidden', 'forum_id', $forumId);
2689
    $form->addElement('hidden', 'thread_id', $threadId);
2690
    $form->addElement('hidden', 'action', $action);
2691
2692
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2693
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2694
        $form->addElement('text', 'poster_name', get_lang('Name'));
2695
        $form->applyFilter('poster_name', 'html_filter');
2696
    }
2697
2698
    $form->addElement('text', 'post_title', get_lang('Title'));
2699
    $form->addHtmlEditor(
2700
        'post_text',
2701
        get_lang('Text'),
2702
        true,
2703
        false,
2704
        api_is_allowed_to_edit(null, true) ? [
2705
            'ToolbarSet' => 'Forum',
2706
            'Width' => '100%',
2707
            'Height' => '300',
2708
        ] : [
2709
            'ToolbarSet' => 'ForumStudent',
2710
            'Width' => '100%',
2711
            'Height' => '300',
2712
            'UserStatus' => 'student',
2713
        ]
2714
    );
2715
    $form->addRule('post_text', get_lang('Required field'), 'required');
2716
2717
    if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2718
        $extraFields = new ExtraField('forum_post');
2719
        $extraFields->addElements(
2720
            $form,
2721
            null,
2722
            [], //exclude
2723
            false, // filter
2724
            false, // tag as select
2725
            ['ask_for_revision'], //show only fields
2726
            [], // order fields
2727
            [] // extra data);
2728
        );
2729
    }
2730
2731
    $iframe = null;
2732
    if ($showPreview) {
2733
        if ('newthread' !== $action && !empty($threadId)) {
2734
            $iframe = '<iframe style="border: 1px solid black"
2735
            src="iframe_thread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId.'#'.$postId.'" width="100%"></iframe>';
2736
        }
2737
        if (!empty($iframe)) {
2738
            $form->addElement('label', get_lang('Thread'), $iframe);
2739
        }
2740
    }
2741
2742
    if (in_array($action, ['quote', 'replymessage'])) {
2743
        $form->addFile('user_upload[]', get_lang('Attachment'));
2744
        $form->addButton(
2745
            'add_attachment',
2746
            get_lang('Add attachment'),
2747
            'paperclip',
2748
            'default',
2749
            'default',
2750
            null,
2751
            ['id' => 'reply-add-attachment']
2752
        );
2753
    } else {
2754
        $form->addFile('user_upload', get_lang('Attachment'));
2755
    }
2756
2757
    if ($giveRevision) {
2758
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
2759
        $form->addHidden('give_revision', 1);
2760
        if (false === $hide) {
2761
            $extraField = new ExtraField('forum_post');
2762
            $extraField->addElements(
2763
                $form,
2764
                null,
2765
                [], //exclude
2766
                false, // filter
2767
                false, // tag as select
2768
                ['revision_language'], //show only fields
2769
                [], // order fields
2770
                [] // extra data
2771
            );
2772
        } else {
2773
            $form->addHidden('extra_revision_language', 1);
2774
        }
2775
    }
2776
2777
    // Setting the class and text of the form title and submit button.
2778
    if ('quote' === $action) {
2779
        $form->addButtonCreate(get_lang('Quote this message'), 'SubmitPost');
2780
    } elseif ('replythread' === $action) {
2781
        $form->addButtonCreate(get_lang('Reply to this thread'), 'SubmitPost');
2782
    } elseif ('replymessage' === $action) {
2783
        $form->addButtonCreate(get_lang('Reply to this message'), 'SubmitPost');
2784
    }
2785
2786
    $defaults['thread_peer_qualify'] = 0;
2787
    if (!empty($form_values)) {
2788
        $defaults['post_title'] = prepare4display($form_values['post_title']);
2789
        $defaults['post_text'] = prepare4display($form_values['post_text']);
2790
        $defaults['post_notification'] = (int) $form_values['post_notification'];
2791
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
2792
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
2793
    }
2794
2795
    // If we are quoting a message we have to retrieve the information of the post we are quoting so that
2796
    // we can add this as default to the textarea.
2797
    // We also need to put the parent_id of the post in a hidden form when
2798
    if (('quote' === $action || 'replymessage' === $action || $giveRevision) && !empty($postId)) {
2799
        // we are quoting or replying to a message (<> reply to a thread !!!)
2800
        $form->addHidden('post_parent_id', $post->getIid());
2801
        // If we are replying or are quoting then we display a default title.
2802
        $posterInfo = api_get_user_info($post->getPosterId());
2803
        $posterName = '';
2804
        if ($posterInfo) {
2805
            $posterName = $posterInfo['complete_name'];
2806
        }
2807
        $defaults['post_title'] = get_lang('Re:').api_html_entity_decode($post->getPostTitle(), ENT_QUOTES);
2808
        // When we are quoting a message then we have to put that message into the wysiwyg editor.
2809
        // Note: The style has to be hardcoded here because using class="quote" didn't work.
2810
        if ('quote' === $action) {
2811
            $defaults['post_text'] = '<div>&nbsp;</div>
2812
                <div style="margin: 5px;">
2813
                    <div style="font-size: 90%; font-style: italic;">'.
2814
                get_lang('Quoting').' '.$posterName.':</div>
2815
                        <div style="color: #006600; font-size: 90%;  font-style: italic; background-color: #FAFAFA; border: #D1D7DC 1px solid; padding: 3px;">'.
2816
                prepare4display($post->getPostText()).'
2817
                        </div>
2818
                    </div>
2819
                <div>&nbsp;</div>
2820
                <div>&nbsp;</div>
2821
            ';
2822
        }
2823
        if ($giveRevision) {
2824
            $defaults['post_text'] = prepare4display($post->getPostText());
2825
        }
2826
    }
2827
2828
    $form->setDefaults(isset($defaults) ? $defaults : []);
2829
2830
    // The course admin can make a thread sticky (=appears with special icon and always on top).
2831
    $form->addRule('post_title', get_lang('Required field'), 'required');
2832
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2833
        $form->addRule(
2834
            'poster_name',
2835
            get_lang('Required field'),
2836
            'required'
2837
        );
2838
    }
2839
2840
    // Validation or display
2841
    if ($form->validate()) {
2842
        $check = Security::check_token('post');
2843
        if ($check) {
2844
            $values = $form->getSubmitValues();
2845
            if (isset($values['thread_qualify_gradebook']) &&
2846
                '1' == $values['thread_qualify_gradebook'] &&
2847
                empty($values['weight_calification'])
2848
            ) {
2849
                Display::addFlash(
2850
                    Display::return_message(
2851
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
2852
                        'error',
2853
                        false
2854
                    )
2855
                );
2856
2857
                return false;
2858
            }
2859
2860
            $postId = 0;
2861
            $threadId = 0;
2862
2863
            switch ($action) {
2864
                case 'quote':
2865
                case 'replythread':
2866
                case 'replymessage':
2867
                    $postId = store_reply($forum, $thread, $values);
2868
2869
                    break;
2870
            }
2871
2872
            if ($postId) {
2873
                if (isset($values['give_revision']) && 1 == $values['give_revision']) {
2874
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2875
                    $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
2876
                    $params = [
2877
                        'item_id' => $postId,
2878
                        'extra_revision_language' => $revisionLanguage,
2879
                    ];
2880
2881
                    $extraFieldValues->saveFieldValues(
2882
                        $params,
2883
                        false,
2884
                        false,
2885
                        ['revision_language']
2886
                    );
2887
                }
2888
2889
                if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2890
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2891
                    $params = [
2892
                        'item_id' => $postId,
2893
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
2894
                    ];
2895
                    $extraFieldValues->saveFieldValues(
2896
                        $params,
2897
                        false,
2898
                        false,
2899
                        ['ask_for_revision']
2900
                    );
2901
                }
2902
            }
2903
2904
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
2905
                [
2906
                    'forum' => $forumId,
2907
                    'thread' => $thread->getIid(),
2908
                ]
2909
            );
2910
2911
            Security::clear_token();
2912
            header('Location: '.$url);
2913
            exit;
2914
        }
2915
    } else {
2916
        $token = Security::get_token();
2917
        $form->addElement('hidden', 'sec_token');
2918
        $form->setConstants(['sec_token' => $token]);
2919
2920
        // Delete from $_SESSION forum attachment from other posts
2921
        // and keep only attachments for new post
2922
        clearAttachedFiles(FORUM_NEW_POST);
2923
        // Get forum attachment ajax table to add it to form
2924
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
2925
        $ajaxHtml = $attachmentAjaxTable;
2926
        $form->addElement('html', $ajaxHtml);
2927
2928
        return $form;
2929
    }
2930
}
2931
2932
function newThread(CForumForum $forum, $form_values = '', $showPreview = true)
2933
{
2934
    $_user = api_get_user_info();
2935
    $forumId = $forum->getIid();
2936
    $my_post = isset($_GET['post']) ? (int) $_GET['post'] : '';
2937
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
2938
    $action = 'new_thread';
2939
2940
    $url = api_get_self().'?'.http_build_query(
2941
            [
2942
                'action' => $action,
2943
                'forum' => $forumId,
2944
                'post' => $my_post,
2945
            ]
2946
        ).'&'.api_get_cidreq();
2947
2948
    $form = new FormValidator(
2949
        'thread',
2950
        'post',
2951
        $url
2952
    );
2953
2954
    // Setting the form elements.
2955
    $form->addElement('hidden', 'forum_id', $forumId);
2956
    $form->addElement('hidden', 'thread_id', 0);
2957
    $form->addElement('hidden', 'action', $action);
2958
2959
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2960
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2961
        $form->addElement('text', 'poster_name', get_lang('Name'));
2962
        $form->applyFilter('poster_name', 'html_filter');
2963
    }
2964
2965
    $form->addElement('text', 'post_title', get_lang('Title'));
2966
    $form->addHtmlEditor(
2967
        'post_text',
2968
        get_lang('Text'),
2969
        true,
2970
        false,
2971
        api_is_allowed_to_edit(null, true) ? [
2972
            'ToolbarSet' => 'Forum',
2973
            'Width' => '100%',
2974
            'Height' => '300',
2975
        ] : [
2976
            'ToolbarSet' => 'ForumStudent',
2977
            'Width' => '100%',
2978
            'Height' => '300',
2979
            'UserStatus' => 'student',
2980
        ]
2981
    );
2982
    $form->addRule('post_text', get_lang('Required field'), 'required');
2983
2984
    $extraFields = new ExtraField('forum_post');
2985
    $extraFields->addElements(
2986
        $form,
2987
        null,
2988
        [], //exclude
2989
        false, // filter
2990
        false, // tag as select
2991
        ['ask_for_revision'], //show only fields
2992
        [], // order fields
2993
        [] // extra data);
2994
    );
2995
2996
    if (Gradebook::is_active() &&
2997
        (api_is_course_admin() || api_is_session_general_coach() || api_is_course_tutor())
2998
    ) {
2999
        $form->addElement('advanced_settings', 'advanced_params', get_lang('Advanced settings'));
3000
        $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3001
3002
        // Thread qualify
3003
        if (Gradebook::is_active()) {
3004
            //Loading gradebook select
3005
            GradebookUtils::load_gradebook_select_in_tool($form);
3006
            $form->addElement(
3007
                'checkbox',
3008
                'thread_qualify_gradebook',
3009
                '',
3010
                get_lang('Grade this thread'),
3011
                'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"'
3012
            );
3013
        } else {
3014
            $form->addElement('hidden', 'thread_qualify_gradebook', false);
3015
        }
3016
3017
        $form->addElement('html', '<div id="options_field" style="display:none">');
3018
        $form->addElement('text', 'numeric_calification', get_lang('Maximum score'));
3019
        $form->applyFilter('numeric_calification', 'html_filter');
3020
        $form->addElement('text', 'calification_notebook_title', get_lang('Column header in Competences Report'));
3021
        $form->applyFilter('calification_notebook_title', 'html_filter');
3022
3023
        $form->addElement(
3024
            'text',
3025
            'weight_calification',
3026
            get_lang('Weight in Report'),
3027
            ['value' => '0.00', 'onfocus' => 'javascript: this.select();']
3028
        );
3029
        $form->applyFilter('weight_calification', 'html_filter');
3030
3031
        $group = [];
3032
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('Yes'), 1);
3033
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('No'), 0);
3034
        $form->addGroup(
3035
            $group,
3036
            '',
3037
            [
3038
                get_lang('Thread scored by peers'),
3039
                get_lang('Thread scored by peersComment'),
3040
            ]
3041
        );
3042
        $form->addElement('html', '</div>');
3043
        $form->addElement('html', '</div>');
3044
    }
3045
3046
    Skill::addSkillsToForm($form, ITEM_TYPE_FORUM_THREAD, 0);
3047
    $form->addElement('checkbox', 'thread_sticky', '', get_lang('This is a sticky message (appears always on top and has a special sticky icon)'));
3048
3049
    $form->addFile('user_upload', get_lang('Attachment'));
3050
3051
    if ($giveRevision) {
3052
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
3053
        $form->addHidden('give_revision', 1);
3054
        if (false === $hide) {
3055
            $extraField = new ExtraField('forum_post');
3056
            $extraField->addElements(
3057
                $form,
3058
                null,
3059
                [], //exclude
3060
                false, // filter
3061
                false, // tag as select
3062
                ['revision_language'], //show only fields
3063
                [], // order fields
3064
                [] // extra data
3065
            );
3066
        } else {
3067
            $form->addHidden('extra_revision_language', 1);
3068
        }
3069
    }
3070
    $form->addButtonCreate(get_lang('Create thread'), 'SubmitPost');
3071
3072
    $defaults['thread_peer_qualify'] = 0;
3073
    if (!empty($form_values)) {
3074
        $defaults['post_title'] = prepare4display($form_values['post_title']);
3075
        $defaults['post_text'] = prepare4display($form_values['post_text']);
3076
        $defaults['post_notification'] = (int) $form_values['post_notification'];
3077
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
3078
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
3079
    }
3080
3081
    $form->setDefaults(isset($defaults) ? $defaults : []);
3082
3083
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3084
    $form->addRule('post_title', get_lang('Required field'), 'required');
3085
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
3086
        $form->addRule(
3087
            'poster_name',
3088
            get_lang('Required field'),
3089
            'required'
3090
        );
3091
    }
3092
3093
    // Validation or display
3094
    if ($form->validate()) {
3095
        $check = Security::check_token('post');
3096
        if ($check) {
3097
            $values = $form->getSubmitValues();
3098
            if (isset($values['thread_qualify_gradebook']) &&
3099
                '1' == $values['thread_qualify_gradebook'] &&
3100
                empty($values['weight_calification'])
3101
            ) {
3102
                Display::addFlash(
3103
                    Display::return_message(
3104
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
3105
                        'error',
3106
                        false
3107
                    )
3108
                );
3109
3110
                return false;
3111
            }
3112
3113
            $newThread = store_thread($forum, $values);
3114
            if ($newThread) {
3115
                Skill::saveSkills($form, ITEM_TYPE_FORUM_THREAD, $newThread->getIid());
3116
                $postId = $newThread->getThreadLastPost();
3117
3118
                if ($postId) {
3119
                    if (isset($values['give_revision']) && 1 == $values['give_revision']) {
3120
                        $extraFieldValues = new ExtraFieldValue('forum_post');
3121
                        $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
3122
3123
                        $params = [
3124
                            'item_id' => $postId,
3125
                            'extra_revision_language' => $revisionLanguage,
3126
                        ];
3127
3128
                        $extraFieldValues->saveFieldValues(
3129
                            $params,
3130
                            false,
3131
                            false,
3132
                            ['revision_language']
3133
                        );
3134
                    }
3135
                    $extraFieldValues = new ExtraFieldValue('forum_post');
3136
                    $params = [
3137
                        'item_id' => $postId,
3138
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
3139
                    ];
3140
                    $extraFieldValues->saveFieldValues(
3141
                        $params,
3142
                        false,
3143
                        false,
3144
                        ['ask_for_revision']
3145
                    );
3146
                }
3147
            }
3148
3149
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
3150
                [
3151
                    'forum' => $forumId,
3152
                    'thread' => $newThread->getIid(),
3153
                ]
3154
            );
3155
3156
            Security::clear_token();
3157
            header('Location: '.$url);
3158
            exit;
3159
        }
3160
    } else {
3161
        $token = Security::get_token();
3162
        $form->addElement('hidden', 'sec_token');
3163
        $form->setConstants(['sec_token' => $token]);
3164
3165
        // Delete from $_SESSION forum attachment from other posts
3166
        // and keep only attachments for new post
3167
        clearAttachedFiles(FORUM_NEW_POST);
3168
        // Get forum attachment ajax table to add it to form
3169
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
3170
        $ajaxHtml = $attachmentAjaxTable;
3171
        $form->addElement('html', $ajaxHtml);
3172
3173
        return $form;
3174
    }
3175
}
3176
3177
/**
3178
 * @param CForumThread $threadInfo
3179
 * @param int          $user_id
3180
 * @param int          $thread_id
3181
 * @param int          $thread_qualify
3182
 * @param int          $qualify_time
3183
 * @param int          $session_id
3184
 *
3185
 * @return array optional
3186
 *
3187
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3188
 *
3189
 * @version October 2008, dokeos  1.8.6
3190
 */
3191
function saveThreadScore(
3192
    CForumThread $threadEntity,
3193
    $user_id,
3194
    $thread_id,
3195
    $thread_qualify = 0,
3196
    $qualify_time,
3197
    $session_id = 0
3198
) {
3199
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3200
3201
    $course_id = api_get_course_int_id();
3202
    $session_id = (int) $session_id;
3203
    $currentUserId = api_get_user_id();
3204
3205
    if ($user_id == (string) ((int) $user_id) &&
3206
        $thread_id == (string) ((int) $thread_id) &&
3207
        $thread_qualify == (string) ((float) $thread_qualify)
3208
    ) {
3209
        $max = $threadEntity->getThreadQualifyMax();
3210
        if ($thread_qualify <= $max) {
3211
            if ($threadEntity->isThreadPeerQualify()) {
3212
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3213
                        WHERE
3214
                            c_id = $course_id AND
3215
                            user_id = $user_id AND
3216
                            qualify_user_id = $currentUserId AND
3217
                            thread_id = ".$thread_id;
3218
            } else {
3219
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3220
                        WHERE
3221
                            c_id = $course_id AND
3222
                            user_id = $user_id AND
3223
                            thread_id = ".$thread_id;
3224
            }
3225
3226
            $result = Database::query($sql);
3227
            $row = Database::fetch_array($result);
3228
3229
            if (0 == $row[0]) {
3230
                $sql = "INSERT INTO $table_threads_qualify (c_id, user_id, thread_id,qualify,qualify_user_id,qualify_time,session_id)
3231
                        VALUES (".$course_id.", '".$user_id."','".$thread_id."',".(float) $thread_qualify.", '".$currentUserId."','".$qualify_time."','".$session_id."')";
3232
                Database::query($sql);
3233
                return 'insert';
3234
            } else {
3235
                saveThreadScoreHistory(
3236
                    '1',
3237
                    $course_id,
3238
                    $user_id,
3239
                    $thread_id
3240
                );
3241
3242
                // Update
3243
                $sql = "UPDATE $table_threads_qualify
3244
                        SET
3245
                            qualify = '".$thread_qualify."',
3246
                            qualify_time = '".$qualify_time."'
3247
                        WHERE
3248
                            c_id = $course_id AND
3249
                            user_id=".$user_id.' AND
3250
                            thread_id='.$thread_id." AND
3251
                            qualify_user_id = $currentUserId
3252
                        ";
3253
                Database::query($sql);
3254
3255
                return 'update';
3256
            }
3257
        } else {
3258
            return null;
3259
        }
3260
    }
3261
}
3262
3263
/**
3264
 * This function shows qualify.
3265
 *
3266
 * @param string $option    contains the information of option to run
3267
 * @param int    $user_id   contains the information the current user id
3268
 * @param int    $thread_id contains the information the current thread id
3269
 *
3270
 * @return int qualify
3271
 *             <code> $option=1 obtained the qualification of the current thread</code>
3272
 *
3273
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3274
 *
3275
 * @version October 2008, dokeos  1.8.6
3276
 */
3277
function showQualify($option, $user_id, $thread_id)
3278
{
3279
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3280
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3281
3282
    $course_id = api_get_course_int_id();
3283
    $user_id = (int) $user_id;
3284
    $thread_id = (int) $thread_id;
3285
3286
    if (empty($user_id) || empty($thread_id)) {
3287
        return false;
3288
    }
3289
3290
    $sql = '';
3291
    switch ($option) {
3292
        case 1:
3293
            $sql = "SELECT qualify FROM $table_threads_qualify
3294
                    WHERE
3295
                        c_id = $course_id AND
3296
                        user_id=".$user_id.' AND
3297
                        thread_id='.$thread_id;
3298
3299
            break;
3300
        case 2:
3301
            $sql = "SELECT thread_qualify_max FROM $table_threads
3302
                    WHERE c_id = $course_id AND thread_id=".$thread_id;
3303
3304
            break;
3305
    }
3306
3307
    if (!empty($sql)) {
3308
        $rs = Database::query($sql);
3309
        $row = Database::fetch_array($rs);
3310
3311
        return $row[0];
3312
    }
3313
3314
    return [];
3315
}
3316
3317
/**
3318
 * This function gets qualify historical.
3319
 *
3320
 * @param int  $user_id   contains the information the current user id
3321
 * @param int  $thread_id contains the information the current thread id
3322
 * @param bool $opt       contains the information of option to run
3323
 *
3324
 * @return array
3325
 *
3326
 * @author Christian Fasanando <[email protected]>,
3327
 * @author Isaac Flores <[email protected]>,
3328
 *
3329
 * @version October 2008, dokeos  1.8.6
3330
 */
3331
function getThreadScoreHistory($user_id, $thread_id, $opt)
3332
{
3333
    $user_id = (int) $user_id;
3334
    $thread_id = (int) $thread_id;
3335
3336
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3337
    $course_id = api_get_course_int_id();
3338
3339
    if ('false' == $opt) {
3340
        $sql = "SELECT * FROM $table_threads_qualify_log
3341
                WHERE
3342
                    c_id = $course_id AND
3343
                    thread_id='".$thread_id."' AND
3344
                    user_id='".$user_id."'
3345
                ORDER BY qualify_time";
3346
    } else {
3347
        $sql = "SELECT * FROM $table_threads_qualify_log
3348
                WHERE
3349
                    c_id = $course_id AND
3350
                    thread_id='".$thread_id."' AND
3351
                    user_id='".$user_id."'
3352
                ORDER BY qualify_time DESC";
3353
    }
3354
    $rs = Database::query($sql);
3355
    $log = [];
3356
    while ($row = Database::fetch_array($rs, 'ASSOC')) {
3357
        $log[] = $row;
3358
    }
3359
3360
    return $log;
3361
}
3362
3363
/**
3364
 * This function stores qualify historical.
3365
 *
3366
 * @param bool contains the information of option to run
3367
 * @param string contains the information the current course id
3368
 * @param int contains the information the current forum id
3369
 * @param int contains the information the current user id
3370
 * @param int contains the information the current thread id
3371
 * @param int contains the information the current qualify
3372
 * @param string $option
3373
 * @param int    $course_id
3374
 * @param int    $user_id
3375
 * @param int    $thread_id
3376
 *
3377
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3378
 *
3379
 * @version October 2008, dokeos  1.8.6
3380
 */
3381
function saveThreadScoreHistory(
3382
    $option,
3383
    $course_id,
3384
    $user_id,
3385
    $thread_id
3386
) {
3387
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3388
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3389
3390
    $course_id = (int) $course_id;
3391
    $qualify_user_id = api_get_user_id();
3392
3393
    if ($user_id == (string) ((int) $user_id) &&
3394
        $thread_id == (string) ((int) $thread_id) && 1 == $option
3395
    ) {
3396
        // Extract information of thread_qualify.
3397
        $sql = "SELECT qualify, qualify_time
3398
                FROM $table_threads_qualify
3399
                WHERE
3400
                    c_id = $course_id AND
3401
                    user_id = ".$user_id.' AND
3402
                    thread_id = '.$thread_id." AND
3403
                    qualify_user_id = $qualify_user_id
3404
                ";
3405
        $rs = Database::query($sql);
3406
        $row = Database::fetch_array($rs);
3407
3408
        // Insert thread_historical.
3409
        $sql = "INSERT INTO $table_threads_qualify_log (c_id, user_id, thread_id, qualify, qualify_user_id,qualify_time,session_id)
3410
                VALUES(".$course_id.", '".$user_id."','".$thread_id."',".(float) $row[0].", '".$qualify_user_id."','".$row[1]."','')";
3411
        Database::query($sql);
3412
    }
3413
}
3414
3415
/**
3416
 * This function shows current thread qualify .
3417
 *
3418
 * @param int $threadId
3419
 * @param int $sessionId
3420
 * @param int $userId
3421
 *
3422
 * @return array or null if is empty
3423
 *
3424
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3425
 *
3426
 * @version December 2008, dokeos  1.8.6
3427
 */
3428
function current_qualify_of_thread($threadId, $sessionId, $userId)
3429
{
3430
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3431
3432
    $course_id = api_get_course_int_id();
3433
    $currentUserId = api_get_user_id();
3434
    $sessionId = (int) $sessionId;
3435
    $threadId = (int) $threadId;
3436
3437
    $sql = "SELECT qualify FROM $table_threads_qualify
3438
            WHERE
3439
                c_id = $course_id AND
3440
                thread_id = $threadId AND
3441
                session_id = $sessionId AND
3442
                qualify_user_id = $currentUserId AND
3443
                user_id = $userId
3444
            ";
3445
    $res = Database::query($sql);
3446
    $row = Database::fetch_array($res, 'ASSOC');
3447
3448
    return $row['qualify'];
3449
}
3450
3451
/**
3452
 * This function stores a reply in the forum_post table.
3453
 * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date).
3454
 *
3455
 * @param array $values
3456
 * @param int   $courseId Optional
3457
 * @param int   $userId   Optional
3458
 *
3459
 * @return int post id
3460
 */
3461
function store_reply(CForumForum $forum, CForumThread $thread, $values, $courseId = 0, $userId = 0)
3462
{
3463
    $courseId = !empty($courseId) ? $courseId : api_get_course_int_id();
3464
    $_course = api_get_course_info_by_id($courseId);
3465
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3466
    $post_date = api_get_utc_datetime();
3467
    $userId = $userId ?: api_get_user_id();
3468
3469
    if (1 == $forum->getAllowAnonymous()) {
3470
        if (api_is_anonymous() && empty($userId)) {
3471
            $userId = api_get_anonymous_id();
3472
        }
3473
    }
3474
3475
    if (empty($userId)) {
3476
        return false;
3477
    }
3478
3479
    $visible = 1;
3480
    if ('1' == $forum->getApprovalDirectPost() &&
3481
        !api_is_allowed_to_edit(null, true)
3482
    ) {
3483
        $visible = 0;
3484
    }
3485
3486
    $upload_ok = 1;
3487
    $new_post_id = 0;
3488
3489
    if ($upload_ok) {
3490
        $course = api_get_course_entity($courseId);
3491
        $session = api_get_session_entity();
3492
3493
        $post = new CForumPost();
3494
        $post
3495
            ->setCId($courseId)
3496
            ->setPostTitle($values['post_title'])
3497
            ->setPostText(isset($values['post_text']) ?: null)
3498
            ->setThread($thread)
3499
            ->setForum($forum)
3500
            ->setPosterId($userId)
3501
            ->setPostNotification(isset($values['post_notification']) ? $values['post_notification'] : null)
3502
            ->setPostParentId(isset($values['post_parent_id']) ? $values['post_parent_id'] : null)
3503
            ->setVisible($visible)
3504
            ->setPostDate(api_get_utc_datetime(null, false, true))
3505
            ->setParent($thread)
3506
            ->addCourseLink(
3507
                $course,
3508
                $session
3509
            );
3510
3511
        $repo = Container::getForumPostRepository();
3512
        $em = $repo->getEntityManager();
3513
        $em->persist($post);
3514
        $em->flush();
3515
3516
        $new_post_id = $post->getIid();
3517
        if ($new_post_id) {
3518
            $values['new_post_id'] = $new_post_id;
3519
            $message = get_lang('The reply has been added');
3520
3521
            if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3522
                foreach ($_POST['file_ids'] as $key => $id) {
3523
                    editAttachedFile(
3524
                        [
3525
                            'comment' => $_POST['file_comments'][$key],
3526
                            'post_id' => $new_post_id,
3527
                        ],
3528
                        $id
3529
                    );
3530
                }
3531
            }
3532
3533
            // Update the thread.
3534
            updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
3535
3536
            // Update the forum.
3537
            /*api_item_property_update(
3538
                $_course,
3539
                TOOL_FORUM,
3540
                $values['forum_id'],
3541
                'NewMessageInForum',
3542
                $userId
3543
            );
3544
3545
            // Insert post
3546
            api_item_property_update(
3547
                $_course,
3548
                TOOL_FORUM_POST,
3549
                $new_post_id,
3550
                'NewPost',
3551
                $userId
3552
            );*/
3553
3554
            if ('1' == $forum->getApprovalDirectPost() &&
3555
                !api_is_allowed_to_edit(null, true)
3556
            ) {
3557
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
3558
            }
3559
3560
            if ($forum->isModerated() &&
3561
                !api_is_allowed_to_edit(null, true)
3562
            ) {
3563
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
3564
            }
3565
3566
            // Setting the notification correctly.
3567
            $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
3568
            if (1 == $my_post_notification) {
3569
                set_notification('thread', $values['thread_id'], true);
3570
            }
3571
3572
            send_notification_mails(
3573
                $forum,
3574
                $thread,
3575
                $values
3576
            );
3577
            add_forum_attachment_file('', $post);
3578
3579
            $logInfo = [
3580
                'tool' => TOOL_FORUM,
3581
                'tool_id' => $values['forum_id'],
3582
                'tool_id_detail' => $values['thread_id'],
3583
                'action' => 'new-post',
3584
                'action_details' => $values['action'],
3585
                'info' => $values['post_title'],
3586
            ];
3587
            Event::registerLog($logInfo);
3588
        }
3589
3590
        Session::erase('formelements');
3591
        Session::erase('origin');
3592
        Session::erase('breadcrumbs');
3593
        Session::erase('addedresource');
3594
        Session::erase('addedresourceid');
3595
3596
        Display::addFlash(Display::return_message($message, 'confirmation', false));
3597
    } else {
3598
        Display::addFlash(
3599
            Display::return_message(
3600
                get_lang('No file was uploaded.').' '.get_lang('Please select a file before pressing the upload button.'),
3601
                'error'
3602
            )
3603
        );
3604
    }
3605
3606
    return $new_post_id;
3607
}
3608
3609
/**
3610
 * This function displays the form that is used to edit a post. This can be a new thread or a reply.
3611
 *
3612
 * @param CForumPost   $post        contains all the information about the current post
3613
 * @param CForumThread $thread      contains all the information about the current thread
3614
 * @param CForumForum  $forum       contains all info about the current forum (to check if attachments are allowed)
3615
 * @param array        $form_values contains the default values to fill the form
3616
 *
3617
 * @author Patrick Cool <[email protected]>, Ghent University
3618
 *
3619
 * @version february 2006, dokeos 1.8
3620
 */
3621
function show_edit_post_form(
3622
    $post,
3623
    $thread,
3624
    $forum,
3625
    $form_values,
3626
    $id_attach = 0
3627
) {
3628
    // Initialize the object.
3629
    $form = new FormValidator(
3630
        'edit_post',
3631
        'post',
3632
        api_get_self().'?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&post='.(int) ($_GET['post'])
3633
    );
3634
    $form->addElement('header', get_lang('Edit a post'));
3635
    // Setting the form elements.
3636
    $form->addElement('hidden', 'post_id', $post->getIid());
3637
    $form->addElement('hidden', 'thread_id', $thread->getIid());
3638
    $form->addElement('hidden', 'id_attach', $id_attach);
3639
3640
    if (empty($post->getPostParentId())) {
3641
        $form->addElement('hidden', 'is_first_post_of_thread', '1');
3642
    }
3643
3644
    $form->addElement('text', 'post_title', get_lang('Title'));
3645
    $form->applyFilter('post_title', 'html_filter');
3646
    $form->addElement(
3647
        'html_editor',
3648
        'post_text',
3649
        get_lang('Text'),
3650
        null,
3651
        api_is_allowed_to_edit(null, true) ? [
3652
            'ToolbarSet' => 'Forum',
3653
            'Width' => '100%',
3654
            'Height' => '400',
3655
        ] : [
3656
            'ToolbarSet' => 'ForumStudent',
3657
            'Width' => '100%',
3658
            'Height' => '400',
3659
            'UserStatus' => 'student',
3660
        ]
3661
    );
3662
    $form->addRule('post_text', get_lang('Required field'), 'required');
3663
3664
    $extraFields = new ExtraField('forum_post');
3665
    $extraFields->addElements($form, $post->getIid());
3666
3667
    $form->addButtonAdvancedSettings('advanced_params');
3668
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3669
3670
    if ($forum->isModerated() && api_is_allowed_to_edit(null, true)) {
3671
        $group = [];
3672
        $group[] = $form->createElement(
3673
            'radio',
3674
            'status',
3675
            null,
3676
            get_lang('Validated'),
3677
            1
3678
        );
3679
        $group[] = $form->createElement(
3680
            'radio',
3681
            'status',
3682
            null,
3683
            get_lang('Waiting for moderation'),
3684
            2
3685
        );
3686
        $group[] = $form->createElement(
3687
            'radio',
3688
            'status',
3689
            null,
3690
            get_lang('Rejected'),
3691
            3
3692
        );
3693
        $form->addGroup($group, 'status', get_lang('Status'));
3694
    }
3695
3696
    $defaults['status']['status'] = $post->getStatus();
3697
3698
    $form->addElement(
3699
        'checkbox',
3700
        'post_notification',
3701
        '',
3702
        get_lang('Notify me by e-mail when somebody replies')
3703
    );
3704
3705
    if (api_is_allowed_to_edit(null, true) &&
3706
        empty($post->getPostParentId())
3707
    ) {
3708
        // The sticky checkbox only appears when it is the first post of a thread.
3709
        $form->addElement(
3710
            'checkbox',
3711
            'thread_sticky',
3712
            '',
3713
            get_lang('This is a sticky message (appears always on top and has a special sticky icon)')
3714
        );
3715
        if (1 == $thread->getThreadSticky()) {
3716
            $defaults['thread_sticky'] = true;
3717
        }
3718
    }
3719
3720
    $form->addElement('html', '</div>');
3721
3722
    $form->addFile('user_upload[]', get_lang('Attachment'));
3723
    $form->addButton(
3724
        'add_attachment',
3725
        get_lang('Add attachment'),
3726
        'paperclip',
3727
        'default',
3728
        'default',
3729
        null,
3730
        ['id' => 'reply-add-attachment']
3731
    );
3732
3733
    $form->addButtonUpdate(get_lang('Edit'), 'SubmitPost');
3734
3735
    // Setting the default values for the form elements.
3736
    $defaults['post_title'] = $post->getPostTitle();
3737
    $defaults['post_text'] = $post->getPostText();
3738
3739
    if (1 == $post->getPostNotification()) {
3740
        $defaults['post_notification'] = true;
3741
    }
3742
3743
    if (!empty($form_values)) {
3744
        $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
3745
        $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
3746
    }
3747
3748
    $form->setDefaults($defaults);
3749
3750
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3751
    $form->addRule('post_title', get_lang('Required field'), 'required');
3752
3753
    // Validation or display
3754
    if ($form->validate()) {
3755
        $values = $form->exportValues();
3756
        $values['item_id'] = $post->getIid();
3757
        $extraFieldValues = new ExtraFieldValue('forum_post');
3758
        $extraFieldValues->saveFieldValues($values);
3759
3760
        store_edit_post($forum, $values);
3761
    } else {
3762
        // Delete from $_SESSION forum attachment from other posts
3763
        clearAttachedFiles($post->getIid());
3764
        // Get forum attachment ajax table to add it to form
3765
        $fileData = getAttachmentsAjaxTable($post->getIid(), $forum->getIid());
3766
        $form->addElement('html', $fileData);
3767
        $form->display();
3768
    }
3769
}
3770
3771
/**
3772
 * This function stores the edit of a post in the forum_post table.
3773
 *
3774
 * @author Patrick Cool <[email protected]>, Ghent University
3775
 *
3776
 * @version february 2006, dokeos 1.8
3777
 */
3778
function store_edit_post(CForumForum $forum, $values)
3779
{
3780
    $logInfo = [
3781
        'tool' => TOOL_FORUM,
3782
        'tool_id' => $_GET['forum'],
3783
        'tool_id_detail' => $values['thread_id'],
3784
        'action' => 'edit-post',
3785
        'action_details' => 'post',
3786
        'info' => $values['post_title'],
3787
    ];
3788
    Event::registerLog($logInfo);
3789
3790
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
3791
    $course_id = api_get_course_int_id();
3792
3793
    //check if this post is the first of the thread
3794
    // First we check if the change affects the thread and if so we commit
3795
    // the changes (sticky and post_title=thread_title are relevant).
3796
    $posts = getPosts($forum, $values['thread_id']);
3797
    $first_post = null;
3798
    if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
3799
        $first_post = $posts[0];
3800
    }
3801
3802
    if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
3803
        // Simple edit
3804
        $params = [
3805
            'thread_title' => $values['post_title'],
3806
            'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
3807
        ];
3808
        $where = ['iid = ?' => [$values['thread_id']]];
3809
        Database::update($threadTable, $params, $where);
3810
    }
3811
3812
    $status = '';
3813
    $updateStatus = false;
3814
    if ($forum->isModerated()) {
3815
        if (api_is_allowed_to_edit(null, true)) {
3816
            $status = $values['status']['status'];
3817
            $updateStatus = true;
3818
        } else {
3819
            $status = CForumPost::STATUS_WAITING_MODERATION;
3820
            $updateStatus = true;
3821
        }
3822
    }
3823
3824
    $postId = $values['post_id'];
3825
    $repo = Container::getForumPostRepository();
3826
    /** @var CForumPost $post */
3827
    $post = $repo->find($postId);
3828
    if ($post) {
3829
        $post
3830
            ->setPostTitle($values['post_title'])
3831
            ->setPostText($values['post_text'])
3832
            ->setPostNotification(isset($values['post_notification']) ? 1 : 0)
3833
        ;
3834
3835
        if ($updateStatus) {
3836
            $post->setStatus($status);
3837
        }
3838
        $repo->getEntityManager()->persist($post);
3839
        $repo->getEntityManager()->flush();
3840
    }
3841
3842
    // Update attached files
3843
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3844
        foreach ($_POST['file_ids'] as $key => $id) {
3845
            editAttachedFile(
3846
                [
3847
                    'comment' => $_POST['file_comments'][$key],
3848
                    'post_id' => $values['post_id'],
3849
                ],
3850
                $id
3851
            );
3852
        }
3853
    }
3854
3855
    if (!empty($values['remove_attach'])) {
3856
        throw new Exception('remove_attach');
3857
        //delete_attachment($post->getIid());
3858
    }
3859
3860
    if (empty($values['id_attach'])) {
3861
        add_forum_attachment_file(
3862
            isset($values['file_comment']) ? $values['file_comment'] : null,
3863
            $post
3864
        );
3865
    } else {
3866
        /*edit_forum_attachment_file(
3867
            isset($values['file_comment']) ? $values['file_comment'] : null,
3868
            $values['post_id'],
3869
            $values['id_attach']
3870
        );*/
3871
    }
3872
3873
    $message = get_lang('The post has been modified').'<br />';
3874
    $message .= get_lang('You can now return to the').
3875
        ' <a href="viewforum.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&">'.
3876
        get_lang('Forum').'</a><br />';
3877
    $message .= get_lang('You can now return to the').
3878
        ' <a
3879
            href="viewthread.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.$values['thread_id'].'&post='.Security::remove_XSS($_GET['post']).'">'.
3880
        get_lang('Message').'</a>';
3881
3882
    Session::erase('formelements');
3883
    Session::erase('origin');
3884
    Session::erase('breadcrumbs');
3885
    Session::erase('addedresource');
3886
    Session::erase('addedresourceid');
3887
3888
    echo Display::return_message($message, 'confirmation', false);
3889
}
3890
3891
/**
3892
 * This function displays the firstname and lastname of the user as a link to the user tool.
3893
 *
3894
 * @param string $user_id names
3895
 * @ in_title : title tootip
3896
 *
3897
 * @return string HTML
3898
 *
3899
 * @author Patrick Cool <[email protected]>, Ghent University
3900
 *
3901
 * @version february 2006, dokeos 1.8
3902
 */
3903
function display_user_link($user_id, $name, $origin = '', $in_title = '')
3904
{
3905
    if (0 != $user_id) {
3906
        $userInfo = api_get_user_info($user_id);
3907
3908
        return '<a href="'.$userInfo['profile_url'].'">'.Security::remove_XSS($userInfo['complete_name']).'</a>';
3909
    } else {
3910
        return $name.' ('.get_lang('Anonymous').')';
3911
    }
3912
}
3913
3914
/**
3915
 * This function displays the user image from the profile, with a link to the user's details.
3916
 *
3917
 * @param int    $user_id User's database ID
3918
 * @param string $name    User's name
3919
 * @param string $origin  the origin where the forum is called (example : learnpath)
3920
 *
3921
 * @return string An HTML with the anchor and the image of the user
3922
 *
3923
 * @author Julio Montoya <[email protected]>
3924
 */
3925
function display_user_image($user_id, $name, $origin = '')
3926
{
3927
    $userInfo = api_get_user_info($user_id);
3928
    $link = '<a href="'.(!empty($origin) ? '#' : $userInfo['profile_url']).'" '.(!empty($origin) ? 'target="_self"' : '').'>';
3929
3930
    if (0 != $user_id) {
3931
        return $link.'<img src="'.$userInfo['avatar'].'"  alt="'.$name.'"  title="'.$name.'" /></a>';
3932
    } else {
3933
        return $link.Display::return_icon('unknown.jpg', $name).'</a>';
3934
    }
3935
}
3936
3937
/**
3938
 * The thread view counter gets increased every time someone looks at the thread.
3939
 *
3940
 * @param int $thread_id
3941
 *
3942
 * @author Patrick Cool <[email protected]>, Ghent University
3943
 *
3944
 * @version february 2006, dokeos 1.8
3945
 */
3946
function increase_thread_view($thread_id)
3947
{
3948
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3949
    $course_id = api_get_course_int_id();
3950
3951
    $sql = "UPDATE $table_threads
3952
            SET thread_views = thread_views + 1
3953
            WHERE
3954
                c_id = $course_id AND
3955
                iid = '".(int) $thread_id."'";
3956
    Database::query($sql);
3957
}
3958
3959
/**
3960
 * The relies counter gets increased every time somebody replies to the thread.
3961
 *
3962
 * @author Patrick Cool <[email protected]>, Ghent University
3963
 *
3964
 * @version february 2006, dokeos 1.8
3965
 *
3966
 * @param int    $threadId
3967
 * @param string $lastPostId
3968
 * @param string $post_date
3969
 */
3970
function updateThreadInfo($threadId, $lastPostId, $post_date)
3971
{
3972
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3973
    $course_id = api_get_course_int_id();
3974
    $sql = "UPDATE $table_threads SET
3975
            thread_replies = thread_replies+1,
3976
            thread_last_post = '".Database::escape_string($lastPostId)."',
3977
            thread_date = '".Database::escape_string($post_date)."'
3978
            WHERE
3979
                c_id = $course_id AND
3980
                iid ='".Database::escape_string($threadId)."'"; // this needs to be cleaned first
3981
    Database::query($sql);
3982
}
3983
3984
/**
3985
 * This function is used to find all the information about what's new in the forum tool.
3986
 *
3987
 * @author Patrick Cool <[email protected]>, Ghent University
3988
 *
3989
 * @version february 2006, dokeos 1.8
3990
 */
3991
function get_whats_new()
3992
{
3993
    $userId = api_get_user_id();
3994
    $course_id = api_get_course_int_id();
3995
3996
    if (empty($course_id) || empty($userId)) {
3997
        return false;
3998
    }
3999
4000
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4001
    $tracking_last_tool_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4002
4003
    $tool = TOOL_FORUM;
4004
    $lastForumAccess = Session::read('last_forum_access');
4005
4006
    if (!$lastForumAccess) {
4007
        $sql = "SELECT * FROM $tracking_last_tool_access
4008
                WHERE
4009
                    access_user_id = $userId AND
4010
                    c_id = $course_id AND
4011
                    access_tool = '".Database::escape_string($tool)."'";
4012
        $result = Database::query($sql);
4013
        $row = Database::fetch_array($result);
4014
        if ($row) {
4015
            Session::write('last_forum_access', $row['access_date']);
4016
            $lastForumAccess = $row['access_date'];
4017
        }
4018
    }
4019
4020
    $whatsNew = Session::read('whatsnew_post_info');
4021
4022
    if (!$whatsNew) {
4023
        if ('' != $lastForumAccess) {
4024
            $postInfo = [];
4025
            $sql = "SELECT * FROM $table_posts
4026
                    WHERE
4027
                        c_id = $course_id AND
4028
                        visible = 1 AND
4029
                        post_date > '".Database::escape_string($lastForumAccess)."'";
4030
            $result = Database::query($sql);
4031
            while ($row = Database::fetch_array($result)) {
4032
                $postInfo[$row['forum_id']][$row['thread_id']][$row['iid']] = $row['post_date'];
4033
            }
4034
            Session::write('whatsnew_post_info', $postInfo);
4035
        }
4036
    }
4037
}
4038
4039
function approvePost(CForumPost $post, $action)
4040
{
4041
    if ('invisible' === $action) {
4042
        $visibility = 0;
4043
    }
4044
4045
    if ('visible' === $action) {
4046
        $visibility = 1;
4047
        handle_mail_cue('post', $post->getIid());
4048
    }
4049
4050
    $post->setVisible($visibility);
4051
    Database::getManager()->persist($post);
4052
    Database::getManager()->flush();
4053
4054
    Display::addFlash(Display::return_message(get_lang('The visibility has been changed')));
4055
}
4056
4057
/**
4058
 * This function retrieves all the unapproved messages for a given forum
4059
 * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see
4060
 * this).
4061
 *
4062
 * @param int $forum_id forum where we want to know the unapproved messages of
4063
 *
4064
 * @return array returns
4065
 *
4066
 * @author Patrick Cool <[email protected]>, Ghent University
4067
 *
4068
 * @version february 2006, dokeos 1.8
4069
 */
4070
function get_unaproved_messages($forum_id)
4071
{
4072
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4073
    $course_id = api_get_course_int_id();
4074
4075
    $return_array = [];
4076
    $sql = "SELECT DISTINCT thread_id FROM $table_posts
4077
            WHERE
4078
                c_id = $course_id AND
4079
                forum_id='".Database::escape_string($forum_id)."' AND
4080
                visible='0' ";
4081
    $result = Database::query($sql);
4082
    while ($row = Database::fetch_array($result)) {
4083
        $return_array[] = $row['thread_id'];
4084
    }
4085
4086
    return $return_array;
4087
}
4088
4089
/**
4090
 * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
4091
 * was added to a given thread.
4092
 */
4093
function send_notification_mails(CForumForum $forum, CForumThread $thread, $reply_info)
4094
{
4095
    $courseEntity = api_get_course_entity($forum->getCId());
4096
    $courseId = $courseEntity->getId();
4097
4098
    $sessionId = api_get_session_id();
4099
    $sessionEntity = api_get_session_entity($sessionId);
4100
4101
    $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4102
4103
    // First we need to check if
4104
    // 1. the forum category is visible
4105
    // 2. the forum is visible
4106
    // 3. the thread is visible
4107
    // 4. the reply is visible (=when there is)
4108
4109
    $current_forum_category = null;
4110
    if ($forum->getForumCategory()) {
4111
        $current_forum_category = $forum->getForumCategory();
4112
    }
4113
4114
    $send_mails = false;
4115
    if ($thread->isVisible($courseEntity, $sessionEntity) &&
4116
        $forum->isVisible($courseEntity, $sessionEntity) &&
4117
        ($current_forum_category && $forum->getForumCategory()->isVisible($courseEntity, $sessionEntity)) &&
4118
        '1' != $forum->getApprovalDirectPost()
4119
    ) {
4120
        $send_mails = true;
4121
    }
4122
4123
    // The forum category, the forum, the thread and the reply are visible to the user
4124
    if ($send_mails && !empty($forum)) {
4125
        $postId = isset($reply_info['new_post_id']) ? $reply_info['new_post_id'] : 0;
4126
        send_notifications($forum, $thread, $postId);
4127
    } else {
4128
        $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4129
        if ($forum) {
4130
            $sql = "SELECT * FROM $table_notification
4131
                    WHERE
4132
                        c_id = ".$courseId." AND
4133
                        (
4134
                            forum_id = '".$forum->getIid()."' OR
4135
                            thread_id = '".$thread->getIid()."'
4136
                        ) ";
4137
            $result = Database::query($sql);
4138
            $user_id = api_get_user_id();
4139
            while ($row = Database::fetch_array($result)) {
4140
                $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
4141
                        VALUES (".$courseId.", '".$thread->getIid()."', '".(int) ($reply_info['new_post_id'])."', '$user_id' )";
4142
                Database::query($sql);
4143
            }
4144
        }
4145
    }
4146
}
4147
4148
/**
4149
 * This function is called whenever something is made visible because there might
4150
 * be new posts and the user might have indicated that (s)he wanted to be
4151
 * informed about the new posts by mail.
4152
 *
4153
 * @param string $content Content type (post, thread, forum, forum_category)
4154
 * @param int    $id      Item DB ID of the corresponding content type
4155
 *
4156
 * @return string language variable
4157
 *
4158
 * @author Patrick Cool <[email protected]>, Ghent University
4159
 *
4160
 * @version february 2006, dokeos 1.8
4161
 */
4162
function handle_mail_cue($content, $id)
4163
{
4164
    $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4165
    $table_forums = Database::get_course_table(TABLE_FORUM);
4166
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4167
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4168
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4169
4170
    $course_id = api_get_course_int_id();
4171
    $id = (int) $id;
4172
4173
    /* If the post is made visible we only have to send mails to the people
4174
     who indicated that they wanted to be informed for that thread.*/
4175
    if ('post' === $content) {
4176
        // Getting the information about the post (need the thread_id).
4177
        /** @var CForumPost $post */
4178
        $post = Container::getForumPostRepository()->find($id);
4179
        $thread_id = $post->getThread()->getIid();
4180
4181
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4182
        $sql = "SELECT users.firstname, users.lastname, users.id as user_id, users.email
4183
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4184
                WHERE
4185
                    posts.c_id = $course_id AND
4186
                    mailcue.c_id = $course_id AND
4187
                    posts.thread_id = $thread_id AND
4188
                    posts.post_notification = '1' AND
4189
                    mailcue.thread_id = $thread_id AND
4190
                    users.id = posts.poster_id AND
4191
                    users.active = 1
4192
                GROUP BY users.email";
4193
4194
        $result = Database::query($sql);
4195
        $forum = Container::getForumRepository()->find($post->getForum()->getIid());
4196
4197
        while ($row = Database::fetch_array($result)) {
4198
            send_mail($row, $forum, $post->getThread(), $post);
4199
        }
4200
    } elseif ('thread' === $content) {
4201
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4202
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
4203
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4204
                WHERE
4205
                    posts.c_id = $course_id AND
4206
                    mailcue.c_id = $course_id AND
4207
                    posts.thread_id = $id AND
4208
                    posts.post_notification = '1' AND
4209
                    mailcue.thread_id = $id AND
4210
                    users.user_id = posts.poster_id AND
4211
                    users.active = 1
4212
                GROUP BY users.email";
4213
        $result = Database::query($sql);
4214
        while ($row = Database::fetch_array($result)) {
4215
            $forum = Container::getForumRepository()->find($row['forum_id']);
4216
            $thread = Container::getForumThreadRepository()->find($id);
4217
            send_mail($row, $forum, $thread);
4218
        }
4219
4220
        // Deleting the relevant entries from the mailcue.
4221
        $sql = "DELETE FROM $table_mailcue
4222
                WHERE c_id = $course_id AND thread_id = $id";
4223
        Database::query($sql);
4224
    } elseif ('forum' == $content) {
4225
        $sql = "SELECT thread_id FROM $table_threads
4226
                WHERE c_id = $course_id AND forum_id = $id";
4227
        $result = Database::query($sql);
4228
        while ($row = Database::fetch_array($result)) {
4229
            handle_mail_cue('thread', $row['thread_id']);
4230
        }
4231
    } elseif ('forum_category' === $content) {
4232
        $sql = "SELECT forum_id FROM $table_forums
4233
                WHERE c_id = $course_id AND forum_category = $id";
4234
        $result = Database::query($sql);
4235
        while ($row = Database::fetch_array($result)) {
4236
            handle_mail_cue('forum', $row['forum_id']);
4237
        }
4238
    } else {
4239
        return get_lang('Error');
4240
    }
4241
}
4242
4243
/**
4244
 * This function sends the mails for the mail notification.
4245
 */
4246
function send_mail($userInfo, CForumForum $forum, CForumThread $thread, CForumPost $postInfo = null)
4247
{
4248
    if (empty($userInfo) || empty($forum) || empty($thread)) {
4249
        return false;
4250
    }
4251
4252
    $_course = api_get_course_info();
4253
    $user_id = api_get_user_id();
4254
    $forumId = $forum->getIid();
4255
    $threadId = $thread->getIid();
4256
4257
    $thread_link = api_get_path(WEB_CODE_PATH).
4258
        'forum/viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId;
4259
4260
    $email_body = get_lang('Dear').' '.api_get_person_name($userInfo['firstname'], $userInfo['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
4261
    $email_body .= get_lang('New Post in the forum').': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4262
4263
    $courseId = api_get_configuration_value('global_forums_course_id');
4264
    $subject = get_lang('New Post in the forum').' - '.$_course['official_code'].': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4265
4266
    $courseInfoTitle = get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
4267
    if (!empty($courseId) && $_course['real_id'] == $courseId) {
4268
        $subject = get_lang('New Post in the forum').': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4269
        $courseInfoTitle = " <br />\n";
4270
    }
4271
    $email_body .= $courseInfoTitle;
4272
4273
    if (!empty($postInfo)) {
4274
        $text = cut(strip_tags($postInfo->getPostText()), 100);
4275
        if (!empty($text)) {
4276
            $email_body .= get_lang('Message').": <br />\n ";
4277
            $email_body .= $text;
4278
            $email_body .= "<br /><br />\n";
4279
        }
4280
    }
4281
4282
    $email_body .= get_lang('You stated that you wanted to be informed by e-mail whenever somebody replies on the thread')."<br />\n";
4283
4284
    if (!empty($thread_link)) {
4285
        $email_body .= get_lang('The thread can be found here').' : <br /><a href="'.$thread_link.'">'.$thread_link."</a>\n";
4286
    }
4287
4288
    if ($userInfo['user_id'] != $user_id) {
4289
        MessageManager::send_message(
4290
            $userInfo['user_id'],
4291
            $subject,
4292
            $email_body,
4293
            [],
4294
            [],
4295
            null,
4296
            null,
4297
            null,
4298
            null,
4299
            $user_id
4300
        );
4301
    }
4302
}
4303
4304
/**
4305
 * This function displays the form for moving a thread to a different (already existing) forum.
4306
 *
4307
 * @author Patrick Cool <[email protected]>, Ghent University
4308
 *
4309
 * @version february 2006, dokeos 1.8
4310
 */
4311
function move_thread_form()
4312
{
4313
    $form = new FormValidator(
4314
        'movepost',
4315
        'post',
4316
        api_get_self().'?forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
4317
    );
4318
    $form->addHeader(get_lang('Move Thread'));
4319
    // Invisible form: the thread_id
4320
    $form->addHidden('thread_id', (int) ($_GET['thread']));
4321
    $forum_categories = get_forum_categories();
4322
4323
    $htmlcontent = '<div class="row">
4324
        <div class="label">
4325
            <span class="form_required">*</span>'.get_lang('Move to').'
4326
        </div>
4327
        <div class="formw">';
4328
    $htmlcontent .= '<select name="forum">';
4329
    foreach ($forum_categories as $category) {
4330
        $htmlcontent .= '<optgroup label="'.$category->getCatTitle().'">';
4331
        $forums = $category->getForums();
4332
        foreach ($forums as $forum) {
4333
            $htmlcontent .= '<option value="'.$forum->getIid().'">'.$forum->getForumTitle().'</option>';
4334
        }
4335
        $htmlcontent .= '</optgroup>';
4336
    }
4337
    $htmlcontent .= '</select>';
4338
    $htmlcontent .= '   </div>
4339
                    </div>';
4340
4341
    $form->addElement('html', $htmlcontent);
4342
4343
    // The OK button
4344
    $form->addButtonSave(get_lang('Move Thread'), 'SubmitForum');
4345
4346
    // Validation or display
4347
    if ($form->validate()) {
4348
        $values = $form->exportValues();
4349
        if (isset($_POST['forum'])) {
4350
            store_move_thread($values);
4351
            Display::addFlash(Display::return_message(get_lang('Moved')));
4352
        }
4353
    } else {
4354
        return $form->returnForm();
4355
    }
4356
}
4357
4358
/**
4359
 * This function displays the form for moving a post message to a different (already existing) or a new thread.
4360
 *
4361
 * @author Patrick Cool <[email protected]>, Ghent University
4362
 *
4363
 * @version february 2006, dokeos 1.8
4364
 */
4365
function move_post_form()
4366
{
4367
    $form = new FormValidator(
4368
        'movepost',
4369
        'post',
4370
        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'])
4371
    );
4372
    // The header for the form
4373
    $form->addElement('header', '', get_lang('Move post'));
4374
4375
    // Invisible form: the post_id
4376
    $form->addElement('hidden', 'post_id', (int) ($_GET['post']));
4377
4378
    // Dropdown list: Threads of this forum
4379
    $threads = get_threads($_GET['forum']);
4380
    $threads_list[0] = get_lang('A new thread');
4381
    foreach ($threads as $thread) {
4382
        $threads_list[$thread->getIid()] = $thread->getThreadTitle();
4383
    }
4384
    $form->addElement('select', 'thread', get_lang('Move toThread'), $threads_list);
4385
    $form->applyFilter('thread', 'html_filter');
4386
4387
    // The OK button
4388
    $form->addButtonSave(get_lang('Move post'), 'submit');
4389
4390
    // Setting the rules
4391
    $form->addRule('thread', get_lang('Required field'), 'required');
4392
4393
    return $form;
4394
}
4395
4396
/**
4397
 * @param array $values
4398
 *
4399
 * @return string HTML language variable
4400
 *
4401
 * @author Patrick Cool <[email protected]>, Ghent University
4402
 *
4403
 * @version february 2006, dokeos 1.8
4404
 */
4405
function store_move_post($values)
4406
{
4407
    $_course = api_get_course_info();
4408
    $course_id = api_get_course_int_id();
4409
4410
    $table_forums = Database::get_course_table(TABLE_FORUM);
4411
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4412
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4413
4414
    $user = api_get_user_entity(api_get_user_id());
4415
    $course = api_get_course_entity($course_id);
4416
    $session = api_get_session_entity();
4417
4418
    if ('0' == $values['thread']) {
4419
        $repoPost = Container::getForumPostRepository();
4420
        $repoThread = Container::getForumThreadRepository();
4421
        $repoForum = Container::getForumRepository();
4422
4423
        $em = $repoPost->getEntityManager();
4424
4425
        /** @var CForumPost $post */
4426
        $post = $repoPost->find($values['post_id']);
4427
        $forumId = $post->getForum()->getIid();
4428
        $threadId = $post->getThread()->getIid();
4429
4430
        $thread = new CForumThread();
4431
        $thread
4432
            ->setCId($course_id)
4433
            ->setThreadTitle($post->getPostTitle())
4434
            ->setForum($post->getForum())
4435
            ->setThreadPosterId($post->getPosterId())
4436
            ->setThreadPosterName($post->getPosterName())
4437
            ->setThreadLastPost($post->getIid())
4438
            ->setThreadDate($post->getPostDate())
4439
            ->setParent($post->getForum())
4440
            ->addCourseLink(
4441
                $user,
4442
                $course,
4443
                $session
4444
            );
4445
4446
        $repo = Container::getForumThreadRepository();
4447
        $em = $repo->getEntityManager();
4448
        $em->persist($thread);
4449
        $em->flush();
4450
4451
        $new_thread_id = $thread->getIid();
4452
4453
        // Storing a new thread.
4454
        /*$params = [
4455
            'c_id' => $course_id,
4456
            'thread_title' => $current_post['post_title'],
4457
            'forum_id' => $current_post['forum_id'],
4458
            'thread_poster_id' => $current_post['poster_id'],
4459
            'thread_poster_name' => $current_post['poster_name'],
4460
            'thread_last_post' => $values['post_id'],
4461
            'thread_date' => $current_post['post_date'],
4462
        ];
4463
4464
        $new_thread_id = Database::insert($table_threads, $params);
4465
4466
        api_item_property_update(
4467
            $_course,
4468
            TOOL_FORUM_THREAD,
4469
            $new_thread_id,
4470
            'visible',
4471
            $current_post['poster_id']
4472
        );*/
4473
4474
        // Moving the post to the newly created thread.
4475
        $sql = "UPDATE $table_posts SET thread_id='".$new_thread_id."', post_parent_id = NULL
4476
                WHERE c_id = $course_id AND iid ='".(int) ($values['post_id'])."'";
4477
        Database::query($sql);
4478
4479
        // Resetting the parent_id of the thread to 0 for all those who had this moved post as parent.
4480
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4481
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
4482
        Database::query($sql);
4483
4484
        // Updating updating the number of threads in the forum.
4485
        $sql = "UPDATE $table_forums SET forum_threads=forum_threads+1
4486
                WHERE c_id = $course_id AND iid ='".$forumId."'";
4487
        Database::query($sql);
4488
4489
        // Resetting the last post of the old thread and decreasing the number of replies and the thread.
4490
        $sql = "SELECT * FROM $table_posts
4491
                WHERE c_id = $course_id AND thread_id='".$threadId."'
4492
                ORDER BY iid DESC";
4493
        $result = Database::query($sql);
4494
        $row = Database::fetch_array($result);
4495
        $sql = "UPDATE $table_threads SET
4496
                    thread_last_post='".$row['iid']."',
4497
                    thread_replies=thread_replies-1
4498
                WHERE
4499
                    c_id = $course_id AND
4500
                    iid ='".$threadId."'";
4501
        Database::query($sql);
4502
    } else {
4503
        // Moving to the chosen thread.
4504
        $sql = 'SELECT thread_id FROM '.$table_posts."
4505
                WHERE c_id = $course_id AND iid = '".$values['post_id']."' ";
4506
        $result = Database::query($sql);
4507
        $row = Database::fetch_array($result);
4508
4509
        $original_thread_id = $row['thread_id'];
4510
        $sql = 'SELECT thread_last_post FROM '.$table_threads."
4511
                WHERE c_id = $course_id AND iid = '".$original_thread_id."' ";
4512
4513
        $result = Database::query($sql);
4514
        $row = Database::fetch_array($result);
4515
        $thread_is_last_post = $row['thread_last_post'];
4516
        // If is this thread, update the thread_last_post with the last one.
4517
4518
        if ($thread_is_last_post == $values['post_id']) {
4519
            $sql = 'SELECT iid as post_id FROM '.$table_posts."
4520
                    WHERE
4521
                        c_id = $course_id AND
4522
                        thread_id = '".$original_thread_id."' AND
4523
                        iid <> '".$values['post_id']."'
4524
                    ORDER BY post_date DESC LIMIT 1";
4525
            $result = Database::query($sql);
4526
4527
            $row = Database::fetch_array($result);
4528
            $thread_new_last_post = $row['post_id'];
4529
4530
            $sql = 'UPDATE '.$table_threads."
4531
                    SET thread_last_post = '".$thread_new_last_post."'
4532
                    WHERE c_id = $course_id AND iid = '".$original_thread_id."' ";
4533
            Database::query($sql);
4534
        }
4535
4536
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies-1
4537
                WHERE c_id = $course_id AND iid ='".$original_thread_id."'";
4538
        Database::query($sql);
4539
4540
        // moving to the chosen thread
4541
        $sql = "UPDATE $table_posts SET thread_id='".(int) ($_POST['thread'])."', post_parent_id = NULL
4542
                WHERE c_id = $course_id AND iid ='".(int) ($values['post_id'])."'";
4543
        Database::query($sql);
4544
4545
        // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
4546
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4547
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
4548
        Database::query($sql);
4549
4550
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies+1
4551
                WHERE c_id = $course_id AND iid ='".(int) ($_POST['thread'])."'";
4552
        Database::query($sql);
4553
    }
4554
4555
    return get_lang('Thread moved');
4556
}
4557
4558
/**
4559
 * @param array $values
4560
 *
4561
 * @return string HTML language variable
4562
 *
4563
 * @author Patrick Cool <[email protected]>, Ghent University
4564
 *
4565
 * @version february 2006, dokeos 1.8
4566
 */
4567
function store_move_thread($values)
4568
{
4569
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4570
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4571
4572
    $courseId = api_get_course_int_id();
4573
    $sessionId = api_get_session_id();
4574
4575
    $forumId = (int) ($_POST['forum']);
4576
    $threadId = (int) ($_POST['thread_id']);
4577
    //$forumInfo = get_forums($forumId);
4578
4579
    // Change the thread table: Setting the forum_id to the new forum.
4580
    $sql = "UPDATE $table_threads SET forum_id = $forumId
4581
            WHERE c_id = $courseId AND thread_id = $threadId";
4582
    Database::query($sql);
4583
4584
    // Changing all the posts of the thread: setting the forum_id to the new forum.
4585
    $sql = "UPDATE $table_posts SET forum_id = $forumId
4586
            WHERE c_id = $courseId AND thread_id= $threadId";
4587
    Database::query($sql);
4588
4589
    // Fix group id, if forum is moved to a different group
4590
    /*if (!empty($forumInfo['to_group_id'])) {
4591
        $groupId = $forumInfo['to_group_id'];
4592
        $item = api_get_item_property_info(
4593
            $courseId,
4594
            TABLE_FORUM_THREAD,
4595
            $threadId,
4596
            $sessionId,
4597
            $groupId
4598
        );
4599
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4600
        $sessionCondition = api_get_session_condition($sessionId);
4601
4602
        if (!empty($item)) {
4603
            if ($item['to_group_id'] != $groupId) {
4604
                $sql = "UPDATE $table
4605
                    SET to_group_id = $groupId
4606
                    WHERE
4607
                      tool = '".TABLE_FORUM_THREAD."' AND
4608
                      c_id = $courseId AND
4609
                      ref = ".$item['ref']."
4610
                      $sessionCondition
4611
                ";
4612
                Database::query($sql);
4613
            }
4614
        } else {
4615
            $sql = "UPDATE $table
4616
                    SET to_group_id = $groupId
4617
                    WHERE
4618
                      tool = '".TABLE_FORUM_THREAD."' AND
4619
                      c_id = $courseId AND
4620
                      ref = ".$threadId."
4621
                      $sessionCondition
4622
            ";
4623
            Database::query($sql);
4624
        }
4625
    }*/
4626
4627
    return get_lang('Thread moved');
4628
}
4629
4630
/**
4631
 * Prepares a string for displaying by highlighting the search results inside, if any.
4632
 *
4633
 * @param string $input the input string
4634
 *
4635
 * @return string the same string with highlighted hits inside
4636
 *
4637
 * @author Patrick Cool <[email protected]>, Ghent University, February 2006 - the initial version.
4638
 * @author Ivan Tcholakov, March 2011 - adaptation for Chamilo LMS.
4639
 */
4640
function prepare4display($input)
4641
{
4642
    static $highlightcolors = ['yellow', '#33CC33', '#3399CC', '#9999FF', '#33CC33'];
4643
    static $search;
4644
4645
    if (!isset($search)) {
4646
        if (isset($_POST['search_term'])) {
4647
            $search = $_POST['search_term']; // No html at all.
4648
        } elseif (isset($_GET['search'])) {
4649
            $search = $_GET['search'];
4650
        } else {
4651
            $search = '';
4652
        }
4653
    }
4654
4655
    if (!empty($search)) {
4656
        if (strstr($search, '+')) {
4657
            $search_terms = explode('+', $search);
4658
        } else {
4659
            $search_terms[] = trim($search);
4660
        }
4661
        $counter = 0;
4662
        foreach ($search_terms as $key => $search_term) {
4663
            $input = api_preg_replace(
4664
                '/'.preg_quote(trim($search_term), '/').'/i',
4665
                '<span style="background-color: '.$highlightcolors[$counter].'">$0</span>',
4666
                $input
4667
            );
4668
            $counter++;
4669
        }
4670
    }
4671
4672
    // TODO: Security should be implemented outside this function.
4673
    // Change this to COURSEMANAGERLOWSECURITY or COURSEMANAGER to lower filtering and allow more styles
4674
    // (see comments of Security::remove_XSS() method to learn about other levels).
4675
4676
    return Security::remove_XSS($input, STUDENT, true);
4677
}
4678
4679
/**
4680
 * Display the search form for the forum and display the search results.
4681
 *
4682
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4683
 *
4684
 * @version march 2008, dokeos 1.8.5
4685
 */
4686
function forum_search()
4687
{
4688
    $form = new FormValidator(
4689
        'forumsearch',
4690
        'post',
4691
        'forumsearch.php?'.api_get_cidreq()
4692
    );
4693
4694
    // Setting the form elements.
4695
    $form->addElement('header', '', get_lang('Search in the Forum'));
4696
    $form->addElement('text', 'search_term', get_lang('Search term'), ['autofocus']);
4697
    $form->applyFilter('search_term', 'html_filter');
4698
    $form->addElement('static', 'search_information', '', get_lang('Search in the ForumInformation'));
4699
    $form->addButtonSearch(get_lang('Search'));
4700
4701
    // Setting the rules.
4702
    $form->addRule('search_term', get_lang('Required field'), 'required');
4703
    $form->addRule('search_term', get_lang('Too short'), 'minlength', 3);
4704
4705
    // Validation or display.
4706
    if ($form->validate()) {
4707
        $values = $form->exportValues();
4708
        $form->setDefaults($values);
4709
        $form->display();
4710
        // Display the search results.
4711
        display_forum_search_results(stripslashes($values['search_term']));
4712
    } else {
4713
        $form->display();
4714
    }
4715
}
4716
4717
/**
4718
 * Display the search results.
4719
 *
4720
 * @param string $search_term
4721
 *
4722
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4723
 *
4724
 * @version march 2008, dokeos 1.8.5
4725
 */
4726
function display_forum_search_results($search_term)
4727
{
4728
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4729
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4730
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
4731
    $session_id = api_get_session_id();
4732
    $course_id = api_get_course_int_id();
4733
4734
    // Defining the search strings as an array.
4735
    if (strstr($search_term, '+')) {
4736
        $search_terms = explode('+', $search_term);
4737
    } else {
4738
        $search_terms[] = $search_term;
4739
    }
4740
4741
    // Search restriction.
4742
    foreach ($search_terms as $value) {
4743
        $search_restriction[] = "
4744
        (
4745
            posts.post_title LIKE '%".Database::escape_string(trim($value))."%' OR
4746
            posts.post_text LIKE '%".Database::escape_string(trim($value))."%'
4747
        )";
4748
    }
4749
4750
    $sessionCondition = api_get_session_condition(
4751
        $session_id,
4752
        true,
4753
        false,
4754
        'item_property.session_id'
4755
    );
4756
4757
    $sql = "SELECT posts.*
4758
            FROM $table_posts posts
4759
            INNER JOIN $table_threads threads
4760
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
4761
            INNER JOIN $table_item_property item_property
4762
            ON (item_property.ref = threads.thread_id AND item_property.c_id = threads.c_id)
4763
            WHERE
4764
                posts.c_id = $course_id AND
4765
                item_property.c_id = $course_id AND
4766
                item_property.visibility = 1
4767
                $sessionCondition AND
4768
                posts.visible = 1 AND
4769
                item_property.tool = '".TOOL_FORUM_THREAD."' AND
4770
                ".implode(' AND ', $search_restriction).'
4771
            GROUP BY posts.post_id';
4772
4773
    // Getting all the information of the forum categories.
4774
    $forum_categories_list = get_forum_categories();
4775
4776
    // Getting all the information of the forums.
4777
    $forum_list = get_forums();
4778
4779
    $result = Database::query($sql);
4780
    $search_results = [];
4781
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4782
        $forumId = $row['forum_id'];
4783
        $forumData = get_forums($forumId);
4784
        $category = isset($forum_categories_list[$forumData['forum_category']]) ? $forum_categories_list[$forumData['forum_category']] : null;
4785
        $display_result = false;
4786
        /*
4787
          We only show it when
4788
          1. forum category is visible
4789
          2. forum is visible
4790
          3. thread is visible (to do)
4791
          4. post is visible
4792
         */
4793
        if (!api_is_allowed_to_edit(null, true)) {
4794
            if (!empty($category)) {
4795
                if ('1' == $category['visibility'] && '1' == $forumData['visibility']) {
4796
                    $display_result = true;
4797
                }
4798
            } else {
4799
                if ('1' == $forumData['visible']) {
4800
                    $display_result = true;
4801
                }
4802
            }
4803
        } else {
4804
            $display_result = true;
4805
        }
4806
4807
        if ($display_result) {
4808
            $categoryName = !empty($category) ? $category['cat_title'] : '';
4809
            $search_results_item = '<li><a href="viewforumcategory.php?'.api_get_cidreq().'&forumcategory='.$forumData['forum_category'].'&search='.urlencode($search_term).'">'.
4810
                prepare4display($categoryName).'</a> &gt; ';
4811
            $search_results_item .= '<a href="viewforum.php?'.api_get_cidreq().'&forum='.$forumId.'&search='.urlencode($search_term).'">'.
4812
                prepare4display($forum_list[$row['forum_id']]['forum_title']).'</a> &gt; ';
4813
            $search_results_item .= '<a href="viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$row['thread_id'].'&search='.urlencode($search_term).'">'.
4814
                prepare4display($row['post_title']).'</a>';
4815
            $search_results_item .= '<br />';
4816
            if (api_strlen($row['post_title']) > 200) {
4817
                $search_results_item .= prepare4display(api_substr(strip_tags($row['post_title']), 0, 200)).'...';
4818
            } else {
4819
                $search_results_item .= prepare4display($row['post_title']);
4820
            }
4821
            $search_results_item .= '</li>';
4822
            $search_results[] = $search_results_item;
4823
        }
4824
    }
4825
    echo '<legend>'.count($search_results).' '.get_lang('Search in the ForumResults').'</legend>';
4826
    echo '<ol>';
4827
    if ($search_results) {
4828
        echo implode($search_results);
4829
    }
4830
    echo '</ol>';
4831
}
4832
4833
/**
4834
 * Return the link to the forum search page.
4835
 *
4836
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4837
 *
4838
 * @version April 2008, dokeos 1.8.5
4839
 */
4840
function search_link()
4841
{
4842
    // @todo implement search
4843
4844
    return '';
4845
4846
    $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...
4847
    $origin = api_get_origin();
4848
    if ('learnpath' != $origin) {
4849
        $return = '<a href="forumsearch.php?'.api_get_cidreq().'&action=search"> ';
4850
        $return .= Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
4851
4852
        if (!empty($_GET['search'])) {
4853
            $return .= ': '.Security::remove_XSS($_GET['search']).' ';
4854
            $url = api_get_self().'?';
4855
            $url_parameter = [];
4856
            foreach ($_GET as $key => $value) {
4857
                if ('search' != $key) {
4858
                    $url_parameter[] = Security::remove_XSS($key).'='.Security::remove_XSS($value);
4859
                }
4860
            }
4861
            $url .= implode('&', $url_parameter);
4862
            $return .= '<a href="'.$url.'">'.Display::return_icon('delete.gif', get_lang('Clean search results')).'</a>';
4863
        }
4864
    }
4865
4866
    return $return;
4867
}
4868
4869
/**
4870
 * This function adds an attachment file into a forum.
4871
 *
4872
 * @param string     $file_comment a comment about file
4873
 * @param CForumPost $post         from forum_post table
4874
 *
4875
 * @return false|null
4876
 */
4877
function add_forum_attachment_file($file_comment, CForumPost $post)
4878
{
4879
    $request = Container::getRequest();
4880
    if (false === $request->files->has('user_upload')) {
4881
        return false;
4882
    }
4883
4884
    $file = $request->files->get('user_upload');
4885
    if (empty($file)) {
4886
        return false;
4887
    }
4888
4889
    $files = [];
4890
    if ($file instanceof UploadedFile) {
4891
        $files[] = $file;
4892
    } else {
4893
        $files = $file;
4894
    }
4895
4896
    /** @var UploadedFile $attachment */
4897
    foreach ($files as $file) {
4898
        $valid = process_uploaded_file($file);
4899
4900
        if (!$valid) {
4901
            continue;
4902
        }
4903
4904
        // Try to add an extension to the file if it hasn't one.
4905
        $new_file_name = add_ext_on_mime(
4906
            stripslashes($file->getPathname()),
4907
            $file->getType()
4908
        );
4909
4910
        // User's file name
4911
        $file_name = $file->getClientOriginalName();
4912
4913
        if (!filter_extension($new_file_name)) {
4914
            Display::addFlash(
4915
                Display::return_message(
4916
                    get_lang('File upload failed: this file extension or file type is prohibited'),
4917
                    'error'
4918
                )
4919
            );
4920
4921
            return;
4922
        }
4923
4924
        $new_file_name = uniqid('');
4925
        $safe_file_comment = Database::escape_string($file_comment);
4926
4927
        $user = api_get_user_entity(api_get_user_id());
4928
        $course = api_get_course_entity(api_get_course_int_id());
4929
        $session = api_get_session_entity(api_get_session_id());
4930
4931
        $attachment = new CForumAttachment();
4932
        $attachment
4933
            ->setCId(api_get_course_int_id())
4934
            ->setComment($safe_file_comment)
4935
            ->setFilename($file_name)
4936
            ->setPath($file_name)
4937
            ->setPost($post)
4938
            ->setSize($file->getSize())
4939
            ->setParent($post)
4940
            ->addCourseLink(
4941
                $course,
4942
                $session
4943
            );
4944
4945
        $repo = Container::getForumAttachmentRepository();
4946
        $em = $repo->getEntityManager();
4947
        $em->persist($attachment);
4948
        $em->flush();
4949
4950
        /*$last_id_file = Database::insert(
4951
            $agenda_forum_attachment,
4952
            [
4953
                'path' => $safe_new_file_name,
4954
            ]
4955
        );*/
4956
4957
        /*api_item_property_update(
4958
            $_course,
4959
            TOOL_FORUM_ATTACH,
4960
            $last_id_file,
4961
            'ForumAttachmentAdded',
4962
            api_get_user_id()
4963
        );*/
4964
    }
4965
}
4966
4967
/**
4968
 * This function edits an attachment file into a forum.
4969
 *
4970
 * @param string $file_comment a comment about file
4971
 * @param int    $post_id
4972
 * @param int    $id_attach    attachment file Id
4973
 */
4974
function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
4975
{
4976
    $_course = api_get_course_info();
4977
    $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
4978
    $course_id = api_get_course_int_id();
4979
4980
    $filesData = [];
4981
4982
    if (!is_array($_FILES['user_upload']['name'])) {
4983
        $filesData[] = $_FILES['user_upload'];
4984
    } else {
4985
        $fileCount = count($_FILES['user_upload']['name']);
4986
        $fileKeys = array_keys($_FILES['user_upload']);
4987
4988
        for ($i = 0; $i < $fileCount; $i++) {
4989
            foreach ($fileKeys as $key) {
4990
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
4991
            }
4992
        }
4993
    }
4994
4995
    foreach ($filesData as $attachment) {
4996
        if (empty($attachment['name'])) {
4997
            continue;
4998
        }
4999
5000
        $upload_ok = process_uploaded_file($attachment);
5001
5002
        if (!$upload_ok) {
5003
            continue;
5004
        }
5005
5006
        $course_dir = $_course['path'].'/upload/forum';
5007
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
5008
        $updir = $sys_course_path.$course_dir;
5009
5010
        // Try to add an extension to the file if it hasn't one.
5011
        $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
5012
        // User's file name
5013
        $file_name = $attachment['name'];
5014
5015
        if (!filter_extension($new_file_name)) {
5016
            Display::addFlash(
5017
                Display::return_message(
5018
                    get_lang('File upload failed: this file extension or file type is prohibited'),
5019
                    'error'
5020
                )
5021
            );
5022
        } else {
5023
            $new_file_name = uniqid('');
5024
            $new_path = $updir.'/'.$new_file_name;
5025
            $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5026
            $safe_file_comment = Database::escape_string($file_comment);
5027
            $safe_file_name = Database::escape_string($file_name);
5028
            $safe_new_file_name = Database::escape_string($new_file_name);
5029
            $safe_post_id = (int) $post_id;
5030
            $safe_id_attach = (int) $id_attach;
5031
            // Storing the attachments if any.
5032
            if ($result) {
5033
                $sql = "UPDATE $table_forum_attachment
5034
                        SET
5035
                            filename = '$safe_file_name',
5036
                            comment = '$safe_file_comment',
5037
                            path = '$safe_new_file_name',
5038
                            post_id = '$safe_post_id',
5039
                            size ='".$attachment['size']."'
5040
                        WHERE c_id = $course_id AND id = '$safe_id_attach'";
5041
                Database::query($sql);
5042
                api_item_property_update(
5043
                    $_course,
5044
                    TOOL_FORUM_ATTACH,
5045
                    $safe_id_attach,
5046
                    'ForumAttachmentUpdated',
5047
                    api_get_user_id()
5048
                );
5049
            }
5050
        }
5051
    }
5052
}
5053
5054
/**
5055
 * Show a list with all the attachments according to the post's id.
5056
 *
5057
 * @param int $postId
5058
 *
5059
 * @return array with the post info
5060
 *
5061
 * @author Julio Montoya
5062
 *
5063
 * @version avril 2008, dokeos 1.8.5
5064
 */
5065
function get_attachment($postId)
5066
{
5067
    $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5068
    $course_id = api_get_course_int_id();
5069
    $row = [];
5070
    $postId = (int) $postId;
5071
5072
    if (empty($postId)) {
5073
        return [];
5074
    }
5075
5076
    $sql = "SELECT iid, path, filename, comment
5077
            FROM $table
5078
            WHERE c_id = $course_id AND post_id = $postId";
5079
    $result = Database::query($sql);
5080
    if (0 != Database::num_rows($result)) {
5081
        $row = Database::fetch_array($result);
5082
    }
5083
5084
    return $row;
5085
}
5086
5087
/**
5088
 * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
5089
 *
5090
 * @param int $postId
5091
 * @param int $attachmentId
5092
 *
5093
 * @return bool
5094
 */
5095
function delete_attachment($postId, $attachmentId)
5096
{
5097
    $repo = Container::getForumPostRepository();
5098
    /** @var CForumPost $post */
5099
    $post = $repo->find($postId);
5100
    if ($post) {
5101
        $repoAttachment = Container::getForumAttachmentRepository();
5102
        $attachment = $repoAttachment->find($attachmentId);
5103
        if ($attachment) {
5104
            $post->removeAttachment($attachment);
5105
            $repo->getEntityManager()->remove($attachment);
5106
        }
5107
        $repo->getEntityManager()->persist($post);
5108
        $repo->getEntityManager()->flush();
5109
5110
        Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
5111
    }
5112
5113
    return true;
5114
5115
    $forum_table_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
0 ignored issues
show
Unused Code introduced by
$forum_table_attachment ...TABLE_FORUM_ATTACHMENT) 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...
5116
    $course_id = api_get_course_int_id();
5117
5118
    $cond = !empty($id_attach) ? ' iid = '.(int) $id_attach.'' : ' post_id = '.(int) $post_id.'';
5119
    $sql = "SELECT path FROM $forum_table_attachment WHERE c_id = $course_id AND $cond";
5120
    $res = Database::query($sql);
5121
    $row = Database::fetch_array($res);
5122
5123
    $course_dir = $_course['path'].'/upload/forum';
5124
    $sys_course_path = api_get_path(SYS_COURSE_PATH);
5125
    $updir = $sys_course_path.$course_dir;
5126
    $my_path = isset($row['path']) ? $row['path'] : null;
5127
    $file = $updir.'/'.$my_path;
5128
    if (Security::check_abs_path($file, $updir)) {
5129
        @unlink($file);
5130
    }
5131
5132
    // Delete from forum_attachment table.
5133
    $sql = "DELETE FROM $forum_table_attachment
5134
            WHERE c_id = $course_id AND $cond ";
5135
    $result = Database::query($sql);
5136
    if (false !== $result) {
5137
        $affectedRows = Database::affected_rows($result);
5138
    } else {
5139
        $affectedRows = 0;
5140
    }
5141
5142
    // Update item_property.
5143
    api_item_property_update(
5144
        $_course,
5145
        TOOL_FORUM_ATTACH,
5146
        $id_attach,
5147
        'ForumAttachmentDelete',
5148
        api_get_user_id()
5149
    );
5150
5151
    if (!empty($result) && !empty($id_attach)) {
5152
        Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
5153
    }
5154
5155
    return $affectedRows;
5156
}
5157
5158
/**
5159
 * This function gets all the forum information of the all the forum of the group.
5160
 *
5161
 * @param array $groupInfo the id of the group we need the fora of (see forum.forum_of_group)
5162
 *
5163
 * @return CForumForum[]
5164
 *
5165
 * @todo this is basically the same code as the get_forums function. Consider merging the two.
5166
 */
5167
function get_forums_of_group($groupInfo)
5168
{
5169
    $groupId = (int) $groupInfo['id'];
5170
5171
    $group = api_get_group_entity($groupId);
5172
    $course = api_get_course_entity();
5173
    $session = api_get_session_entity();
5174
5175
    $repo = Container::getForumRepository();
5176
5177
    $qb = $repo->getResourcesByCourse($course, $session, $group);
5178
5179
    return $qb->getQuery()->getResult();
5180
5181
    $table_forums = Database::get_course_table(TABLE_FORUM);
0 ignored issues
show
Unused Code introduced by
$table_forums = Database...urse_table(TABLE_FORUM) 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...
5182
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
5183
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5184
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
5185
    $course_id = api_get_course_int_id();
5186
    $groupId = (int) $groupInfo['id'];
5187
5188
    // Student
5189
    // Select all the forum information of all forums (that are visible to students).
5190
    $sql = "SELECT * FROM $table_forums forum
5191
            INNER JOIN $table_item_property item_properties
5192
            ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5193
            WHERE
5194
                forum.forum_of_group = $groupId AND
5195
                forum.c_id = $course_id AND
5196
                item_properties.c_id = $course_id AND
5197
                item_properties.visibility = 1 AND
5198
                item_properties.tool = '".TOOL_FORUM."'
5199
            ORDER BY forum.forum_order ASC";
5200
5201
    // Select the number of threads of the forums (only the threads that are visible).
5202
    $sql2 = "SELECT
5203
                count(thread_id) AS number_of_threads,
5204
                threads.forum_id
5205
            FROM $table_threads threads
5206
            INNER JOIN $table_item_property item_properties
5207
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5208
            WHERE
5209
                threads.c_id = $course_id AND
5210
                item_properties.c_id = $course_id AND
5211
                item_properties.visibility = 1 AND
5212
                item_properties.tool='".TOOL_FORUM_THREAD."'
5213
            GROUP BY threads.forum_id";
5214
5215
    // Select the number of posts of the forum (post that are visible and that are in a thread that is visible).
5216
    $sql3 = "SELECT count(post_id) AS number_of_posts, posts.forum_id
5217
            FROM $table_posts posts
5218
            INNER JOIN $table_threads threads
5219
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
5220
            INNER JOIN $table_item_property item_properties
5221
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5222
            WHERE
5223
                posts.visible=1 AND
5224
                posts.c_id = $course_id AND
5225
                item_properties.c_id = $course_id AND
5226
                threads.c_id = $course_id AND
5227
                item_properties.visibility = 1 AND
5228
                item_properties.tool='".TOOL_FORUM_THREAD."'
5229
            GROUP BY threads.forum_id";
5230
5231
    // Course Admin
5232
    if (api_is_allowed_to_edit()) {
5233
        // Select all the forum information of all forums (that are not deleted).
5234
        $sql = "SELECT *
5235
                FROM $table_forums forum
5236
                INNER JOIN $table_item_property item_properties
5237
                ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5238
                WHERE
5239
                    forum.forum_of_group = $groupId AND
5240
                    forum.c_id = $course_id AND
5241
                    item_properties.c_id = $course_id AND
5242
                    item_properties.visibility <> 2 AND
5243
                    item_properties.tool = '".TOOL_FORUM."'
5244
                ORDER BY forum_order ASC";
5245
5246
        // Select the number of threads of the forums (only the threads that are not deleted).
5247
        $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id
5248
                 FROM $table_threads threads
5249
                 INNER JOIN $table_item_property item_properties
5250
                 ON (threads.thread_id=item_properties.ref AND item_properties.c_id = threads.c_id)
5251
                 WHERE
5252
                    threads.c_id = $course_id AND
5253
                    item_properties.c_id = $course_id AND
5254
                    item_properties.visibility <> 2 AND
5255
                    item_properties.tool='".TOOL_FORUM_THREAD."'
5256
                GROUP BY threads.forum_id";
5257
        // Select the number of posts of the forum.
5258
        $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id
5259
                FROM $table_posts
5260
                WHERE c_id = $course_id
5261
                GROUP BY forum_id";
5262
    }
5263
5264
    // Handling all the forum information.
5265
    $result = Database::query($sql);
5266
    $forum_list = [];
5267
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5268
        $forum_list[$row['forum_id']] = $row;
5269
    }
5270
5271
    // Handling the thread count information.
5272
    $result2 = Database::query($sql2);
5273
    while ($row2 = Database::fetch_array($result2, 'ASSOC')) {
5274
        if (is_array($forum_list)) {
5275
            if (array_key_exists($row2['forum_id'], $forum_list)) {
5276
                $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
5277
            }
5278
        }
5279
    }
5280
5281
    // Handling the post count information.
5282
    $result3 = Database::query($sql3);
5283
    while ($row3 = Database::fetch_array($result3, 'ASSOC')) {
5284
        if (is_array($forum_list)) {
5285
            if (array_key_exists($row3['forum_id'], $forum_list)) {
5286
                // This is needed because sql3 takes also the deleted forums into account.
5287
                $forum_list[$row3['forum_id']]['number_of_posts'] = $row3['number_of_posts'];
5288
            }
5289
        }
5290
    }
5291
5292
    // Finding the last post information
5293
    // (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname).
5294
    if (!empty($forum_list)) {
5295
        foreach ($forum_list as $key => $value) {
5296
            $lastPost = get_last_post_information($key, api_is_allowed_to_edit());
5297
            if ($lastPost) {
5298
                $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
5299
                $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
5300
                $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
5301
                $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
5302
                $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
5303
                $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
5304
            }
5305
        }
5306
    }
5307
5308
    return $forum_list;
5309
}
5310
5311
/**
5312
 * This function stores which users have to be notified of which forums or threads.
5313
 *
5314
 * @param string $content    does the user want to be notified about a forum or about a thread
5315
 * @param int    $id         the id of the forum or thread
5316
 * @param bool   $addOnly
5317
 * @param array  $userInfo
5318
 * @param array  $courseInfo
5319
 *
5320
 * @return string language variable
5321
 *
5322
 * @author  Patrick Cool <[email protected]>, Ghent University, Belgium
5323
 * @author  Julio Montoya
5324
 *
5325
 * @since   May 2008 v1.8.5
5326
 */
5327
function set_notification($content, $id, $addOnly = false, $userInfo = [], $courseInfo = [])
5328
{
5329
    $userInfo = empty($userInfo) ? api_get_user_info() : $userInfo;
5330
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
5331
    $id = (int) $id;
5332
5333
    if (empty($userInfo) || empty($courseInfo) || empty($id) || empty($content)) {
5334
        return false;
5335
    }
5336
5337
    // Database table definition
5338
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5339
    $course_id = $courseInfo['real_id'];
5340
5341
    // Which database field do we have to store the id in?
5342
    $field = 'thread_id';
5343
    if ('forum' === $content) {
5344
        $field = 'forum_id';
5345
    }
5346
5347
    $userId = $userInfo['user_id'];
5348
5349
    // First we check if the notification is already set for this.
5350
    $sql = "SELECT * FROM $table_notification
5351
            WHERE
5352
                c_id = $course_id AND
5353
                $field = $id AND
5354
                user_id = $userId ";
5355
    $result = Database::query($sql);
5356
    $total = Database::num_rows($result);
5357
5358
    // If the user did not indicate that (s)he wanted to be notified already
5359
    // then we store the notification request (to prevent double notification requests).
5360
    if ($total <= 0) {
5361
        $notification = new CForumNotification();
5362
        $notification
5363
            ->setCId($course_id)
5364
            ->setUserId($userId)
5365
        ;
5366
5367
        if ('forum' === $content) {
5368
            $notification->setForumId($id);
5369
        } else {
5370
            $notification->setThreadId($id);
5371
        }
5372
5373
        $em = Database::getManager();
5374
        $em->persist($notification);
5375
        $em->flush();
5376
5377
        Session::erase('forum_notification');
5378
        getNotificationsPerUser(0, true);
5379
5380
        return get_lang('You will be notified of new posts by e-mail.');
5381
    } else {
5382
        if (!$addOnly) {
5383
            $sql = "DELETE FROM $table_notification
5384
                    WHERE
5385
                        c_id = $course_id AND
5386
                        $field = $id AND
5387
                        user_id = $userId ";
5388
            Database::query($sql);
5389
            Session::erase('forum_notification');
5390
            getNotificationsPerUser(0, true);
5391
5392
            return get_lang('You will no longer be notified of new posts by email');
5393
        }
5394
    }
5395
}
5396
5397
/**
5398
 * This function retrieves all the email adresses of the users who wanted to be notified
5399
 * about a new post in a certain forum or thread.
5400
 *
5401
 * @param string $content does the user want to be notified about a forum or about a thread
5402
 * @param int    $id      the id of the forum or thread
5403
 *
5404
 * @return array returns
5405
 *
5406
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5407
 * @author Julio Montoya
5408
 *
5409
 * @version May 2008, dokeos 1.8.5
5410
 *
5411
 * @since May 2008, dokeos 1.8.5
5412
 */
5413
function get_notifications($content, $id)
5414
{
5415
    // Database table definition
5416
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5417
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5418
    $course_id = api_get_course_int_id();
5419
5420
    // Which database field contains the notification?
5421
    $field = 'thread_id';
5422
    if ('forum' === $content) {
5423
        $field = 'forum_id';
5424
    }
5425
5426
    $id = (int) $id;
5427
5428
    $sql = "SELECT user.id as user_id, user.firstname, user.lastname, user.email, user.id user
5429
            FROM $table_users user, $table_notification notification
5430
            WHERE
5431
                notification.c_id = $course_id AND user.active = 1 AND
5432
                user.id = notification.user_id AND
5433
                notification.$field = $id ";
5434
5435
    $result = Database::query($sql);
5436
    $return = [];
5437
5438
    while ($row = Database::fetch_array($result)) {
5439
        $return['user'.$row['user_id']] = ['email' => $row['email'], 'user_id' => $row['user_id']];
5440
    }
5441
5442
    return $return;
5443
}
5444
5445
/**
5446
 * Get all the users who need to receive a notification of a new post (those subscribed to
5447
 * the forum or the thread).
5448
 *
5449
 * @param int $post_id the id of the post
5450
 *
5451
 * @return false|null
5452
 *
5453
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5454
 *
5455
 * @version May 2008, dokeos 1.8.5
5456
 *
5457
 * @since May 2008, dokeos 1.8.5
5458
 */
5459
function send_notifications(CForumForum $forum, CForumThread $thread, $post_id = 0)
5460
{
5461
    if (!$forum) {
5462
        return false;
5463
    }
5464
5465
    // Users who subscribed to the forum
5466
    $users_to_be_notified_by_forum = get_notifications('forum', $forum->getIid());
5467
5468
    // User who subscribed to the thread
5469
    $users_to_be_notified_by_thread = [];
5470
    if (!$thread) {
5471
        $users_to_be_notified_by_thread = get_notifications('thread', $thread->getIid());
5472
    }
5473
5474
    $postInfo = null;
5475
    if (!empty($post_id)) {
5476
        $postInfo = Container::getForumPostRepository()->find($post_id);
5477
    }
5478
5479
    // Merging the two
5480
    $users_to_be_notified = array_merge($users_to_be_notified_by_forum, $users_to_be_notified_by_thread);
5481
5482
    if (is_array($users_to_be_notified)) {
5483
        foreach ($users_to_be_notified as $value) {
5484
            $userInfo = api_get_user_info($value['user_id']);
5485
            send_mail($userInfo, $forum, $thread, $postInfo);
5486
        }
5487
    }
5488
}
5489
5490
/**
5491
 * Get all the notification subscriptions of the user
5492
 * = which forums and which threads does the user wants to be informed of when a new
5493
 * post is added to this thread.
5494
 *
5495
 * @param int  $user_id the user_id of a user (default = 0 => the current user)
5496
 * @param bool $force   force get the notification subscriptions (even if the information is already in the session
5497
 *
5498
 * @return array
5499
 *
5500
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5501
 *
5502
 * @version May 2008, dokeos 1.8.5
5503
 *
5504
 * @since May 2008, dokeos 1.8.5
5505
 */
5506
function getNotificationsPerUser($user_id = 0, $force = false, $course_id = 0)
5507
{
5508
    // Database table definition
5509
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5510
    $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
5511
    if (empty($course_id) || -1 == $course_id) {
5512
        return null;
5513
    }
5514
5515
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
5516
5517
    if (!isset($_SESSION['forum_notification']) ||
5518
        $_SESSION['forum_notification']['course'] != $course_id ||
5519
        true == $force
5520
    ) {
5521
        $_SESSION['forum_notification']['course'] = $course_id;
5522
        $sql = "SELECT * FROM $table_notification
5523
                WHERE c_id = $course_id AND user_id='".$user_id."'";
5524
5525
        $result = Database::query($sql);
5526
        while ($row = Database::fetch_array($result)) {
5527
            if (null !== $row['forum_id']) {
5528
                $_SESSION['forum_notification']['forum'][] = $row['forum_id'];
5529
            }
5530
            if (null !== $row['thread_id']) {
5531
                $_SESSION['forum_notification']['thread'][] = $row['thread_id'];
5532
            }
5533
        }
5534
    }
5535
}
5536
5537
/**
5538
 * This function counts the number of post inside a thread.
5539
 *
5540
 * @param int $thread_id
5541
 *
5542
 * @return int the number of post inside a thread
5543
 *
5544
 * @author Jhon Hinojosa <[email protected]>,
5545
 *
5546
 * @version octubre 2008, dokeos 1.8
5547
 */
5548
function count_number_of_post_in_thread($thread_id)
5549
{
5550
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5551
    $course_id = api_get_course_int_id();
5552
    if (empty($course_id)) {
5553
        return 0;
5554
    }
5555
    $sql = "SELECT count(*) count FROM $table_posts
5556
            WHERE
5557
                c_id = $course_id AND
5558
                thread_id='".(int) $thread_id."' ";
5559
    $result = Database::query($sql);
5560
5561
    $count = 0;
5562
    if (Database::num_rows($result) > 0) {
5563
        $row = Database::fetch_array($result);
5564
        $count = $row['count'];
5565
    }
5566
5567
    return $count;
5568
}
5569
5570
/**
5571
 * This function counts the number of post inside a thread user.
5572
 *
5573
 * @param int $thread_id
5574
 * @param int $user_id
5575
 *
5576
 * @return int the number of post inside a thread user
5577
 */
5578
function count_number_of_post_for_user_thread($thread_id, $user_id)
5579
{
5580
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5581
    $course_id = api_get_course_int_id();
5582
    $sql = "SELECT count(iid) as count
5583
            FROM $table_posts
5584
            WHERE c_id = $course_id AND
5585
                  thread_id=".(int) $thread_id.' AND
5586
                  poster_id = '.(int) $user_id.' AND visible = 1 ';
5587
    $result = Database::query($sql);
5588
    $count = 0;
5589
    if (Database::num_rows($result) > 0) {
5590
        $count = Database::fetch_array($result);
5591
        $count = $count['count'];
5592
    }
5593
5594
    return $count;
5595
}
5596
5597
/**
5598
 * This function retrieves information of statistical.
5599
 *
5600
 * @param int $thread_id
5601
 * @param int $user_id
5602
 * @param int $course_id
5603
 *
5604
 * @return array the information of statistical
5605
 *
5606
 * @author Jhon Hinojosa <[email protected]>,
5607
 *
5608
 * @version oct 2008, dokeos 1.8
5609
 */
5610
function get_statistical_information($thread_id, $user_id, $course_id)
5611
{
5612
    $result = [];
5613
    $courseInfo = api_get_course_info_by_id($course_id);
5614
    $result['user_course'] = CourseManager::get_users_count_in_course($courseInfo['code']);
5615
    $result['post'] = count_number_of_post_in_thread($thread_id);
5616
    $result['user_post'] = count_number_of_post_for_user_thread($thread_id, $user_id);
5617
5618
    return $result;
5619
}
5620
5621
/**
5622
 * This function return the posts inside a thread from a given user.
5623
 *
5624
 * @param string $course_code
5625
 * @param int    $thread_id
5626
 * @param int    $user_id
5627
 *
5628
 * @return array posts inside a thread
5629
 *
5630
 * @author Jhon Hinojosa <[email protected]>,
5631
 *
5632
 * @version oct 2008, dokeos 1.8
5633
 */
5634
function get_thread_user_post($course_code, $thread_id, $user_id)
5635
{
5636
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5637
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5638
    $thread_id = (int) $thread_id;
5639
    $user_id = (int) $user_id;
5640
    $course_info = api_get_user_info($course_code);
5641
    $course_id = $course_info['real_id'];
5642
5643
    if (empty($course_id)) {
5644
        $course_id = api_get_course_int_id();
5645
    }
5646
    $sql = "SELECT * FROM $table_posts posts
5647
            LEFT JOIN  $table_users users
5648
                ON posts.poster_id=users.user_id
5649
            WHERE
5650
                posts.c_id = $course_id AND
5651
                posts.thread_id='$thread_id'
5652
                AND posts.poster_id='$user_id'
5653
            ORDER BY posts.post_id ASC";
5654
5655
    $result = Database::query($sql);
5656
    $post_list = [];
5657
    while ($row = Database::fetch_array($result)) {
5658
        $row['status'] = '1';
5659
        $post_list[] = $row;
5660
        $sql = "SELECT * FROM $table_posts posts
5661
                LEFT JOIN $table_users users
5662
                ON (posts.poster_id=users.user_id)
5663
                WHERE
5664
                    posts.c_id = $course_id AND
5665
                    posts.thread_id='$thread_id'
5666
                    AND posts.post_parent_id='".$row['post_id']."'
5667
                ORDER BY posts.post_id ASC";
5668
        $result2 = Database::query($sql);
5669
        while ($row2 = Database::fetch_array($result2)) {
5670
            $row2['status'] = '0';
5671
            $post_list[] = $row2;
5672
        }
5673
    }
5674
5675
    return $post_list;
5676
}
5677
5678
/**
5679
 * This function get the name of an thread by id.
5680
 *
5681
 * @param int $thread_id
5682
 *
5683
 * @return string
5684
 *
5685
 * @author Christian Fasanando
5686
 * @author Julio Montoya <[email protected]> Adding security
5687
 */
5688
function get_name_thread_by_id($thread_id)
5689
{
5690
    $t_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
5691
    $course_id = api_get_course_int_id();
5692
    $sql = "SELECT thread_title
5693
            FROM $t_forum_thread
5694
            WHERE c_id = $course_id AND thread_id = '".(int) $thread_id."' ";
5695
    $result = Database::query($sql);
5696
    $row = Database::fetch_array($result);
5697
5698
    return $row[0];
5699
}
5700
5701
/**
5702
 * This function gets all the post written by an user.
5703
 *
5704
 * @param int $user_id
5705
 *
5706
 * @return string
5707
 */
5708
function get_all_post_from_user($user_id, $courseId)
5709
{
5710
    $j = 0;
5711
    $forums = get_forums($courseId);
5712
    krsort($forums);
5713
    $forum_results = '';
5714
5715
    foreach ($forums as $forum) {
5716
        $forumId = $forum->getIid();
5717
5718
        /*if (0 == $forum['visibility']) {
5719
            continue;
5720
        }*/
5721
        if ($j <= 4) {
5722
            $threads = get_threads($forumId);
5723
5724
            if ($threads) {
5725
                $i = 0;
5726
                $hand_forums = '';
5727
                $post_counter = 0;
5728
                foreach ($threads as $thread) {
5729
                    /*if (0 == $thread['visibility']) {
5730
                        continue;
5731
                    }*/
5732
                    if ($i <= 4) {
5733
                        $post_list = get_thread_user_post_limit(
5734
                            $courseId,
5735
                            $thread->getIid(),
5736
                            $user_id,
5737
                            1
5738
                        );
5739
                        $post_counter = count($post_list);
5740
                        if (is_array($post_list) && count($post_list) > 0) {
5741
                            $hand_forums .= '<div id="social-thread">';
5742
                            $hand_forums .= Display::return_icon(
5743
                                'thread.png',
5744
                                get_lang('Thread'),
5745
                                '',
5746
                                ICON_SIZE_MEDIUM
5747
                            );
5748
                            $hand_forums .= '&nbsp;'.Security::remove_XSS($thread->getThreadTitle(), STUDENT);
5749
                            $hand_forums .= '</div>';
5750
5751
                            foreach ($post_list as $posts) {
5752
                                $hand_forums .= '<div id="social-post">';
5753
                                $hand_forums .= '<strong>'.Security::remove_XSS($posts['post_title'], STUDENT).'</strong>';
5754
                                $hand_forums .= '<br / >';
5755
                                $hand_forums .= Security::remove_XSS($posts['post_text'], STUDENT);
5756
                                $hand_forums .= '</div>';
5757
                                $hand_forums .= '<br / >';
5758
                            }
5759
                        }
5760
                    }
5761
                    $i++;
5762
                }
5763
                $forum_results .= '<div id="social-forum">';
5764
                $forum_results .= '<div class="clear"></div><br />';
5765
                $forum_results .= '<div id="social-forum-title">'.
5766
                    Display::return_icon('forum.gif', get_lang('Forum')).'&nbsp;'.Security::remove_XSS($forum->getForumTitle(), STUDENT).
5767
                    '<div style="float:right;margin-top:-35px">
5768
                        <a href="../forum/viewforum.php?'.api_get_cidreq_params($courseId).'&forum='.$forum->getIid().' " >'.
5769
                    get_lang('See forum').'
5770
                        </a>
5771
                     </div></div>';
5772
                $forum_results .= '<br / >';
5773
                if ($post_counter > 0) {
5774
                    $forum_results .= $hand_forums;
5775
                }
5776
                $forum_results .= '</div>';
5777
            }
5778
            $j++;
5779
        }
5780
    }
5781
5782
    return $forum_results;
5783
}
5784
5785
/**
5786
 * @param int $thread_id
5787
 * @param int $user_id
5788
 * @param int $limit
5789
 *
5790
 * @return array
5791
 */
5792
function get_thread_user_post_limit($courseId, $thread_id, $user_id, $limit = 10)
5793
{
5794
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5795
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5796
5797
    $courseId = (int) $courseId;
5798
5799
    $sql = "SELECT * FROM $table_posts posts
5800
            LEFT JOIN $table_users users
5801
                ON posts.poster_id=users.user_id
5802
            WHERE
5803
                posts.c_id = $courseId AND
5804
                posts.thread_id='".Database::escape_string($thread_id)."' AND
5805
                posts.poster_id='".Database::escape_string($user_id)."'
5806
            ORDER BY posts.post_id DESC LIMIT $limit ";
5807
    $result = Database::query($sql);
5808
    $post_list = [];
5809
    while ($row = Database::fetch_array($result)) {
5810
        $row['status'] = '1';
5811
        $post_list[] = $row;
5812
    }
5813
5814
    return $post_list;
5815
}
5816
5817
/**
5818
 * @param string $userId
5819
 * @param array  $courseInfo
5820
 * @param int    $sessionId
5821
 *
5822
 * @return array
5823
 */
5824
function getForumCreatedByUser($userId, $courseInfo, $sessionId)
5825
{
5826
    if (empty($userId) || empty($courseInfo)) {
5827
        return [];
5828
    }
5829
5830
    $courseId = $courseInfo['real_id'];
5831
    $items = api_get_item_property_list_by_tool_by_user(
5832
        $userId,
5833
        'forum',
5834
        $courseId,
5835
        $sessionId
5836
    );
5837
5838
    $forumList = [];
5839
    if (!empty($items)) {
5840
        foreach ($items as $forum) {
5841
            $forumInfo = get_forums(
5842
                $forum['ref'],
5843
                $courseInfo['code'],
5844
                true,
5845
                $sessionId
5846
            );
5847
            if (!empty($forumInfo) && isset($forumInfo['forum_title'])) {
5848
                $forumList[] = [
5849
                    $forumInfo['forum_title'],
5850
                    api_get_local_time($forum['insert_date']),
5851
                    api_get_local_time($forum['lastedit_date']),
5852
                ];
5853
            }
5854
        }
5855
    }
5856
5857
    return $forumList;
5858
}
5859
5860
/**
5861
 * This function builds an array of all the posts in a given thread
5862
 * where the key of the array is the post_id
5863
 * It also adds an element children to the array which itself is an array
5864
 * that contains all the id's of the first-level children.
5865
 *
5866
 * @return array containing all the information on the posts of a thread
5867
 *
5868
 * @author Patrick Cool <[email protected]>, Ghent University
5869
 */
5870
function calculate_children($rows)
5871
{
5872
    $sorted_rows = [0 => []];
5873
    if (!empty($rows)) {
5874
        foreach ($rows as $row) {
5875
            $rows_with_children[$row['post_id']] = $row;
5876
            $rows_with_children[$row['post_parent_id']]['children'][] = $row['post_id'];
5877
        }
5878
5879
        $rows = $rows_with_children;
5880
        forumRecursiveSort($rows, $sorted_rows);
5881
        unset($sorted_rows[0]);
5882
    }
5883
5884
    return $sorted_rows;
5885
}
5886
5887
/**
5888
 * @param $rows
5889
 * @param $threads
5890
 * @param int $seed
5891
 * @param int $indent
5892
 */
5893
function forumRecursiveSort($rows, &$threads, $seed = 0, $indent = 0)
5894
{
5895
    if ($seed > 0) {
5896
        $threads[$rows[$seed]['post_id']] = $rows[$seed];
5897
        $threads[$rows[$seed]['post_id']]['indent_cnt'] = $indent;
5898
        $indent++;
5899
    }
5900
5901
    if (isset($rows[$seed]['children'])) {
5902
        foreach ($rows[$seed]['children'] as $child) {
5903
            forumRecursiveSort($rows, $threads, $child, $indent);
5904
        }
5905
    }
5906
}
5907
5908
/**
5909
 * Update forum attachment data, used to update comment and post ID.
5910
 *
5911
 * @param array $array    (field => value) to update forum attachment row
5912
 * @param int   $id       ID to find row to update
5913
 * @param int   $courseId course ID to find row to update
5914
 *
5915
 * @return int number of affected rows
5916
 */
5917
function editAttachedFile($array, $id, $courseId = null)
5918
{
5919
    // Init variables
5920
    $setString = '';
5921
    $id = (int) $id;
5922
    $courseId = (int) $courseId;
5923
    if (empty($courseId)) {
5924
        // $courseId can be null, use api method
5925
        $courseId = api_get_course_int_id();
5926
    }
5927
    /*
5928
     * Check if Attachment ID and Course ID are greater than zero
5929
     * and array of field values is not empty
5930
     */
5931
    if ($id > 0 && $courseId > 0 && !empty($array) && is_array($array)) {
5932
        foreach ($array as $key => &$item) {
5933
            $item = Database::escape_string($item);
5934
            $setString .= $key.' = "'.$item.'", ';
5935
        }
5936
        // Delete last comma
5937
        $setString = substr($setString, 0, strlen($setString) - 2);
5938
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5939
        $sql = "UPDATE $forumAttachmentTable
5940
                SET $setString WHERE c_id = $courseId AND id = $id";
5941
        $result = Database::query($sql);
5942
        if (false !== $result) {
5943
            $affectedRows = Database::affected_rows($result);
5944
            if ($affectedRows > 0) {
5945
                /*
5946
                 * If exist in $_SESSION variable, then delete them from it
5947
                 * because they would be deprecated
5948
                 */
5949
                if (!empty($_SESSION['forum']['upload_file'][$courseId][$id])) {
5950
                    unset($_SESSION['forum']['upload_file'][$courseId][$id]);
5951
                }
5952
            }
5953
5954
            return $affectedRows;
5955
        }
5956
    }
5957
5958
    return 0;
5959
}
5960
5961
/**
5962
 * Return a table where the attachments will be set.
5963
 *
5964
 * @param int $postId Forum Post ID
5965
 *
5966
 * @return string The Forum Attachments Ajax Table
5967
 */
5968
function getAttachmentsAjaxTable($postId = 0)
5969
{
5970
    $postId = (int) $postId;
5971
    $courseId = api_get_course_int_id();
5972
    $attachIds = getAttachmentIdsByPostId($postId, $courseId);
5973
    $fileDataContent = '';
5974
    // Update comment to show if form did not pass validation
5975
    if (!empty($_REQUEST['file_ids']) && is_array($_REQUEST['file_ids'])) {
5976
        // 'file_ids is the name from forum attachment ajax form
5977
        foreach ($_REQUEST['file_ids'] as $key => $attachId) {
5978
            if (!empty($_SESSION['forum']['upload_file'][$courseId][$attachId]) &&
5979
                is_array($_SESSION['forum']['upload_file'][$courseId][$attachId])
5980
            ) {
5981
                // If exist forum attachment then update into $_SESSION data
5982
                $_SESSION['forum']['upload_file'][$courseId][$attachId]['comment'] = $_POST['file_comments'][$key];
5983
            }
5984
        }
5985
    }
5986
5987
    // Get data to fill into attachment files table
5988
    if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
5989
        is_array($_SESSION['forum']['upload_file'][$courseId])
5990
    ) {
5991
        $uploadedFiles = $_SESSION['forum']['upload_file'][$courseId];
5992
        foreach ($uploadedFiles as $k => $uploadedFile) {
5993
            if (!empty($uploadedFile) && in_array($uploadedFile['id'], $attachIds)) {
5994
                // Buil html table including an input with attachmentID
5995
                $fileDataContent .= '<tr id="'.$uploadedFile['id'].'" ><td>'.$uploadedFile['name'].'</td><td>'.$uploadedFile['size'].'</td><td>&nbsp;'.$uploadedFile['result'].
5996
                    ' </td><td> <input style="width:90%;" type="text" value="'.$uploadedFile['comment'].'" name="file_comments[]"> </td><td>'.
5997
                    $uploadedFile['delete'].'</td>'.
5998
                    '<input type="hidden" value="'.$uploadedFile['id'].'" name="file_ids[]">'.'</tr>';
5999
            } else {
6000
                /*
6001
                 * If attachment data is empty, then delete it from $_SESSION
6002
                 * because could generate and empty row into html table
6003
                 */
6004
                unset($_SESSION['forum']['upload_file'][$courseId][$k]);
6005
            }
6006
        }
6007
    }
6008
    $style = empty($fileDataContent) ? 'display: none;' : '';
6009
    // Forum attachment Ajax table
6010
    return '
6011
    <div class="control-group " style="'.$style.'">
6012
        <label class="control-label">'.get_lang('Attachments list').'</label>
6013
        <div class="controls">
6014
            <table id="attachmentFileList" class="files data_table span10">
6015
                <tr>
6016
                    <th>'.get_lang('Filename').'</th>
6017
                    <th>'.get_lang('Size').'</th>
6018
                    <th>'.get_lang('Status').'</th>
6019
                    <th>'.get_lang('Comment').'</th>
6020
                    <th>'.get_lang('Delete').'</th>
6021
                </tr>
6022
                '.$fileDataContent.'
6023
            </table>
6024
        </div>
6025
    </div>';
6026
}
6027
6028
/**
6029
 * Return an array of prepared attachment data to build forum attachment table
6030
 * Also, save this array into $_SESSION to do available the attachment data.
6031
 *
6032
 * @param int $forumId
6033
 * @param int $threadId
6034
 * @param int $postId
6035
 * @param int $attachId
6036
 * @param int $courseId
6037
 *
6038
 * @return array
6039
 */
6040
function getAttachedFiles(
6041
    $forumId,
6042
    $threadId,
6043
    $postId = 0,
6044
    $attachId = 0,
6045
    $courseId = 0
6046
) {
6047
    $forumId = (int) $forumId;
6048
    $courseId = (int) $courseId;
6049
    $attachId = (int) $attachId;
6050
    $postId = (int) $postId;
6051
    $threadId = !empty($threadId) ? (int) $threadId : isset($_REQUEST['thread']) ? (int) ($_REQUEST['thread']) : '';
6052
    if (empty($courseId)) {
6053
        // $courseId can be null, use api method
6054
        $courseId = api_get_course_int_id();
6055
    }
6056
    if (empty($forumId)) {
6057
        if (!empty($_REQUEST['forum'])) {
6058
            $forumId = (int) $_REQUEST['forum'];
6059
        } else {
6060
            // if forum ID is empty, cannot generate delete url
6061
6062
            return [];
6063
        }
6064
    }
6065
    // Check if exist at least one of them to filter forum attachment select query
6066
    if (empty($postId) && empty($attachId)) {
6067
        return [];
6068
    }
6069
6070
    if (empty($postId)) {
6071
        $filter = "AND iid = $attachId";
6072
    } elseif (empty($attachId)) {
6073
        $filter = "AND post_id = $postId";
6074
    } else {
6075
        $filter = "AND post_id = $postId AND iid = $attachId";
6076
    }
6077
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6078
    $sql = "SELECT iid
6079
            FROM $forumAttachmentTable
6080
            WHERE c_id = $courseId $filter";
6081
    $result = Database::query($sql);
6082
    $json = [];
6083
    if (Database::num_rows($result) > 0) {
6084
        $repo = Container::getForumAttachmentRepository();
6085
        while ($row = Database::fetch_array($result, 'ASSOC')) {
6086
            /** @var CForumAttachment $attachment */
6087
            $attachment = $repo->find($row['iid']);
6088
            $downloadUrl = $repo->getResourceFileDownloadUrl($attachment);
6089
6090
            // name contains an URL to download attachment file and its filename
6091
            $json['name'] = Display::url(
6092
                api_htmlentities($attachment->getFilename()),
6093
                $downloadUrl,
6094
                ['target' => '_blank', 'class' => 'attachFilename']
6095
            );
6096
            $json['id'] = $row['iid'];
6097
            $json['comment'] = $attachment->getComment();
6098
            // Format file size
6099
            $json['size'] = format_file_size($attachment->getSize());
6100
            // Check if $row is consistent
6101
            if ($attachment) {
6102
                // Set result as success and bring delete URL
6103
                $json['result'] = Display::return_icon('accept.png', get_lang('Uploaded.'));
6104
                $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&action=delete_attach&forum='.$forumId.'&thread='.$threadId.'&id_attach='.$row['iid'];
6105
                $json['delete'] = Display::url(
6106
                    Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL),
6107
                    $url,
6108
                    ['class' => 'deleteLink']
6109
                );
6110
            } else {
6111
                // If not, set an exclamation result
6112
                $json['result'] = Display::return_icon('exclamation.png', get_lang('Error'));
6113
            }
6114
            // Store array data into $_SESSION
6115
            $_SESSION['forum']['upload_file'][$courseId][$json['id']] = $json;
6116
        }
6117
    }
6118
6119
    return $json;
6120
}
6121
6122
/**
6123
 * Clear forum attachment data stored in $_SESSION,
6124
 * If is not defined post, it will clear all forum attachment data from course.
6125
 *
6126
 * @param int $postId   -1 : Clear all attachments from course stored in $_SESSION
6127
 *                      0 : Clear attachments from course, except from temporal post "0"
6128
 *                      but without delete them from file system and database
6129
 *                      Other values : Clear attachments from course except specified post
6130
 *                      and delete them from file system and database
6131
 * @param int $courseId : Course ID, if it is null, will use api_get_course_int_id()
6132
 *
6133
 * @return array
6134
 */
6135
function clearAttachedFiles($postId = 0, $courseId = 0)
6136
{
6137
    // Init variables
6138
    $courseId = (int) $courseId;
6139
    $postId = (int) $postId;
6140
    $array = [];
6141
    if (empty($courseId)) {
6142
        // $courseId can be null, use api method
6143
        $courseId = api_get_course_int_id();
6144
    }
6145
    if (-1 === $postId) {
6146
        // If post ID is -1 then delete course's attachment data from $_SESSION
6147
        if (!empty($_SESSION['forum']['upload_file'][$courseId])) {
6148
            $array = array_keys($_SESSION['forum']['upload_file'][$courseId]);
6149
            unset($_SESSION['forum']['upload_file'][$courseId]);
6150
        }
6151
    } else {
6152
        $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6153
        if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6154
            is_array($_SESSION['forum']['upload_file'][$courseId])) {
6155
            foreach ($_SESSION['forum']['upload_file'][$courseId] as $attachId => $attach) {
6156
                if (!in_array($attachId, $attachIds)) {
6157
                    // If attach ID is not into specified post, delete attachment
6158
                    // Save deleted attachment ID
6159
                    $array[] = $attachId;
6160
                    if (0 !== $postId) {
6161
                        // Post 0 is temporal, delete them from file system and DB
6162
                        delete_attachment(0, $attachId);
6163
                    }
6164
                    // Delete attachment data from $_SESSION
6165
                    unset($_SESSION['forum']['upload_file'][$courseId][$attachId]);
6166
                }
6167
            }
6168
        }
6169
    }
6170
6171
    return $array;
6172
}
6173
6174
/**
6175
 * Returns an array of forum attachment ids into a course and forum post.
6176
 *
6177
 * @param int $postId
6178
 * @param int $courseId
6179
 *
6180
 * @return array
6181
 */
6182
function getAttachmentIdsByPostId($postId, $courseId = 0)
6183
{
6184
    $array = [];
6185
    $courseId = (int) $courseId;
6186
    $postId = (int) $postId;
6187
    if (empty($courseId)) {
6188
        // $courseId can be null, use api method
6189
        $courseId = api_get_course_int_id();
6190
    }
6191
    if ($courseId > 0) {
6192
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6193
        $sql = "SELECT iid FROM $forumAttachmentTable
6194
                WHERE c_id = $courseId AND post_id = $postId";
6195
        $result = Database::query($sql);
6196
        if (false !== $result && Database::num_rows($result) > 0) {
6197
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6198
                $array[] = $row['iid'];
6199
            }
6200
        }
6201
    }
6202
6203
    return $array;
6204
}
6205
6206
/**
6207
 * Check if the forum category exists looking for its title.
6208
 *
6209
 * @param string $title     The forum category title
6210
 * @param int    $courseId  The course ID
6211
 * @param int    $sessionId Optional. The session ID
6212
 *
6213
 * @return bool
6214
 */
6215
function getForumCategoryByTitle($title, $courseId, $sessionId = 0)
6216
{
6217
    $sessionId = (int) $sessionId;
6218
    $courseId = (int) $courseId;
6219
    $forumCategoryTable = Database::get_course_table(TABLE_FORUM_CATEGORY);
6220
    $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6221
6222
    $fakeFrom = "$forumCategoryTable fc
6223
        INNER JOIN $itemProperty ip ";
6224
6225
    if (0 === $sessionId) {
6226
        $fakeFrom .= '
6227
            ON (
6228
                fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND (fc.session_id = ip.session_id OR ip.session_id IS NULL)
6229
            )
6230
        ';
6231
    } else {
6232
        $fakeFrom .= '
6233
            ON (
6234
                fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND fc.session_id = ip.session_id
6235
            )
6236
        ';
6237
    }
6238
6239
    $resultData = Database::select(
6240
        'fc.*',
6241
        $fakeFrom,
6242
        [
6243
            'where' => [
6244
                'ip.visibility != ? AND ' => 2,
6245
                'ip.tool = ? AND ' => TOOL_FORUM_CATEGORY,
6246
                'fc.session_id = ? AND ' => $sessionId,
6247
                'fc.cat_title = ? AND ' => $title,
6248
                'fc.c_id = ?' => $courseId,
6249
            ],
6250
        ],
6251
        'first'
6252
    );
6253
6254
    if (empty($resultData)) {
6255
        return false;
6256
    }
6257
6258
    return $resultData;
6259
}
6260
6261
/**
6262
 * @param array $row
6263
 * @param bool  $addWrapper
6264
 *
6265
 * @return string
6266
 */
6267
function getPostStatus(CForumForum $forum, $row, $addWrapper = true)
6268
{
6269
    $statusIcon = '';
6270
    if ($forum->isModerated()) {
6271
        if ($addWrapper) {
6272
            $statusIcon = '<br /><br /><span id="status_post_'.$row['iid'].'">';
6273
        }
6274
        $row['status'] = empty($row['status']) ? 2 : $row['status'];
6275
6276
        $addUrl = false;
6277
        $showStatus = false;
6278
        if (api_is_allowed_to_edit(false, true)) {
6279
            $addUrl = true;
6280
        } else {
6281
            if ($row['user_id'] == api_get_user_id()) {
6282
                $showStatus = true;
6283
            }
6284
        }
6285
6286
        $label = '';
6287
        $icon = '';
6288
        $buttonType = '';
6289
        switch ($row['status']) {
6290
            case CForumPost::STATUS_VALIDATED:
6291
                $label = get_lang('Validated');
6292
                $icon = 'check-circle';
6293
                $buttonType = 'success';
6294
6295
                break;
6296
            case CForumPost::STATUS_WAITING_MODERATION:
6297
                $label = get_lang('Waiting for moderation');
6298
                $icon = 'warning';
6299
                $buttonType = 'warning';
6300
6301
                break;
6302
            case CForumPost::STATUS_REJECTED:
6303
                $label = get_lang('Rejected');
6304
                $icon = 'minus-circle';
6305
                $buttonType = 'danger';
6306
6307
                break;
6308
        }
6309
6310
        if ($addUrl) {
6311
            $statusIcon .= Display::toolbarButton(
6312
                $label.'&nbsp;',
6313
                'javascript:void(0)',
6314
                $icon,
6315
                $buttonType,
6316
                ['class' => 'change_post_status']
6317
            );
6318
        } else {
6319
            if ($showStatus) {
6320
                $statusIcon .= Display::label(
6321
                    Display::returnFontAwesomeIcon($icon).$label,
6322
                    $buttonType
6323
                );
6324
            }
6325
        }
6326
6327
        if ($addWrapper) {
6328
            $statusIcon .= '</span>';
6329
        }
6330
    }
6331
6332
    return $statusIcon;
6333
}
6334
6335
/**
6336
 * @param CForumForum $forum
6337
 * @param int         $threadId
6338
 * @param int         $status
6339
 */
6340
function getCountPostsWithStatus($status, $forum, $threadId = null)
6341
{
6342
    $em = Database::getManager();
6343
    $criteria = Criteria::create();
6344
    $criteria
6345
        ->where(Criteria::expr()->eq('status', $status))
6346
        ->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
6347
        ->andWhere(Criteria::expr()->eq('visible', 1))
6348
    ;
6349
6350
    if (!empty($threadId)) {
6351
        $criteria->andWhere(Criteria::expr()->eq('thread', $threadId));
6352
    }
6353
6354
    $qb = $em->getRepository(CForumPost::class)->createQueryBuilder('p');
6355
    $qb->select('count(p.iid)')
6356
        ->addCriteria($criteria);
6357
6358
    return $qb->getQuery()->getSingleScalarResult();
6359
}
6360
6361
/**
6362
 * @param CForumForum $forum
6363
 * @param CForumPost  $post
6364
 *
6365
 * @return bool
6366
 */
6367
function postIsEditableByStudent($forum, $post)
6368
{
6369
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
6370
        return true;
6371
    }
6372
6373
    if (1 == $forum->isModerated()) {
6374
        if (null === $post->getStatus()) {
6375
            return true;
6376
        } else {
6377
            return in_array(
6378
                $post->getStatus(),
6379
                [
6380
                    CForumPost::STATUS_WAITING_MODERATION,
6381
                    CForumPost::STATUS_REJECTED,
6382
                ]
6383
            );
6384
        }
6385
    }
6386
6387
    return true;
6388
}
6389
6390
/**
6391
 * @param CForumPost $post
6392
 *
6393
 * @return bool
6394
 */
6395
function savePostRevision(CForumPost $post)
6396
{
6397
    $userId = api_get_user_id();
6398
6399
    if ($post->getPosterId() != $userId) {
6400
        return false;
6401
    }
6402
6403
    $status = (int) !postNeedsRevision($post);
6404
    $extraFieldValue = new ExtraFieldValue('forum_post');
6405
    $params = [
6406
        'item_id' => $post->getIid(),
6407
        'extra_ask_for_revision' => ['extra_ask_for_revision' => $status],
6408
    ];
6409
    if (empty($status)) {
6410
        unset($params['extra_ask_for_revision']);
6411
    }
6412
    $extraFieldValue->saveFieldValues(
6413
        $params,
6414
        true,
6415
        false,
6416
        ['ask_for_revision']
6417
    );
6418
}
6419
6420
/**
6421
 * @param int $postId
6422
 *
6423
 * @return string
6424
 */
6425
function getPostRevision($postId)
6426
{
6427
    $extraFieldValue = new ExtraFieldValue('forum_post');
6428
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6429
        $postId,
6430
        'revision_language'
6431
    );
6432
    $revision = '';
6433
    if ($value && isset($value['value'])) {
6434
        $revision = $value['value'];
6435
    }
6436
6437
    return $revision;
6438
}
6439
6440
function postNeedsRevision(CForumPost $post): bool
6441
{
6442
    $postId = $post->getIid();
6443
    $extraFieldValue = new ExtraFieldValue('forum_post');
6444
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6445
        $postId,
6446
        'ask_for_revision'
6447
    );
6448
    $hasRevision = false;
6449
    if ($value && isset($value['value'])) {
6450
        return 1 == $value['value'];
6451
    }
6452
6453
    return $hasRevision;
6454
}
6455
6456
/**
6457
 * @param CForumPost   $post
6458
 * @param array $threadInfo
6459
 *
6460
 * @return string
6461
 */
6462
function getAskRevisionButton(CForumPost $post, $threadInfo)
6463
{
6464
    if (false === api_get_configuration_value('allow_forum_post_revisions')) {
6465
        return '';
6466
    }
6467
6468
    $postId = $post->getIid();
6469
6470
    $status = 'btn-default';
6471
    if (postNeedsRevision($post)) {
6472
        $status = 'btn-success';
6473
    }
6474
6475
    return Display::url(
6476
        get_lang('Ask for a revision'),
6477
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6478
        api_get_cidreq().'&action=ask_revision&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6479
        ['class' => "btn $status", 'title' => get_lang('Ask for a revision')]
6480
    );
6481
}
6482
6483
/**
6484
 * @param int   $postId
6485
 * @param array $threadInfo
6486
 *
6487
 * @return string
6488
 */
6489
function giveRevisionButton($postId, $threadInfo)
6490
{
6491
    $postId = (int) $postId;
6492
6493
    return Display::toolbarButton(
6494
        get_lang('Give revision'),
6495
        api_get_path(WEB_CODE_PATH).'forum/reply.php?'.api_get_cidreq().'&'.http_build_query(
6496
            [
6497
                'forum' => $threadInfo['forum_id'],
6498
                'thread' => $threadInfo['thread_id'],
6499
                'post' => $postId = (int) $postId,
6500
                'action' => 'replymessage',
6501
                'give_revision' => 1,
6502
            ]
6503
        ),
6504
        'reply',
6505
        'primary',
6506
        ['id' => "reply-to-post-{$postId}"]
6507
    );
6508
}
6509
6510
/**
6511
 * @param int   $postId
6512
 * @param array $threadInfo
6513
 *
6514
 * @return string
6515
 */
6516
function getReportButton($postId, $threadInfo)
6517
{
6518
    $postId = (int) $postId;
6519
6520
    return Display::url(
6521
        Display::returnFontAwesomeIcon('flag'),
6522
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6523
        api_get_cidreq().'&action=report&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6524
        ['class' => 'btn btn-danger', 'title' => get_lang('Report')]
6525
    );
6526
}
6527
6528
/**
6529
 * @return bool
6530
 */
6531
function reportAvailable()
6532
{
6533
    $extraFieldValue = new ExtraFieldValue('course');
6534
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6535
        api_get_course_int_id(),
6536
        'allow_forum_report_button'
6537
    );
6538
    $allowReport = false;
6539
    if ($value && isset($value['value']) && 1 == $value['value']) {
6540
        $allowReport = true;
6541
    }
6542
6543
    return $allowReport;
6544
}
6545
6546
/**
6547
 * @return array
6548
 */
6549
function getReportRecipients()
6550
{
6551
    $extraFieldValue = new ExtraFieldValue('course');
6552
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6553
        api_get_course_int_id(),
6554
        'forum_report_recipients'
6555
    );
6556
    $users = [];
6557
    if ($value && isset($value['value'])) {
6558
        $usersType = explode(';', $value['value']);
6559
6560
        foreach ($usersType as $type) {
6561
            switch ($type) {
6562
                case 'teachers':
6563
                    $teachers = CourseManager::get_teacher_list_from_course_code(api_get_course_id());
6564
                    if (!empty($teachers)) {
6565
                        $users = array_merge($users, array_column($teachers, 'user_id'));
6566
                    }
6567
6568
                break;
6569
                case 'admins':
6570
                    $admins = UserManager::get_all_administrators();
6571
                    if (!empty($admins)) {
6572
                        $users = array_merge($users, array_column($admins, 'user_id'));
6573
                    }
6574
6575
                    break;
6576
                case 'community_managers':
6577
                    $managers = api_get_configuration_value('community_managers_user_list');
6578
                    if (!empty($managers) && isset($managers['users'])) {
6579
                        $users = array_merge($users, $managers['users']);
6580
                    }
6581
6582
                    break;
6583
            }
6584
        }
6585
6586
        $users = array_unique(array_filter($users));
6587
    }
6588
6589
    return $users;
6590
}
6591
6592
/**
6593
 * @param CForumPost $post
6594
 * @param array      $forumInfo
6595
 * @param array      $threadInfo
6596
 *
6597
 * @return bool
6598
 */
6599
function reportPost(CForumPost $post, $forumInfo, $threadInfo)
6600
{
6601
    if (!reportAvailable()) {
6602
        return false;
6603
    }
6604
6605
    if (empty($forumInfo) || empty($threadInfo)) {
6606
        return false;
6607
    }
6608
6609
    $postId = $post->getIid();
6610
6611
    $currentUser = api_get_user_info();
6612
    $users = getReportRecipients();
6613
    if (!empty($users)) {
6614
        $url = api_get_path(WEB_CODE_PATH).
6615
            'forum/viewthread.php?forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'].'&'.api_get_cidreq().'&post_id='.$postId.'#post_id_'.$postId;
6616
        $postLink = Display::url(
6617
            $post->getPostTitle(),
6618
            $url
6619
        );
6620
        $subject = get_lang('Post reported');
6621
        $content = sprintf(
6622
            get_lang('User %s has reported the message %s in the forum %s'),
6623
            $currentUser['complete_name'],
6624
            $postLink,
6625
            $forumInfo['forum_title']
6626
        );
6627
        foreach ($users as $userId) {
6628
            MessageManager::send_message_simple($userId, $subject, $content);
6629
        }
6630
    }
6631
6632
}
6633