Passed
Push — master ( b51a91...3398ac )
by Julito
14:21 queued 01:32
created

handleForum()   F

Complexity

Conditions 32
Paths 3458

Size

Total Lines 138
Code Lines 101

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 32
eloc 101
c 0
b 0
f 0
nc 3458
nop 1
dl 0
loc 138
rs 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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