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

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
3881
                $totalFileSize += $_FILES['user_upload']['size'][$i];
3882
            }
3883
            if ($totalFileSize > $maxFileSize) {
3884
                $upload_ok = 0;
3885
                $errMessage = get_lang('FileSizeIsTooBig').' '.get_lang('MaxFileSize').' : '.getIniMaxFileSizeInBytes(true);
3886
            }
3887
        } else {
3888
            if ($maxFileSize > 0 && $_FILES['user_upload']['size'] <= $maxFileSize) {
3889
                $upload_ok = process_uploaded_file($_FILES['user_upload']);
3890
            } else {
3891
                $upload_ok = 0;
3892
                $errMessage = get_lang('FileSizeIsTooBig').' '.get_lang('MaxFileSize').' : '.getIniMaxFileSizeInBytes(true);
3893
            }
3894
        }
3895
    }
3896
3897
    if ($upload_ok) {
3898
        // We first store an entry in the forum_post table.
3899
        $new_post_id = Database::insert(
3900
            $table_posts,
3901
            [
3902
                'c_id' => $courseId,
3903
                'post_title' => $values['post_title'],
3904
                'post_text' => isset($values['post_text']) ? ($values['post_text']) : null,
3905
                'thread_id' => $values['thread_id'],
3906
                'forum_id' => $values['forum_id'],
3907
                'poster_id' => $userId,
3908
                'post_id' => 0,
3909
                'post_date' => $post_date,
3910
                'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : null,
3911
                'post_parent_id' => isset($values['post_parent_id']) ? $values['post_parent_id'] : null,
3912
                'visible' => $visible,
3913
            ]
3914
        );
3915
3916
        if ($new_post_id) {
3917
            $sql = "UPDATE $table_posts SET post_id = iid WHERE iid = $new_post_id";
3918
            Database::query($sql);
3919
3920
            $values['new_post_id'] = $new_post_id;
3921
            $message = get_lang('ReplyAdded');
3922
3923
            if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3924
                foreach ($_POST['file_ids'] as $key => $id) {
3925
                    editAttachedFile(
3926
                        [
3927
                            'comment' => $_POST['file_comments'][$key],
3928
                            'post_id' => $new_post_id,
3929
                        ],
3930
                        $id
3931
                    );
3932
                }
3933
            }
3934
3935
            // Update the thread.
3936
            updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
3937
3938
            // Update the forum.
3939
            api_item_property_update(
3940
                $_course,
3941
                TOOL_FORUM,
3942
                $values['forum_id'],
3943
                'NewMessageInForum',
3944
                $userId
3945
            );
3946
3947
            // Insert post
3948
            api_item_property_update(
3949
                $_course,
3950
                TOOL_FORUM_POST,
3951
                $new_post_id,
3952
                'NewPost',
3953
                $userId
3954
            );
3955
3956
            if ($current_forum['approval_direct_post'] == '1' &&
3957
                !api_is_allowed_to_edit(null, true)
3958
            ) {
3959
                $message .= '<br />'.get_lang('MessageHasToBeApproved').'<br />';
3960
            }
3961
3962
            if ($current_forum['moderated'] &&
3963
                !api_is_allowed_to_edit(null, true)
3964
            ) {
3965
                $message .= '<br />'.get_lang('MessageHasToBeApproved').'<br />';
3966
            }
3967
3968
            // Setting the notification correctly.
3969
            $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
3970
            if ($my_post_notification == 1) {
3971
                set_notification('thread', $values['thread_id'], true);
3972
            }
3973
3974
            send_notification_mails(
3975
                $values['forum_id'],
3976
                $values['thread_id'],
3977
                $values
3978
            );
3979
            add_forum_attachment_file('', $new_post_id);
3980
3981
            $logInfo = [
3982
                'tool' => TOOL_FORUM,
3983
                'tool_id' => $values['forum_id'],
3984
                'tool_id_detail' => $values['thread_id'],
3985
                'action' => 'new-post',
3986
                'action_details' => $values['action'],
3987
                'info' => $values['post_title'],
3988
            ];
3989
            Event::registerLog($logInfo);
3990
        }
3991
3992
        Session::erase('formelements');
3993
        Session::erase('origin');
3994
        Session::erase('breadcrumbs');
3995
        Session::erase('addedresource');
3996
        Session::erase('addedresourceid');
3997
3998
        Display::addFlash(Display::return_message($message, 'confirmation', false));
3999
    } else {
4000
        Display::addFlash(
4001
            Display::return_message(
4002
                $errMessage,
4003
                'error'
4004
            )
4005
        );
4006
4007
        return false;
4008
    }
4009
4010
    return $new_post_id;
4011
}
4012
4013
/**
4014
 * This function displays the form that is used to edit a post. This can be a new thread or a reply.
4015
 *
4016
 * @param array contains all the information about the current post
4017
 * @param array contains all the information about the current thread
4018
 * @param array contains all info about the current forum (to check if attachments are allowed)
4019
 * @param array contains the default values to fill the form
4020
 *
4021
 * @author Patrick Cool <[email protected]>, Ghent University
4022
 *
4023
 * @version february 2006, dokeos 1.8
4024
 */
4025
function show_edit_post_form(
4026
    $current_post,
4027
    $current_thread,
4028
    $current_forum,
4029
    $form_values = [],
4030
    $id_attach = 0
4031
) {
4032
    // Initialize the object.
4033
    $form = new FormValidator(
4034
        'edit_post',
4035
        'post',
4036
        api_get_self().'?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&post='.intval($_GET['post'])
4037
    );
4038
    $form->addElement('header', get_lang('EditPost'));
4039
    // Setting the form elements.
4040
    $form->addElement('hidden', 'post_id', $current_post['post_id']);
4041
    $form->addElement('hidden', 'thread_id', $current_thread['thread_id']);
4042
    $form->addElement('hidden', 'id_attach', $id_attach);
4043
4044
    if (empty($current_post['post_parent_id'])) {
4045
        $form->addElement('hidden', 'is_first_post_of_thread', '1');
4046
    }
4047
4048
    $form->addElement('text', 'post_title', get_lang('Title'));
4049
    $form->applyFilter('post_title', 'html_filter');
4050
    $form->addElement(
4051
        'html_editor',
4052
        'post_text',
4053
        get_lang('Text'),
4054
        null,
4055
        api_is_allowed_to_edit(null, true) ? [
4056
            'ToolbarSet' => 'Forum',
4057
            'Width' => '100%',
4058
            'Height' => '400',
4059
        ] : [
4060
            'ToolbarSet' => 'ForumStudent',
4061
            'Width' => '100%',
4062
            'Height' => '400',
4063
            'UserStatus' => 'student',
4064
        ]
4065
    );
4066
    $form->addRule('post_text', get_lang('ThisFieldIsRequired'), 'required');
4067
4068
    $extraFields = new ExtraField('forum_post');
4069
    $extraFields->addElements($form, $current_post['post_id']);
4070
4071
    $form->addButtonAdvancedSettings('advanced_params');
4072
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
4073
4074
    if ($current_forum['moderated'] && api_is_allowed_to_edit(null, true)) {
4075
        $group = [];
4076
        $group[] = $form->createElement(
4077
            'radio',
4078
            'status',
4079
            null,
4080
            get_lang('Validated'),
4081
            1
4082
        );
4083
        $group[] = $form->createElement(
4084
            'radio',
4085
            'status',
4086
            null,
4087
            get_lang('WaitingModeration'),
4088
            2
4089
        );
4090
        $group[] = $form->createElement(
4091
            'radio',
4092
            'status',
4093
            null,
4094
            get_lang('Rejected'),
4095
            3
4096
        );
4097
        $form->addGroup($group, 'status', get_lang('Status'));
4098
    }
4099
4100
    $defaults['status']['status'] = isset($current_post['status']) && !empty($current_post['status']) ? $current_post['status'] : 2;
4101
    $form->addElement(
4102
        'checkbox',
4103
        'post_notification',
4104
        '',
4105
        get_lang('NotifyByEmail').' ('.$current_post['email'].')'
4106
    );
4107
4108
    if (api_is_allowed_to_edit(null, true) &&
4109
        empty($current_post['post_parent_id'])
4110
    ) {
4111
        // The sticky checkbox only appears when it is the first post of a thread.
4112
        $form->addElement('checkbox', 'thread_sticky', '', get_lang('StickyPost'));
4113
        if ($current_thread['thread_sticky'] == 1) {
4114
            $defaults['thread_sticky'] = true;
4115
        }
4116
    }
4117
4118
    $form->addElement('html', '</div>');
4119
4120
    $form->addFile('user_upload[]', get_lang('Attachment'));
4121
    $form->addButton(
4122
        'add_attachment',
4123
        get_lang('AddAttachment'),
4124
        'paperclip',
4125
        'default',
4126
        'default',
4127
        null,
4128
        ['id' => 'reply-add-attachment']
4129
    );
4130
4131
    $form->addButtonUpdate(get_lang('Modify'), 'SubmitPost');
4132
4133
    // Setting the default values for the form elements.
4134
    $defaults['post_title'] = $current_post['post_title'];
4135
    $defaults['post_text'] = $current_post['post_text'];
4136
4137
    if ($current_post['post_notification'] == 1) {
4138
        $defaults['post_notification'] = true;
4139
    }
4140
4141
    if (!empty($form_values)) {
4142
        $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
4143
        $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
4144
    }
4145
4146
    $form->setDefaults($defaults);
4147
4148
    // The course admin can make a thread sticky (=appears with special icon and always on top).
4149
4150
    $form->addRule('post_title', get_lang('ThisFieldIsRequired'), 'required');
4151
4152
    // Validation or display
4153
    if ($form->validate()) {
4154
        $values = $form->exportValues();
4155
4156
        $values['item_id'] = $current_post['post_id'];
4157
        $extraFieldValues = new ExtraFieldValue('forum_post');
4158
        $extraFieldValues->saveFieldValues($values);
4159
4160
        store_edit_post($current_forum, $values);
4161
    } else {
4162
        // Delete from $_SESSION forum attachment from other posts
4163
        clearAttachedFiles($current_post['post_id']);
4164
        // Get forum attachment ajax table to add it to form
4165
        $fileData = getAttachmentsAjaxTable($current_post['post_id'], $current_forum['forum_id']);
4166
        $form->addElement('html', $fileData);
4167
        $form->display();
4168
    }
4169
}
4170
4171
/**
4172
 * This function stores the edit of a post in the forum_post table.
4173
 *
4174
 * @param array
4175
 *
4176
 * @author Patrick Cool <[email protected]>, Ghent University
4177
 *
4178
 * @version february 2006, dokeos 1.8
4179
 */
4180
function store_edit_post($forumInfo, $values)
4181
{
4182
    $logInfo = [
4183
        'tool' => TOOL_FORUM,
4184
        'tool_id' => $_GET['forum'],
4185
        'tool_id_detail' => $values['thread_id'],
4186
        'action' => 'edit-post',
4187
        'action_details' => 'post',
4188
        'info' => $values['post_title'],
4189
    ];
4190
    Event::registerLog($logInfo);
4191
4192
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
4193
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4194
    $course_id = api_get_course_int_id();
4195
4196
    //check if this post is the first of the thread
4197
    // First we check if the change affects the thread and if so we commit
4198
    // the changes (sticky and post_title=thread_title are relevant).
4199
4200
    $posts = getPosts($forumInfo, $values['thread_id']);
4201
    $first_post = null;
4202
    if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
4203
        $first_post = $posts[0];
4204
    }
4205
4206
    if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
4207
        // Simple edit
4208
        $params = [
4209
            'thread_title' => $values['post_title'],
4210
            'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
4211
        ];
4212
        $where = ['c_id = ? AND thread_id = ?' => [$course_id, $values['thread_id']]];
4213
        Database::update($threadTable, $params, $where);
4214
    }
4215
4216
    $status = '';
4217
    $updateStatus = false;
4218
    if ($forumInfo['moderated']) {
4219
        if (api_is_allowed_to_edit(null, true)) {
4220
            $status = $values['status']['status'];
4221
            $updateStatus = true;
4222
        } else {
4223
            $status = CForumPost::STATUS_WAITING_MODERATION;
4224
            $updateStatus = true;
4225
        }
4226
    }
4227
4228
    // Update the post_title and the post_text.
4229
    $params = [
4230
        'post_title' => $values['post_title'],
4231
        'post_text' => $values['post_text'],
4232
        'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : '',
4233
    ];
4234
4235
    if ($updateStatus) {
4236
        $params['status'] = $status;
4237
    }
4238
4239
    $where = ['c_id = ? AND post_id = ?' => [$course_id, $values['post_id']]];
4240
    Database::update($table_posts, $params, $where);
4241
4242
    // Update attached files
4243
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
4244
        foreach ($_POST['file_ids'] as $key => $id) {
4245
            editAttachedFile(
4246
                [
4247
                    'comment' => $_POST['file_comments'][$key],
4248
                    'post_id' => $values['post_id'],
4249
                ],
4250
                $id
4251
            );
4252
        }
4253
    }
4254
4255
    if (!empty($values['remove_attach'])) {
4256
        delete_attachment($values['post_id']);
4257
    }
4258
4259
    if (empty($values['id_attach'])) {
4260
        add_forum_attachment_file(
4261
            isset($values['file_comment']) ? $values['file_comment'] : null,
4262
            $values['post_id']
4263
        );
4264
    } else {
4265
        edit_forum_attachment_file(
4266
            isset($values['file_comment']) ? $values['file_comment'] : null,
4267
            $values['post_id'],
4268
            $values['id_attach']
4269
        );
4270
    }
4271
4272
    $message = get_lang('EditPostStored').'<br />';
4273
    $message .= get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&">'.get_lang('Forum').'</a><br />';
4274
    $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>';
4275
4276
    Session::erase('formelements');
4277
    Session::erase('origin');
4278
    Session::erase('breadcrumbs');
4279
    Session::erase('addedresource');
4280
    Session::erase('addedresourceid');
4281
4282
    echo Display::return_message($message, 'confirmation', false);
