Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

main/forum/forumfunction.inc.php (1 issue)

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