Passed
Push — master ( 8dc8d6...0b0f56 )
by Julito
10:41
created

get_last_post_by_thread()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 27
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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