4283
}
4284
4285
/**
4286
 * This function displays the firstname and lastname of the user as a link to the user tool.
4287
 *
4288
 * @param string names
4289
 * @ in_title : title tootip
4290
 *
4291
 * @return string HTML
4292
 *
4293
 * @author Patrick Cool <[email protected]>, Ghent University
4294
 *
4295
 * @version february 2006, dokeos 1.8
4296
 */
4297
function display_user_link($user_id, $name, $origin = '', $in_title = '')
4298
{
4299
    if ($user_id != 0) {
4300
        $userInfo = api_get_user_info($user_id);
4301
4302
        return '<a href="'.$userInfo['profile_url'].'">'.Security::remove_XSS($userInfo['complete_name']).'</a>';
4303
    } else {
4304
        return $name.' ('.get_lang('Anonymous').')';
4305
    }
4306
}
4307
4308
/**
4309
 * This function displays the user image from the profile, with a link to the user's details.
4310
 *
4311
 * @param   int     User's database ID
4312
 * @param   string  User's name
4313
 * @param   string  the origin where the forum is called (example : learnpath)
4314
 *
4315
 * @return string An HTML with the anchor and the image of the user
4316
 *
4317
 * @author Julio Montoya <[email protected]>
4318
 */
4319
function display_user_image($user_id, $name, $origin = '')
4320
{
4321
    $userInfo = api_get_user_info($user_id);
4322
    $link = '<a href="'.(!empty($origin) ? '#' : $userInfo['profile_url']).'" '.(!empty($origin) ? 'target="_self"' : '').'>';
4323
4324
    if ($user_id != 0) {
4325
        return $link.'<img src="'.$userInfo['avatar'].'"  alt="'.$name.'"  title="'.$name.'" /></a>';
4326
    } else {
4327
        return $link.Display::return_icon('unknown.jpg', $name).'</a>';
4328
    }
4329
}
4330
4331
/**
4332
 * The thread view counter gets increased every time someone looks at the thread.
4333
 *
4334
 * @param int
4335
 *
4336
 * @author Patrick Cool <[email protected]>, Ghent University
4337
 *
4338
 * @version february 2006, dokeos 1.8
4339
 */
4340
function increase_thread_view($thread_id)
4341
{
4342
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4343
    $course_id = api_get_course_int_id();
4344
4345
    $sql = "UPDATE $table_threads
4346
            SET thread_views = thread_views + 1
4347
            WHERE
4348
                c_id = $course_id AND
4349
                thread_id = '".intval($thread_id)."'";
4350
    Database::query($sql);
4351
}
4352
4353
/**
4354
 * The relies counter gets increased every time somebody replies to the thread.
4355
 *
4356
 * @author Patrick Cool <[email protected]>, Ghent University
4357
 *
4358
 * @version february 2006, dokeos 1.8
4359
 *
4360
 * @param int    $threadId
4361
 * @param string $lastPostId
4362
 * @param string $post_date
4363
 */
4364
function updateThreadInfo($threadId, $lastPostId, $post_date)
4365
{
4366
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4367
    $course_id = api_get_course_int_id();
4368
    $sql = "UPDATE $table_threads SET
4369
            thread_replies = thread_replies+1,
4370
            thread_last_post = '".Database::escape_string($lastPostId)."',
4371
            thread_date = '".Database::escape_string($post_date)."'
4372
            WHERE
4373
                c_id = $course_id AND
4374
                thread_id='".Database::escape_string($threadId)."'"; // this needs to be cleaned first
4375
    Database::query($sql);
4376
}
4377
4378
/**
4379
 * This function is used to find all the information about what's new in the forum tool.
4380
 *
4381
 * @author Patrick Cool <[email protected]>, Ghent University
4382
 *
4383
 * @version february 2006, dokeos 1.8
4384
 */
4385
function get_whats_new()
4386
{
4387
    $userId = api_get_user_id();
4388
    $course_id = api_get_course_int_id();
4389
4390
    if (empty($course_id) || empty($userId)) {
4391
        return false;
4392
    }
4393
4394
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4395
    $tracking_last_tool_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4396
4397
    $tool = TOOL_FORUM;
4398
    $lastForumAccess = Session::read('last_forum_access');
4399
4400
    if (!$lastForumAccess) {
4401
        $sql = "SELECT * FROM $tracking_last_tool_access
4402
                WHERE
4403
                    access_user_id = $userId AND
4404
                    c_id = $course_id AND
4405
                    access_tool = '".Database::escape_string($tool)."'";
4406
        $result = Database::query($sql);
4407
        $row = Database::fetch_array($result);
4408
        if (isset($row['access_date'])) {
4409
            Session::write('last_forum_access', $row['access_date']);
4410
            $lastForumAccess = $row['access_date'];
4411
        }
4412
    }
4413
4414
    $whatsNew = Session::read('whatsnew_post_info');
4415
4416
    if (!$whatsNew) {
4417
        if ($lastForumAccess != '') {
4418
            $postInfo = [];
4419
            $sql = "SELECT * FROM $table_posts
4420
                    WHERE
4421
                        c_id = $course_id AND
4422
                        visible = 1 AND
4423
                        post_date > '".Database::escape_string($lastForumAccess)."'";
4424
            $result = Database::query($sql);
4425
            while ($row = Database::fetch_array($result)) {
4426
                $postInfo[$row['forum_id']][$row['thread_id']][$row['post_id']] = $row['post_date'];
4427
            }
4428
            Session::write('whatsnew_post_info', $postInfo);
4429
        }
4430
    }
4431
}
4432
4433
/**
4434
 * This function approves a post = change.
4435
 *
4436
 * @param int    $post_id the id of the post that will be deleted
4437
 * @param string $action  make the post visible or invisible
4438
 *
4439
 * @return string language variable
4440
 *
4441
 * @author Patrick Cool <[email protected]>, Ghent University
4442
 *
4443
 * @version february 2006, dokeos 1.8
4444
 */
4445
function approve_post($post_id, $action)
4446
{
4447
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4448
    $course_id = api_get_course_int_id();
4449
4450
    if ($action == 'invisible') {
4451
        $visibility_value = 0;
4452
    }
4453
4454
    if ($action == 'visible') {
4455
        $visibility_value = 1;
4456
        handle_mail_cue('post', $post_id);
4457
    }
4458
4459
    $sql = "UPDATE $table_posts SET
4460
            visible='".Database::escape_string($visibility_value)."'
4461
            WHERE c_id = $course_id AND post_id='".Database::escape_string($post_id)."'";
4462
    $return = Database::query($sql);
4463
4464
    if ($return) {
4465
        return 'PostVisibilityChanged';
4466
    }
4467
}
4468
4469
/**
4470
 * This function retrieves all the unapproved messages for a given forum
4471
 * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see this).
4472
 *
4473
 * @param $forum_id the forum where we want to know the unapproved messages of
4474
 *
4475
 * @return array returns
4476
 *
4477
 * @author Patrick Cool <[email protected]>, Ghent University
4478
 *
4479
 * @version february 2006, dokeos 1.8
4480
 */
4481
function get_unaproved_messages($forum_id)
4482
{
4483
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4484
    $course_id = api_get_course_int_id();
4485
4486
    $return_array = [];
4487
    $sql = "SELECT DISTINCT thread_id FROM $table_posts
4488
            WHERE
4489
                c_id = $course_id AND
4490
                forum_id='".Database::escape_string($forum_id)."' AND
4491
                visible='0' ";
4492
    $result = Database::query($sql);
4493
    while ($row = Database::fetch_array($result)) {
4494
        $return_array[] = $row['thread_id'];
4495
    }
4496
4497
    return $return_array;
4498
}
4499
4500
/**
4501
 * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
4502
 * was added to a given thread.
4503
 *
4504
 * @param int $forumId
4505
 * @param int $thread_id
4506
 * @param int $reply_info
4507
 *
4508
 * @author Patrick Cool <[email protected]>, Ghent University
4509
 *
4510
 * @version february 2006, dokeos 1.8
4511
 *
4512
 * @return void
4513
 */
4514
function send_notification_mails($forumId, $thread_id, $reply_info)
4515
{
4516
    if (api_get_course_setting('hide_forum_notifications') == '1') {
4517
        return;
4518
    }
4519
4520
    $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4521
4522
    // First we need to check if
4523
    // 1. the forum category is visible
4524
    // 2. the forum is visible
4525
    // 3. the thread is visible
4526
    // 4. the reply is visible (=when there is)
4527
    $current_thread = get_thread_information($forumId, $thread_id);
4528
    $current_forum = get_forum_information($current_thread['forum_id'], $current_thread['c_id']);
4529
4530
    $current_forum_category = null;
4531
    if (isset($current_forum['forum_category'])) {
4532
        $current_forum_category = get_forumcategory_information($current_forum['forum_category']);
4533
    }
4534
4535
    $send_mails = false;
4536
    if ($current_thread['visibility'] == '1' &&
4537
        $current_forum['visibility'] == '1' &&
4538
        ($current_forum_category && $current_forum_category['visibility'] == '1') &&
4539
        $current_forum['approval_direct_post'] != '1'
4540
    ) {
4541
        $send_mails = true;
4542
    }
4543
4544
    // The forum category, the forum, the thread and the reply are visible to the user
4545
    if ($send_mails && !empty($forumId)) {
4546
        $postId = isset($reply_info['new_post_id']) ? $reply_info['new_post_id'] : 0;
4547
        send_notifications($forumId, $thread_id, $postId);
4548
    } else {
4549
        $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4550
        if (isset($current_forum['forum_id'])) {
4551
            $sql = "SELECT * FROM $table_notification
4552
                    WHERE
4553
                        c_id = ".api_get_course_int_id()." AND
4554
                        (
4555
                            forum_id = '".intval($current_forum['forum_id'])."' OR
4556
                            thread_id = '".intval($thread_id)."'
4557
                        ) ";
4558
4559
            $result = Database::query($sql);
4560
            $user_id = api_get_user_id();
4561
            while ($row = Database::fetch_array($result)) {
4562
                $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
4563
                        VALUES (".api_get_course_int_id().", '".intval($thread_id)."', '".intval($reply_info['new_post_id'])."', '$user_id' )";
4564
                Database::query($sql);
4565
            }
4566
        }
4567
    }
4568
}
4569
4570
/**
4571
 * This function is called whenever something is made visible because there might
4572
 * be new posts and the user might have indicated that (s)he wanted to be
4573
 * informed about the new posts by mail.
4574
 *
4575
 * @param string $content Content type (post, thread, forum, forum_category)
4576
 * @param int    $id      Item DB ID of the corresponding content type
4577
 *
4578
 * @return string language variable
4579
 *
4580
 * @author Patrick Cool <[email protected]>, Ghent University
4581
 *
4582
 * @version february 2006, dokeos 1.8
4583
 */
4584
function handle_mail_cue($content, $id)
4585
{
4586
    $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4587
    $table_forums = Database::get_course_table(TABLE_FORUM);
4588
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4589
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4590
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4591
4592
    $course_id = api_get_course_int_id();
4593
    $id = (int) $id;
4594
4595
    /* If the post is made visible we only have to send mails to the people
4596
     who indicated that they wanted to be informed for that thread.*/
4597
    if ($content == 'post') {
4598
        // Getting the information about the post (need the thread_id).
4599
        $post_info = get_post_information($id);
4600
        $thread_id = (int) $post_info['thread_id'];
4601
4602
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4603
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email
4604
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4605
                WHERE
4606
                    posts.c_id = $course_id AND
4607
                    mailcue.c_id = $course_id AND
4608
                    posts.thread_id = $thread_id AND
4609
                    posts.post_notification = '1' AND
4610
                    mailcue.thread_id = $thread_id AND
4611
                    users.user_id = posts.poster_id AND
4612
                    users.active = 1
4613
                GROUP BY users.email";
4614
4615
        $result = Database::query($sql);
4616
        while ($row = Database::fetch_array($result)) {
4617
            $forumInfo = get_forum_information($post_info['forum_id']);
4618
            send_mail($row, $forumInfo, get_thread_information($post_info['forum_id'], $post_info['thread_id']), $post_info);
4619
        }
4620
    } elseif ($content == 'thread') {
4621
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4622
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
4623
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4624
                WHERE
4625
                    posts.c_id = $course_id AND
4626
                    mailcue.c_id = $course_id AND
4627
                    posts.thread_id = $id AND
4628
                    posts.post_notification = '1' AND
4629
                    mailcue.thread_id = $id AND
4630
                    users.user_id = posts.poster_id AND
4631
                    users.active = 1
4632
                GROUP BY users.email";
4633
        $result = Database::query($sql);
4634
        while ($row = Database::fetch_array($result)) {
4635
            $forumInfo = get_forum_information($row['forum_id']);
4636
            send_mail($row, $forumInfo, get_thread_information($row['forum_id'], $id));
4637
        }
4638
4639
        // Deleting the relevant entries from the mailcue.
4640
        $sql = "DELETE FROM $table_mailcue
4641
                WHERE c_id = $course_id AND thread_id = $id";
4642
        Database::query($sql);
4643
    } elseif ($content == 'forum') {
4644
        $sql = "SELECT thread_id FROM $table_threads
4645
                WHERE c_id = $course_id AND forum_id = $id";
4646
        $result = Database::query($sql);
4647
        while ($row = Database::fetch_array($result)) {
4648
            handle_mail_cue('thread', $row['thread_id']);
4649
        }
4650
    } elseif ($content == 'forum_category') {
4651
        $sql = "SELECT forum_id FROM $table_forums
4652
                WHERE c_id = $course_id AND forum_category = $id";
4653
        $result = Database::query($sql);
4654
        while ($row = Database::fetch_array($result)) {
4655
            handle_mail_cue('forum', $row['forum_id']);
4656
        }
4657
    } else {
4658
        return get_lang('Error');
4659
    }
4660
}
4661
4662
/**
4663
 * This function sends the mails for the mail notification.
4664
 *
4665
 * @param array
4666
 * @param array
4667
 * @param array
4668
 * @param array
4669
 *
4670
 * @author Patrick Cool <[email protected]>, Ghent University
4671
 *
4672
 * @version february 2006, dokeos 1.8
4673
 */
4674
function send_mail($userInfo, $forumInfo, $thread_information, $postInfo = [])
4675
{
4676
    if (empty($userInfo) || empty($forumInfo) || empty($thread_information)) {
4677
        return false;
4678
    }
4679
4680
    $_course = api_get_course_info();
4681
    $user_id = api_get_user_id();
4682
4683
    $thread_link = '';
4684
    if (isset($thread_information) && is_array($thread_information)) {
4685
        $thread_link = api_get_path(WEB_CODE_PATH).
4686
            'forum/viewthread.php?'.api_get_cidreq().'&forum='.$thread_information['forum_id'].'&thread='.$thread_information['thread_id'];
4687
    }
4688
    $email_body = get_lang('Dear').' '.api_get_person_name($userInfo['firstname'], $userInfo['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
4689
    $email_body .= get_lang('NewForumPost').': '.$forumInfo['forum_title'].' - '.$thread_information['thread_title']." <br />\n";
4690
4691
    $courseId = api_get_configuration_value('global_forums_course_id');
4692
    $subject = get_lang('NewForumPost').' - '.$_course['official_code'].': '.$forumInfo['forum_title'].' - '.$thread_information['thread_title']." <br />\n";
4693
4694
    $courseInfoTitle = get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
4695
    if (!empty($courseId) && $_course['real_id'] == $courseId) {
4696
        $subject = get_lang('NewForumPost').': '.$forumInfo['forum_title'].' - '.$thread_information['thread_title']." <br />\n";
4697
        $courseInfoTitle = " <br />\n";
4698
    }
4699
    $email_body .= $courseInfoTitle;
4700
4701
    if (!empty($postInfo) && isset($postInfo['post_text'])) {
4702
        $text = cut(strip_tags($postInfo['post_text']), 100);
4703
        if (!empty($text)) {
4704
            $email_body .= get_lang('Message').": <br />\n ";
4705
            $email_body .= $text;
4706
            $email_body .= "<br /><br />\n";
4707
        }
4708
    }
4709
4710
    $email_body .= get_lang('YouWantedToStayInformed')."<br />\n";
4711
4712
    if (!empty($thread_link)) {
4713
        $email_body .= get_lang('ThreadCanBeFoundHere')." : <br /><a href=\"".$thread_link."\">".$thread_link."</a>\n";
4714
    }
4715
4716
    if ($userInfo['user_id'] != $user_id) {
4717
        MessageManager::send_message(
4718
            $userInfo['user_id'],
4719
            $subject,
4720
            $email_body,
4721
            [],
4722
            [],
4723
            null,
4724
            null,
4725
            null,
4726
            null,
4727
            $user_id
4728
        );
4729
    }
4730
}
4731
4732
/**
4733
 * This function displays the form for moving a thread to a different (already existing) forum.
4734
 *
4735
 * @author Patrick Cool <[email protected]>, Ghent University
4736
 *
4737
 * @version february 2006, dokeos 1.8
4738
 */
4739
function move_thread_form()
4740
{
4741
    $form = new FormValidator(
4742
        'movepost',
4743
        'post',
4744
        api_get_self().'?forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
4745
    );
4746
    // The header for the form
4747
    $form->addElement('header', get_lang('MoveThread'));
4748
    // Invisible form: the thread_id
4749
    $form->addElement('hidden', 'thread_id', intval($_GET['thread']));
4750
    // the fora
4751
    $forum_categories = get_forum_categories();
4752
    $forums = get_forums();
4753
4754
    $htmlcontent = '<div class="row">
4755
        <div class="label">
4756
            <span class="form_required">*</span>'.get_lang('MoveTo').'
4757
        </div>
4758
        <div class="formw">';
4759
    $htmlcontent .= '<select name="forum">';
4760
    foreach ($forum_categories as $category) {
4761
        $htmlcontent .= '<optgroup label="'.$category['cat_title'].'">';
4762
        foreach ($forums as $key => $forum) {
4763
            if (isset($forum['forum_category'])) {
4764
                if ($forum['forum_category'] == $category['cat_id']) {
4765
                    $htmlcontent .= '<option value="'.$forum['forum_id'].'">'.
4766
                        Security::remove_XSS($forum['forum_title']).'</option>';
4767
                }
4768
            }
4769
        }
4770
        $htmlcontent .= '</optgroup>';
4771
    }
4772
    $htmlcontent .= "</select>";
4773
    $htmlcontent .= '   </div>
4774
                    </div>';
4775
4776
    $form->addElement('html', $htmlcontent);
4777
4778
    // The OK button
4779
    $form->addButtonSave(get_lang('MoveThread'), 'SubmitForum');
4780
4781
    // Validation or display
4782
    if ($form->validate()) {
4783
        $values = $form->exportValues();
4784
        if (isset($_POST['forum'])) {
4785
            store_move_thread($values);
4786
        }
4787
    } else {
4788
        $form->display();
4789
    }
4790
}
4791
4792
/**
4793
 * This function displays the form for moving a post message to a different (already existing) or a new thread.
4794
 *
4795
 * @author Patrick Cool <[email protected]>, Ghent University
4796
 *
4797
 * @version february 2006, dokeos 1.8
4798
 */
4799
function move_post_form()
4800
{
4801
    $form = new FormValidator(
4802
        'movepost',
4803
        'post',
4804
        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'])
4805
    );
4806
    // The header for the form
4807
    $form->addElement('header', '', get_lang('MovePost'));
4808
4809
    // Invisible form: the post_id
4810
    $form->addElement('hidden', 'post_id', intval($_GET['post']));
4811
4812
    // Dropdown list: Threads of this forum
4813
    $threads = get_threads($_GET['forum']);
4814
    //my_print_r($threads);
4815
    $threads_list[0] = get_lang('ANewThread');
4816
    foreach ($threads as $key => $value) {
4817
        $threads_list[$value['thread_id']] = $value['thread_title'];
4818
    }
4819
    $form->addElement('select', 'thread', get_lang('MoveToThread'), $threads_list);
4820
    $form->applyFilter('thread', 'html_filter');
4821
4822
    // The OK button
4823
    $form->addButtonSave(get_lang('MovePost'), 'submit');
4824
4825
    // Setting the rules
4826
    $form->addRule('thread', get_lang('ThisFieldIsRequired'), 'required');
4827
4828
    // Validation or display
4829
    if ($form->validate()) {
4830
        $values = $form->exportValues();
4831
        store_move_post($values);
4832
    } else {
4833
        return $form->returnForm();
4834
    }
4835
}
4836
4837
/**
4838
 * @param array
4839
 *
4840
 * @return string HTML language variable
4841
 *
4842
 * @author Patrick Cool <[email protected]>, Ghent University
4843
 *
4844
 * @version february 2006, dokeos 1.8
4845
 */
4846
function store_move_post($values)
4847
{
4848
    $_course = api_get_course_info();
4849
    $course_id = api_get_course_int_id();
4850
4851
    $table_forums = Database::get_course_table(TABLE_FORUM);
4852
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4853
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4854
4855
    if ($values['thread'] == '0') {
4856
        $current_post = get_post_information($values['post_id']);
4857
4858
        // Storing a new thread.
4859
        $params = [
4860
            'c_id' => $course_id,
4861
            'thread_title' => $current_post['post_title'],
4862
            'forum_id' => $current_post['forum_id'],
4863
            'thread_poster_id' => $current_post['poster_id'],
4864
            'thread_poster_name' => $current_post['poster_name'],
4865
            'thread_last_post' => $values['post_id'],
4866
            'thread_date' => $current_post['post_date'],
4867
        ];
4868
4869
        $new_thread_id = Database::insert($table_threads, $params);
4870
4871
        api_item_property_update(
4872
            $_course,
4873
            TOOL_FORUM_THREAD,
4874
            $new_thread_id,
4875
            'visible',
4876
            $current_post['poster_id']
4877
        );
4878
4879
        // Moving the post to the newly created thread.
4880
        $sql = "UPDATE $table_posts SET thread_id='".intval($new_thread_id)."', post_parent_id = NULL
4881
                WHERE c_id = $course_id AND post_id='".intval($values['post_id'])."'";
4882
        Database::query($sql);
4883
4884
        // Resetting the parent_id of the thread to 0 for all those who had this moved post as parent.
4885
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4886
                WHERE c_id = $course_id AND post_parent_id='".intval($values['post_id'])."'";
4887
        Database::query($sql);
4888
4889
        // Updating updating the number of threads in the forum.
4890
        $sql = "UPDATE $table_forums SET forum_threads=forum_threads+1
4891
                WHERE c_id = $course_id AND forum_id='".intval($current_post['forum_id'])."'";
4892
        Database::query($sql);
4893
4894
        // Resetting the last post of the old thread and decreasing the number of replies and the thread.
4895
        $sql = "SELECT * FROM $table_posts
4896
                WHERE c_id = $course_id AND thread_id='".intval($current_post['thread_id'])."'
4897
                ORDER BY post_id DESC";
4898
        $result = Database::query($sql);
4899
        $row = Database::fetch_array($result);
4900
        $sql = "UPDATE $table_threads SET
4901
                    thread_last_post='".$row['post_id']."',
4902
                    thread_replies=thread_replies-1
4903
                WHERE
4904
                    c_id = $course_id AND
4905
                    thread_id='".intval($current_post['thread_id'])."'";
4906
        Database::query($sql);
4907
    } else {
4908
        // Moving to the chosen thread.
4909
        $sql = "SELECT thread_id FROM ".$table_posts."
4910
                WHERE c_id = $course_id AND post_id = '".$values['post_id']."' ";
4911
        $result = Database::query($sql);
4912
        $row = Database::fetch_array($result);
4913
4914
        $original_thread_id = $row['thread_id'];
4915
4916
        $sql = "SELECT thread_last_post FROM ".$table_threads."
4917
                WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
4918
4919
        $result = Database::query($sql);
4920
        $row = Database::fetch_array($result);
4921
        $thread_is_last_post = $row['thread_last_post'];
4922
        // If is this thread, update the thread_last_post with the last one.
4923
4924
        if ($thread_is_last_post == $values['post_id']) {
4925
            $sql = "SELECT post_id FROM ".$table_posts."
4926
                    WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' AND post_id <> '".$values['post_id']."'
4927
                    ORDER BY post_date DESC LIMIT 1";
4928
            $result = Database::query($sql);
4929
4930
            $row = Database::fetch_array($result);
4931
            $thread_new_last_post = $row['post_id'];
4932
4933
            $sql = "UPDATE ".$table_threads." SET thread_last_post = '".$thread_new_last_post."'
4934
                    WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
4935
            Database::query($sql);
4936
        }
4937
4938
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies-1
4939
                WHERE c_id = $course_id AND thread_id='".$original_thread_id."'";
4940
        Database::query($sql);
4941
4942
        // moving to the chosen thread
4943
        $sql = "UPDATE $table_posts SET thread_id='".intval($_POST['thread'])."', post_parent_id = NULL
4944
                WHERE c_id = $course_id AND post_id='".intval($values['post_id'])."'";
4945
        Database::query($sql);
4946
4947
        // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
4948
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4949
                WHERE c_id = $course_id AND post_parent_id='".intval($values['post_id'])."'";
4950
        Database::query($sql);
4951
4952
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies+1
4953
                WHERE c_id = $course_id AND thread_id='".intval($_POST['thread'])."'";
4954
        Database::query($sql);
4955
    }
4956
4957
    return get_lang('ThreadMoved');
4958
}
4959
4960
/**
4961
 * @param array
4962
 *
4963
 * @return string HTML language variable
4964
 *
4965
 * @author Patrick Cool <[email protected]>, Ghent University
4966
 *
4967
 * @version february 2006, dokeos 1.8
4968
 */
4969
function store_move_thread($values)
4970
{
4971
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4972
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4973
4974
    $courseId = api_get_course_int_id();
4975
    $sessionId = api_get_session_id();
4976
4977
    $forumId = intval($_POST['forum']);
4978
    $threadId = intval($_POST['thread_id']);
4979
    $forumInfo = get_forums($forumId);
4980
4981
    // Change the thread table: Setting the forum_id to the new forum.
4982
    $sql = "UPDATE $table_threads SET forum_id = $forumId
4983
            WHERE c_id = $courseId AND thread_id = $threadId";
4984
    Database::query($sql);
4985
4986
    // Changing all the posts of the thread: setting the forum_id to the new forum.
4987
    $sql = "UPDATE $table_posts SET forum_id = $forumId
4988
            WHERE c_id = $courseId AND thread_id= $threadId";
4989
    Database::query($sql);
4990
    // Fix group id, if forum is moved to a different group
4991
    if (!empty($forumInfo['to_group_id'])) {
4992
        $groupId = $forumInfo['to_group_id'];
4993
        $item = api_get_item_property_info(
4994
            $courseId,
4995
            TABLE_FORUM_THREAD,
4996
            $threadId,
4997
            $sessionId,
4998
            $groupId
4999
        );
5000
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
5001
        $sessionCondition = api_get_session_condition($sessionId);
5002
5003
        if (!empty($item)) {
5004
            if ($item['to_group_id'] != $groupId) {
5005
                $sql = "UPDATE $table
5006
                    SET to_group_id = $groupId
5007
                    WHERE
5008
                      tool = '".TABLE_FORUM_THREAD."' AND
5009
                      c_id = $courseId AND
5010
                      ref = ".$item['ref']."
5011
                      $sessionCondition
5012
                ";
5013
                Database::query($sql);
5014
            }
5015
        } else {
5016
            $sql = "UPDATE $table
5017
                    SET to_group_id = $groupId
5018
                    WHERE
5019
                      tool = '".TABLE_FORUM_THREAD."' AND
5020
                      c_id = $courseId AND
5021
                      ref = ".$threadId."
5022
                      $sessionCondition
5023
            ";
5024
            Database::query($sql);
5025
        }
5026
    }
5027
5028
    return get_lang('ThreadMoved');
5029
}
5030
5031
/**
5032
 * Prepares a string for displaying by highlighting the search results inside, if any.
5033
 *
5034
 * @param string $input the input string
5035
 *
5036
 * @return string the same string with highlighted hits inside
5037
 *
5038
 * @author Patrick Cool <[email protected]>, Ghent University, February 2006 - the initial version.
5039
 * @author Ivan Tcholakov, March 2011 - adaptation for Chamilo LMS.
5040
 */
5041
function prepare4display($input)
5042
{
5043
    static $highlightcolors = ['yellow', '#33CC33', '#3399CC', '#9999FF', '#33CC33'];
5044
    static $search;
5045
5046
    if (!isset($search)) {
5047
        if (isset($_POST['search_term'])) {
5048
            $search = $_POST['search_term']; // No html at all.
5049
        } elseif (isset($_GET['search'])) {
5050
            $search = $_GET['search'];
5051
        } else {
5052
            $search = '';
5053
        }
5054
    }
5055
5056
    if (!empty($search)) {
5057
        if (strstr($search, '+')) {
5058
            $search_terms = explode('+', $search);
5059
        } else {
5060
            $search_terms[] = trim($search);
5061
        }
5062
        $counter = 0;
5063
        foreach ($search_terms as $key => $search_term) {
5064
            $input = api_preg_replace(
5065
                '/'.preg_quote(trim($search_term), '/').'/i',
5066
                '<span style="background-color: '.$highlightcolors[$counter].'">$0</span>',
5067
                $input
5068
            );
5069
            $counter++;
5070
        }
5071
    }
5072
5073
    // TODO: Security should be implemented outside this function.
5074
    // Change this to COURSEMANAGERLOWSECURITY or COURSEMANAGER to lower filtering and allow more styles
5075
    // (see comments of Security::remove_XSS() method to learn about other levels).
5076
5077
    return Security::remove_XSS($input, STUDENT, true);
5078
}
5079
5080
/**
5081
 * Display the search form for the forum and display the search results.
5082
 *
5083
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5084
 *
5085
 * @version march 2008, dokeos 1.8.5
5086
 */
5087
function forum_search()
5088
{
5089
    $form = new FormValidator(
5090
        'forumsearch',
5091
        'post',
5092
        'forumsearch.php?'.api_get_cidreq()
5093
    );
5094
5095
    // Setting the form elements.
5096
    $form->addElement('header', '', get_lang('ForumSearch'));
5097
    $form->addElement('text', 'search_term', get_lang('SearchTerm'), ['autofocus']);
5098
    $form->applyFilter('search_term', 'html_filter');
5099
    $form->addElement('static', 'search_information', '', get_lang('ForumSearchInformation'));
5100
    $form->addButtonSearch(get_lang('Search'));
5101
5102
    // Setting the rules.
5103
    $form->addRule('search_term', get_lang('ThisFieldIsRequired'), 'required');
5104
    $form->addRule('search_term', get_lang('TooShort'), 'minlength', 3);
5105
5106
    // Validation or display.
5107
    if ($form->validate()) {
5108
        $values = $form->exportValues();
5109
        $form->setDefaults($values);
5110
        $form->display();
5111
        // Display the search results.
5112
        display_forum_search_results(stripslashes($values['search_term']));
5113
    } else {
5114
        $form->display();
5115
    }
5116
}
5117
5118
/**
5119
 * Display the search results.
5120
 *
5121
 * @param string
5122
 * @param string $search_term
5123
 *
5124
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5125
 *
5126
 * @version march 2008, dokeos 1.8.5
5127
 */
5128
function display_forum_search_results($search_term)
5129
{
5130
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
5131
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5132
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
5133
    $session_id = api_get_session_id();
5134
    $course_id = api_get_course_int_id();
5135
5136
    // Defining the search strings as an array.
5137
    if (strstr($search_term, '+')) {
5138
        $search_terms = explode('+', $search_term);
5139
    } else {
5140
        $search_terms[] = $search_term;
5141
    }
5142
5143
    // Search restriction.
5144
    foreach ($search_terms as $value) {
5145
        $search_restriction[] = "
5146
        (
5147
            posts.post_title LIKE '%".Database::escape_string(trim($value))."%' OR
5148
            posts.post_text LIKE '%".Database::escape_string(trim($value))."%'
5149
        )";
5150
    }
5151
    $shareForumInSessions = (1 == api_get_course_setting('share_forums_in_sessions'));
5152
    $sessionCondition = '';
5153
    if (!$shareForumInSessions) {
5154
        $sessionCondition = api_get_session_condition(
5155
            $session_id,
5156
            true,
5157
            false,
5158
            'item_property.session_id'
5159
        );
5160
    }
5161
5162
    $sql = "SELECT posts.*
5163
            FROM $table_posts posts
5164
            INNER JOIN $table_threads threads
5165
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
5166
            INNER JOIN $table_item_property item_property
5167
            ON (item_property.ref = threads.thread_id AND item_property.c_id = threads.c_id)
5168
            WHERE
5169
                posts.c_id = $course_id AND
5170
                item_property.c_id = $course_id AND
5171
                item_property.visibility = 1
5172
                $sessionCondition AND
5173
                posts.visible = 1 AND
5174
                item_property.tool = '".TOOL_FORUM_THREAD."' AND
5175
                ".implode(' AND ', $search_restriction)."
5176
            GROUP BY posts.post_id";
5177
5178
    // Getting all the information of the forum categories.
5179
    $forum_categories_list = get_forum_categories();
5180
5181
    // Getting all the information of the forums.
5182
    $forum_list = get_forums();
5183
5184
    $result = Database::query($sql);
5185
    $search_results = [];
5186
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5187
        $forumId = $row['forum_id'];
5188
        $forumData = get_forums($forumId);
5189
        $category = isset($forum_categories_list[$forumData['forum_category']]) ? $forum_categories_list[$forumData['forum_category']] : null;
5190
        $display_result = false;
5191
        /*
5192
          We only show it when
5193
          1. forum category is visible
5194
          2. forum is visible
5195
          3. thread is visible (to do)
5196
          4. post is visible
5197
         */
5198
        if (!api_is_allowed_to_edit(null, true)) {
5199
            if (!empty($category)) {
5200
                if ($category['visibility'] == '1' && $forumData['visibility'] == '1') {
5201
                    $display_result = true;
5202
                }
5203
            } else {
5204
                if ($forumData['visible'] == '1') {
5205
                    $display_result = true;
5206
                }
5207
            }
5208
        } else {
5209
            $display_result = true;
5210
        }
5211
5212
        if ($display_result) {
5213
            $categoryName = !empty($category) ? $category['cat_title'] : '';
5214
            $search_results_item = '<li><a href="viewforumcategory.php?'.api_get_cidreq().'&forumcategory='.$forumData['forum_category'].'&search='.urlencode($search_term).'">'.
5215
                prepare4display($categoryName).'</a> &gt; ';
5216
            $search_results_item .= '<a href="viewforum.php?'.api_get_cidreq().'&forum='.$forumId.'&search='.urlencode($search_term).'">'.
5217
                prepare4display($forum_list[$row['forum_id']]['forum_title']).'</a> &gt; ';
5218
            $search_results_item .= '<a href="viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$row['thread_id'].'&search='.urlencode($search_term).'">'.
5219
                prepare4display($row['post_title']).'</a>';
5220
            $search_results_item .= '<br />';
5221
            if (api_strlen($row['post_title']) > 200) {
5222
                $search_results_item .= prepare4display(api_substr(strip_tags($row['post_title']), 0, 200)).'...';
5223
            } else {
5224
                $search_results_item .= prepare4display($row['post_title']);
5225
            }
5226
            $search_results_item .= '</li>';
5227
            $search_results[] = $search_results_item;
5228
        }
5229
    }
5230
    echo '<legend>'.count($search_results).' '.get_lang('ForumSearchResults').'</legend>';
5231
    echo '<ol>';
5232
    if ($search_results) {
5233
        echo implode($search_results);
5234
    }
5235
    echo '</ol>';
5236
}
5237
5238
/**
5239
 * Return the link to the forum search page.
5240
 *
5241
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5242
 *
5243
 * @version April 2008, dokeos 1.8.5
5244
 */
5245
function search_link()
5246
{
5247
    $return = '';
5248
    $origin = api_get_origin();
5249
    if ($origin != 'learnpath') {
5250
        $return = '<a href="forumsearch.php?'.api_get_cidreq().'&action=search"> ';
5251
        $return .= Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
5252
5253
        if (!empty($_GET['search'])) {
5254
            $return .= ': '.Security::remove_XSS($_GET['search']).' ';
5255
            $url = api_get_self().'?';
5256
            $url_parameter = [];
5257
            foreach ($_GET as $key => $value) {
5258
                if ($key != 'search') {
5259
                    $url_parameter[] = Security::remove_XSS($key).'='.Security::remove_XSS($value);
5260
                }
5261
            }
5262
            $url = $url.implode('&', $url_parameter);
5263
            $return .= '<a href="'.$url.'">'.Display::return_icon('delete.gif', get_lang('RemoveSearchResults')).'</a>';
5264
        }
5265
    }
5266
5267
    return $return;
5268
}
5269
5270
/**
5271
 * This function adds an attachment file into a forum.
5272
 *
5273
 * @param string $file_comment a comment about file
5274
 * @param int    $last_id      from forum_post table
5275
 *
5276
 * @return false|null
5277
 */
5278
function add_forum_attachment_file($file_comment, $last_id)
5279
{
5280
    $_course = api_get_course_info();
5281
    $agenda_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5282
5283
    if (empty($_FILES['user_upload'])) {
5284
        return false;
5285
    }
5286
5287
    $filesData = [];
5288
5289
    if (!is_array($_FILES['user_upload']['name'])) {
5290
        $filesData[] = $_FILES['user_upload'];
5291
    } else {
5292
        $fileCount = count($_FILES['user_upload']['name']);
5293
        $fileKeys = array_keys($_FILES['user_upload']);
5294
        for ($i = 0; $i < $fileCount; $i++) {
5295
            foreach ($fileKeys as $key) {
5296
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
5297
            }
5298
        }
5299
    }
5300
5301
    $maxFileSize = getIniMaxFileSizeInBytes();
5302
    foreach ($filesData as $attachment) {
5303
        if (empty($attachment['name'])) {
5304
            continue;
5305
        }
5306
5307
        if ($maxFileSize > 0 && $attachment['size'] > $maxFileSize) {
5308
            continue;
5309
        }
5310
5311
        $upload_ok = process_uploaded_file($attachment);
5312
5313
        if (!$upload_ok) {
5314
            continue;
5315
        }
5316
5317
        $course_dir = $_course['path'].'/upload/forum';
5318
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
5319
        $updir = $sys_course_path.$course_dir;
5320
5321
        // Try to add an extension to the file if it hasn't one.
5322
        $new_file_name = add_ext_on_mime(
5323
            stripslashes($attachment['name']),
5324
            $attachment['type']
5325
        );
5326
        // User's file name
5327
        $file_name = $attachment['name'];
5328
5329
        if (!filter_extension($new_file_name)) {
5330
            Display::addFlash(
5331
                Display::return_message(
5332
                    get_lang('UplUnableToSaveFileFilteredExtension'),
5333
                    'error'
5334
                )
5335
            );
5336
5337
            return;
5338
        }
5339
5340
        $new_file_name = uniqid('');
5341
        $new_path = $updir.'/'.$new_file_name;
5342
        $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5343
        $safe_file_comment = Database::escape_string($file_comment);
5344
        $safe_file_name = Database::escape_string($file_name);
5345
        $safe_new_file_name = Database::escape_string($new_file_name);
5346
        $last_id = intval($last_id);
5347
        // Storing the attachments if any.
5348
        if (!$result) {
5349
            return;
5350
        }
5351
5352
        $last_id_file = Database::insert(
5353
            $agenda_forum_attachment,
5354
            [
5355
                'c_id' => api_get_course_int_id(),
5356
                'filename' => $safe_file_name,
5357
                'comment' => $safe_file_comment,
5358
                'path' => $safe_new_file_name,
5359
                'post_id' => $last_id,
5360
                'size' => intval($attachment['size']),
5361
            ]
5362
        );
5363
5364
        api_item_property_update(
5365
            $_course,
5366
            TOOL_FORUM_ATTACH,
5367
            $last_id_file,
5368
            'ForumAttachmentAdded',
5369
            api_get_user_id()
5370
        );
5371
    }
5372
}
5373
5374
/**
5375
 * This function edits an attachment file into a forum.
5376
 *
5377
 * @param string $file_comment a comment about file
5378
 * @param int    $post_id
5379
 * @param int    $id_attach    attachment file Id
5380
 */
5381
function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
5382
{
5383
    $_course = api_get_course_info();
5384
    $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5385
    $course_id = api_get_course_int_id();
5386
5387
    $filesData = [];
5388
5389
    if (!is_array($_FILES['user_upload']['name'])) {
5390
        $filesData[] = $_FILES['user_upload'];
5391
    } else {
5392
        $fileCount = count($_FILES['user_upload']['name']);
5393
        $fileKeys = array_keys($_FILES['user_upload']);
5394
5395
        for ($i = 0; $i < $fileCount; $i++) {
5396
            foreach ($fileKeys as $key) {
5397
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
5398
            }
5399
        }
5400
    }
5401
5402
    $maxFileSize = getIniMaxFileSizeInBytes();
5403
    foreach ($filesData as $attachment) {
5404
        if (empty($attachment['name'])) {
5405
            continue;
5406
        }
5407
5408
        if ($maxFileSize > 0 && $attachment['size'] > $maxFileSize) {
5409
            continue;
5410
        }
5411
5412
        $upload_ok = process_uploaded_file($attachment);
5413
        if (!$upload_ok) {
5414
            continue;
5415
        }
5416
5417
        $course_dir = $_course['path'].'/upload/forum';
5418
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
5419
        $updir = $sys_course_path.$course_dir;
5420
5421
        // Try to add an extension to the file if it hasn't one.
5422
        $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
5423
        // User's file name
5424
        $file_name = $attachment['name'];
5425
5426
        if (!filter_extension($new_file_name)) {
5427
            Display::addFlash(
5428
                Display::return_message(
5429
                    get_lang('UplUnableToSaveFileFilteredExtension'),
5430
                    'error'
5431
                )
5432
            );
5433
        } else {
5434
            $new_file_name = uniqid('');
5435
            $new_path = $updir.'/'.$new_file_name;
5436
            $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5437
            $safe_file_comment = Database::escape_string($file_comment);
5438
            $safe_file_name = Database::escape_string($file_name);
5439
            $safe_new_file_name = Database::escape_string($new_file_name);
5440
            $safe_post_id = (int) $post_id;
5441
            $safe_id_attach = (int) $id_attach;
5442
            // Storing the attachments if any.
5443
            if ($result) {
5444
                $sql = "UPDATE $table_forum_attachment
5445
                        SET
5446
                            filename = '$safe_file_name',
5447
                            comment = '$safe_file_comment',
5448
                            path = '$safe_new_file_name',
5449
                            post_id = '$safe_post_id',
5450
                            size ='".$attachment['size']."'
5451
                        WHERE c_id = $course_id AND id = '$safe_id_attach'";
5452
                Database::query($sql);
5453
                api_item_property_update(
5454
                    $_course,
5455
                    TOOL_FORUM_ATTACH,
5456
                    $safe_id_attach,
5457
                    'ForumAttachmentUpdated',
5458
                    api_get_user_id()
5459
                );
5460
            }
5461
        }
5462
    }
5463
}
5464
5465
/**
5466
 * Show a list with all the attachments according to the post's id.
5467
 *
5468
 * @param int $postId
5469
 *
5470
 * @return array with the post info
5471
 *
5472
 * @author Julio Montoya
5473
 *
5474
 * @version avril 2008, dokeos 1.8.5
5475
 */
5476
function get_attachment($postId)
5477
{
5478
    $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5479
    $course_id = api_get_course_int_id();
5480
    $row = [];
5481
    $postId = (int) $postId;
5482
5483
    if (empty($postId)) {
5484
        return [];
5485
    }
5486
5487
    $sql = "SELECT iid, path, filename, comment
5488
            FROM $table
5489
            WHERE c_id = $course_id AND post_id = $postId";
5490
    $result = Database::query($sql);
5491
    if (Database::num_rows($result) != 0) {
5492
        $row = Database::fetch_array($result);
5493
    }
5494
5495
    return $row;
5496
}
5497
5498
/**
5499
 * @param int $postId
5500
 *
5501
 * @return array
5502
 */
5503
function getAllAttachment($postId)
5504
{
5505
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5506
    $courseId = api_get_course_int_id();
5507
    $postId = (int) $postId;
5508
5509
    if (empty($postId)) {
5510
        return [];
5511
    }
5512
5513
    $columns = ['iid', 'path', 'filename', 'comment'];
5514
    $conditions = [
5515
        'where' => [
5516
            'c_id = ? AND post_id = ?' => [$courseId, $postId],
5517
        ],
5518
    ];
5519
    $array = Database::select(
5520
        $columns,
5521
        $forumAttachmentTable,
5522
        $conditions,
5523
        'all',
5524
        'ASSOC'
5525
    );
5526
5527
    return $array;
5528
}
5529
5530
/**
5531
 * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
5532
 *
5533
 * @param int $post_id
5534
 * @param int $id_attach
5535
 *
5536
 * @return int
5537
 *
5538
 * @author Julio Montoya
5539
 *
5540
 * @version october 2014, chamilo 1.9.8
5541
 */
5542
function delete_attachment($post_id, $id_attach = 0)
5543
{
5544
    $_course = api_get_course_info();
5545
5546
    $forum_table_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5547
    $course_id = api_get_course_int_id();
5548
5549
    $cond = (!empty($id_attach)) ? " iid = ".(int) $id_attach."" : " post_id = ".(int) $post_id."";
5550
    $sql = "SELECT path FROM $forum_table_attachment WHERE c_id = $course_id AND $cond";
5551
    $res = Database::query($sql);
5552
    $row = Database::fetch_array($res);
5553
5554
    $course_dir = $_course['path'].'/upload/forum';
5555
    $sys_course_path = api_get_path(SYS_COURSE_PATH);
5556
    $updir = $sys_course_path.$course_dir;
5557
    $my_path = isset($row['path']) ? $row['path'] : null;
5558
    $file = $updir.'/'.$my_path;
5559
    if (Security::check_abs_path($file, $updir)) {
5560
        @unlink($file);
5561
    }
5562
5563
    // Delete from forum_attachment table.
5564
    $sql = "DELETE FROM $forum_table_attachment
5565
            WHERE c_id = $course_id AND $cond ";
5566
    $result = Database::query($sql);
5567
    if ($result !== false) {
5568
        $affectedRows = Database::affected_rows($result);
5569
    } else {
5570
        $affectedRows = 0;
5571
    }
5572
5573
    // Update item_property.
5574
    api_item_property_update(
5575
        $_course,
5576
        TOOL_FORUM_ATTACH,
5577
        $id_attach,
5578
        'ForumAttachmentDelete',
5579
        api_get_user_id()
5580
    );
5581
5582
    if (!empty($result) && !empty($id_attach)) {
5583
        Display::addFlash(Display::return_message(get_lang('AttachmentFileDeleteSuccess'), 'confirmation'));
5584
    }
5585
5586
    return $affectedRows;
5587
}
5588
5589
/**
5590
 * This function gets all the forum information of the all the forum of the group.
5591
 *
5592
 * @param array $groupInfo the id of the group we need the fora of (see forum.forum_of_group)
5593
 *
5594
 * @return array
5595
 *
5596
 * @todo this is basically the same code as the get_forums function. Consider merging the two.
5597
 */
5598
function get_forums_of_group($groupInfo)
5599
{
5600
    $table_forums = Database::get_course_table(TABLE_FORUM);
5601
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
5602
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5603
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
5604
    $course_id = api_get_course_int_id();
5605
    $groupId = (int) $groupInfo['id'];
5606
5607
    // Student
5608
    // Select all the forum information of all forums (that are visible to students).
5609
    $sql = "SELECT * FROM $table_forums forum
5610
            INNER JOIN $table_item_property item_properties
5611
            ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5612
            WHERE
5613
                forum.forum_of_group = $groupId AND
5614
                forum.c_id = $course_id AND
5615
                item_properties.c_id = $course_id AND
5616
                item_properties.visibility = 1 AND
5617
                item_properties.tool = '".TOOL_FORUM."'
5618
            ORDER BY forum.forum_order ASC";
5619
5620
    // Select the number of threads of the forums (only the threads that are visible).
5621
    $sql2 = "SELECT
5622
                count(thread_id) AS number_of_threads,
5623
                threads.forum_id
5624
            FROM $table_threads threads
5625
            INNER JOIN $table_item_property item_properties
5626
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5627
            WHERE
5628
                threads.c_id = $course_id AND
5629
                item_properties.c_id = $course_id AND
5630
                item_properties.visibility = 1 AND
5631
                item_properties.tool='".TOOL_FORUM_THREAD."'
5632
            GROUP BY threads.forum_id";
5633
5634
    // Select the number of posts of the forum (post that are visible and that are in a thread that is visible).
5635
    $sql3 = "SELECT count(post_id) AS number_of_posts, posts.forum_id
5636
            FROM $table_posts posts
5637
            INNER JOIN $table_threads threads
5638
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
5639
            INNER JOIN $table_item_property item_properties
5640
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5641
            WHERE
5642
                posts.visible=1 AND
5643
                posts.c_id = $course_id AND
5644
                item_properties.c_id = $course_id AND
5645
                threads.c_id = $course_id AND
5646
                item_properties.visibility = 1 AND
5647
                item_properties.tool='".TOOL_FORUM_THREAD."'
5648
            GROUP BY threads.forum_id";
5649
5650
    // Course Admin
5651
    if (api_is_allowed_to_edit()) {
5652
        // Select all the forum information of all forums (that are not deleted).
5653
        $sql = "SELECT *
5654
                FROM $table_forums forum
5655
                INNER JOIN $table_item_property item_properties
5656
                ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5657
                WHERE
5658
                    forum.forum_of_group = $groupId AND
5659
                    forum.c_id = $course_id AND
5660
                    item_properties.c_id = $course_id AND
5661
                    item_properties.visibility <> 2 AND
5662
                    item_properties.tool = '".TOOL_FORUM."'
5663
                ORDER BY forum_order ASC";
5664
5665
        // Select the number of threads of the forums (only the threads that are not deleted).
5666
        $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id
5667
                 FROM $table_threads threads
5668
                 INNER JOIN $table_item_property item_properties
5669
                 ON (threads.thread_id=item_properties.ref AND item_properties.c_id = threads.c_id)
5670
                 WHERE
5671
                    threads.c_id = $course_id AND
5672
                    item_properties.c_id = $course_id AND
5673
                    item_properties.visibility <> 2 AND
5674
                    item_properties.tool='".TOOL_FORUM_THREAD."'
5675
                GROUP BY threads.forum_id";
5676
        // Select the number of posts of the forum.
5677
        $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id
5678
                FROM $table_posts
5679
                WHERE c_id = $course_id
5680
                GROUP BY forum_id";
5681
    }
5682
5683
    // Handling all the forum information.
5684
    $result = Database::query($sql);
5685
    $forum_list = [];
5686
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5687
        $forum_list[$row['forum_id']] = $row;
5688
    }
5689
5690
    // Handling the thread count information.
5691
    $result2 = Database::query($sql2);
5692
    while ($row2 = Database::fetch_array($result2, 'ASSOC')) {
5693
        if (is_array($forum_list)) {
5694
            if (array_key_exists($row2['forum_id'], $forum_list)) {
5695
                $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
5696
            }
5697
        }
5698
    }
5699
5700
    // Handling the post count information.
5701
    $result3 = Database::query($sql3);
5702
    while ($row3 = Database::fetch_array($result3, 'ASSOC')) {
5703
        if (is_array($forum_list)) {
5704
            if (array_key_exists($row3['forum_id'], $forum_list)) {
5705
                // This is needed because sql3 takes also the deleted forums into account.
5706
                $forum_list[$row3['forum_id']]['number_of_posts'] = $row3['number_of_posts'];
5707
            }
5708
        }
5709
    }
5710
5711
    // Finding the last post information
5712
    // (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname).
5713
    if (!empty($forum_list)) {
5714
        foreach ($forum_list as $key => $value) {
5715
            $lastPost = get_last_post_information($key, api_is_allowed_to_edit());
5716
            if ($lastPost) {
5717
                $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
5718
                $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
5719
                $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
5720
                $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
5721
                $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
5722
                $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
5723
            }
5724
        }
5725
    }
5726
5727
    return $forum_list;
5728
}
5729
5730
/**
5731
 * This function stores which users have to be notified of which forums or threads.
5732
 *
5733
 * @param string $content    does the user want to be notified about a forum or about a thread
5734
 * @param int    $id         the id of the forum or thread
5735
 * @param bool   $addOnly
5736
 * @param array  $userInfo
5737
 * @param array  $courseInfo
5738
 *
5739
 * @return string language variable
5740
 *
5741
 * @author  Patrick Cool <[email protected]>, Ghent University, Belgium
5742
 * @author  Julio Montoya
5743
 *
5744
 * @since   May 2008 v1.8.5
5745
 */
5746
function set_notification($content, $id, $addOnly = false, $userInfo = [], $courseInfo = [])
5747
{
5748
    $userInfo = empty($userInfo) ? api_get_user_info() : $userInfo;
5749
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
5750
    $id = (int) $id;
5751
5752
    if (empty($userInfo) || empty($courseInfo) || empty($id) || empty($content)) {
5753
        return false;
5754
    }
5755
5756
    // Database table definition
5757
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5758
5759
    $course_id = $courseInfo['real_id'];
5760
5761
    // Which database field do we have to store the id in?
5762
    $field = 'thread_id';
5763
    if ($content === 'forum') {
5764
        $field = 'forum_id';
5765
    }
5766
5767
    $userId = $userInfo['user_id'];
5768
5769
    // First we check if the notification is already set for this.
5770
    $sql = "SELECT * FROM $table_notification
5771
            WHERE
5772
                c_id = $course_id AND
5773
                $field = $id AND
5774
                user_id = $userId ";
5775
    $result = Database::query($sql);
5776
    $total = Database::num_rows($result);
5777
5778
    // If the user did not indicate that (s)he wanted to be notified already
5779
    // then we store the notification request (to prevent double notification requests).
5780
    if ($total <= 0) {
5781
        $sql = "INSERT INTO $table_notification (c_id, $field, user_id)
5782
                VALUES ($course_id, '$id','$userId')";
5783
        Database::query($sql);
5784
        Session::erase('forum_notification');
5785
        getNotificationsPerUser(0, true);
5786
5787
        return get_lang('YouWillBeNotifiedOfNewPosts');
5788
    } else {
5789
        if (!$addOnly) {
5790
            $sql = "DELETE FROM $table_notification
5791
                    WHERE
5792
                        c_id = $course_id AND
5793
                        $field = $id AND
5794
                        user_id = $userId ";
5795
            Database::query($sql);
5796
            Session::erase('forum_notification');
5797
            getNotificationsPerUser(0, true);
5798
5799
            return get_lang('YouWillNoLongerBeNotifiedOfNewPosts');
5800
        }
5801
    }
5802
}
5803
5804
/**
5805
 * This function retrieves all the email adresses of the users who wanted to be notified
5806
 * about a new post in a certain forum or thread.
5807
 *
5808
 * @param string $content does the user want to be notified about a forum or about a thread
5809
 * @param int    $id      the id of the forum or thread
5810
 *
5811
 * @return array returns
5812
 *
5813
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5814
 * @author Julio Montoya
5815
 *
5816
 * @version May 2008, dokeos 1.8.5
5817
 *
5818
 * @since May 2008, dokeos 1.8.5
5819
 */
5820
function get_notifications($content, $id)
5821
{
5822
    // Database table definition
5823
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5824
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5825
    $course_id = api_get_course_int_id();
5826
5827
    // Which database field contains the notification?
5828
    $field = 'thread_id';
5829
    if ($content === 'forum') {
5830
        $field = 'forum_id';
5831
    }
5832
5833
    $id = (int) $id;
5834
5835
    $sql = "SELECT user.user_id, user.firstname, user.lastname, user.email, user.user_id user
5836
            FROM $table_users user, $table_notification notification
5837
            WHERE
5838
                notification.c_id = $course_id AND user.active = 1 AND
5839
                user.user_id = notification.user_id AND
5840
                notification.$field = $id ";
5841
5842
    $result = Database::query($sql);
5843
    $return = [];
5844
5845
    while ($row = Database::fetch_array($result)) {
5846
        $return['user'.$row['user_id']] = ['email' => $row['email'], 'user_id' => $row['user_id']];
5847
    }
5848
5849
    return $return;
5850
}
5851
5852
/**
5853
 * Get all the users who need to receive a notification of a new post (those subscribed to
5854
 * the forum or the thread).
5855
 *
5856
 * @param int $forum_id  the id of the forum
5857
 * @param int $thread_id the id of the thread
5858
 * @param int $post_id   the id of the post
5859
 *
5860
 * @return false|null
5861
 *
5862
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5863
 *
5864
 * @version May 2008, dokeos 1.8.5
5865
 *
5866
 * @since May 2008, dokeos 1.8.5
5867
 */
5868
function send_notifications($forum_id = 0, $thread_id = 0, $post_id = 0)
5869
{
5870
    $forum_id = (int) $forum_id;
5871
    // Users who subscribed to the forum
5872
    if ($forum_id != 0) {
5873
        $users_to_be_notified_by_forum = get_notifications('forum', $forum_id);
5874
    } else {
5875
        return false;
5876
    }
5877
5878
    $current_thread = get_thread_information($forum_id, $thread_id);
5879
    $courseInfo = api_get_course_info_by_id($current_thread['c_id']);
5880
5881
    // User who subscribed to the thread
5882
    if ($thread_id != 0) {
5883
        $users_to_be_notified_by_thread = get_notifications('thread', $thread_id);
5884
    }
5885
5886
    $postInfo = [];
5887
    if (!empty($post_id)) {
5888
        $postInfo = get_post_information($post_id);
5889
    }
5890
5891
    // Merging the two
5892
    $users_to_be_notified = array_merge($users_to_be_notified_by_forum, $users_to_be_notified_by_thread);
5893
    $forumInfo = get_forum_information($forum_id);
5894
5895
    if (is_array($users_to_be_notified)) {
5896
        foreach ($users_to_be_notified as $value) {
5897
            $notifyUser = true;
5898
            $shareForumsInSessions = api_get_course_setting('share_forums_in_sessions', $courseInfo);
5899
            if (($shareForumsInSessions === -1 || !$shareForumsInSessions) && $current_thread['session_id'] != 0) {
5900
                $notifyUser = false;
5901
                $userSessions = SessionManager::get_sessions_by_user($value['user_id']);
5902
                foreach ($userSessions as $userSession) {
5903
                    if ($userSession['session_id'] == $current_thread['session_id']) {
5904
                        $notifyUser = true;
5905
                    }
5906
                }
5907
            }
5908
            if ($notifyUser === true) {
5909
                $userInfo = api_get_user_info($value['user_id']);
5910
                send_mail($userInfo, $forumInfo, $current_thread, $postInfo);
5911
            }
5912
        }
5913
    }
5914
}
5915
5916
/**
5917
 * Get all the notification subscriptions of the user
5918
 * = which forums and which threads does the user wants to be informed of when a new
5919
 * post is added to this thread.
5920
 *
5921
 * @param int  $user_id the user_id of a user (default = 0 => the current user)
5922
 * @param bool $force   force get the notification subscriptions (even if the information is already in the session
5923
 *
5924
 * @return array
5925
 *
5926
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5927
 *
5928
 * @version May 2008, dokeos 1.8.5
5929
 *
5930
 * @since May 2008, dokeos 1.8.5
5931
 */
5932
function getNotificationsPerUser($user_id = 0, $force = false, $course_id = 0)
5933
{
5934
    // Database table definition
5935
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5936
    $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
5937
    if (empty($course_id) || $course_id == -1) {
5938
        return null;
5939
    }
5940
5941
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
5942
5943
    if (!isset($_SESSION['forum_notification']) ||
5944
        $_SESSION['forum_notification']['course'] != $course_id ||
5945
        $force == true
5946
    ) {
5947
        $_SESSION['forum_notification']['course'] = $course_id;
5948
        $sql = "SELECT * FROM $table_notification
5949
                WHERE c_id = $course_id AND user_id='".$user_id."'";
5950
5951
        $result = Database::query($sql);
5952
        while ($row = Database::fetch_array($result)) {
5953
            if (!is_null($row['forum_id'])) {
5954
                $_SESSION['forum_notification']['forum'][] = $row['forum_id'];
5955
            }
5956
            if (!is_null($row['thread_id'])) {
5957
                $_SESSION['forum_notification']['thread'][] = $row['thread_id'];
5958
            }
5959
        }
5960
    }
5961
}
5962
5963
/**
5964
 * This function counts the number of post inside a thread.
5965
 *
5966
 * @param int $thread_id
5967
 *
5968
 * @return int the number of post inside a thread
5969
 *
5970
 * @author Jhon Hinojosa <[email protected]>,
5971
 *
5972
 * @version octubre 2008, dokeos 1.8
5973
 */
5974
function count_number_of_post_in_thread($thread_id)
5975
{
5976
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5977
    $course_id = api_get_course_int_id();
5978
    if (empty($course_id)) {
5979
        return 0;
5980
    }
5981
    $sql = "SELECT count(*) count FROM $table_posts
5982
            WHERE
5983
                c_id = $course_id AND
5984
                thread_id='".intval($thread_id)."' ";
5985
    $result = Database::query($sql);
5986
5987
    $count = 0;
5988
    if (Database::num_rows($result) > 0) {
5989
        $row = Database::fetch_array($result);
5990
        $count = $row['count'];
5991
    }
5992
5993
    return $count;
5994
}
5995
5996
/**
5997
 * This function counts the number of post inside a thread user.
5998
 *
5999
 * @param int $thread_id
6000
 * @param int $user_id
6001
 *
6002
 * @return int the number of post inside a thread user
6003
 */
6004
function count_number_of_post_for_user_thread($thread_id, $user_id)
6005
{
6006
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
6007
    $course_id = api_get_course_int_id();
6008
    $sql = "SELECT count(iid) as count
6009
            FROM $table_posts
6010
            WHERE c_id = $course_id AND
6011
                  thread_id=".intval($thread_id)." AND
6012
                  poster_id = ".intval($user_id)." AND visible = 1 ";
6013
    $result = Database::query($sql);
6014
    $count = 0;
6015
    if (Database::num_rows($result) > 0) {
6016
        $count = Database::fetch_array($result);
6017
        $count = $count['count'];
6018
    }
6019
6020
    return $count;
6021
}
6022
6023
/**
6024
 * This function retrieves information of statistical.
6025
 *
6026
 * @param int $thread_id
6027
 * @param int $user_id
6028
 * @param int $course_id
6029
 *
6030
 * @return array the information of statistical
6031
 *
6032
 * @author Jhon Hinojosa <[email protected]>,
6033
 *
6034
 * @version oct 2008, dokeos 1.8
6035
 */
6036
function get_statistical_information($thread_id, $user_id, $course_id)
6037
{
6038
    $result = [];
6039
    $courseInfo = api_get_course_info_by_id($course_id);
6040
    $result['user_course'] = CourseManager::get_users_count_in_course($courseInfo['code']);
6041
    $result['post'] = count_number_of_post_in_thread($thread_id);
6042
    $result['user_post'] = count_number_of_post_for_user_thread($thread_id, $user_id);
6043
6044
    return $result;
6045
}
6046
6047
/**
6048
 * This function return the posts inside a thread from a given user.
6049
 *
6050
 * @param string $course_code
6051
 * @param int    $thread_id
6052
 * @param int    $user_id
6053
 *
6054
 * @return array posts inside a thread
6055
 *
6056
 * @author Jhon Hinojosa <[email protected]>,
6057
 *
6058
 * @version oct 2008, dokeos 1.8
6059
 */
6060
function get_thread_user_post($course_code, $thread_id, $user_id)
6061
{
6062
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
6063
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
6064
    $thread_id = intval($thread_id);
6065
    $user_id = intval($user_id);
6066
    $course_info = api_get_user_info($course_code);
6067
    $course_id = $course_info['real_id'];
6068
6069
    if (empty($course_id)) {
6070
        $course_id = api_get_course_int_id();
6071
    }
6072
    $sql = "SELECT * FROM $table_posts posts
6073
            LEFT JOIN  $table_users users
6074
                ON posts.poster_id=users.user_id
6075
            WHERE
6076
                posts.c_id = $course_id AND
6077
                posts.thread_id='$thread_id'
6078
                AND posts.poster_id='$user_id'
6079
            ORDER BY posts.post_id ASC";
6080
6081
    $result = Database::query($sql);
6082
    $post_list = [];
6083
    while ($row = Database::fetch_array($result)) {
6084
        $row['status'] = '1';
6085
        $post_list[] = $row;
6086
        $sql = "SELECT * FROM $table_posts posts
6087
                LEFT JOIN $table_users users
6088
                ON (posts.poster_id=users.user_id)
6089
                WHERE
6090
                    posts.c_id = $course_id AND
6091
                    posts.thread_id='$thread_id'
6092
                    AND posts.post_parent_id='".$row['post_id']."'
6093
                ORDER BY posts.post_id ASC";
6094
        $result2 = Database::query($sql);
6095
        while ($row2 = Database::fetch_array($result2)) {
6096
            $row2['status'] = '0';
6097
            $post_list[] = $row2;
6098
        }
6099
    }
6100
6101
    return $post_list;
6102
}
6103
6104
/**
6105
 * This function get the name of an thread by id.
6106
 *
6107
 * @param int thread_id
6108
 *
6109
 * @return string
6110
 *
6111
 * @author Christian Fasanando
6112
 * @author Julio Montoya <[email protected]> Adding security
6113
 */
6114
function get_name_thread_by_id($thread_id)
6115
{
6116
    $t_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
6117
    $course_id = api_get_course_int_id();
6118
    $sql = "SELECT thread_title
6119
            FROM $t_forum_thread
6120
            WHERE c_id = $course_id AND thread_id = '".intval($thread_id)."' ";
6121
    $result = Database::query($sql);
6122
    $row = Database::fetch_array($result);
6123
6124
    return $row[0];
6125
}
6126
6127
/**
6128
 * This function gets all the post written by an user.
6129
 *
6130
 * @param int    $user_id
6131
 * @param string $course_code
6132
 *
6133
 * @return string
6134
 */
6135
function get_all_post_from_user($user_id, $course_code)
6136
{
6137
    $j = 0;
6138
    $forums = get_forums('', $course_code);
6139
    krsort($forums);
6140
    $forum_results = '';
6141
6142
    foreach ($forums as $forum) {
6143
        if ($forum['visibility'] == 0) {
6144
            continue;
6145
        }
6146
        if ($j <= 4) {
6147
            $threads = get_threads($forum['forum_id']);
6148
6149
            if (is_array($threads)) {
6150
                $i = 0;
6151
                $hand_forums = '';
6152
                $post_counter = 0;
6153
                foreach ($threads as $thread) {
6154
                    if ($thread['visibility'] == 0) {
6155
                        continue;
6156
                    }
6157
                    if ($i <= 4) {
6158
                        $post_list = get_thread_user_post_limit(
6159
                            $course_code,
6160
                            $thread['thread_id'],
6161
                            $user_id,
6162
                            1
6163
                        );
6164
                        $post_counter = count($post_list);
6165
                        if (is_array($post_list) && count($post_list) > 0) {
6166
                            $hand_forums .= '<div id="social-thread">';
6167
                            $hand_forums .= Display::return_icon(
6168
                                'thread.png',
6169
                                get_lang('Thread'),
6170
                                '',
6171
                                ICON_SIZE_MEDIUM
6172
                            );
6173
                            $hand_forums .= '&nbsp;'.Security::remove_XSS($thread['thread_title'], STUDENT);
6174
                            $hand_forums .= '</div>';
6175
6176
                            foreach ($post_list as $posts) {
6177
                                $hand_forums .= '<div id="social-post">';
6178
                                $hand_forums .= '<strong>'.Security::remove_XSS($posts['post_title'], STUDENT).'</strong>';
6179
                                $hand_forums .= '<br / >';
6180
                                $hand_forums .= Security::remove_XSS($posts['post_text'], STUDENT);
6181
                                $hand_forums .= '</div>';
6182
                                $hand_forums .= '<br / >';
6183
                            }
6184
                        }
6185
                    }
6186
                    $i++;
6187
                }
6188
                $forum_results .= '<div id="social-forum">';
6189
                $forum_results .= '<div class="clear"></div><br />';
6190
                $forum_results .= '<div id="social-forum-title">'.
6191
                    Display::return_icon('forum.gif', get_lang('Forum')).'&nbsp;'.Security::remove_XSS($forum['forum_title'], STUDENT).
6192
                    '<div style="float:right;margin-top:-35px">
6193
                        <a href="../forum/viewforum.php?'.api_get_cidreq_params($course_code).'&forum='.$forum['forum_id'].' " >'.
6194
                    get_lang('SeeForum').'
6195
                        </a>
6196
                     </div></div>';
6197
                $forum_results .= '<br / >';
6198
                if ($post_counter > 0) {
6199
                    $forum_results .= $hand_forums;
6200
                }
6201
                $forum_results .= '</div>';
6202
            }
6203
            $j++;
6204
        }
6205
    }
6206
6207
    return $forum_results;
6208
}
6209
6210
/**
6211
 * @param string $course_code
6212
 * @param int    $thread_id
6213
 * @param int    $user_id
6214
 * @param int    $limit
6215
 *
6216
 * @return array
6217
 */
6218
function get_thread_user_post_limit($course_code, $thread_id, $user_id, $limit = 10)
6219
{
6220
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
6221
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
6222
6223
    $course_info = api_get_course_info($course_code);
6224
    $course_id = $course_info['real_id'];
6225
    $limit = (int) $limit;
6226
6227
    $sql = "SELECT * FROM $table_posts posts
6228
            LEFT JOIN  $table_users users
6229
                ON posts.poster_id=users.user_id
6230
            WHERE
6231
                posts.c_id = $course_id AND
6232
                posts.thread_id='".Database::escape_string($thread_id)."' AND
6233
                posts.poster_id='".Database::escape_string($user_id)."'
6234
            ORDER BY posts.post_id DESC
6235
            LIMIT $limit ";
6236
    $result = Database::query($sql);
6237
    $post_list = [];
6238
    while ($row = Database::fetch_array($result)) {
6239
        $row['status'] = '1';
6240
        $post_list[] = $row;
6241
    }
6242
6243
    return $post_list;
6244
}
6245
6246
/**
6247
 * @param string $userId
6248
 * @param array  $courseInfo
6249
 * @param int    $sessionId
6250
 *
6251
 * @return array
6252
 */
6253
function getForumCreatedByUser($userId, $courseInfo, $sessionId)
6254
{
6255
    if (empty($userId) || empty($courseInfo)) {
6256
        return [];
6257
    }
6258
6259
    $courseId = $courseInfo['real_id'];
6260
    $items = api_get_item_property_list_by_tool_by_user(
6261
        $userId,
6262
        'forum',
6263
        $courseId,
6264
        $sessionId
6265
    );
6266
6267
    $forumList = [];
6268
    if (!empty($items)) {
6269
        foreach ($items as $forum) {
6270
            $forumInfo = get_forums(
6271
                $forum['ref'],
6272
                $courseInfo['code'],
6273
                true,
6274
                $sessionId
6275
            );
6276
            if (!empty($forumInfo) && isset($forumInfo['forum_title'])) {
6277
                $forumList[] = [
6278
                    $forumInfo['forum_title'],
6279
                    api_get_local_time($forum['insert_date']),
6280
                    api_get_local_time($forum['lastedit_date']),
6281
                ];
6282
            }
6283
        }
6284
    }
6285
6286
    return $forumList;
6287
}
6288
6289
/**
6290
 * This function builds an array of all the posts in a given thread
6291
 * where the key of the array is the post_id
6292
 * It also adds an element children to the array which itself is an array
6293
 * that contains all the id's of the first-level children.
6294
 *
6295
 * @return array $rows containing all the information on the posts of a thread
6296
 *
6297
 * @author Patrick Cool <[email protected]>, Ghent University
6298
 */
6299
function calculate_children($rows)
6300
{
6301
    $sorted_rows = [0 => []];
6302
    if (!empty($rows)) {
6303
        foreach ($rows as $row) {
6304
            $rows_with_children[$row['post_id']] = $row;
6305
            $rows_with_children[$row['post_parent_id']]['children'][] = $row['post_id'];
6306
        }
6307
6308
        $rows = $rows_with_children;
6309
        forumRecursiveSort($rows, $sorted_rows);
6310
        unset($sorted_rows[0]);
6311
    }
6312
6313
    return $sorted_rows;
6314
}
6315
6316
/**
6317
 * @param $rows
6318
 * @param $threads
6319
 * @param int $seed
6320
 * @param int $indent
6321
 */
6322
function forumRecursiveSort($rows, &$threads, $seed = 0, $indent = 0)
6323
{
6324
    if ($seed > 0) {
6325
        $threads[$rows[$seed]['post_id']] = $rows[$seed];
6326
        $threads[$rows[$seed]['post_id']]['indent_cnt'] = $indent;
6327
        $indent++;
6328
    }
6329
6330
    if (isset($rows[$seed]['children'])) {
6331
        foreach ($rows[$seed]['children'] as $child) {
6332
            forumRecursiveSort($rows, $threads, $child, $indent);
6333
        }
6334
    }
6335
}
6336
6337
/**
6338
 * Update forum attachment data, used to update comment and post ID.
6339
 *
6340
 * @param $array array (field => value) to update forum attachment row
6341
 * @param $id attach ID to find row to update
6342
 * @param null $courseId course ID to find row to update
6343
 *
6344
 * @return int number of affected rows
6345
 */
6346
function editAttachedFile($array, $id, $courseId = null)
6347
{
6348
    // Init variables
6349
    $setString = '';
6350
    $id = (int) $id;
6351
    $courseId = (int) $courseId;
6352
    if (empty($courseId)) {
6353
        // $courseId can be null, use api method
6354
        $courseId = api_get_course_int_id();
6355
    }
6356
    /*
6357
     * Check if Attachment ID and Course ID are greater than zero
6358
     * and array of field values is not empty
6359
     */
6360
    if ($id > 0 && $courseId > 0 && !empty($array) && is_array($array)) {
6361
        foreach ($array as $key => &$item) {
6362
            $item = Database::escape_string($item);
6363
            $setString .= $key.' = "'.$item.'", ';
6364
        }
6365
        // Delete last comma
6366
        $setString = substr($setString, 0, strlen($setString) - 2);
6367
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6368
        $sql = "UPDATE $forumAttachmentTable
6369
                SET $setString WHERE c_id = $courseId AND id = $id";
6370
        $result = Database::query($sql);
6371
        if ($result !== false) {
6372
            $affectedRows = Database::affected_rows($result);
6373
            if ($affectedRows > 0) {
6374
                /*
6375
                 * If exist in $_SESSION variable, then delete them from it
6376
                 * because they would be deprecated
6377
                 */
6378
                if (!empty($_SESSION['forum']['upload_file'][$courseId][$id])) {
6379
                    unset($_SESSION['forum']['upload_file'][$courseId][$id]);
6380
                }
6381
            }
6382
6383
            return $affectedRows;
6384
        }
6385
    }
6386
6387
    return 0;
6388
}
6389
6390
/**
6391
 * Return a table where the attachments will be set.
6392
 *
6393
 * @param int $postId Forum Post ID
6394
 *
6395
 * @return string The Forum Attachments Ajax Table
6396
 */
6397
function getAttachmentsAjaxTable($postId = 0)
6398
{
6399
    $postId = (int) $postId;
6400
    $courseId = api_get_course_int_id();
6401
    $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6402
    $fileDataContent = '';
6403
    // Update comment to show if form did not pass validation
6404
    if (!empty($_REQUEST['file_ids']) && is_array($_REQUEST['file_ids'])) {
6405
        // 'file_ids is the name from forum attachment ajax form
6406
        foreach ($_REQUEST['file_ids'] as $key => $attachId) {
6407
            if (!empty($_SESSION['forum']['upload_file'][$courseId][$attachId]) &&
6408
                is_array($_SESSION['forum']['upload_file'][$courseId][$attachId])
6409
            ) {
6410
                // If exist forum attachment then update into $_SESSION data
6411
                $_SESSION['forum']['upload_file'][$courseId][$attachId]['comment'] = $_POST['file_comments'][$key];
6412
            }
6413
        }
6414
    }
6415
6416
    // Get data to fill into attachment files table
6417
    if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6418
        is_array($_SESSION['forum']['upload_file'][$courseId])
6419
    ) {
6420
        $uploadedFiles = $_SESSION['forum']['upload_file'][$courseId];
6421
        foreach ($uploadedFiles as $k => $uploadedFile) {
6422
            if (!empty($uploadedFile) && in_array($uploadedFile['id'], $attachIds)) {
6423
                // Buil html table including an input with attachmentID
6424
                $fileDataContent .= '<tr id="'.$uploadedFile['id'].'" ><td>'.$uploadedFile['name'].'</td><td>'.$uploadedFile['size'].'</td><td>&nbsp;'.$uploadedFile['result'].
6425
                    ' </td><td> <input style="width:90%;" type="text" value="'.$uploadedFile['comment'].'" name="file_comments[]"> </td><td>'.
6426
                    $uploadedFile['delete'].'</td>'.
6427
                    '<input type="hidden" value="'.$uploadedFile['id'].'" name="file_ids[]">'.'</tr>';
6428
            } else {
6429
                /*
6430
                 * If attachment data is empty, then delete it from $_SESSION
6431
                 * because could generate and empty row into html table
6432
                 */
6433
                unset($_SESSION['forum']['upload_file'][$courseId][$k]);
6434
            }
6435
        }
6436
    }
6437
    $style = empty($fileDataContent) ? 'display: none;' : '';
6438
    // Forum attachment Ajax table
6439
    $fileData = '
6440
    <div class="control-group " style="'.$style.'">
6441
        <label class="control-label">'.get_lang('AttachmentList').'</label>
6442
        <div class="controls">
6443
            <table id="attachmentFileList" class="files table table-hover table-striped data_table span10">
6444
                <tr>
6445
                    <th>'.get_lang('FileName').'</th>
6446
                    <th>'.get_lang('Size').'</th>
6447
                    <th>'.get_lang('Status').'</th>
6448
                    <th>'.get_lang('Comment').'</th>
6449
                    <th>'.get_lang('Delete').'</th>
6450
                </tr>
6451
                '.$fileDataContent.'
6452
            </table>
6453
        </div>
6454
    </div>';
6455
6456
    return $fileData;
6457
}
6458
6459
/**
6460
 * Return an array of prepared attachment data to build forum attachment table
6461
 * Also, save this array into $_SESSION to do available the attachment data.
6462
 *
6463
 * @param int $forumId
6464
 * @param int $threadId
6465
 * @param int $postId
6466
 * @param int $attachId
6467
 * @param int $courseId
6468
 *
6469
 * @return array
6470
 */
6471
function getAttachedFiles(
6472
    $forumId,
6473
    $threadId,
6474
    $postId = 0,
6475
    $attachId = 0,
6476
    $courseId = 0
6477
) {
6478
    $forumId = (int) $forumId;
6479
    $courseId = (int) $courseId;
6480
    $attachId = (int) $attachId;
6481
    $postId = (int) $postId;
6482
    $threadId = (int) $threadId;
6483
6484
    if (empty($courseId)) {
6485
        // $courseId can be null, use api method
6486
        $courseId = api_get_course_int_id();
6487
    }
6488
    if (empty($forumId)) {
6489
        if (!empty($_REQUEST['forum'])) {
6490
            $forumId = (int) $_REQUEST['forum'];
6491
        } else {
6492
            // if forum ID is empty, cannot generate delete url
6493
6494
            return [];
6495
        }
6496
    }
6497
    // Check if exist at least one of them to filter forum attachment select query
6498
    if (empty($postId) && empty($attachId)) {
6499
        return [];
6500
    } elseif (empty($postId)) {
6501
        $filter = "AND iid = $attachId";
6502
    } elseif (empty($attachId)) {
6503
        $filter = "AND post_id = $postId";
6504
    } else {
6505
        $filter = "AND post_id = $postId AND iid = $attachId";
6506
    }
6507
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6508
    $sql = "SELECT iid, comment, filename, path, size
6509
            FROM $forumAttachmentTable
6510
            WHERE c_id = $courseId $filter";
6511
    $result = Database::query($sql);
6512
    $json = [];
6513
    if ($result !== false && Database::num_rows($result) > 0) {
6514
        while ($row = Database::fetch_array($result, 'ASSOC')) {
6515
            // name contains an URL to download attachment file and its filename
6516
            $json['filename'] = $row['filename'];
6517
            $json['path'] = $row['path'];
6518
            $json['name'] = Display::url(
6519
                api_htmlentities($row['filename']),
6520
                api_get_path(WEB_CODE_PATH).'forum/download.php?file='.$row['path'].'&'.api_get_cidreq(),
6521
                ['target' => '_blank', 'class' => 'attachFilename']
6522
            );
6523
            $json['id'] = $row['iid'];
6524
            $json['comment'] = $row['comment'];
6525
            // Format file size
6526
            $json['size'] = format_file_size($row['size']);
6527
            // Check if $row is consistent
6528
            if (!empty($row) && is_array($row)) {
6529
                // Set result as success and bring delete URL
6530
                $json['result'] = Display::return_icon('accept.png', get_lang('Uploaded'));
6531
                $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&action=delete_attach&forum='.$forumId.'&thread='.$threadId.'&id_attach='.$row['iid'];
6532
                $json['delete'] = Display::url(
6533
                    Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL),
6534
                    $url,
6535
                    ['class' => 'deleteLink']
6536
                );
6537
            } else {
6538
                // If not, set an exclamation result
6539
                $json['result'] = Display::return_icon('exclamation.png', get_lang('Error'));
6540
            }
6541
            // Store array data into $_SESSION
6542
            $_SESSION['forum']['upload_file'][$courseId][$json['id']] = $json;
6543
        }
6544
    }
6545
6546
    return $json;
6547
}
6548
6549
/**
6550
 * Clear forum attachment data stored in $_SESSION,
6551
 * If is not defined post, it will clear all forum attachment data from course.
6552
 *
6553
 * @param int $postId   -1 : Clear all attachments from course stored in $_SESSION
6554
 *                      0 : Clear attachments from course, except from temporal post "0"
6555
 *                      but without delete them from file system and database
6556
 *                      Other values : Clear attachments from course except specified post
6557
 *                      and delete them from file system and database
6558
 * @param int $courseId : Course ID, if it is null, will use api_get_course_int_id()
6559
 *
6560
 * @return array
6561
 */
6562
function clearAttachedFiles($postId = 0, $courseId = 0)
6563
{
6564
    // Init variables
6565
    $courseId = (int) $courseId;
6566
    $postId = (int) $postId;
6567
    $array = [];
6568
    if (empty($courseId)) {
6569
        // $courseId can be null, use api method
6570
        $courseId = api_get_course_int_id();
6571
    }
6572
    if ($postId === -1) {
6573
        // If post ID is -1 then delete course's attachment data from $_SESSION
6574
        if (!empty($_SESSION['forum']['upload_file'][$courseId])) {
6575
            $array = array_keys($_SESSION['forum']['upload_file'][$courseId]);
6576
            unset($_SESSION['forum']['upload_file'][$courseId]);
6577
        }
6578
    } else {
6579
        $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6580
        if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6581
            is_array($_SESSION['forum']['upload_file'][$courseId])) {
6582
            foreach ($_SESSION['forum']['upload_file'][$courseId] as $attachId => $attach) {
6583
                if (!in_array($attachId, $attachIds)) {
6584
                    // If attach ID is not into specified post, delete attachment
6585
                    // Save deleted attachment ID
6586
                    $array[] = $attachId;
6587
                    if ($postId !== 0) {
6588
                        // Post 0 is temporal, delete them from file system and DB
6589
                        delete_attachment(0, $attachId);
6590
                    }
6591
                    // Delete attachment data from $_SESSION
6592
                    unset($_SESSION['forum']['upload_file'][$courseId][$attachId]);
6593
                }
6594
            }
6595
        }
6596
    }
6597
6598
    return $array;
6599
}
6600
6601
/**
6602
 * Returns an array of forum attachment ids into a course and forum post.
6603
 *
6604
 * @param int $postId
6605
 * @param int $courseId
6606
 *
6607
 * @return array
6608
 */
6609
function getAttachmentIdsByPostId($postId, $courseId = 0)
6610
{
6611
    $array = [];
6612
    $courseId = (int) $courseId;
6613
    $postId = (int) $postId;
6614
    if (empty($courseId)) {
6615
        // $courseId can be null, use api method
6616
        $courseId = api_get_course_int_id();
6617
    }
6618
    if ($courseId > 0) {
6619
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6620
        $sql = "SELECT id FROM $forumAttachmentTable
6621
                WHERE c_id = $courseId AND post_id = $postId";
6622
        $result = Database::query($sql);
6623
        if ($result !== false && Database::num_rows($result) > 0) {
6624
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6625
                $array[] = $row['id'];
6626
            }
6627
        }
6628
    }
6629
6630
    return $array;
6631
}
6632
6633
/**
6634
 * Check if the forum category exists looking for its title.
6635
 *
6636
 * @param string $title     The forum category title
6637
 * @param int    $courseId  The course ID
6638
 * @param int    $sessionId Optional. The session ID
6639
 *
6640
 * @return bool
6641
 */
6642
function getForumCategoryByTitle($title, $courseId, $sessionId = 0)
6643
{
6644
    $sessionId = (int) $sessionId;
6645
    $courseId = (int) $courseId;
6646
    $forumCategoryTable = Database::get_course_table(TABLE_FORUM_CATEGORY);
6647
    $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6648
6649
    $fakeFrom = "$forumCategoryTable fc
6650
        INNER JOIN $itemProperty ip ";
6651
6652
    if ($sessionId === 0) {
6653
        $fakeFrom .= "
6654
            ON (
6655
                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)
6656
            )
6657
        ";
6658
    } else {
6659
        $fakeFrom .= "
6660
            ON (
6661
                fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND fc.session_id = ip.session_id
6662
            )
6663
        ";
6664
    }
6665
6666
    $resultData = Database::select(
6667
        'fc.*',
6668
        $fakeFrom,
6669
        [
6670
            'where' => [
6671
                'ip.visibility != ? AND ' => 2,
6672
                'ip.tool = ? AND ' => TOOL_FORUM_CATEGORY,
6673
                'fc.session_id = ? AND ' => $sessionId,
6674
                'fc.cat_title = ? AND ' => $title,
6675
                'fc.c_id = ?' => $courseId,
6676
            ],
6677
        ],
6678
        'first'
6679
    );
6680
6681
    if (empty($resultData)) {
6682
        return false;
6683
    }
6684
6685
    return $resultData;
6686
}
6687
6688
/**
6689
 * @param array $current_forum
6690
 * @param array $row
6691
 * @param bool  $addWrapper
6692
 *
6693
 * @return string
6694
 */
6695
function getPostStatus($current_forum, $row, $addWrapper = true)
6696
{
6697
    $statusIcon = '';
6698
    if ($current_forum['moderated']) {
6699
        if ($addWrapper) {
6700
            $statusIcon = '<br /><br /><span id="status_post_'.$row['iid'].'">';
6701
        }
6702
        $row['status'] = empty($row['status']) ? 2 : $row['status'];
6703
6704
        $addUrl = false;
6705
        $showStatus = false;
6706
        if (api_is_allowed_to_edit(false, true)) {
6707
            $addUrl = true;
6708
        } else {
6709
            if ($row['user_id'] == api_get_user_id()) {
6710
                $showStatus = true;
6711
            }
6712
        }
6713
6714
        $label = '';
6715
        $icon = '';
6716
        $buttonType = '';
6717
        switch ($row['status']) {
6718
            case CForumPost::STATUS_VALIDATED:
6719
                $label = get_lang('Validated');
6720
                $icon = 'check-circle';
6721
                $buttonType = 'success';
6722
                break;
6723
            case CForumPost::STATUS_WAITING_MODERATION:
6724
                $label = get_lang('WaitingModeration');
6725
                $icon = 'warning';
6726
                $buttonType = 'warning';
6727
                break;
6728
            case CForumPost::STATUS_REJECTED:
6729
                $label = get_lang('Rejected');
6730
                $icon = 'minus-circle';
6731
                $buttonType = 'danger';
6732
                break;
6733
        }
6734
6735
        if ($addUrl) {
6736
            $statusIcon .= Display::toolbarButton(
6737
                $label.'&nbsp;',
6738
                'javascript:void(0)',
6739
                $icon,
6740
                $buttonType,
6741
                ['class' => 'change_post_status']
6742
            );
6743
        } else {
6744
            if ($showStatus) {
6745
                $statusIcon .= Display::label(
6746
                    Display::returnFontAwesomeIcon($icon).$label,
6747
                    $buttonType
6748
                );
6749
            }
6750
        }
6751
6752
        if ($addWrapper) {
6753
            $statusIcon .= '</span>';
6754
        }
6755
    }
6756
6757
    return $statusIcon;
6758
}
6759
6760
/**
6761
 * @param array $forumInfo
6762
 * @param int   $threadId
6763
 * @param int   $status
6764
 *
6765
 * @return mixed
6766
 */
6767
function getCountPostsWithStatus($status, $forumInfo, $threadId = null)
6768
{
6769
    $em = Database::getManager();
6770
    $criteria = Criteria::create();
6771
    $criteria
6772
        ->where(Criteria::expr()->eq('status', $status))
6773
        ->andWhere(Criteria::expr()->eq('cId', $forumInfo['c_id']))
6774
        ->andWhere(Criteria::expr()->eq('visible', 1))
6775
    ;
6776
6777
    if (!empty($threadId)) {
6778
        $criteria->andWhere(Criteria::expr()->eq('threadId', $threadId));
6779
    }
6780
6781
    $qb = $em->getRepository('ChamiloCourseBundle:CForumPost')->createQueryBuilder('p');
6782
    $qb->select('count(p.iid)')
6783
        ->addCriteria($criteria);
6784
6785
    return $qb->getQuery()->getSingleScalarResult();
6786
}
6787
6788
/**
6789
 * @param array $forum
6790
 * @param array $post
6791
 *
6792
 * @return bool
6793
 */
6794
function postIsEditableByStudent($forum, $post)
6795
{
6796
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
6797
        return true;
6798
    }
6799
6800
    if ($forum['moderated'] == 1) {
6801
        if (is_null($post['status'])) {
6802
            return true;
6803
        } else {
6804
            return in_array(
6805
                $post['status'],
6806
                [
6807
                    CForumPost::STATUS_WAITING_MODERATION,
6808
                    CForumPost::STATUS_REJECTED,
6809
                ]
6810
            );
6811
        }
6812
    } else {
6813
        return true;
6814
    }
6815
}
6816
6817
/**
6818
 * @param int $postId
6819
 *
6820
 * @return bool
6821
 */
6822
function savePostRevision($postId)
6823
{
6824
    $postData = get_post_information($postId);
6825
6826
    if (empty($postData)) {
6827
        return false;
6828
    }
6829
6830
    $userId = api_get_user_id();
6831
6832
    if ($postData['poster_id'] != $userId) {
6833
        return false;
6834
    }
6835
6836
    $status = (int) !postNeedsRevision($postId);
6837
    $extraFieldValue = new ExtraFieldValue('forum_post');
6838
    $params = [
6839
        'item_id' => $postId,
6840
        'extra_ask_for_revision' => ['extra_ask_for_revision' => $status],
6841
    ];
6842
    if (empty($status)) {
6843
        unset($params['extra_ask_for_revision']);
6844
    }
6845
    $extraFieldValue->saveFieldValues(
6846
        $params,
6847
        true,
6848
        false,
6849
        ['ask_for_revision']
6850
    );
6851
}
6852
6853
/**
6854
 * @param int $postId
6855
 *
6856
 * @return string
6857
 */
6858
function getPostRevision($postId)
6859
{
6860
    $extraFieldValue = new ExtraFieldValue('forum_post');
6861
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6862
        $postId,
6863
        'revision_language'
6864
    );
6865
    $revision = '';
6866
    if ($value && isset($value['value'])) {
6867
        $revision = $value['value'];
6868
    }
6869
6870
    return $revision;
6871
}
6872
6873
/**
6874
 * @param int $postId
6875
 *
6876
 * @return bool
6877
 */
6878
function postNeedsRevision($postId)
6879
{
6880
    $extraFieldValue = new ExtraFieldValue('forum_post');
6881
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6882
        $postId,
6883
        'ask_for_revision'
6884
    );
6885
    $hasRevision = false;
6886
    if ($value && isset($value['value'])) {
6887
        return $value['value'] == 1;
6888
    }
6889
6890
    return $hasRevision;
6891
}
6892
6893
/**
6894
 * @param int   $postId
6895
 * @param array $threadInfo
6896
 *
6897
 * @return string
6898
 */
6899
function getAskRevisionButton($postId, $threadInfo)
6900
{
6901
    if (api_get_configuration_value('allow_forum_post_revisions') === false) {
6902
        return '';
6903
    }
6904
6905
    $postId = (int) $postId;
6906
6907
    $status = 'btn-default';
6908
    if (postNeedsRevision($postId)) {
6909
        $status = 'btn-success';
6910
    }
6911
6912
    return Display::url(
6913
        get_lang('AskRevision'),
6914
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6915
        api_get_cidreq().'&action=ask_revision&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6916
        ['class' => "btn $status", 'title' => get_lang('AskRevision')]
6917
    );
6918
}
6919
6920
/**
6921
 * @param int   $postId
6922
 * @param array $threadInfo
6923
 *
6924
 * @return string
6925
 */
6926
function giveRevisionButton($postId, $threadInfo)
6927
{
6928
    $postId = (int) $postId;
6929
6930
    return Display::toolbarButton(
6931
        get_lang('GiveRevision'),
6932
        api_get_path(WEB_CODE_PATH).'forum/reply.php?'.api_get_cidreq().'&'.http_build_query(
6933
            [
6934
                'forum' => $threadInfo['forum_id'],
6935
                'thread' => $threadInfo['thread_id'],
6936
                'post' => $postId = (int) $postId,
6937
                'action' => 'replymessage',
6938
                'give_revision' => 1,
6939
            ]
6940
        ),
6941
        'reply',
6942
        'primary',
6943
        ['id' => "reply-to-post-{$postId}"]
6944
    );
6945
}
6946
6947
/**
6948
 * @param int   $postId
6949
 * @param array $threadInfo
6950
 *
6951
 * @return string
6952
 */
6953
function getReportButton($postId, $threadInfo)
6954
{
6955
    $postId = (int) $postId;
6956
6957
    return Display::url(
6958
        Display::returnFontAwesomeIcon('flag'),
6959
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6960
        api_get_cidreq().'&action=report&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6961
        ['class' => 'btn btn-danger', 'title' => get_lang('Report')]
6962
    );
6963
}
6964
6965
/**
6966
 * @return bool
6967
 */
6968
function reportAvailable()
6969
{
6970
    $extraFieldValue = new ExtraFieldValue('course');
6971
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6972
        api_get_course_int_id(),
6973
        'allow_forum_report_button'
6974
    );
6975
    $allowReport = false;
6976
    if ($value && isset($value['value']) && $value['value'] == 1) {
6977
        $allowReport = true;
6978
    }
6979
6980
    return $allowReport;
6981
}
6982
6983
/**
6984
 * @return array
6985
 */
6986
function getReportRecipients()
6987
{
6988
    $extraFieldValue = new ExtraFieldValue('course');
6989
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6990
        api_get_course_int_id(),
6991
        'forum_report_recipients'
6992
    );
6993
    $users = [];
6994
    if ($value && isset($value['value'])) {
6995
        $usersType = explode(';', $value['value']);
6996
6997
        foreach ($usersType as $type) {
6998
            switch ($type) {
6999
                case 'teachers':
7000
                    $teachers = CourseManager::get_teacher_list_from_course_code(api_get_course_id());
7001
                    if (!empty($teachers)) {
7002
                        $users = array_merge($users, array_column($teachers, 'user_id'));
7003
                    }
7004
                break;
7005
                case 'admins':
7006
                    $admins = UserManager::get_all_administrators();
7007
                    if (!empty($admins)) {
7008
                        $users = array_merge($users, array_column($admins, 'user_id'));
7009
                    }
7010
                    break;
7011
                case 'community_managers':
7012
                    $managers = api_get_configuration_value('community_managers_user_list');
7013
                    if (!empty($managers) && isset($managers['users'])) {
7014
                        $users = array_merge($users, $managers['users']);
7015
                    }
7016
                    break;
7017
            }
7018
        }
7019
7020
        $users = array_unique(array_filter($users));
7021
    }
7022
7023
    return $users;
7024
}
7025
7026
/**
7027
 * @param int   $postId
7028
 * @param array $forumInfo
7029
 * @param array $threadInfo
7030
 *
7031
 * @return bool
7032
 */
7033
function reportPost($postId, $forumInfo, $threadInfo)
7034
{
7035
    if (!reportAvailable()) {
7036
        return false;
7037
    }
7038
7039
    if (empty($forumInfo) || empty($threadInfo)) {
7040
        return false;
7041
    }
7042
7043
    $postId = (int) $postId;
7044
7045
    $postData = get_post_information($postId);
7046
    $currentUser = api_get_user_info();
7047
7048
    if (!empty($postData)) {
7049
        $users = getReportRecipients();
7050
        if (!empty($users)) {
7051
            $url = api_get_path(WEB_CODE_PATH).
7052
                'forum/viewthread.php?forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'].'&'.api_get_cidreq().'&post_id='.$postId.'#post_id_'.$postId;
7053
            $postLink = Display::url(
7054
                $postData['post_title'],
7055
                $url
7056
            );
7057
            $subject = get_lang('ForumPostReported');
7058
            $content = sprintf(
7059
                get_lang('UserXReportedPostXInForumX'),
7060
                $currentUser['complete_name'],
7061
                $postLink,
7062
                $forumInfo['forum_title']
7063
            );
7064
            foreach ($users as $userId) {
7065
                MessageManager::send_message_simple($userId, $subject, $content);
7066
            }
7067
        }
7068
    }
7069
}
7070