Passed
Push — master ( 5b6eb8...1cb62c )
by Julito
09:41
created

reportAvailable()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
nc 2
nop 0
dl 0
loc 13
rs 10
c 1
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CourseBundle\Entity\CForumPost;
5
use Chamilo\CourseBundle\Entity\CForumThread;
6
use Chamilo\UserBundle\Entity\User;
7
use ChamiloSession as Session;
8
use Doctrine\Common\Collections\Criteria;
9
10
/**
11
 * These files are a complete rework of the forum. The database structure is
12
 * based on phpBB but all the code is rewritten. A lot of new functionalities
13
 * are added:
14
 * - forum categories and forums can be sorted up or down, locked or made invisible
15
 * - consistent and integrated forum administration
16
 * - forum options:     are students allowed to edit their post?
17
 *                         moderation of posts (approval)
18
 *                         reply only forums (students cannot create new threads)
19
 *                         multiple forums per group
20
 * - sticky messages
21
 * - new view option: nested view
22
 * - quoting a message.
23
 *
24
 * @package chamilo.forum
25
 *
26
 * @todo convert into a class
27
 */
28
define('FORUM_NEW_POST', 0);
29
getNotificationsPerUser();
30
31
$htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
32
$htmlHeadXtra[] = '<script>
33
34
function check_unzip() {
35
    if (document.upload.unzip.checked){
36
        document.upload.if_exists[0].disabled=true;
37
        document.upload.if_exists[1].checked=true;
38
        document.upload.if_exists[2].disabled=true;
39
    } else {
40
        document.upload.if_exists[0].checked=true;
41
        document.upload.if_exists[0].disabled=false;
42
        document.upload.if_exists[2].disabled=false;
43
    }
44
}
45
function setFocus() {
46
    $("#title_file").focus();
47
}
48
</script>';
49
// The next javascript script is to manage ajax upload file
50
$htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
51
52
// Recover Thread ID, will be used to generate delete attachment URL to do ajax
53
$threadId = isset($_REQUEST['thread']) ? intval($_REQUEST['thread']) : 0;
54
$forumId = isset($_REQUEST['forum']) ? intval($_REQUEST['forum']) : 0;
55
56
$ajaxUrl = api_get_path(WEB_AJAX_PATH).'forum.ajax.php?'.api_get_cidreq();
57
// The next javascript script is to delete file by ajax
58
$htmlHeadXtra[] = '<script>
59
$(function () {
60
    $(document).on("click", ".deleteLink", function(e) {
61
        e.preventDefault();
62
        e.stopPropagation();
63
        var l = $(this);
64
        var id = l.closest("tr").attr("id");
65
        var filename = l.closest("tr").find(".attachFilename").html();
66
        if (confirm("'.get_lang('AreYouSureToDeleteJS').'", filename)) {
67
            $.ajax({
68
                type: "POST",
69
                url: "'.$ajaxUrl.'&a=delete_file&attachId=" + id +"&thread='.$threadId.'&forum='.$forumId.'",
70
                dataType: "json",
71
                success: function(data) {
72
                    if (data.error == false) {
73
                        l.closest("tr").remove();
74
                        if ($(".files td").length < 1) {
75
                            $(".files").closest(".control-group").hide();
76
                        }
77
                    }
78
                }
79
            })
80
        }
81
    });
82
});
83
</script>';
84
85
/**
86
 * This function handles all the forum and forum categories actions. This is a wrapper for the
87
 * forum and forum categories. All this code code could go into the section where this function is
88
 * called but this make the code there cleaner.
89
 *
90
 * @param int $lp_id Learning path Id
91
 *
92
 * @author Patrick Cool <[email protected]>, Ghent University
93
 * @author Juan Carlos Raña Trabado (return to lp_id)
94
 *
95
 * @version may 2011, Chamilo 1.8.8
96
 */
97
function handle_forum_and_forumcategories($lp_id = null)
98
{
99
    $action_forum_cat = isset($_GET['action']) ? $_GET['action'] : '';
100
    $get_content = isset($_GET['content']) ? $_GET['content'] : '';
101
    $post_submit_cat = isset($_POST['SubmitForumCategory']) ? true : false;
102
    $post_submit_forum = isset($_POST['SubmitForum']) ? true : false;
103
    $get_id = isset($_GET['id']) ? intval($_GET['id']) : '';
104
    $forum_categories_list = get_forum_categories();
105
106
    // Verify if forum category exists
107
    if (empty($forum_categories_list)) {
108
        $get_content = 'forumcategory';
109
    }
110
111
    $content = '';
112
113
    // Adding a forum category
114
    if (($action_forum_cat == 'add' && $get_content == 'forumcategory') || $post_submit_cat) {
115
        $content = show_add_forumcategory_form([], $lp_id); //$lp_id when is called from learning path
116
    }
117
118
    // Adding a forum
119
    if ((($action_forum_cat == 'add' || $action_forum_cat == 'edit') && $get_content == 'forum') ||
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($action_forum_cat == 'a...) || $post_submit_forum, Probably Intended Meaning: $action_forum_cat == 'ad... || $post_submit_forum)
Loading history...
120
        $post_submit_forum
121
    ) {
122
        $inputvalues = [];
123
        if ($action_forum_cat == 'edit' && $get_id || $post_submit_forum) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($action_forum_cat == 'e...) || $post_submit_forum, Probably Intended Meaning: $action_forum_cat == 'ed... || $post_submit_forum)
Loading history...
124
            $inputvalues = get_forums($get_id);
0 ignored issues
show
Bug introduced by
It seems like $get_id can also be of type string; however, parameter $id of get_forums() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

124
            $inputvalues = get_forums(/** @scrutinizer ignore-type */ $get_id);
Loading history...
125
        }
126
        $content = show_add_forum_form($inputvalues, $lp_id);
127
    }
128
129
    // Edit a forum category
130
    if (($action_forum_cat == 'edit' && $get_content == 'forumcategory') ||
131
        (isset($_POST['SubmitEditForumCategory'])) ? true : false
132
    ) {
133
        $forum_category = get_forum_categories($get_id);
134
        $content = show_edit_forumcategory_form($forum_category);
135
    }
136
137
    // Delete a forum category
138
    if ($action_forum_cat == 'delete') {
139
        $id_forum = intval($get_id);
140
        $list_threads = get_threads($id_forum);
141
142
        for ($i = 0; $i < count($list_threads); $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...
143
            deleteForumCategoryThread('thread', $list_threads[$i]['thread_id']);
144
            $link_info = GradebookUtils::isResourceInCourseGradebook(
145
                api_get_course_id(),
146
                5,
147
                $list_threads[$i]['thread_id'],
148
                api_get_session_id()
149
            );
150
            if ($link_info !== false) {
151
                GradebookUtils::remove_resource_from_course_gradebook($link_info['id']);
152
            }
153
        }
154
        deleteForumCategoryThread($get_content, $get_id);
155
    }
156
157
    // Change visibility of a forum or a forum category.
158
    if ($action_forum_cat == 'invisible' || $action_forum_cat == 'visible') {
159
        $return_message = change_visibility($get_content, $get_id, $action_forum_cat);
0 ignored issues
show
Bug introduced by
It seems like $get_id can also be of type string; however, parameter $id of change_visibility() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

159
        $return_message = change_visibility($get_content, /** @scrutinizer ignore-type */ $get_id, $action_forum_cat);
Loading history...
160
        Display::addFlash(
161
            Display::return_message($return_message, 'confirmation', false)
162
        );
163
    }
164
    // Change lock status of a forum or a forum category.
165
    if ($action_forum_cat == 'lock' || $action_forum_cat == 'unlock') {
166
        $return_message = change_lock_status($get_content, $get_id, $action_forum_cat);
0 ignored issues
show
Bug introduced by
It seems like $get_id can also be of type string; however, parameter $id of change_lock_status() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

166
        $return_message = change_lock_status($get_content, /** @scrutinizer ignore-type */ $get_id, $action_forum_cat);
Loading history...
167
        Display::addFlash(
168
            Display::return_message($return_message, 'confirmation', false)
169
        );
170
    }
171
    // Move a forum or a forum category.
172
    if ($action_forum_cat == 'move' && isset($_GET['direction'])) {
173
        $return_message = move_up_down($get_content, $_GET['direction'], $get_id);
174
        Display::addFlash(
175
            Display::return_message($return_message, 'confirmation', false)
176
        );
177
    }
178
179
    return $content;
180
}
181
182
/**
183
 * This function displays the form that is used to add a forum category.
184
 *
185
 * @param array $inputvalues (deprecated, set to null when calling)
186
 * @param int   $lp_id       Learning path ID
187
 *
188
 * @return string
189
 *
190
 * @author Patrick Cool <[email protected]>, Ghent University
191
 * @author Juan Carlos Raña Trabado (return to lp_id)
192
 *
193
 * @version may 2011, Chamilo 1.8.8
194
 */
195
function show_add_forumcategory_form($inputvalues = [], $lp_id)
196
{
197
    $form = new FormValidator(
198
        'forumcategory',
199
        'post',
200
        'index.php?'.api_get_cidreq()
201
    );
202
    // hidden field if from learning path
203
    $form->addElement('hidden', 'lp_id', $lp_id);
204
    // Setting the form elements.
205
    $form->addElement('header', get_lang('AddForumCategory'));
206
    $form->addElement('text', 'forum_category_title', get_lang('Title'), ['autofocus']);
207
    $form->addElement(
208
        'html_editor',
209
        'forum_category_comment',
210
        get_lang('Description'),
211
        null,
212
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
213
    );
214
215
    $extraField = new ExtraField('forum_category');
216
    $returnParams = $extraField->addElements(
217
        $form,
218
        null,
219
        [], //exclude
220
        false, // filter
221
        false, // tag as select
222
        [], //show only fields
223
        [], // order fields
224
        [] // extra data
225
    );
226
227
    $form->addButtonCreate(get_lang('CreateCategory'), 'SubmitForumCategory');
228
229
    // Setting the rules.
230
    $form->addRule('forum_category_title', get_lang('ThisFieldIsRequired'), 'required');
231
232
    // The validation or display
233
    if ($form->validate()) {
234
        $check = Security::check_token('post');
235
        if ($check) {
236
            $values = $form->exportValues();
237
            store_forumcategory($values);
238
        }
239
        Security::clear_token();
240
    } else {
241
        $token = Security::get_token();
242
        $form->addElement('hidden', 'sec_token');
243
        $form->setConstants(['sec_token' => $token]);
244
245
        return $form->returnForm();
246
    }
247
}
248
249
/**
250
 * This function displays the form that is used to add a forum category.
251
 *
252
 * @param array $inputvalues
253
 * @param int   $lp_id
254
 *
255
 * @author Patrick Cool <[email protected]>, Ghent University
256
 * @author Juan Carlos Raña Trabado (return to lp_id)
257
 *
258
 * @version may 2011, Chamilo 1.8.8
259
 */
260
function show_add_forum_form($inputvalues = [], $lp_id)
261
{
262
    $_course = api_get_course_info();
263
    $form = new FormValidator('forumcategory', 'post', 'index.php?'.api_get_cidreq());
264
265
    // The header for the form
266
    $form_title = get_lang('AddForum');
267
    if (!empty($inputvalues)) {
268
        $form_title = get_lang('EditForum');
269
    }
270
271
    $form->addElement('header', $form_title);
272
273
    // We have a hidden field if we are editing.
274
    if (!empty($inputvalues) && is_array($inputvalues)) {
275
        $my_forum_id = isset($inputvalues['forum_id']) ? $inputvalues['forum_id'] : null;
276
        $form->addElement('hidden', 'forum_id', $my_forum_id);
277
    }
278
    $lp_id = intval($lp_id);
279
280
    // hidden field if from learning path
281
    $form->addElement('hidden', 'lp_id', $lp_id);
282
283
    // The title of the forum
284
    $form->addElement('text', 'forum_title', get_lang('Title'), ['autofocus']);
285
286
    // The comment of the forum.
287
    $form->addElement(
288
        'html_editor',
289
        'forum_comment',
290
        get_lang('Description'),
291
        null,
292
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
293
    );
294
295
    // Dropdown list: Forum categories
296
    $forum_categories = get_forum_categories();
297
    foreach ($forum_categories as $key => $value) {
298
        $forum_categories_titles[$value['cat_id']] = $value['cat_title'];
299
    }
300
    $form->addElement(
301
        'select',
302
        'forum_category',
303
        get_lang('InForumCategory'),
304
        $forum_categories_titles
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $forum_categories_titles seems to be defined by a foreach iteration on line 297. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
305
    );
306
    $form->applyFilter('forum_category', 'html_filter');
307
308
    if ($_course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD) {
309
        // This is for horizontal
310
        $group = [];
311
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('Yes'), 1);
312
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('No'), 0);
313
        $form->addGroup($group, 'allow_anonymous_group', get_lang('AllowAnonymousPosts'));
314
    }
315
316
    $form->addButtonAdvancedSettings('advanced_params');
317
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
318
319
    $form->addDateTimePicker(
320
        'start_time',
321
        [get_lang('ForumStartDate'), get_lang('ForumStartDateComment')],
322
        ['id' => 'start_time']
323
    );
324
325
    $form->addDateTimePicker(
326
        'end_time',
327
        [get_lang('ForumEndDate'), get_lang('ForumEndDateComment')],
328
        ['id' => 'end_time']
329
    );
330
331
    $form->addRule(
332
        ['start_time', 'end_time'],
333
        get_lang('StartDateMustBeBeforeTheEndDate'),
334
        'compare_datetime_text',
335
        '< allow_empty'
336
    );
337
338
    $group = [];
339
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('Yes'), 1);
340
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('No'), 0);
341
    $form->addGroup($group, 'moderated', get_lang('ModeratedForum'));
342
343
    $group = [];
344
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('Yes'), 1);
345
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('No'), 0);
346
    $form->addGroup($group, 'students_can_edit_group', get_lang('StudentsCanEdit'));
347
348
    $group = [];
349
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Approval'), 1);
350
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Direct'), 0);
351
352
    $group = [];
353
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('Yes'), 1);
354
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('No'), 0);
355
356
    $group = [];
357
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('Yes'), 1);
358
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('No'), 0);
359
    $form->addGroup($group, 'allow_new_threads_group', get_lang('AllowNewThreads'));
360
361
    $group = [];
362
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Flat'), 'flat');
363
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Threaded'), 'threaded');
364
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Nested'), 'nested');
365
    $form->addGroup($group, 'default_view_type_group', get_lang('DefaultViewType'));
366
367
    // Drop down list: Groups
368
    $groups = GroupManager::get_group_list();
369
    $groups_titles[0] = get_lang('NotAGroupForum');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$groups_titles was never initialized. Although not strictly required by PHP, it is generally a good practice to add $groups_titles = array(); before regardless.
Loading history...
370
    foreach ($groups as $key => $value) {
371
        $groups_titles[$value['id']] = $value['name'];
372
    }
373
    $form->addElement('select', 'group_forum', get_lang('ForGroup'), $groups_titles);
374
375
    // Public or private group forum
376
    $group = [];
377
    $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Public'), 'public');
378
    $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Private'), 'private');
379
    $form->addGroup($group, 'public_private_group_forum_group', get_lang('PublicPrivateGroupForum'));
380
381
    // Forum image
382
    $form->addProgress();
383
    if (!empty($inputvalues['forum_image'])) {
384
        $baseImagePath = api_get_course_path().'/upload/forum/images/'.$inputvalues['forum_image'];
385
        $image_path = api_get_path(WEB_COURSE_PATH).$baseImagePath;
386
        $sysImagePath = api_get_path(SYS_COURSE_PATH).$baseImagePath;
387
388
        if (file_exists($sysImagePath)) {
389
            $show_preview_image = Display::img(
390
                $image_path,
391
                null,
392
                ['class' => 'img-responsive']
393
            );
394
            $form->addElement('label', get_lang('PreviewImage'), $show_preview_image);
395
            $form->addElement('checkbox', 'remove_picture', null, get_lang('DelImage'));
396
        }
397
    }
398
    $forum_image = isset($inputvalues['forum_image']) ? $inputvalues['forum_image'] : '';
399
    $form->addElement('file', 'picture', ($forum_image != '' ? get_lang('UpdateImage') : get_lang('AddImage')));
400
    $form->addRule(
401
        'picture',
402
        get_lang('OnlyImagesAllowed'),
403
        'filetype',
404
        ['jpg', 'jpeg', 'png', 'gif']
405
    );
406
407
    //$forumId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
408
    //$skillList = Skill::addSkillsToForm($form, ITEM_TYPE_FORUM, $forumId);
409
410
    $form->addElement('html', '</div>');
411
412
    // The OK button
413
    if (isset($_GET['id']) && $_GET['action'] == 'edit') {
414
        $form->addButtonUpdate(get_lang('ModifyForum'), 'SubmitForum');
415
    } else {
416
        $form->addButtonCreate(get_lang('CreateForum'), 'SubmitForum');
417
    }
418
419
    // setting the rules
420
    $form->addRule('forum_title', get_lang('ThisFieldIsRequired'), 'required');
421
    $form->addRule('forum_category', get_lang('ThisFieldIsRequired'), 'required');
422
423
    $defaultSettingAllowNewThreads = api_get_default_tool_setting('forum', 'allow_new_threads', 0);
424
425
    // Settings the defaults
426
    if (empty($inputvalues) || !is_array($inputvalues)) {
427
        $defaults['moderated']['moderated'] = 0;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$defaults was never initialized. Although not strictly required by PHP, it is generally a good practice to add $defaults = array(); before regardless.
Loading history...
428
        $defaults['allow_anonymous_group']['allow_anonymous'] = 0;
429
        $defaults['students_can_edit_group']['students_can_edit'] = 0;
430
        $defaults['approval_direct_group']['approval_direct'] = 0;
431
        $defaults['allow_attachments_group']['allow_attachments'] = 1;
432
        $defaults['allow_new_threads_group']['allow_new_threads'] = $defaultSettingAllowNewThreads;
433
        $defaults['default_view_type_group']['default_view_type'] = api_get_setting('default_forum_view');
434
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = 'public';
435
        if (isset($_GET['forumcategory'])) {
436
            $defaults['forum_category'] = Security::remove_XSS($_GET['forumcategory']);
437
        }
438
    } else {
439
        // the default values when editing = the data in the table
440
        $defaults['forum_id'] = isset($inputvalues['forum_id']) ? $inputvalues['forum_id'] : null;
441
        $defaults['forum_title'] = prepare4display(isset($inputvalues['forum_title']) ? $inputvalues['forum_title'] : null);
442
        $defaults['forum_comment'] = prepare4display(isset($inputvalues['forum_comment']) ? $inputvalues['forum_comment'] : null);
443
        $defaults['start_time'] = isset($inputvalues['start_time']) ? api_get_local_time($inputvalues['start_time']) : null;
444
        $defaults['end_time'] = isset($inputvalues['end_time']) ? api_get_local_time($inputvalues['end_time']) : null;
445
        $defaults['moderated']['moderated'] = isset($inputvalues['moderated']) ? $inputvalues['moderated'] : 0;
446
        $defaults['forum_category'] = isset($inputvalues['forum_category']) ? $inputvalues['forum_category'] : null;
447
        $defaults['allow_anonymous_group']['allow_anonymous'] = isset($inputvalues['allow_anonymous']) ? $inputvalues['allow_anonymous'] : null;
448
        $defaults['students_can_edit_group']['students_can_edit'] = isset($inputvalues['allow_edit']) ? $inputvalues['allow_edit'] : null;
449
        $defaults['approval_direct_group']['approval_direct'] = isset($inputvalues['approval_direct_post']) ? $inputvalues['approval_direct_post'] : null;
450
        $defaults['allow_attachments_group']['allow_attachments'] = isset($inputvalues['allow_attachments']) ? $inputvalues['allow_attachments'] : null;
451
        $defaults['allow_new_threads_group']['allow_new_threads'] = isset($inputvalues['allow_new_threads']) ? $inputvalues['allow_new_threads'] : $defaultSettingAllowNewThreads;
452
        $defaults['default_view_type_group']['default_view_type'] = isset($inputvalues['default_view']) ? $inputvalues['default_view'] : null;
453
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = isset($inputvalues['forum_group_public_private']) ? $inputvalues['forum_group_public_private'] : null;
454
        $defaults['group_forum'] = isset($inputvalues['forum_of_group']) ? $inputvalues['forum_of_group'] : null;
455
    }
456
457
    // $defaults['skills'] = array_keys($skillList);
458
459
    $form->setDefaults($defaults);
460
    // Validation or display
461
    if ($form->validate()) {
462
        $check = Security::check_token('post');
463
        if ($check) {
464
            $values = $form->getSubmitValues();
465
            $forumId = store_forum($values, '', true);
466
            if ($forumId) {
467
                // Skill::saveSkills($form, ITEM_TYPE_FORUM, $forumId);
468
                if (isset($values['forum_id'])) {
469
                    Display::addFlash(Display::return_message(get_lang('ForumEdited'), 'confirmation'));
470
                } else {
471
                    Display::addFlash(Display::return_message(get_lang('ForumAdded'), 'confirmation'));
472
                }
473
            }
474
        }
475
        Security::clear_token();
476
    } else {
477
        $token = Security::get_token();
478
        $form->addElement('hidden', 'sec_token');
479
        $form->setConstants(['sec_token' => $token]);
480
481
        return $form->returnForm();
482
    }
483
}
484
485
/**
486
 * This function deletes the forum image if exists.
487
 *
488
 * @param int forum id
489
 *
490
 * @return bool true if success
491
 *
492
 * @author Julio Montoya <[email protected]>
493
 *
494
 * @version february 2006, dokeos 1.8
495
 */
496
function delete_forum_image($forum_id)
497
{
498
    $table_forums = Database::get_course_table(TABLE_FORUM);
499
    $course_id = api_get_course_int_id();
500
    $forum_id = intval($forum_id);
501
502
    $sql = "SELECT forum_image FROM $table_forums
503
            WHERE forum_id = $forum_id AND c_id = $course_id";
504
    $result = Database::query($sql);
505
    $row = Database::fetch_array($result);
506
    if ($row['forum_image'] != '') {
507
        $file = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/forum/images/'.$row['forum_image'];
508
        if (file_exists($file)) {
509
            unlink($file);
510
        }
511
512
        return true;
513
    } else {
514
        return false;
515
    }
516
}
517
518
/**
519
 * This function displays the form that is used to edit a forum category.
520
 *
521
 * @param array
522
 *
523
 * @return string
524
 *
525
 * @author Patrick Cool <[email protected]>, Ghent University
526
 *
527
 * @version february 2006, dokeos 1.8
528
 */
529
function show_edit_forumcategory_form($inputvalues = [])
530
{
531
    $categoryId = $inputvalues['cat_id'];
532
    $form = new FormValidator('forumcategory', 'post', 'index.php?'.api_get_cidreq().'&id='.$categoryId);
533
534
    // Setting the form elements.
535
    $form->addElement('header', '', get_lang('EditForumCategory'));
536
    $form->addElement('hidden', 'forum_category_id');
537
    $form->addElement('text', 'forum_category_title', get_lang('Title'));
538
539
    $form->addElement(
540
        'html_editor',
541
        'forum_category_comment',
542
        get_lang('Comment'),
543
        null,
544
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
545
    );
546
547
    $extraField = new ExtraField('forum_category');
548
    $returnParams = $extraField->addElements(
549
        $form,
550
        $categoryId,
551
        [], //exclude
552
        false, // filter
553
        false, // tag as select
554
        [], //show only fields
555
        [], // order fields
556
        [] // extra data
557
    );
558
559
    $form->addButtonUpdate(get_lang('ModifyCategory'), 'SubmitEditForumCategory');
560
561
    // Setting the default values.
562
    $defaultvalues['forum_category_id'] = $inputvalues['cat_id'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$defaultvalues was never initialized. Although not strictly required by PHP, it is generally a good practice to add $defaultvalues = array(); before regardless.
Loading history...
563
    $defaultvalues['forum_category_title'] = $inputvalues['cat_title'];
564
    $defaultvalues['forum_category_comment'] = $inputvalues['cat_comment'];
565
    $form->setDefaults($defaultvalues);
566
567
    // Setting the rules.
568
    $form->addRule('forum_category_title', get_lang('ThisFieldIsRequired'), 'required');
569
570
    // Validation or display
571
    if ($form->validate()) {
572
        $check = Security::check_token('post');
573
        if ($check) {
574
            $values = $form->exportValues();
575
            store_forumcategory($values);
576
        }
577
        Security::clear_token();
578
    } else {
579
        $token = Security::get_token();
580
        $form->addElement('hidden', 'sec_token');
581
        $form->setConstants(['sec_token' => $token]);
582
583
        return $form->returnForm();
584
    }
585
}
586
587
/**
588
 * This function stores the forum category in the database.
589
 * The new category is added to the end.
590
 *
591
 * @param array $values
592
 * @param array $courseInfo
593
 * @param bool  $showMessage
594
 *
595
 * @author Patrick Cool <[email protected]>, Ghent University
596
 *
597
 * @version february 2006, dokeos 1.8
598
 */
599
function store_forumcategory($values, $courseInfo = [], $showMessage = true)
600
{
601
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
602
    $course_id = $courseInfo['real_id'];
603
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
604
605
    // Find the max cat_order. The new forum category is added at the end => max cat_order + &
606
    $sql = "SELECT MAX(cat_order) as sort_max
607
            FROM $table_categories
608
            WHERE c_id = $course_id";
609
    $result = Database::query($sql);
610
    $row = Database::fetch_array($result);
611
    $new_max = $row['sort_max'] + 1;
612
    $session_id = api_get_session_id();
613
    $clean_cat_title = $values['forum_category_title'];
614
    $last_id = null;
615
616
    if (isset($values['forum_category_id'])) {
617
        // Storing after edition.
618
        $params = [
619
            'cat_title' => $clean_cat_title,
620
            'cat_comment' => isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '',
621
        ];
622
623
        Database::update(
624
            $table_categories,
625
            $params,
626
            [
627
                'c_id = ? AND cat_id = ?' => [
628
                    $course_id,
629
                    $values['forum_category_id'],
630
                ],
631
            ]
632
        );
633
634
        api_item_property_update(
635
            $courseInfo,
636
            TOOL_FORUM_CATEGORY,
637
            $values['forum_category_id'],
638
            'ForumCategoryUpdated',
639
            api_get_user_id()
640
        );
641
        $return_message = get_lang('ForumCategoryEdited');
642
643
        $logInfo = [
644
            'tool' => TOOL_FORUM,
645
            'tool_id' => 0,
646
            'tool_id_detail' => 0,
647
            'action' => 'update-forumcategory',
648
            'action_details' => 'forumcategory',
649
            'info' => $clean_cat_title,
650
        ];
651
        Event::registerLog($logInfo);
652
653
        $values['item_id'] = $values['forum_category_id'];
654
    } else {
655
        $params = [
656
            'c_id' => $course_id,
657
            'cat_title' => $clean_cat_title,
658
            'cat_comment' => isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '',
659
            'cat_order' => $new_max,
660
            'session_id' => $session_id,
661
            'locked' => 0,
662
            'cat_id' => 0,
663
        ];
664
        $last_id = Database::insert($table_categories, $params);
665
666
        if ($last_id > 0) {
667
            $sql = "UPDATE $table_categories SET cat_id = $last_id WHERE iid = $last_id";
668
            Database::query($sql);
669
670
            api_item_property_update(
671
                $courseInfo,
672
                TOOL_FORUM_CATEGORY,
673
                $last_id,
0 ignored issues
show
Bug introduced by
It seems like $last_id can also be of type false; however, parameter $item_id of api_item_property_update() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

673
                /** @scrutinizer ignore-type */ $last_id,
Loading history...
674
                'ForumCategoryAdded',
675
                api_get_user_id()
676
            );
677
            api_set_default_visibility(
678
                $last_id,
0 ignored issues
show
Bug introduced by
It seems like $last_id can also be of type false; however, parameter $item_id of api_set_default_visibility() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

678
                /** @scrutinizer ignore-type */ $last_id,
Loading history...
679
                TOOL_FORUM_CATEGORY,
680
                0,
681
                $courseInfo
682
            );
683
        }
684
        $return_message = get_lang('ForumCategoryAdded');
685
686
        $logInfo = [
687
            'tool' => TOOL_FORUM,
688
            'tool_id' => 0,
689
            'tool_id_detail' => 0,
690
            'action' => 'new-forumcategory',
691
            'action_details' => 'forumcategory',
692
            'info' => $clean_cat_title,
693
        ];
694
        Event::registerLog($logInfo);
695
696
        $values['item_id'] = $last_id;
697
    }
698
699
    $extraFieldValue = new ExtraFieldValue('forum_category');
700
    $extraFieldValue->saveFieldValues($values);
701
702
    if ($showMessage) {
703
        Display::addFlash(Display::return_message($return_message, 'confirmation'));
704
    }
705
706
    return $last_id;
707
}
708
709
/**
710
 * This function stores the forum in the database. The new forum is added to the end.
711
 *
712
 * @param array $values
713
 * @param array $courseInfo
714
 * @param bool  $returnId
715
 *
716
 * @return string language variable
717
 *
718
 * @author Patrick Cool <[email protected]>, Ghent University
719
 *
720
 * @version february 2006, dokeos 1.8
721
 */
722
function store_forum($values, $courseInfo = [], $returnId = false)
723
{
724
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
725
    $courseId = $courseInfo['real_id'];
726
    $session_id = api_get_session_id();
727
    $group_id = api_get_group_id();
728
    if (isset($values['group_id']) && !empty($values['group_id'])) {
729
        $group_id = $values['group_id'];
730
    }
731
    $groupInfo = [];
732
    if (!empty($group_id)) {
733
        $groupInfo = GroupManager::get_group_properties($group_id);
734
    }
735
736
    $table_forums = Database::get_course_table(TABLE_FORUM);
737
738
    // Find the max forum_order for the given category. The new forum is added at the end => max cat_order + &
739
    if (is_null($values['forum_category'])) {
740
        $new_max = null;
741
    } else {
742
        $sql = "SELECT MAX(forum_order) as sort_max
743
                FROM $table_forums
744
                WHERE
745
                    c_id = $courseId AND
746
                    forum_category='".Database::escape_string($values['forum_category'])."'";
747
        $result = Database::query($sql);
748
        $row = Database::fetch_array($result);
749
        $new_max = $row['sort_max'] + 1;
750
    }
751
752
    // Forum images
753
    $has_attachment = false;
754
    $image_moved = true;
755
    if (!empty($_FILES['picture']['name'])) {
756
        $upload_ok = process_uploaded_file($_FILES['picture']);
757
        $has_attachment = true;
758
    }
759
760
    // Remove existing picture if it was requested.
761
    if (!empty($_POST['remove_picture'])) {
762
        delete_forum_image($values['forum_id']);
763
    }
764
765
    $new_file_name = '';
766
    if (isset($upload_ok)) {
767
        if ($has_attachment) {
768
            $course_dir = $courseInfo['path'].'/upload/forum/images';
769
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
770
            $updir = $sys_course_path.$course_dir;
771
            // Try to add an extension to the file if it hasn't one.
772
            $new_file_name = add_ext_on_mime(
773
                Database::escape_string($_FILES['picture']['name']),
774
                $_FILES['picture']['type']
775
            );
776
            if (!filter_extension($new_file_name)) {
777
                //Display::addFlash(Display::return_message(get_lang('UplUnableToSaveFileFilteredExtension'), 'error'));
778
                $image_moved = false;
779
            } else {
780
                $file_extension = explode('.', $_FILES['picture']['name']);
781
                $file_extension = strtolower($file_extension[sizeof($file_extension) - 1]);
782
                $new_file_name = uniqid('').'.'.$file_extension;
783
                $new_path = $updir.'/'.$new_file_name;
784
                $result = @move_uploaded_file($_FILES['picture']['tmp_name'], $new_path);
785
                // Storing the attachments if any
786
                if ($result) {
787
                    $image_moved = true;
788
                }
789
            }
790
        }
791
    }
792
793
    if (isset($values['forum_id'])) {
794
        // Storing after edition.
795
        $params = [
796
            'forum_title' => $values['forum_title'],
797
            'forum_comment' => isset($values['forum_comment']) ? $values['forum_comment'] : null,
798
            'forum_category' => isset($values['forum_category']) ? $values['forum_category'] : null,
799
            'allow_anonymous' => isset($values['allow_anonymous_group']['allow_anonymous']) ? $values['allow_anonymous_group']['allow_anonymous'] : null,
800
            'allow_edit' => isset($values['students_can_edit_group']['students_can_edit']) ? $values['students_can_edit_group']['students_can_edit'] : null,
801
            'approval_direct_post' => isset($values['approval_direct_group']['approval_direct']) ? $values['approval_direct_group']['approval_direct'] : null,
802
            'allow_attachments' => isset($values['allow_attachments_group']['allow_attachments']) ? $values['allow_attachments_group']['allow_attachments'] : null,
803
            'allow_new_threads' => isset($values['allow_new_threads_group']['allow_new_threads']) ? $values['allow_new_threads_group']['allow_new_threads'] : null,
804
            'default_view' => isset($values['default_view_type_group']['default_view_type']) ? $values['default_view_type_group']['default_view_type'] : null,
805
            'forum_of_group' => isset($values['group_forum']) ? $values['group_forum'] : null,
806
            '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,
807
            'moderated' => $values['moderated']['moderated'],
808
            'start_time' => !empty($values['start_time']) ? api_get_utc_datetime($values['start_time']) : null,
809
            'end_time' => !empty($values['end_time']) ? api_get_utc_datetime($values['end_time']) : null,
810
            'session_id' => $session_id,
811
            'lp_id' => isset($values['lp_id']) ? intval($values['lp_id']) : 0,
812
        ];
813
814
        if (isset($upload_ok)) {
815
            if ($has_attachment) {
816
                $params['forum_image'] = $new_file_name;
817
            }
818
        }
819
820
        if (isset($values['remove_picture']) && $values['remove_picture'] == 1) {
821
            $params['forum_image'] = '';
822
            delete_forum_image($values['forum_id']);
823
        }
824
825
        // Move groups from one group to another
826
        if (isset($values['group_forum'])) {
827
            $forumData = get_forums($values['forum_id']);
828
            $currentGroupId = $forumData['forum_of_group'];
829
            if ($currentGroupId != $values['group_forum']) {
830
                $threads = get_threads($values['forum_id']);
831
                $toGroupId = 'NULL';
832
                if (!empty($values['group_forum'])) {
833
                    $toGroupId = $values['group_forum'];
834
                }
835
                $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
836
                foreach ($threads as $thread) {
837
                    $sql = "UPDATE $tableItemProperty 
838
                            SET to_group_id = $toGroupId
839
                            WHERE 
840
                                tool = '".TOOL_FORUM_THREAD."' AND
841
                                ref = ".$thread['thread_id']." AND
842
                                c_id = ".$courseId;
843
                    Database::query($sql);
844
845
                    $posts = getPosts(
846
                        $forumData,
847
                        $thread['thread_id']
848
                    );
849
850
                    foreach ($posts as $post) {
851
                        $postId = $post['post_id'];
852
                        $attachMentList = getAllAttachment($postId);
853
                        if (!empty($attachMentList)) {
854
                            foreach ($attachMentList as $attachMent) {
855
                                $sql = "UPDATE $tableItemProperty 
856
                                        SET to_group_id = $toGroupId
857
                                        WHERE 
858
                                            tool = '".TOOL_FORUM_ATTACH."' AND 
859
                                            ref = ".$attachMent['iid']." AND
860
                                            c_id = ".$courseId;
861
                                Database::query($sql);
862
                            }
863
                        }
864
865
                        $sql = "UPDATE $tableItemProperty 
866
                                SET to_group_id = $toGroupId
867
                                WHERE 
868
                                    tool = '".TOOL_FORUM_POST."' AND
869
                                    ref = $postId AND
870
                                    c_id = $courseId";
871
                        Database::query($sql);
872
                    }
873
                }
874
            }
875
        }
876
877
        Database::update(
878
            $table_forums,
879
            $params,
880
            ['c_id = ? AND forum_id = ?' => [$courseId, $values['forum_id']]]
881
        );
882
883
        api_item_property_update(
884
            $courseInfo,
885
            TOOL_FORUM,
886
            Database::escape_string($values['forum_id']),
887
            'ForumUpdated',
888
            api_get_user_id(),
889
            $groupInfo
890
        );
891
892
        $return_message = get_lang('ForumEdited');
893
        $forumId = $values['forum_id'];
894
895
        $logInfo = [
896
            'tool' => TOOL_FORUM,
897
            'tool_id' => $values['forum_id'],
898
            'tool_id_detail' => 0,
899
            'action' => 'update-forum',
900
            'action_details' => 'forum',
901
            'info' => $values['forum_title'],
902
        ];
903
        Event::registerLog($logInfo);
904
    } else {
905
        if ($image_moved) {
906
            $new_file_name = isset($new_file_name) ? $new_file_name : '';
907
        }
908
        $params = [
909
            'c_id' => $courseId,
910
            'forum_title' => $values['forum_title'],
911
            'forum_image' => $new_file_name,
912
            'forum_comment' => isset($values['forum_comment']) ? $values['forum_comment'] : null,
913
            'forum_category' => isset($values['forum_category']) ? $values['forum_category'] : null,
914
            'allow_anonymous' => isset($values['allow_anonymous_group']['allow_anonymous']) ? $values['allow_anonymous_group']['allow_anonymous'] : null,
915
            'allow_edit' => isset($values['students_can_edit_group']['students_can_edit']) ? $values['students_can_edit_group']['students_can_edit'] : null,
916
            'approval_direct_post' => isset($values['approval_direct_group']['approval_direct']) ? $values['approval_direct_group']['approval_direct'] : null,
917
            'allow_attachments' => isset($values['allow_attachments_group']['allow_attachments']) ? $values['allow_attachments_group']['allow_attachments'] : null,
918
            'allow_new_threads' => isset($values['allow_new_threads_group']['allow_new_threads']) ? $values['allow_new_threads_group']['allow_new_threads'] : null,
919
            'default_view' => isset($values['default_view_type_group']['default_view_type']) ? $values['default_view_type_group']['default_view_type'] : null,
920
            'forum_of_group' => isset($values['group_forum']) ? $values['group_forum'] : null,
921
            '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,
922
            'moderated' => isset($values['moderated']['moderated']) ? (int) $values['moderated']['moderated'] : 0,
923
            'start_time' => !empty($values['start_time']) ? api_get_utc_datetime($values['start_time']) : null,
924
            'end_time' => !empty($values['end_time']) ? api_get_utc_datetime($values['end_time']) : null,
925
            'forum_order' => isset($new_max) ? $new_max : null,
926
            'session_id' => $session_id,
927
            'lp_id' => isset($values['lp_id']) ? intval($values['lp_id']) : 0,
928
            'locked' => 0,
929
            'forum_id' => 0,
930
        ];
931
932
        $forumId = Database::insert($table_forums, $params);
933
        if ($forumId > 0) {
934
            $sql = "UPDATE $table_forums SET forum_id = iid WHERE iid = $forumId";
935
            Database::query($sql);
936
937
            api_item_property_update(
938
                $courseInfo,
939
                TOOL_FORUM,
940
                $forumId,
0 ignored issues
show
Bug introduced by
It seems like $forumId can also be of type false; however, parameter $item_id of api_item_property_update() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

940
                /** @scrutinizer ignore-type */ $forumId,
Loading history...
941
                'ForumAdded',
942
                api_get_user_id(),
943
                $groupInfo
944
            );
945
946
            api_set_default_visibility(
947
                $forumId,
0 ignored issues
show
Bug introduced by
It seems like $forumId can also be of type false; however, parameter $item_id of api_set_default_visibility() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

947
                /** @scrutinizer ignore-type */ $forumId,
Loading history...
948
                TOOL_FORUM,
949
                $group_id,
950
                $courseInfo
951
            );
952
953
            $logInfo = [
954
                'tool' => TOOL_FORUM,
955
                'tool_id' => $forumId,
956
                'tool_id_detail' => 0,
957
                'action' => 'new-forum',
958
                'action_details' => 'forum',
959
                'info' => $values['forum_title'],
960
            ];
961
            Event::registerLog($logInfo);
962
        }
963
        $return_message = get_lang('ForumAdded');
964
    }
965
966
    if ($returnId) {
967
        return $forumId;
968
    }
969
970
    return $return_message;
971
}
972
973
/**
974
 * This function deletes a forum or a forum category
975
 * This function currently does not delete the forums inside the category,
976
 * nor the threads and replies inside these forums.
977
 * For the moment this is the easiest method and it has the advantage that it
978
 * allows to recover fora that were acidently deleted
979
 * when the forum category got deleted.
980
 *
981
 * @param $content = what we are deleting (a forum or a forum category)
0 ignored issues
show
Documentation Bug introduced by
The doc comment = at position 0 could not be parsed: Unknown type name '=' at position 0 in =.
Loading history...
982
 * @param $id the id of the forum category that has to be deleted
983
 *
984
 * @todo write the code for the cascading deletion of the forums inside a
985
 * forum category and also the threads and replies inside these forums
986
 * @todo config setting for recovery or not
987
 * (see also the documents tool: real delete or not).
988
 *
989
 * @return string
990
 *
991
 * @author Patrick Cool <[email protected]>, Ghent University
992
 *
993
 * @version february 2006, dokeos 1.8
994
 */
995
function deleteForumCategoryThread($content, $id)
996
{
997
    $_course = api_get_course_info();
998
    $table_forums = Database::get_course_table(TABLE_FORUM);
999
    $table_forums_post = Database::get_course_table(TABLE_FORUM_POST);
1000
    $table_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
1001
    $course_id = api_get_course_int_id();
1002
    $groupId = api_get_group_id();
1003
    $groupInfo = GroupManager::get_group_properties($groupId);
1004
    $userId = api_get_user_id();
1005
    $id = intval($id);
1006
1007
    // Delete all attachment file about this tread id.
1008
    $sql = "SELECT post_id FROM $table_forums_post
1009
            WHERE c_id = $course_id AND thread_id = '".$id."' ";
1010
    $res = Database::query($sql);
1011
    while ($poster_id = Database::fetch_row($res)) {
1012
        delete_attachment($poster_id[0]);
1013
    }
1014
1015
    $tool_constant = null;
1016
    $return_message = '';
1017
    if ($content == 'forumcategory') {
1018
        $tool_constant = TOOL_FORUM_CATEGORY;
1019
        $return_message = get_lang('ForumCategoryDeleted');
1020
1021
        if (!empty($forum_list)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $forum_list does not exist. Did you maybe mean $forum_id?
Loading history...
1022
            $sql = "SELECT forum_id FROM $table_forums
1023
                    WHERE c_id = $course_id AND forum_category='".$id."'";
1024
            $result = Database::query($sql);
1025
            $row = Database::fetch_array($result);
1026
            foreach ($row as $arr_forum) {
1027
                $forum_id = $arr_forum['forum_id'];
1028
                api_item_property_update(
1029
                    $_course,
1030
                    'forum',
1031
                    $forum_id,
1032
                    'delete',
1033
                    api_get_user_id()
1034
                );
1035
            }
1036
        }
1037
    }
1038
1039
    if ($content == 'forum') {
1040
        $tool_constant = TOOL_FORUM;
1041
        $return_message = get_lang('ForumDeleted');
1042
1043
        if (!empty($number_threads)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $number_threads seems to never exist and therefore empty should always be true.
Loading history...
1044
            $sql = "SELECT thread_id FROM $table_forum_thread 
1045
                    WHERE c_id = $course_id AND forum_id = $id ";
1046
            $result = Database::query($sql);
1047
            $row = Database::fetch_array($result);
1048
            foreach ($row as $arr_forum) {
1049
                $forum_id = $arr_forum['thread_id'];
1050
                api_item_property_update(
1051
                    $_course,
1052
                    'forum_thread',
1053
                    $forum_id,
1054
                    'delete',
1055
                    api_get_user_id()
1056
                );
1057
            }
1058
        }
1059
    }
1060
1061
    if ($content == 'thread') {
1062
        $tool_constant = TOOL_FORUM_THREAD;
1063
        $return_message = get_lang('ThreadDeleted');
1064
        Skill::deleteSkillsFromItem($id, ITEM_TYPE_FORUM_THREAD);
1065
    }
1066
1067
    api_item_property_update(
1068
        $_course,
1069
        $tool_constant,
1070
        $id,
1071
        'delete',
1072
        $userId,
1073
        $groupInfo
1074
    );
1075
1076
    // Check if this returns a true and if so => return $return_message, if not => return false;
1077
    if (!empty($return_message)) {
1078
        Display::addFlash(Display::return_message($return_message, 'confirmation', false));
1079
    }
1080
1081
    return $return_message;
1082
}
1083
1084
/**
1085
 * This function deletes a forum post. This separate function is needed because forum posts do not appear
1086
 * in the item_property table (yet)
1087
 * and because deleting a post also has consequence on the posts that have this post as parent_id
1088
 * (they are also deleted).
1089
 * an alternative would be to store the posts also in item_property and mark this post as deleted (visibility = 2).
1090
 * We also have to decrease the number of replies in the thread table.
1091
 *
1092
 * @param $post_id the id of the post that will be deleted
1093
 *
1094
 * @todo write recursive function that deletes all the posts that have this message as parent
1095
 *
1096
 * @return string language variable
1097
 *
1098
 * @author Patrick Cool <[email protected]>, Ghent University
1099
 * @author Hubert Borderiou Function cleanead and fixed
1100
 *
1101
 * @version february 2006
1102
 */
1103
function delete_post($post_id)
1104
{
1105
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1106
    $post_id = intval($post_id);
1107
    $course_id = api_get_course_int_id();
1108
    $em = Database::getManager();
1109
1110
    $post = $em
1111
        ->getRepository('ChamiloCourseBundle:CForumPost')
1112
        ->findOneBy(['cId' => $course_id, 'postId' => $post_id]);
1113
1114
    if ($post) {
1115
        $em
1116
            ->createQuery('
1117
                UPDATE ChamiloCourseBundle:CForumPost p
1118
                SET p.postParentId = :parent_of_deleted_post
1119
                WHERE
1120
                    p.cId = :course AND
1121
                    p.postParentId = :post AND
1122
                    p.threadId = :thread_of_deleted_post AND
1123
                    p.forumId = :forum_of_deleted_post
1124
            ')
1125
            ->execute([
1126
                'parent_of_deleted_post' => $post->getPostParentId(),
1127
                'course' => $course_id,
1128
                'post' => $post->getPostId(),
1129
                'thread_of_deleted_post' => $post->getThread() ? $post->getThread()->getIid() : 0,
1130
                'forum_of_deleted_post' => $post->getForumId(),
1131
            ]);
1132
1133
        $em->remove($post);
1134
        $em->flush();
1135
1136
        // Delete attachment file about this post id.
1137
        delete_attachment($post_id);
1138
    }
1139
1140
    $last_post_of_thread = check_if_last_post_of_thread($_GET['thread']);
1141
1142
    if (is_array($last_post_of_thread)) {
1143
        // Decreasing the number of replies for this thread and also changing the last post information.
1144
        $sql = "UPDATE $table_threads
1145
                SET
1146
                    thread_replies = thread_replies - 1,
1147
                    thread_last_post = ".intval($last_post_of_thread['post_id']).",
1148
                    thread_date='".Database::escape_string($last_post_of_thread['post_date'])."'
1149
                WHERE c_id = $course_id AND thread_id = ".intval($_GET['thread']);
1150
        Database::query($sql);
1151
1152
        return 'PostDeleted';
1153
    }
1154
    if (!$last_post_of_thread) {
0 ignored issues
show
introduced by
$last_post_of_thread is of type an, thus it always evaluated to true.
Loading history...
1155
        // We deleted the very single post of the thread so we need to delete the entry in the thread table also.
1156
        $sql = "DELETE FROM $table_threads
1157
                WHERE c_id = $course_id AND thread_id = ".intval($_GET['thread']);
1158
        Database::query($sql);
1159
1160
        return 'PostDeletedSpecial';
1161
    }
1162
}
1163
1164
/**
1165
 * This function gets the all information of the last (=most recent) post of the thread
1166
 * This can be done by sorting the posts that have the field thread_id=$thread_id and sort them by post_date.
1167
 *
1168
 * @param $thread_id the id of the thread we want to know the last post of
1169
 *
1170
 * @return an array or bool if there is a last post found, false if there is
1171
 *            no post entry linked to that thread => thread will be deleted
1172
 *
1173
 * @author Patrick Cool <[email protected]>, Ghent University
1174
 *
1175
 * @version february 2006, dokeos 1.8
1176
 */
1177
function check_if_last_post_of_thread($thread_id)
1178
{
1179
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1180
    $course_id = api_get_course_int_id();
1181
    $sql = "SELECT * FROM $table_posts
1182
            WHERE c_id = $course_id AND thread_id = ".intval($thread_id)."
1183
            ORDER BY post_date DESC";
1184
    $result = Database::query($sql);
1185
    if (Database::num_rows($result) > 0) {
1186
        $row = Database::fetch_array($result);
1187
1188
        return $row;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $row also could return the type array which is incompatible with the documented return type an.
Loading history...
1189
    } else {
1190
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type an.
Loading history...
1191
    }
1192
}
1193
1194
/**
1195
 * @param string $content                   Type of content forum category, forum, thread, post
1196
 * @param int    $id                        the id of the content we want to make invisible
1197
 * @param int    $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
1198
 * @param array  $additional_url_parameters
1199
 *
1200
 * @return string HTML
1201
 */
1202
function return_visible_invisible_icon(
1203
    $content,
1204
    $id,
1205
    $current_visibility_status,
1206
    $additional_url_parameters = ''
1207
) {
1208
    $html = '';
1209
    $id = (int) $id;
1210
    $current_visibility_status = (int) $current_visibility_status;
1211
1212
    if ($current_visibility_status == 1) {
1213
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1214
        if (is_array($additional_url_parameters)) {
1215
            foreach ($additional_url_parameters as $key => $value) {
1216
                $html .= $key.'='.$value.'&';
1217
            }
1218
        }
1219
        $html .= 'action=invisible&content='.$content.'&id='.$id.'">'.
1220
            Display::return_icon('visible.png', get_lang('MakeInvisible'), [], ICON_SIZE_SMALL).'</a>';
1221
    }
1222
    if ($current_visibility_status == 0) {
1223
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1224
        if (is_array($additional_url_parameters)) {
1225
            foreach ($additional_url_parameters as $key => $value) {
1226
                $html .= $key.'='.$value.'&';
1227
            }
1228
        }
1229
        $html .= 'action=visible&content='.$content.'&id='.$id.'">'.
1230
            Display::return_icon('invisible.png', get_lang('MakeVisible'), [], ICON_SIZE_SMALL).'</a>';
1231
    }
1232
1233
    return $html;
1234
}
1235
1236
/**
1237
 * @param $content
1238
 * @param $id
1239
 * @param $current_lock_status
1240
 * @param string $additional_url_parameters
1241
 *
1242
 * @return string
1243
 */
1244
function return_lock_unlock_icon($content, $id, $current_lock_status, $additional_url_parameters = '')
1245
{
1246
    $html = '';
1247
    $id = intval($id);
1248
    //check if the forum is blocked due
1249
    if ($content == 'thread') {
1250
        if (api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD)) {
1251
            $html .= Display::return_icon(
1252
                'lock_na.png',
1253
                get_lang('ResourceLockedByGradebook'),
1254
                [],
1255
                ICON_SIZE_SMALL
1256
            );
1257
1258
            return $html;
1259
        }
1260
    }
1261
    if ($current_lock_status == '1') {
1262
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1263
        if (is_array($additional_url_parameters)) {
1264
            foreach ($additional_url_parameters as $key => $value) {
1265
                $html .= $key.'='.$value.'&';
1266
            }
1267
        }
1268
        $html .= 'action=unlock&content='.$content.'&id='.$id.'">'.
1269
            Display::return_icon('lock.png', get_lang('Unlock'), [], ICON_SIZE_SMALL).'</a>';
1270
    }
1271
    if ($current_lock_status == '0') {
1272
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1273
        if (is_array($additional_url_parameters)) {
1274
            foreach ($additional_url_parameters as $key => $value) {
1275
                $html .= $key.'='.$value.'&';
1276
            }
1277
        }
1278
        $html .= 'action=lock&content='.$content.'&id='.$id.'">'.
1279
            Display::return_icon('unlock.png', get_lang('Lock'), [], ICON_SIZE_SMALL).'</a>';
1280
    }
1281
1282
    return $html;
1283
}
1284
1285
/**
1286
 * This function takes care of the display of the up and down icon.
1287
 *
1288
 * @param string $content what is it that we want to make (in)visible: forum category, forum, thread, post
1289
 * @param int    $id      is the id of the item we want to display the icons for
1290
 * @param array  $list    is an array of all the items. All items in this list should have
1291
 *                        an up and down icon except for the first (no up icon) and the last (no down icon)
1292
 *                        The key of this $list array is the id of the item.
1293
 *
1294
 * @return string HTML
1295
 */
1296
function return_up_down_icon($content, $id, $list)
1297
{
1298
    $id = (int) $id;
1299
    $total_items = count($list);
1300
    $position = 0;
1301
    $internal_counter = 0;
1302
    $forumCategory = isset($_GET['forumcategory']) ? Security::remove_XSS($_GET['forumcategory']) : null;
1303
1304
    if (is_array($list)) {
1305
        foreach ($list as $key => $listitem) {
1306
            $internal_counter++;
1307
            if ($id == $key) {
1308
                $position = $internal_counter;
1309
            }
1310
        }
1311
    }
1312
1313
    if ($position > 1) {
1314
        $return_value = '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=up&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('MoveUp').'">'.
1315
            Display::return_icon('up.png', get_lang('MoveUp'), [], ICON_SIZE_SMALL).'</a>';
1316
    } else {
1317
        $return_value = Display::return_icon('up_na.png', '-', [], ICON_SIZE_SMALL);
1318
    }
1319
1320
    if ($position < $total_items) {
1321
        $return_value .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=down&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('MoveDown').'" >'.
1322
            Display::return_icon('down.png', get_lang('MoveDown'), [], ICON_SIZE_SMALL).'</a>';
1323
    } else {
1324
        $return_value .= Display::return_icon('down_na.png', '-', [], ICON_SIZE_SMALL);
1325
    }
1326
1327
    return $return_value;
1328
}
1329
1330
/**
1331
 * This function changes the visibility in the database (item_property).
1332
 *
1333
 * @param string $content           what is it that we want to make (in)visible: forum category, forum, thread, post
1334
 * @param int    $id                the id of the content we want to make invisible
1335
 * @param string $target_visibility what is the current status of the visibility (0 = invisible, 1 = visible)
1336
 *
1337
 * @todo change the get parameter so that it matches the tool constants.
1338
 * @todo check if api_item_property_update returns true or false => returnmessage depends on it.
1339
 * @todo move to itemmanager
1340
 *
1341
 * @return string language variable
1342
 *
1343
 * @author Patrick Cool <[email protected]>, Ghent University
1344
 *
1345
 * @version february 2006, dokeos 1.8
1346
 */
1347
function change_visibility($content, $id, $target_visibility)
1348
{
1349
    $_course = api_get_course_info();
1350
    $constants = [
1351
        'forumcategory' => TOOL_FORUM_CATEGORY,
1352
        'forum' => TOOL_FORUM,
1353
        'thread' => TOOL_FORUM_THREAD,
1354
    ];
1355
    api_item_property_update(
1356
        $_course,
1357
        $constants[$content],
1358
        $id,
1359
        $target_visibility,
1360
        api_get_user_id()
1361
    );
1362
1363
    if ($target_visibility == 'visible') {
1364
        handle_mail_cue($content, $id);
1365
    }
1366
1367
    return get_lang('VisibilityChanged');
1368
}
1369
1370
/**
1371
 * This function changes the lock status in the database.
1372
 *
1373
 * @param string $content what is it that we want to (un)lock: forum category, forum, thread, post
1374
 * @param int    $id      the id of the content we want to (un)lock
1375
 * @param string $action  do we lock (=>locked value in db = 1) or unlock (=> locked value in db = 0)
1376
 *
1377
 * @return string language variable
1378
 *
1379
 * @todo move to item manager
1380
 *
1381
 * @author Patrick Cool <[email protected]>, Ghent University
1382
 *
1383
 * @version february 2006, dokeos 1.8
1384
 */
1385
function change_lock_status($content, $id, $action)
1386
{
1387
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1388
    $table_forums = Database::get_course_table(TABLE_FORUM);
1389
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1390
1391
    // Determine the relevant table.
1392
    if ($content == 'forumcategory') {
1393
        $table = $table_categories;
1394
        $id_field = 'cat_id';
1395
    } elseif ($content == 'forum') {
1396
        $table = $table_forums;
1397
        $id_field = 'forum_id';
1398
    } elseif ($content == 'thread') {
1399
        $table = $table_threads;
1400
        $id_field = 'thread_id';
1401
    } else {
1402
        return get_lang('Error');
1403
    }
1404
1405
    // Determine what we are doing => defines the value for the database and the return message.
1406
    if ($action == 'lock') {
1407
        $db_locked = 1;
1408
        $return_message = get_lang('Locked');
1409
    } elseif ($action == 'unlock') {
1410
        $db_locked = 0;
1411
        $return_message = get_lang('Unlocked');
1412
    } else {
1413
        return get_lang('Error');
1414
    }
1415
1416
    $course_id = api_get_course_int_id();
1417
1418
    // Doing the change in the database
1419
    $sql = "UPDATE $table SET locked='".Database::escape_string($db_locked)."'
1420
            WHERE c_id = $course_id AND $id_field='".Database::escape_string($id)."'";
1421
    if (Database::query($sql)) {
1422
        return $return_message;
1423
    } else {
1424
        return get_lang('Error');
1425
    }
1426
}
1427
1428
/**
1429
 * This function moves a forum or a forum category up or down.
1430
 *
1431
 * @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
1432
 * @param $direction do we want to move it up or down
1433
 * @param $id the id of the content we want to make invisible
1434
 *
1435
 * @todo consider removing the table_item_property calls here but this can
1436
 * prevent unwanted side effects when a forum does not have an entry in
1437
 * the item_property table but does have one in the forum table.
1438
 *
1439
 * @return string language variable
1440
 *
1441
 * @author Patrick Cool <[email protected]>, Ghent University
1442
 *
1443
 * @version february 2006, dokeos 1.8
1444
 */
1445
function move_up_down($content, $direction, $id)
1446
{
1447
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1448
    $table_forums = Database::get_course_table(TABLE_FORUM);
1449
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1450
    $course_id = api_get_course_int_id();
1451
    $id = intval($id);
1452
1453
    // Determine which field holds the sort order.
1454
    if ($content == 'forumcategory') {
1455
        $table = $table_categories;
1456
        $sort_column = 'cat_order';
1457
        $id_column = 'cat_id';
1458
        $sort_column = 'cat_order';
1459
    } elseif ($content == 'forum') {
1460
        $table = $table_forums;
1461
        $sort_column = 'forum_order';
1462
        $id_column = 'forum_id';
1463
        $sort_column = 'forum_order';
1464
        // We also need the forum_category of this forum.
1465
        $sql = "SELECT forum_category FROM $table_forums
1466
                WHERE c_id = $course_id AND forum_id = ".intval($id);
1467
        $result = Database::query($sql);
1468
        $row = Database::fetch_array($result);
1469
        $forum_category = $row['forum_category'];
1470
    } else {
1471
        return get_lang('Error');
1472
    }
1473
1474
    // Determine the need for sorting ascending or descending order.
1475
    if ($direction == 'down') {
1476
        $sort_direction = 'ASC';
1477
    } elseif ($direction == 'up') {
1478
        $sort_direction = 'DESC';
1479
    } else {
1480
        return get_lang('Error');
1481
    }
1482
1483
    // The SQL statement
1484
    if ($content == 'forumcategory') {
1485
        $sql = "SELECT *
1486
                FROM $table_categories forum_categories, $table_item_property item_properties
1487
                WHERE
1488
                    forum_categories.c_id = $course_id AND
1489
                    item_properties.c_id = $course_id AND
1490
                    forum_categories.cat_id=item_properties.ref AND
1491
                    item_properties.tool='".TOOL_FORUM_CATEGORY."'
1492
                ORDER BY forum_categories.cat_order $sort_direction";
1493
    }
1494
    if ($content == 'forum') {
1495
        $sql = "SELECT *
1496
            FROM $table
1497
            WHERE
1498
                c_id = $course_id AND
1499
                forum_category='".Database::escape_string($forum_category)."'
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $forum_category does not seem to be defined for all execution paths leading up to this point.
Loading history...
1500
            ORDER BY forum_order $sort_direction";
1501
    }
1502
    // Finding the items that need to be switched.
1503
    $result = Database::query($sql);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sql does not seem to be defined for all execution paths leading up to this point.
Loading history...
1504
    $found = false;
1505
    while ($row = Database::fetch_array($result)) {
1506
        if ($found) {
1507
            $next_id = $row[$id_column];
1508
            $next_sort = $row[$sort_column];
1509
            $found = false;
1510
        }
1511
        if ($id == $row[$id_column]) {
1512
            $this_id = $id;
1513
            $this_sort = $row[$sort_column];
1514
            $found = true;
1515
        }
1516
    }
1517
1518
    // Committing the switch.
1519
    // We do an extra check if we do not have illegal values. If your remove this if statement you will
1520
    // be able to mess with the sorting by refreshing the page over and over again.
1521
    if ($this_sort != '' && $next_sort != '' && $next_id != '' && $this_id != '') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $this_sort does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $next_sort does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $next_id does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $this_id does not seem to be defined for all execution paths leading up to this point.
Loading history...
1522
        $sql = "UPDATE $table SET $sort_column='".Database::escape_string($this_sort)."'
1523
                WHERE c_id = $course_id AND $id_column='".Database::escape_string($next_id)."'";
1524
        Database::query($sql);
1525
1526
        $sql = "UPDATE $table SET $sort_column='".Database::escape_string($next_sort)."'
1527
                WHERE c_id = $course_id AND $id_column='".Database::escape_string($this_id)."'";
1528
        Database::query($sql);
1529
    }
1530
1531
    return get_lang(ucfirst($content).'Moved');
1532
}
1533
1534
/**
1535
 * Retrieve all the information off the forum categories (or one specific) for the current course.
1536
 * The categories are sorted according to their sorting order (cat_order.
1537
 *
1538
 * @param int|string $id        default ''. When an id is passed we only find the information
1539
 *                              about that specific forum category. If no id is passed we get all the forum categories.
1540
 * @param int        $courseId  Optional. The course ID
1541
 * @param int        $sessionId Optional. The session ID
1542
 *
1543
 * @return array containing all the information about all the forum categories
1544
 *
1545
 * @author Patrick Cool <[email protected]>, Ghent University
1546
 *
1547
 * @version february 2006, dokeos 1.8
1548
 */
1549
function get_forum_categories($id = '', $courseId = 0, $sessionId = 0)
1550
{
1551
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1552
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1553
1554
    // Condition for the session
1555
    $session_id = $sessionId ?: api_get_session_id();
1556
    $course_id = $courseId ?: api_get_course_int_id();
1557
1558
    $condition_session = api_get_session_condition(
1559
        $session_id,
1560
        true,
1561
        true,
1562
        'forum_categories.session_id'
1563
    );
1564
    $condition_session .= " AND forum_categories.c_id = $course_id AND item_properties.c_id = $course_id";
1565
1566
    if (empty($id)) {
1567
        $sql = "SELECT *
1568
                FROM $table_item_property item_properties 
1569
                INNER JOIN $table_categories forum_categories
1570
                ON (
1571
                    forum_categories.cat_id = item_properties.ref AND 
1572
                    item_properties.c_id = forum_categories.c_id
1573
                )
1574
                WHERE                    
1575
                    item_properties.visibility = 1 AND
1576
                    item_properties.tool = '".TOOL_FORUM_CATEGORY."'
1577
                    $condition_session
1578
                ORDER BY forum_categories.cat_order ASC";
1579
        if (api_is_allowed_to_edit()) {
1580
            $sql = "SELECT *
1581
                    FROM $table_item_property item_properties  
1582
                    INNER JOIN $table_categories forum_categories
1583
                    ON (
1584
                        forum_categories.cat_id = item_properties.ref AND 
1585
                        item_properties.c_id = forum_categories.c_id
1586
                    )
1587
                    WHERE                        
1588
                        item_properties.visibility<>2 AND
1589
                        item_properties.tool='".TOOL_FORUM_CATEGORY."'
1590
                        $condition_session
1591
                    ORDER BY forum_categories.cat_order ASC";
1592
        }
1593
    } else {
1594
        $sql = "SELECT *
1595
                FROM $table_item_property item_properties 
1596
                INNER JOIN $table_categories forum_categories
1597
                ON (
1598
                    forum_categories.cat_id = item_properties.ref AND 
1599
                    item_properties.c_id = forum_categories.c_id
1600
                )
1601
                WHERE                    
1602
                    item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
1603
                    forum_categories.cat_id = ".intval($id)."
1604
                    $condition_session
1605
                ORDER BY forum_categories.cat_order ASC";
1606
    }
1607
1608
    $result = Database::query($sql);
1609
    $forum_categories_list = [];
1610
    $extraFieldValue = new ExtraFieldValue('forum_category');
1611
    while ($row = Database::fetch_assoc($result)) {
1612
        $row['extra_fields'] = $extraFieldValue->getAllValuesByItem($row['cat_id']);
1613
1614
        if (empty($id)) {
1615
            $forum_categories_list[$row['cat_id']] = $row;
1616
        } else {
1617
            $forum_categories_list = $row;
1618
        }
1619
    }
1620
1621
    return $forum_categories_list;
1622
}
1623
1624
/**
1625
 * This function retrieves all the fora in a given forum category.
1626
 *
1627
 * @param int $cat_id   the id of the forum category
1628
 * @param int $courseId Optional. The course ID
1629
 *
1630
 * @return array containing all the information about the forums (regardless of their category)
1631
 *
1632
 * @author Patrick Cool <[email protected]>, Ghent University
1633
 *
1634
 * @version february 2006, dokeos 1.8
1635
 */
1636
function get_forums_in_category($cat_id, $courseId = 0)
1637
{
1638
    $table_forums = Database::get_course_table(TABLE_FORUM);
1639
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1640
1641
    $forum_list = [];
1642
    $course_id = $courseId ?: api_get_course_int_id();
1643
    $cat_id = (int) $cat_id;
1644
1645
    $sql = "SELECT * FROM $table_forums forum 
1646
            INNER JOIN $table_item_property item_properties
1647
            ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
1648
            WHERE
1649
                forum.forum_category = '".$cat_id."' AND                
1650
                item_properties.visibility = 1 AND
1651
                forum.c_id = $course_id AND
1652
                item_properties.c_id = $course_id AND
1653
                item_properties.tool = '".TOOL_FORUM."'                 
1654
            ORDER BY forum.forum_order ASC";
1655
    if (api_is_allowed_to_edit()) {
1656
        $sql = "SELECT * FROM $table_forums forum  
1657
                INNER JOIN $table_item_property item_properties
1658
                ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
1659
                WHERE
1660
                    forum.forum_category = '".$cat_id."' AND                    
1661
                    item_properties.visibility <> 2 AND
1662
                    item_properties.tool = '".TOOL_FORUM."' AND
1663
                    item_properties.c_id = $course_id AND
1664
                    forum.c_id = $course_id
1665
                ORDER BY forum_order ASC";
1666
    }
1667
    $result = Database::query($sql);
1668
    while ($row = Database::fetch_array($result)) {
1669
        $forum_list[$row['forum_id']] = $row;
1670
    }
1671
1672
    return $forum_list;
1673
}
1674
1675
/**
1676
 * Retrieve all the forums (regardless of their category) or of only one.
1677
 * The forums are sorted according to the forum_order.
1678
 * Since it does not take the forum category into account there probably
1679
 * will be two or more forums that have forum_order=1, ...
1680
 *
1681
 * @param int    $id                 forum id
1682
 * @param string $course_code
1683
 * @param bool   $includeGroupsForum
1684
 * @param int    $sessionId
1685
 *
1686
 * @return array an array containing all the information about the forums (regardless of their category)
1687
 *
1688
 * @todo check $sql4 because this one really looks fishy.
1689
 *
1690
 * @author Patrick Cool <[email protected]>, Ghent University
1691
 *
1692
 * @version february 2006, dokeos 1.8
1693
 */
1694
function get_forums(
1695
    $id = '',
1696
    $course_code = '',
1697
    $includeGroupsForum = true,
1698
    $sessionId = 0
1699
) {
1700
    $course_info = api_get_course_info($course_code);
1701
1702
    $table_forums = Database::get_course_table(TABLE_FORUM);
1703
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1704
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1705
1706
    // Condition for the session
1707
    $session_id = intval($sessionId) ?: api_get_session_id();
1708
    $sessionIdLink = $session_id === 0 ? '' : ' AND threads.session_id = item_properties.session_id';
1709
1710
    $condition_session = api_get_session_condition(
1711
        $session_id,
1712
        true,
1713
        false,
1714
        'item_properties.session_id'
1715
    );
1716
1717
    $course_id = $course_info['real_id'];
1718
1719
    $forum_list = [];
1720
    $includeGroupsForumSelect = '';
1721
    if (!$includeGroupsForum) {
1722
        $includeGroupsForumSelect = " AND (forum_of_group = 0 OR forum_of_group IS NULL) ";
1723
    }
1724
1725
    if ($id == '') {
1726
        // Student
1727
        // Select all the forum information of all forums (that are visible to students).
1728
        $sql = "SELECT item_properties.*, forum.* 
1729
                FROM $table_forums forum
1730
                INNER JOIN $table_item_property item_properties
1731
                ON (
1732
                    forum.forum_id = item_properties.ref AND
1733
                    forum.c_id = item_properties.c_id
1734
                )
1735
                WHERE
1736
                    item_properties.visibility = 1 AND
1737
                    item_properties.tool = '".TOOL_FORUM."'
1738
                    $condition_session AND
1739
                    forum.c_id = $course_id AND
1740
                    item_properties.c_id = $course_id
1741
                    $includeGroupsForumSelect
1742
                ORDER BY forum.forum_order ASC";
1743
1744
        // Select the number of threads of the forums (only the threads that are visible).
1745
        $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1746
                FROM $table_threads threads
1747
                INNER JOIN $table_item_property item_properties
1748
                ON (
1749
                    threads.thread_id = item_properties.ref AND
1750
                    threads.c_id = item_properties.c_id
1751
                    $sessionIdLink
1752
                )
1753
                WHERE
1754
                    item_properties.visibility=1 AND
1755
                    item_properties.tool='".TOOL_FORUM_THREAD."' AND
1756
                    threads.c_id = $course_id AND
1757
                    item_properties.c_id = $course_id
1758
                GROUP BY threads.forum_id";
1759
1760
        // Course Admin
1761
        if (api_is_allowed_to_edit()) {
1762
            // Select all the forum information of all forums (that are not deleted).
1763
            $sql = "SELECT item_properties.*, forum.* 
1764
                    FROM $table_forums forum
1765
                    INNER JOIN $table_item_property item_properties
1766
                    ON (
1767
                        forum.forum_id = item_properties.ref AND
1768
                        forum.c_id = item_properties.c_id
1769
                    )
1770
                    WHERE
1771
                        item_properties.visibility <> 2 AND
1772
                        item_properties.tool = '".TOOL_FORUM."'
1773
                        $condition_session AND
1774
                        forum.c_id = $course_id AND
1775
                        item_properties.c_id = $course_id
1776
                        $includeGroupsForumSelect
1777
                    ORDER BY forum_order ASC";
1778
1779
            // Select the number of threads of the forums (only the threads that are not deleted).
1780
            $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1781
                    FROM $table_threads threads
1782
                    INNER JOIN $table_item_property item_properties
1783
                    ON (
1784
                        threads.thread_id = item_properties.ref AND
1785
                        threads.c_id = item_properties.c_id
1786
                        $sessionIdLink
1787
                    )
1788
                    WHERE
1789
                        item_properties.visibility<>2 AND
1790
                        item_properties.tool='".TOOL_FORUM_THREAD."' AND
1791
                        threads.c_id = $course_id AND
1792
                        item_properties.c_id = $course_id
1793
                    GROUP BY threads.forum_id";
1794
        }
1795
    } else {
1796
        // GETTING ONE SPECIFIC FORUM
1797
        /* We could do the splitup into student and course admin also but we want
1798
        to have as much as information about a certain forum as possible
1799
        so we do not take too much information into account. This function
1800
         (or this section of the function) is namely used to fill the forms
1801
        when editing a forum (and for the moment it is the only place where
1802
        we use this part of the function) */
1803
1804
        // Select all the forum information of the given forum (that is not deleted).
1805
        $sql = "SELECT * FROM $table_item_property item_properties 
1806
                INNER JOIN $table_forums forum
1807
                ON (forum.forum_id = item_properties.ref AND forum.c_id = item_properties.c_id)
1808
                WHERE
1809
                    forum.forum_id = ".intval($id)." AND
1810
                    forum.c_id = $course_id AND
1811
                    item_properties.visibility != 2 AND
1812
                    item_properties.tool = '".TOOL_FORUM."'
1813
                ORDER BY forum_order ASC";
1814
1815
        // Select the number of threads of the forum.
1816
        $sql2 = "SELECT count(*) AS number_of_threads, forum_id
1817
                FROM $table_threads
1818
                WHERE
1819
                    forum_id = ".intval($id)."
1820
                GROUP BY forum_id";
1821
    }
1822
1823
    // Handling all the forum information.
1824
    $result = Database::query($sql);
1825
    while ($row = Database::fetch_assoc($result)) {
1826
        if ($id == '') {
1827
            $forum_list[$row['forum_id']] = $row;
1828
        } else {
1829
            $forum_list = $row;
1830
        }
1831
    }
1832
1833
    // Handling the thread count information.
1834
    $result2 = Database::query($sql2);
1835
    while ($row2 = Database::fetch_array($result2)) {
1836
        if ($id == '') {
1837
            $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
1838
        } else {
1839
            $forum_list['number_of_threads'] = $row2['number_of_threads'];
1840
        }
1841
    }
1842
1843
    /* Finding the last post information
1844
    (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)*/
1845
    if ($id == '') {
1846
        if (is_array($forum_list)) {
1847
            foreach ($forum_list as $key => $value) {
1848
                $last_post_info_of_forum = get_last_post_information(
1849
                    $key,
1850
                    api_is_allowed_to_edit(),
1851
                    $course_id
1852
                );
1853
1854
                if ($last_post_info_of_forum) {
1855
                    $forum_list[$key]['last_post_id'] = $last_post_info_of_forum['last_post_id'];
1856
                    $forum_list[$key]['last_poster_id'] = $last_post_info_of_forum['last_poster_id'];
1857
                    $forum_list[$key]['last_post_date'] = $last_post_info_of_forum['last_post_date'];
1858
                    $forum_list[$key]['last_poster_name'] = $last_post_info_of_forum['last_poster_name'];
1859
                    $forum_list[$key]['last_poster_lastname'] = $last_post_info_of_forum['last_poster_lastname'];
1860
                    $forum_list[$key]['last_poster_firstname'] = $last_post_info_of_forum['last_poster_firstname'];
1861
                    $forum_list[$key]['last_post_title'] = $last_post_info_of_forum['last_post_title'];
1862
                    $forum_list[$key]['last_post_text'] = $last_post_info_of_forum['last_post_text'];
1863
                }
1864
            }
1865
        } else {
1866
            $forum_list = [];
1867
        }
1868
    } else {
1869
        $last_post_info_of_forum = get_last_post_information(
1870
            $id,
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type string; however, parameter $forum_id of get_last_post_information() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1870
            /** @scrutinizer ignore-type */ $id,
Loading history...
1871
            api_is_allowed_to_edit(),
1872
            $course_id
1873
        );
1874
        if ($last_post_info_of_forum) {
1875
            $forum_list['last_post_id'] = $last_post_info_of_forum['last_post_id'];
1876
            $forum_list['last_poster_id'] = $last_post_info_of_forum['last_poster_id'];
1877
            $forum_list['last_post_date'] = $last_post_info_of_forum['last_post_date'];
1878
            $forum_list['last_poster_name'] = $last_post_info_of_forum['last_poster_name'];
1879
            $forum_list['last_poster_lastname'] = $last_post_info_of_forum['last_poster_lastname'];
1880
            $forum_list['last_poster_firstname'] = $last_post_info_of_forum['last_poster_firstname'];
1881
            $forum_list['last_post_title'] = $last_post_info_of_forum['last_post_title'];
1882
            $forum_list['last_post_text'] = $last_post_info_of_forum['last_post_text'];
1883
        }
1884
    }
1885
1886
    return $forum_list;
1887
}
1888
1889
/**
1890
 * @param int  $course_id
1891
 * @param int  $thread_id
1892
 * @param int  $forum_id
1893
 * @param bool $show_visible
1894
 *
1895
 * @return array|bool
1896
 */
1897
function get_last_post_by_thread($course_id, $thread_id, $forum_id, $show_visible = true)
1898
{
1899
    if (empty($thread_id) || empty($forum_id) || empty($course_id)) {
1900
        return false;
1901
    }
1902
1903
    $thread_id = intval($thread_id);
1904
    $forum_id = intval($forum_id);
1905
    $course_id = intval($course_id);
1906
1907
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1908
    $sql = "SELECT * FROM $table_posts
1909
            WHERE 
1910
                c_id = $course_id AND 
1911
                thread_id = $thread_id AND 
1912
                forum_id = $forum_id";
1913
1914
    if ($show_visible == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1915
        $sql .= " AND visible = 1 ";
1916
    }
1917
1918
    $sql .= " ORDER BY post_id DESC LIMIT 1";
1919
    $result = Database::query($sql);
1920
    if (Database::num_rows($result)) {
1921
        return Database::fetch_array($result, 'ASSOC');
1922
    } else {
1923
        return false;
1924
    }
1925
}
1926
1927
/**
1928
 * This function gets all the last post information of a certain forum.
1929
 *
1930
 * @param int  $forum_id        the id of the forum we want to know the last post information of
1931
 * @param bool $show_invisibles
1932
 * @param string course db name
1933
 * @param int $sessionId Optional. The session id
1934
 *
1935
 * @return array containing all the information about the last post
1936
 *               (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)
1937
 *
1938
 * @author Patrick Cool <[email protected]>, Ghent University
1939
 *
1940
 * @version february 2006, dokeos 1.8
1941
 */
1942
function get_last_post_information($forum_id, $show_invisibles = false, $course_id = null, $sessionId = 0)
1943
{
1944
    if (!isset($course_id)) {
1945
        $course_id = api_get_course_int_id();
1946
    } else {
1947
        $course_id = intval($course_id);
1948
    }
1949
    $sessionId = $sessionId ? intval($sessionId) : api_get_session_id();
1950
1951
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1952
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1953
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
1954
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1955
1956
    $forum_id = intval($forum_id);
1957
    $return_array = [];
1958
1959
    // First get the threads to make sure there is no inconsistency in the
1960
    // database between forum and thread
1961
    $sql = "SELECT thread_id FROM $table_threads 
1962
            WHERE 
1963
                forum_id = $forum_id AND 
1964
                c_id = $course_id AND 
1965
                session_id = $sessionId";
1966
    $result = Database::query($sql);
1967
    if (Database::num_rows($result) == 0) {
1968
        // If there are no threads in this forum, then there are no posts
1969
        return [];
1970
    }
1971
    $threads = [];
1972
    while ($row = Database::fetch_row($result)) {
1973
        $threads[] = $row[0];
1974
    }
1975
    $threadsList = implode(',', $threads);
1976
    // Now get the posts that are linked to these threads
1977
    $sql = "SELECT
1978
                post.post_id,
1979
                post.forum_id,
1980
                post.poster_id,
1981
                post.poster_name,
1982
                post.post_date,
1983
                users.lastname,
1984
                users.firstname,
1985
                post.visible,
1986
                thread_properties.visibility AS thread_visibility,
1987
                forum_properties.visibility AS forum_visibility,
1988
                post.post_title,
1989
                post.post_text
1990
            FROM
1991
                $table_posts post,
1992
                $table_users users,
1993
                $table_item_property thread_properties,
1994
                $table_item_property forum_properties
1995
            WHERE
1996
                post.forum_id = $forum_id
1997
                AND post.thread_id IN ($threadsList)
1998
                AND post.poster_id = users.user_id
1999
                AND post.thread_id = thread_properties.ref
2000
                AND thread_properties.tool='".TOOL_FORUM_THREAD."'
2001
                AND post.forum_id=forum_properties.ref
2002
                AND forum_properties.tool='".TOOL_FORUM."'
2003
                AND post.c_id = $course_id AND
2004
                thread_properties.c_id = $course_id AND
2005
                forum_properties.c_id = $course_id
2006
            ORDER BY post.post_id DESC";
2007
    $result = Database::query($sql);
2008
2009
    if ($show_invisibles) {
2010
        $row = Database::fetch_array($result);
2011
        $return_array['last_post_id'] = $row['post_id'];
2012
        $return_array['last_poster_id'] = $row['poster_id'];
2013
        $return_array['last_post_date'] = $row['post_date'];
2014
        $return_array['last_poster_name'] = $row['poster_name'];
2015
        $return_array['last_poster_lastname'] = $row['lastname'];
2016
        $return_array['last_poster_firstname'] = $row['firstname'];
2017
        $return_array['last_post_title'] = $row['post_title'];
2018
        $return_array['last_post_text'] = $row['post_text'];
2019
2020
        return $return_array;
2021
    } else {
2022
        // We have to loop through the results to find the first one that is
2023
        // actually visible to students (forum_category, forum, thread AND post are visible).
2024
        while ($row = Database::fetch_array($result)) {
2025
            if ($row['visible'] == '1' && $row['thread_visibility'] == '1' && $row['forum_visibility'] == '1') {
2026
                $return_array['last_post_id'] = $row['post_id'];
2027
                $return_array['last_poster_id'] = $row['poster_id'];
2028
                $return_array['last_post_date'] = $row['post_date'];
2029
                $return_array['last_poster_name'] = $row['poster_name'];
2030
                $return_array['last_poster_lastname'] = $row['lastname'];
2031
                $return_array['last_poster_firstname'] = $row['firstname'];
2032
                $return_array['last_post_title'] = $row['post_title'];
2033
                $return_array['last_post_text'] = $row['post_text'];
2034
2035
                return $return_array;
2036
            }
2037
        }
2038
    }
2039
}
2040
2041
/**
2042
 * Retrieve all the threads of a given forum.
2043
 *
2044
 * @param int      $forum_id
2045
 * @param int|null $courseId  Optional If is null then it is considered the current course
2046
 * @param int|null $sessionId Optional. If is null then it is considered the current session
2047
 *
2048
 * @return array containing all the information about the threads
2049
 *
2050
 * @author Patrick Cool <[email protected]>, Ghent University
2051
 *
2052
 * @version february 2006, dokeos 1.8
2053
 */
2054
function get_threads($forum_id, $courseId = null, $sessionId = null)
2055
{
2056
    $groupId = api_get_group_id();
2057
    $sessionId = $sessionId !== null ? (int) $sessionId : api_get_session_id();
2058
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2059
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2060
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
2061
2062
    $courseId = $courseId !== null ? (int) $courseId : api_get_course_int_id();
2063
    $groupInfo = GroupManager::get_group_properties($groupId);
2064
    $groupCondition = '';
2065
2066
    if (!empty($groupInfo)) {
2067
        $groupIid = $groupInfo['iid'];
2068
        $groupCondition = " AND item_properties.to_group_id = '$groupIid' ";
2069
    }
2070
2071
    $sessionCondition = api_get_session_condition(
2072
        $sessionId,
2073
        true,
2074
        false,
2075
        'item_properties.session_id'
2076
    );
2077
2078
    // important note:  it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
2079
    // because we also have thread.* in it. This is because thread has a field locked and post also has the same field
2080
    // since we are merging these we would have the post.locked value but in fact we want the thread.locked value
2081
    // This is why it is added to the end of the field selection
2082
    $sql = "SELECT DISTINCT
2083
                item_properties.*,
2084
                users.firstname,
2085
                users.lastname,
2086
                users.user_id,
2087
                thread.locked as locked,
2088
                thread.*
2089
            FROM $table_threads thread
2090
            INNER JOIN $table_item_property item_properties
2091
            ON
2092
                thread.thread_id = item_properties.ref AND
2093
                item_properties.c_id = thread.c_id AND
2094
                item_properties.tool = '".TABLE_FORUM_THREAD."' 
2095
                $groupCondition
2096
                $sessionCondition
2097
            LEFT JOIN $table_users users
2098
                ON thread.thread_poster_id = users.user_id
2099
            WHERE
2100
                item_properties.visibility='1' AND
2101
                thread.forum_id = ".intval($forum_id)." AND
2102
                thread.c_id = $courseId 
2103
            ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
2104
2105
    if (api_is_allowed_to_edit()) {
2106
        $sql = "SELECT DISTINCT
2107
                    item_properties.*,
2108
                    users.firstname,
2109
                    users.lastname,
2110
                    users.user_id,
2111
                    thread.locked as locked,
2112
                    thread.*
2113
                FROM $table_threads thread
2114
                INNER JOIN $table_item_property item_properties
2115
                ON
2116
                    thread.thread_id = item_properties.ref AND
2117
                    item_properties.c_id = thread.c_id AND
2118
                    item_properties.tool = '".TABLE_FORUM_THREAD."'
2119
                    $groupCondition
2120
                    $sessionCondition
2121
                LEFT JOIN $table_users users
2122
                    ON thread.thread_poster_id=users.user_id
2123
                WHERE
2124
                    item_properties.visibility<>2 AND
2125
                    thread.forum_id = ".intval($forum_id)." AND
2126
                    thread.c_id = $courseId 
2127
                ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
2128
    }
2129
    $result = Database::query($sql);
2130
    $list = [];
2131
    $alreadyAdded = [];
2132
    while ($row = Database::fetch_array($result, 'ASSOC')) {
2133
        if (in_array($row['thread_id'], $alreadyAdded)) {
2134
            continue;
2135
        }
2136
        $list[] = $row;
2137
        $alreadyAdded[] = $row['thread_id'];
2138
    }
2139
2140
    return $list;
2141
}
2142
2143
/**
2144
 * Get a thread by Id and course id.
2145
 *
2146
 * @param int $threadId the thread Id
2147
 * @param int $cId      the course id
2148
 *
2149
 * @return array containing all the information about the thread
2150
 */
2151
function getThreadInfo($threadId, $cId)
2152
{
2153
    $repo = Database::getManager()->getRepository('ChamiloCourseBundle:CForumThread');
2154
    $forumThread = $repo->findOneBy(['threadId' => $threadId, 'cId' => $cId]);
2155
2156
    $thread = [];
2157
    if ($forumThread) {
2158
        $thread['threadId'] = $forumThread->getThreadId();
2159
        $thread['threadTitle'] = $forumThread->getThreadTitle();
2160
        $thread['forumId'] = $forumThread->getForum() ? $forumThread->getForum()->getIid() : 0;
2161
        $thread['sessionId'] = $forumThread->getSessionId();
2162
        $thread['threadSticky'] = $forumThread->getThreadSticky();
2163
        $thread['locked'] = $forumThread->getLocked();
2164
        $thread['threadTitleQualify'] = $forumThread->getThreadTitleQualify();
2165
        $thread['threadQualifyMax'] = $forumThread->getThreadQualifyMax();
2166
        $thread['threadCloseDate'] = $forumThread->getThreadCloseDate();
2167
        $thread['threadWeight'] = $forumThread->getThreadWeight();
2168
        $thread['threadPeerQualify'] = $forumThread->isThreadPeerQualify();
2169
    }
2170
2171
    return $thread;
2172
}
2173
2174
/**
2175
 * Retrieve all posts of a given thread.
2176
 *
2177
 * @param array  $forumInfo
2178
 * @param int    $threadId       The thread ID
2179
 * @param string $orderDirection Optional. The direction for sort the posts
2180
 * @param bool   $recursive      Optional. If the list is recursive
2181
 * @param int    $postId         Optional. The post ID for recursive list
2182
 * @param int    $depth          Optional. The depth to indicate the indent
2183
 *
2184
 * @todo move to a repository
2185
 *
2186
 * @return array containing all the information about the posts of a given thread
2187
 */
2188
function getPosts(
2189
    $forumInfo,
2190
    $threadId,
2191
    $orderDirection = 'ASC',
2192
    $recursive = false,
2193
    $postId = null,
2194
    $depth = -1
2195
) {
2196
    $em = Database::getManager();
2197
2198
    if (api_is_allowed_to_edit(false, true)) {
2199
        $visibleCriteria = Criteria::expr()->neq('visible', 2);
2200
    } else {
2201
        $visibleCriteria = Criteria::expr()->eq('visible', 1);
2202
    }
2203
2204
    $criteria = Criteria::create();
2205
    $criteria
2206
        ->where(Criteria::expr()->eq('thread', $threadId))
2207
        ->andWhere(Criteria::expr()->eq('cId', $forumInfo['c_id']))
2208
        ->andWhere($visibleCriteria)
2209
    ;
2210
2211
    $groupId = api_get_group_id();
2212
    $groupInfo = GroupManager::get_group_properties($groupId);
2213
    $filterModerated = true;
2214
2215
    if (empty($groupId)) {
2216
        if (api_is_allowed_to_edit()) {
2217
            $filterModerated = false;
2218
        }
2219
    } else {
2220
        if (GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo) ||
2221
            api_is_allowed_to_edit(false, true)
2222
        ) {
2223
            $filterModerated = false;
2224
        }
2225
    }
2226
2227
    if ($recursive) {
2228
        $criteria->andWhere(Criteria::expr()->eq('postParentId', $postId));
2229
    }
2230
2231
    $qb = $em->getRepository('ChamiloCourseBundle:CForumPost')->createQueryBuilder('p');
2232
    $qb->select('p')
2233
        ->addCriteria($criteria)
2234
        ->addOrderBy('p.postId', $orderDirection);
2235
2236
    if ($filterModerated && $forumInfo['moderated'] == 1) {
2237
        if (!api_is_allowed_to_edit(false, true)) {
2238
            $userId = api_get_user_id();
2239
            $qb->andWhere(
2240
                "p.status = 1 OR 
2241
                    (p.status = ".CForumPost::STATUS_WAITING_MODERATION." AND p.posterId = $userId) OR
2242
                    (p.status = ".CForumPost::STATUS_REJECTED." AND p.posterId = $userId) OR
2243
                    (p.status IS NULL AND p.posterId = $userId) 
2244
                    "
2245
            );
2246
        }
2247
    }
2248
2249
    $posts = $qb->getQuery()->getResult();
2250
    $depth++;
2251
2252
    $list = [];
2253
    /** @var CForumPost $post */
2254
    foreach ($posts as $post) {
2255
        $postInfo = [
2256
            'iid' => $post->getIid(),
2257
            'c_id' => $post->getCId(),
2258
            'post_id' => $post->getPostId(),
2259
            'post_title' => $post->getPostTitle(),
2260
            'post_text' => $post->getPostText(),
2261
            'thread_id' => $post->getThread() ? $post->getThread()->getIid() : 0,
2262
            'forum_id' => $post->getForumId(),
2263
            'poster_id' => $post->getPosterId(),
2264
            'poster_name' => $post->getPosterName(),
2265
            'post_date' => $post->getPostDate(),
2266
            'post_notification' => $post->getPostNotification(),
2267
            'post_parent_id' => $post->getPostParentId(),
2268
            'visible' => $post->getVisible(),
2269
            'status' => $post->getStatus(),
2270
            'indent_cnt' => $depth,
2271
        ];
2272
2273
        $posterId = $post->getPosterId();
2274
        if (!empty($posterId)) {
2275
            $user = api_get_user_entity($posterId);
2276
            if ($user) {
2277
                $postInfo['user_id'] = $user->getUserId();
2278
                $postInfo['username'] = $user->getUsername();
2279
                $postInfo['username_canonical'] = $user->getUsernameCanonical();
2280
                $postInfo['lastname'] = $user->getLastname();
2281
                $postInfo['firstname'] = $user->getFirstname();
2282
                $postInfo['complete_name'] = UserManager::formatUserFullName($user);
2283
            }
2284
        }
2285
2286
        $list[] = $postInfo;
2287
2288
        if (!$recursive) {
2289
            continue;
2290
        }
2291
        $list = array_merge(
2292
            $list,
2293
            getPosts(
2294
                $forumInfo,
2295
                $threadId,
2296
                $orderDirection,
2297
                $recursive,
2298
                $post->getPostId(),
2299
                $depth
2300
            )
2301
        );
2302
    }
2303
2304
    return $list;
2305
}
2306
2307
/**
2308
 * This function retrieves all the information of a post.
2309
 *
2310
 * @param int $post_id integer that indicates the forum
2311
 *
2312
 * @return array returns
2313
 *
2314
 * @author Patrick Cool <[email protected]>, Ghent University
2315
 *
2316
 * @version february 2006, dokeos 1.8
2317
 */
2318
function get_post_information($post_id)
2319
{
2320
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
2321
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
2322
    $course_id = api_get_course_int_id();
2323
    $post_id = (int) $post_id;
2324
2325
    if (empty($post_id)) {
2326
        return [];
2327
    }
2328
2329
    $sql = "SELECT posts.*, email FROM ".$table_posts." posts, ".$table_users." users
2330
            WHERE
2331
                c_id = $course_id AND
2332
                posts.poster_id=users.user_id AND
2333
                posts.post_id = ".$post_id;
2334
    $result = Database::query($sql);
2335
    $row = Database::fetch_array($result, 'ASSOC');
2336
2337
    return $row;
2338
}
2339
2340
/**
2341
 * This function retrieves all the information of a thread.
2342
 *
2343
 * @param int $forumId
2344
 * @param $thread_id integer that indicates the forum
2345
 * @param int|null $sessionId Optional. If is null then it is considered the current session
2346
 *
2347
 * @return array returns
2348
 *
2349
 * @author Patrick Cool <[email protected]>, Ghent University
2350
 *
2351
 * @version february 2006, dokeos 1.8
2352
 */
2353
function get_thread_information($forumId, $thread_id, $sessionId = null)
2354
{
2355
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2356
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2357
    $thread_id = intval($thread_id);
2358
    $sessionId = $sessionId !== null ? intval($sessionId) : api_get_session_id();
2359
    $sessionCondition = api_get_session_condition(
2360
        $sessionId,
2361
        true,
2362
        false,
2363
        'threads.session_id'
2364
    );
2365
    $forumCondition = '';
2366
    if (!empty($forumId)) {
2367
        $forumId = (int) $forumId;
2368
        $forumCondition = " threads.forum_id = $forumId AND ";
2369
    }
2370
    $sql = "SELECT * FROM $table_item_property item_properties
2371
            INNER JOIN
2372
            $table_threads threads
2373
            ON (item_properties.ref = threads.thread_id AND threads.c_id = item_properties.c_id)
2374
            WHERE
2375
                $forumCondition
2376
                item_properties.tool= '".TOOL_FORUM_THREAD."' AND                
2377
                threads.thread_id = $thread_id 
2378
                $sessionCondition
2379
            ";
2380
2381
    $result = Database::query($sql);
2382
    $row = Database::fetch_assoc($result);
2383
2384
    return $row;
2385
}
2386
2387
/**
2388
 * This function retrieves forum thread users details.
2389
 *
2390
 * @param   int Thread ID
2391
 * @param   string  Course DB name (optional)
2392
 *
2393
 * @return Doctrine\DBAL\Driver\Statement|null array Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2394
 *
2395
 * @author Christian Fasanando <[email protected]>,
2396
 *
2397
 * @todo     this function need to be improved
2398
 *
2399
 * @version octubre 2008, dokeos 1.8
2400
 */
2401
function get_thread_users_details($thread_id)
2402
{
2403
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2404
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2405
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2406
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2407
2408
    $course_id = api_get_course_int_id();
2409
2410
    $is_western_name_order = api_is_western_name_order();
2411
    if ($is_western_name_order) {
2412
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2413
    } else {
2414
        $orderby = 'ORDER BY user.lastname, user.firstname';
2415
    }
2416
2417
    if (api_get_session_id()) {
2418
        $session_info = api_get_session_info(api_get_session_id());
2419
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2420
        //not showing coaches
2421
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2422
                FROM $t_posts p, $t_users user, $t_session_rel_user session_rel_user_rel_course
2423
                WHERE 
2424
                    p.poster_id = user.id AND
2425
                    user.id = session_rel_user_rel_course.user_id AND
2426
                    session_rel_user_rel_course.status<>'2' AND
2427
                    session_rel_user_rel_course.user_id NOT IN ($user_to_avoid) AND
2428
                    p.thread_id = ".intval($thread_id)." AND
2429
                    session_id = ".api_get_session_id()." AND
2430
                    p.c_id = $course_id AND
2431
                    session_rel_user_rel_course.c_id = ".$course_id." $orderby ";
2432
    } else {
2433
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2434
                FROM $t_posts p, $t_users user, $t_course_user course_user
2435
                WHERE 
2436
                    p.poster_id = user.id
2437
                    AND user.id = course_user.user_id
2438
                    AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
2439
                    AND p.thread_id = ".intval($thread_id)."
2440
                    AND course_user.status NOT IN('1') AND
2441
                    p.c_id = $course_id AND
2442
                    course_user.c_id = ".$course_id." $orderby";
2443
    }
2444
    $result = Database::query($sql);
2445
2446
    return $result;
2447
}
2448
2449
/**
2450
 * This function retrieves forum thread users qualify.
2451
 *
2452
 * @param   int Thread ID
2453
 * @param   string  Course DB name (optional)
2454
 *
2455
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2456
 *
2457
 * @author Jhon Hinojosa
2458
 *
2459
 * @todo     this function need to be improved
2460
 */
2461
function get_thread_users_qualify($thread_id)
2462
{
2463
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2464
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2465
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2466
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2467
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2468
2469
    $course_id = api_get_course_int_id();
2470
    $sessionId = api_get_session_id();
2471
2472
    $is_western_name_order = api_is_western_name_order();
2473
    if ($is_western_name_order) {
2474
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2475
    } else {
2476
        $orderby = 'ORDER BY user.lastname, user.firstname';
2477
    }
2478
2479
    if ($sessionId) {
2480
        $session_info = api_get_session_info($sessionId);
2481
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2482
        //not showing coaches
2483
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2484
                FROM $t_posts post , $t_users user, $t_session_rel_user scu, $t_qualify qualify
2485
                WHERE poster_id = user.id
2486
                    AND post.poster_id = qualify.user_id
2487
                    AND user.id = scu.user_id
2488
                    AND scu.status<>'2'
2489
                    AND scu.user_id NOT IN ($user_to_avoid)
2490
                    AND qualify.thread_id = ".intval($thread_id)."
2491
                    AND post.thread_id = ".intval($thread_id)."
2492
                    AND scu.session_id = $sessionId
2493
                    AND scu.c_id = ".$course_id." AND
2494
                    qualify.c_id = $course_id AND
2495
                    post.c_id = $course_id
2496
                $orderby ";
2497
    } else {
2498
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2499
                FROM $t_posts post,
2500
                     $t_qualify qualify,
2501
                     $t_users user,
2502
                     $t_course_user course_user
2503
                WHERE
2504
                     post.poster_id = user.id
2505
                     AND post.poster_id = qualify.user_id
2506
                     AND user.id = course_user.user_id
2507
                     AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
2508
                     AND qualify.thread_id = ".intval($thread_id)."
2509
                     AND post.thread_id = ".intval($thread_id)."
2510
                     AND course_user.status not in('1')
2511
                     AND course_user.c_id = $course_id
2512
                     AND qualify.c_id = $course_id
2513
                     AND post.c_id = $course_id
2514
                 $orderby ";
2515
    }
2516
    $result = Database::query($sql);
2517
2518
    return $result;
2519
}
2520
2521
/**
2522
 * This function retrieves forum thread users not qualify.
2523
 *
2524
 * @param   int Thread ID
2525
 * @param   string  Course DB name (optional)
2526
 *
2527
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2528
 *
2529
 * @author   Jhon Hinojosa<[email protected]>,
2530
 *
2531
 * @version oct 2008, dokeos 1.8
2532
 */
2533
function get_thread_users_not_qualify($thread_id)
2534
{
2535
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2536
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2537
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2538
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2539
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2540
2541
    $is_western_name_order = api_is_western_name_order();
2542
    if ($is_western_name_order) {
2543
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2544
    } else {
2545
        $orderby = 'ORDER BY user.lastname, user.firstname';
2546
    }
2547
2548
    $course_id = api_get_course_int_id();
2549
2550
    $sql1 = "SELECT user_id FROM  $t_qualify
2551
             WHERE c_id = $course_id AND thread_id = '".$thread_id."'";
2552
    $result1 = Database::query($sql1);
2553
    $cad = '';
2554
    while ($row = Database::fetch_array($result1)) {
2555
        $cad .= $row['user_id'].',';
2556
    }
2557
    if ($cad == '') {
2558
        $cad = '0';
2559
    } else {
2560
        $cad = substr($cad, 0, strlen($cad) - 1);
2561
    }
2562
2563
    if (api_get_session_id()) {
2564
        $session_info = api_get_session_info(api_get_session_id());
2565
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2566
        //not showing coaches
2567
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2568
                FROM $t_posts post , $t_users user, $t_session_rel_user session_rel_user_rel_course
2569
                WHERE poster_id = user.id
2570
                    AND user.id NOT IN (".$cad.")
2571
                    AND user.id = session_rel_user_rel_course.user_id
2572
                    AND session_rel_user_rel_course.status<>'2'
2573
                    AND session_rel_user_rel_course.user_id NOT IN ($user_to_avoid)
2574
                    AND post.thread_id = ".intval($thread_id)."
2575
                    AND session_id = ".api_get_session_id()."
2576
                    AND session_rel_user_rel_course.c_id = $course_id AND post.c_id = $course_id $orderby ";
2577
    } else {
2578
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2579
                FROM $t_posts post, $t_users user,$t_course_user course_user
2580
                WHERE post.poster_id = user.id
2581
                AND user.id NOT IN (".$cad.")
2582
                AND user.id = course_user.user_id
2583
                AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
2584
                AND post.thread_id = ".intval($thread_id)."
2585
                AND course_user.status not in('1')
2586
                AND course_user.c_id = $course_id AND post.c_id = $course_id  $orderby";
2587
    }
2588
    $result = Database::query($sql);
2589
2590
    return $result;
2591
}
2592
2593
/**
2594
 * This function retrieves all the information of a given forum_id.
2595
 *
2596
 * @param $forum_id integer that indicates the forum
2597
 *
2598
 * @return array returns
2599
 *
2600
 * @author Patrick Cool <[email protected]>, Ghent University
2601
 *
2602
 * @version february 2006, dokeos 1.8
2603
 *
2604
 * @deprecated this functionality is now moved to get_forums($forum_id)
2605
 */
2606
function get_forum_information($forum_id, $courseId = 0)
2607
{
2608
    $table_forums = Database::get_course_table(TABLE_FORUM);
2609
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2610
    $courseId = empty($courseId) ? api_get_course_int_id() : intval($courseId);
2611
    $forum_id = intval($forum_id);
2612
2613
    $sql = "SELECT *
2614
            FROM $table_forums forums
2615
            INNER JOIN $table_item_property item_properties
2616
            ON (forums.c_id = item_properties.c_id)
2617
            WHERE
2618
                item_properties.tool = '".TOOL_FORUM."' AND
2619
                item_properties.ref = '".$forum_id."' AND
2620
                forums.forum_id = '".$forum_id."' AND
2621
                forums.c_id = ".$courseId."
2622
            ";
2623
2624
    $result = Database::query($sql);
2625
    $row = Database::fetch_array($result, 'ASSOC');
2626
    $row['approval_direct_post'] = 0;
2627
    // We can't anymore change this option, so it should always be activated.
2628
2629
    return $row;
2630
}
2631
2632
/**
2633
 * This function retrieves all the information of a given forumcategory id.
2634
 *
2635
 * @param $cat_id integer that indicates the forum
2636
 *
2637
 * @return array returns if there are category or bool returns if there aren't category
2638
 *
2639
 * @author Patrick Cool <[email protected]>, Ghent University
2640
 *
2641
 * @version february 2006, dokeos 1.8
2642
 */
2643
function get_forumcategory_information($cat_id)
2644
{
2645
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
2646
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2647
2648
    $course_id = api_get_course_int_id();
2649
    $sql = "SELECT *
2650
            FROM $table_categories forumcategories 
2651
            INNER JOIN $table_item_property item_properties
2652
            ON (forumcategories.c_id = item_properties.c_id)
2653
            WHERE
2654
                forumcategories.c_id = $course_id AND
2655
                item_properties.c_id = $course_id AND
2656
                item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
2657
                item_properties.ref='".Database::escape_string($cat_id)."' AND
2658
                forumcategories.cat_id='".Database::escape_string($cat_id)."'";
2659
    $result = Database::query($sql);
2660
    $row = Database::fetch_array($result);
2661
2662
    return $row;
2663
}
2664
2665
/**
2666
 * This function counts the number of forums inside a given category.
2667
 *
2668
 * @param int $cat_id the id of the forum category
2669
 *
2670
 * @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return the number
2671
 *      of visible forums, $countinvisible=1 would return the number of visible and invisible forums
2672
 *
2673
 * @return int the number of forums inside the given category
2674
 *
2675
 * @author Patrick Cool <[email protected]>, Ghent University
2676
 *
2677
 * @version february 2006, dokeos 1.8
2678
 */
2679
function count_number_of_forums_in_category($cat_id)
2680
{
2681
    $table_forums = Database::get_course_table(TABLE_FORUM);
2682
    $course_id = api_get_course_int_id();
2683
    $cat_id = (int) $cat_id;
2684
    $sql = "SELECT count(*) AS number_of_forums
2685
            FROM $table_forums
2686
            WHERE c_id = $course_id AND forum_category = $cat_id";
2687
    $result = Database::query($sql);
2688
    $row = Database::fetch_array($result);
2689
2690
    return $row['number_of_forums'];
2691
}
2692
2693
/**
2694
 * This function update a thread.
2695
 *
2696
 * @param array $values - The form Values
2697
 */
2698
function updateThread($values)
2699
{
2700
    if (!api_is_allowed_to_edit()) {
2701
        return '';
2702
    }
2703
2704
    $logInfo = [
2705
        'tool' => TOOL_FORUM,
2706
        'tool_id' => $values['forum_id'],
2707
        'tool_id_detail' => $values['thread_id'],
2708
        'action' => 'edit-thread',
2709
        'action_details' => 'thread',
2710
        'info' => $values['thread_title'],
2711
    ];
2712
    Event::registerLog($logInfo);
2713
2714
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
2715
    $courseId = api_get_course_int_id();
2716
    $courseCode = api_get_course_id();
2717
    $sessionId = api_get_session_id();
2718
2719
    // Simple update + set gradebook values to null
2720
    $params = [
2721
        'thread_title' => $values['thread_title'],
2722
        'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
2723
    ];
2724
    $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2725
    Database::update($threadTable, $params, $where);
2726
2727
    $id = $values['thread_id'];
2728
    $linkInfo = GradebookUtils::isResourceInCourseGradebook(
2729
        $courseCode,
2730
        LINK_FORUM_THREAD,
2731
        $id,
2732
        $sessionId
2733
    );
2734
    $linkId = $linkInfo['id'];
2735
    $em = Database::getManager();
2736
    $gradebookLink = null;
2737
    if (!empty($linkId)) {
2738
        $gradebookLink = $em->getRepository('ChamiloCoreBundle:GradebookLink')->find($linkId);
2739
    }
2740
2741
    // values 1 or 0
2742
    $check = isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : false;
2743
    if ($check) {
2744
        $title = Security::remove_XSS(stripslashes($values['calification_notebook_title']));
2745
        $value = isset($values['numeric_calification']) ? intval($values['numeric_calification']) : 0;
2746
        $weight = isset($values['weight_calification']) ? floatval($values['weight_calification']) : 0;
2747
        $description = '';
2748
        // Update title
2749
        $params = [
2750
            'thread_title_qualify' => $values['calification_notebook_title'],
2751
            'thread_qualify_max' => api_float_val($values['numeric_calification']),
2752
            'thread_weight' => api_float_val($values['weight_calification']),
2753
            'thread_peer_qualify' => $values['thread_peer_qualify'],
2754
        ];
2755
        $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2756
        Database::update($threadTable, $params, $where);
2757
2758
        if (!$linkInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $linkInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2759
            GradebookUtils::add_resource_to_course_gradebook(
2760
                $values['category_id'],
2761
                $courseCode,
2762
                LINK_FORUM_THREAD,
2763
                $id,
2764
                $title,
2765
                $weight,
2766
                $value,
2767
                $description,
2768
                1,
2769
                $sessionId
2770
            );
2771
        } else {
2772
            if ($gradebookLink) {
2773
                $gradebookLink->setWeight($weight);
2774
                $em->persist($gradebookLink);
2775
                $em->flush();
2776
            }
2777
        }
2778
    } else {
2779
        $params = [
2780
            'thread_title_qualify' => '',
2781
            'thread_qualify_max' => '',
2782
            'thread_weight' => '',
2783
            'thread_peer_qualify' => '',
2784
        ];
2785
        $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2786
        Database::update($threadTable, $params, $where);
2787
2788
        if (!empty($linkInfo)) {
2789
            if ($gradebookLink) {
2790
                $em->remove($gradebookLink);
2791
                $em->flush();
2792
            }
2793
        }
2794
    }
2795
2796
    $message = get_lang('EditPostStored').'<br />';
2797
    Display::addFlash(Display::return_message($message, 'confirmation', false));
2798
}
2799
2800
/**
2801
 * This function stores a new thread. This is done through an entry in the forum_thread table AND
2802
 * in the forum_post table because. The threads are also stored in the item_property table. (forum posts are not (yet)).
2803
 *
2804
 * @param array $current_forum
2805
 * @param array $values
2806
 * @param array $courseInfo
2807
 * @param bool  $showMessage
2808
 * @param int   $userId        Optional. The user ID
2809
 * @param int   $sessionId
2810
 *
2811
 * @return CForumThread
2812
 *
2813
 * @author Patrick Cool <[email protected]>, Ghent University
2814
 *
2815
 * @version february 2006, dokeos 1.8
2816
 */
2817
function store_thread(
2818
    $current_forum,
2819
    $values,
2820
    $courseInfo = [],
2821
    $showMessage = true,
2822
    $userId = 0,
2823
    $sessionId = 0
2824
) {
2825
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
2826
    $userId = $userId ?: api_get_user_id();
2827
    $course_id = $courseInfo['real_id'];
2828
    $courseCode = $courseInfo['code'];
2829
    $groupId = api_get_group_id();
2830
    $groupInfo = GroupManager::get_group_properties($groupId);
2831
    $sessionId = $sessionId ?: api_get_session_id();
2832
2833
    $em = Database::getManager();
2834
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2835
    $upload_ok = 1;
2836
    $has_attachment = false;
2837
2838
    if (!empty($_FILES['user_upload']['name'])) {
2839
        $upload_ok = process_uploaded_file($_FILES['user_upload']);
2840
        $has_attachment = true;
2841
    }
2842
2843
    if (!$upload_ok) {
2844
        if ($showMessage) {
2845
            Display::addFlash(
2846
                Display::return_message(
2847
                    get_lang('UplNoFileUploaded'),
2848
                    'error',
2849
                    false
2850
                )
2851
            );
2852
        }
2853
2854
        return null;
2855
    }
2856
2857
    $post_date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
2858
    $visible = 1;
2859
    if ($current_forum['approval_direct_post'] == '1' && !api_is_allowed_to_edit(null, true)) {
2860
        $visible = 0; // The post has not been approved yet.
2861
    }
2862
    $clean_post_title = $values['post_title'];
2863
2864
    $forum = $em->find('ChamiloCourseBundle:CForumForum', $values['forum_id']);
2865
2866
    // We first store an entry in the forum_thread table because the thread_id is used in the forum_post table.
2867
    $lastThread = new CForumThread();
2868
    $lastThread
2869
        ->setCId($course_id)
2870
        ->setThreadTitle($clean_post_title)
2871
        ->setForum($forum)
2872
        ->setThreadPosterId($userId)
2873
        ->setThreadPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2874
        ->setThreadDate($post_date)
2875
        ->setThreadSticky(isset($values['thread_sticky']) ? $values['thread_sticky'] : 0)
0 ignored issues
show
Bug introduced by
It seems like IssetNode ? $values['thread_sticky'] : 0 can also be of type integer; however, parameter $threadSticky of Chamilo\CourseBundle\Ent...read::setThreadSticky() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2875
        ->setThreadSticky(/** @scrutinizer ignore-type */ isset($values['thread_sticky']) ? $values['thread_sticky'] : 0)
Loading history...
2876
        ->setThreadTitleQualify(
2877
            isset($values['calification_notebook_title']) ? $values['calification_notebook_title'] : null
2878
        )
2879
        ->setThreadQualifyMax(isset($values['numeric_calification']) ? (int) $values['numeric_calification'] : 0)
2880
        ->setThreadWeight(isset($values['weight_calification']) ? (int) $values['weight_calification'] : 0)
2881
        ->setThreadPeerQualify(isset($values['thread_peer_qualify']) ? (bool) $values['thread_peer_qualify'] : false)
2882
        ->setSessionId($sessionId)
2883
        ->setLpItemId(isset($values['lp_item_id']) ? (int) $values['lp_item_id'] : 0)
2884
        ->setThreadId(0)
2885
        ->setLocked(0)
2886
    ;
2887
2888
    $em->persist($lastThread);
2889
    $em->flush();
2890
2891
    // Add option gradebook qualify.
2892
    if (isset($values['thread_qualify_gradebook']) &&
2893
        1 == $values['thread_qualify_gradebook']
2894
    ) {
2895
        // Add function gradebook.
2896
        $resourcename = stripslashes($values['calification_notebook_title']);
2897
        GradebookUtils::add_resource_to_course_gradebook(
2898
            $values['category_id'],
2899
            $courseCode,
2900
            5,
2901
            $lastThread->getIid(),
2902
            $resourcename,
2903
            $values['weight_calification'],
2904
            $values['numeric_calification'],
2905
            '',
2906
            0,
2907
            $sessionId
2908
        );
2909
    }
2910
2911
    if ($lastThread->getIid()) {
2912
        $lastThread->setThreadId($lastThread->getIid());
2913
2914
        $em->merge($lastThread);
2915
        $em->flush();
2916
2917
        api_item_property_update(
2918
            $courseInfo,
2919
            TOOL_FORUM_THREAD,
2920
            $lastThread->getIid(),
2921
            'ForumThreadAdded',
2922
            $userId,
2923
            $groupInfo,
2924
            null,
2925
            null,
2926
            null,
2927
            $sessionId
2928
        );
2929
2930
        // If the forum properties tell that the posts have to be approved
2931
        // we have to put the whole thread invisible,
2932
        // because otherwise the students will see the thread and not the post
2933
        // in the thread.
2934
        // We also have to change $visible because the post itself has to be
2935
        // visible in this case (otherwise the teacher would have
2936
        // to make the thread visible AND the post.
2937
        // Default behaviour
2938
        api_set_default_visibility(
2939
            $lastThread->getIid(),
2940
            TOOL_FORUM_THREAD,
2941
            $groupId,
2942
            $courseInfo,
2943
            $sessionId,
2944
            $userId
2945
        );
2946
2947
        if ($visible == 0) {
2948
            api_item_property_update(
2949
                $courseInfo,
2950
                TOOL_FORUM_THREAD,
2951
                $lastThread->getIid(),
2952
                'invisible',
2953
                $userId,
2954
                $groupInfo
2955
            );
2956
            $visible = 1;
2957
        }
2958
2959
        $logInfo = [
2960
            'tool' => TOOL_FORUM,
2961
            'tool_id' => $values['forum_id'],
2962
            'tool_id_detail' => $lastThread->getIid(),
2963
            'action' => 'new-thread',
2964
            'action_details' => '',
2965
            'info' => $clean_post_title,
2966
        ];
2967
        Event::registerLog($logInfo);
2968
    }
2969
2970
    // We now store the content in the table_post table.
2971
    $lastPost = new CForumPost();
2972
    $lastPost
2973
        ->setCId($course_id)
2974
        ->setPostTitle($clean_post_title)
2975
        ->setPostText($values['post_text'])
2976
        ->setThread($lastThread)
2977
        ->setForumId($values['forum_id'])
2978
        ->setPosterId($userId)
2979
        ->setPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2980
        ->setPostDate($post_date)
2981
        ->setPostNotification(isset($values['post_notification']) ? (int) $values['post_notification'] : null)
0 ignored issues
show
Bug introduced by
It seems like IssetNode ? (int)$values...t_notification'] : null can also be of type integer; however, parameter $postNotification of Chamilo\CourseBundle\Ent...::setPostNotification() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2981
        ->setPostNotification(/** @scrutinizer ignore-type */ isset($values['post_notification']) ? (int) $values['post_notification'] : null)
Loading history...
2982
        ->setPostParentId(null)
2983
        ->setVisible($visible)
2984
        ->setPostId(0)
2985
        ->setStatus(CForumPost::STATUS_VALIDATED);
2986
2987
    if ($current_forum['moderated']) {
2988
        $lastPost->setStatus(
2989
            api_is_course_admin() ? CForumPost::STATUS_VALIDATED : CForumPost::STATUS_WAITING_MODERATION
2990
        );
2991
    }
2992
2993
    $em->persist($lastPost);
2994
    $em->flush();
2995
2996
    $lastPostId = $lastPost->getIid();
2997
2998
    $lastThread->setThreadLastPost($lastPostId);
2999
3000
    $em->merge($lastThread);
3001
    $em->flush();
3002
3003
    $logInfo = [
3004
        'tool' => TOOL_FORUM,
3005
        'tool_id' => $values['forum_id'],
3006
        'tool_id_detail' => $lastThread->getIid(),
3007
        'action' => 'new-post',
3008
        'info' => $clean_post_title,
3009
    ];
3010
    Event::registerLog($logInfo);
3011
3012
    if ($lastPostId) {
3013
        $lastPost->setPostId($lastPostId);
3014
        $em->merge($lastPost);
3015
        $em->flush();
3016
    }
3017
3018
    // Update attached files
3019
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3020
        foreach ($_POST['file_ids'] as $key => $id) {
3021
            editAttachedFile(
3022
                [
3023
                    'comment' => $_POST['file_comments'][$key],
3024
                    'post_id' => $lastPostId,
3025
                ],
3026
                $id
3027
            );
3028
        }
3029
    }
3030
3031
    // Now we have to update the thread table to fill the thread_last_post
3032
    // field (so that we know when the thread has been updated for the last time).
3033
    $sql = "UPDATE $table_threads
3034
            SET thread_last_post = '".Database::escape_string($lastPostId)."'
3035
            WHERE
3036
                c_id = $course_id AND
3037
                thread_id='".Database::escape_string($lastThread->getIid())."'";
3038
    $result = Database::query($sql);
3039
    $message = get_lang('NewThreadStored');
3040
3041
    // Overwrite default message.
3042
    if ($current_forum['moderated'] &&
3043
        !api_is_allowed_to_edit(null, true)
3044
    ) {
3045
        $message = get_lang('MessageHasToBeApproved');
3046
    }
3047
3048
    // Storing the attachments if any.
3049
    if ($has_attachment) {
3050
        // Try to add an extension to the file if it hasn't one.
3051
        $new_file_name = add_ext_on_mime(
3052
            stripslashes($_FILES['user_upload']['name']),
3053
            $_FILES['user_upload']['type']
3054
        );
3055
3056
        if (!filter_extension($new_file_name)) {
3057
            if ($showMessage) {
3058
                Display::addFlash(Display::return_message(
3059
                    get_lang('UplUnableToSaveFileFilteredExtension'),
3060
                    'error'
3061
                ));
3062
            }
3063
        } else {
3064
            if ($result) {
0 ignored issues
show
introduced by
$result is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
3065
                add_forum_attachment_file(
3066
                    isset($values['file_comment']) ? $values['file_comment'] : null,
3067
                    $lastPostId
3068
                );
3069
            }
3070
        }
3071
    } else {
3072
        $message .= '<br />';
3073
    }
3074
3075
    if ($current_forum['approval_direct_post'] == '1' &&
3076
        !api_is_allowed_to_edit(null, true)
3077
    ) {
3078
        $message .= get_lang('MessageHasToBeApproved').'<br />';
3079
        $message .= get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
3080
            get_lang('Forum').'</a><br />';
3081
    } else {
3082
        $message .= get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
3083
            get_lang('Forum').'</a><br />';
3084
        $message .= get_lang('ReturnTo').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&thread='.$lastThread->getIid().'">'.
3085
            get_lang('Message').'</a>';
3086
    }
3087
    $reply_info['new_post_id'] = $lastPostId;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$reply_info was never initialized. Although not strictly required by PHP, it is generally a good practice to add $reply_info = array(); before regardless.
Loading history...
3088
    $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
3089
3090
    if ($my_post_notification == 1) {
3091
        set_notification('thread', $lastThread->getIid(), true);
3092
    }
3093
3094
    send_notification_mails(
3095
        $current_forum['forum_id'],
3096
        $lastThread->getIid(),
3097
        $reply_info,
3098
        $courseInfo['code']
3099
    );
3100
3101
    Session::erase('formelements');
3102
    Session::erase('origin');
3103
    Session::erase('breadcrumbs');
3104
    Session::erase('addedresource');
3105
    Session::erase('addedresourceid');
3106
3107
    if ($showMessage) {
3108
        Display::addFlash(Display::return_message($message, 'success', false));
3109
    }
3110
3111
    return $lastThread;
3112
}
3113
3114
/**
3115
 * This function displays the form that is used to add a post. This can be a new thread or a reply.
3116
 *
3117
 * @param array  $current_forum
3118
 * @param string $action        is the parameter that determines if we are
3119
 *                              1. newthread: adding a new thread (both empty) => No I-frame
3120
 *                              2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete thread (if enabled)
3121
 *                              3. replymessage: Replying to a message ($action =replymessage) => I-frame with the complete thread (if enabled)
3122
 *                              (I first thought to put and I-frame with the message only)
3123
 *                              4. quote: Quoting a message ($action= quotemessage) => I-frame with the complete thread (if enabled).
3124
 *                              The message will be in the reply. (I first thought not to put an I-frame here)
3125
 *
3126
 * @return FormValidator
3127
 *
3128
 * @author Patrick Cool <[email protected]>, Ghent University
3129
 *
3130
 * @version february 2006, dokeos 1.8
3131
 */
3132
function show_add_post_form($current_forum, $action, $id = '', $form_values = '')
3133
{
3134
    $_user = api_get_user_info();
3135
    $action = isset($action) ? Security::remove_XSS($action) : '';
3136
    $myThread = isset($_GET['thread']) ? (int) $_GET['thread'] : '';
3137
    $forumId = isset($_GET['forum']) ? (int) $_GET['forum'] : '';
3138
    $my_post = isset($_GET['post']) ? (int) $_GET['post'] : '';
3139
    $giveRevision = (isset($_GET['give_revision']) && $_GET['give_revision'] == 1);
3140
3141
    $url = api_get_self().'?'.http_build_query(
3142
        [
3143
            'action' => $action,
3144
            'forum' => $forumId,
3145
            'thread' => $myThread,
3146
            'post' => $my_post,
3147
        ]
3148
    ).'&'.api_get_cidreq();
3149
3150
    $form = new FormValidator(
3151
        'thread',
3152
        'post',
3153
        $url
3154
    );
3155
3156
    $form->setConstants(['forum' => '5']);
3157
3158
    // Setting the form elements.
3159
    $form->addElement('hidden', 'forum_id', $forumId);
3160
    $form->addElement('hidden', 'thread_id', $myThread);
3161
    $form->addElement('hidden', 'action', $action);
3162
3163
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
3164
    if ($current_forum['allow_anonymous'] == 1 && !isset($_user['user_id'])) {
3165
        $form->addElement('text', 'poster_name', get_lang('Name'));
3166
        $form->applyFilter('poster_name', 'html_filter');
3167
    }
3168
3169
    $form->addElement('text', 'post_title', get_lang('Title'));
3170
    $form->addHtmlEditor(
3171
        'post_text',
3172
        get_lang('Text'),
3173
        true,
3174
        false,
3175
        api_is_allowed_to_edit(null, true) ? [
3176
            'ToolbarSet' => 'Forum',
3177
            'Width' => '100%',
3178
            'Height' => '300',
3179
        ] : [
3180
            'ToolbarSet' => 'ForumStudent',
3181
            'Width' => '100%',
3182
            'Height' => '300',
3183
            'UserStatus' => 'student',
3184
        ]
3185
    );
3186
    $form->addRule('post_text', get_lang('ThisFieldIsRequired'), 'required');
3187
3188
    if (in_array($action, ['newthread', 'replythread', 'replymessage', 'quote'])) {
3189
        $extraFields = new ExtraField('forum_post');
3190
        $extraFields->addElements(
3191
            $form,
3192
            null,
3193
            [], //exclude
3194
            false, // filter
3195
            false, // tag as select
3196
            ['ask_for_revision'], //show only fields
3197
            [], // order fields
3198
            [] // extra data);
3199
        );
3200
    }
3201
3202
    $iframe = null;
3203
    $myThread = Security::remove_XSS($myThread);
3204
    if ($action != 'newthread' && !empty($myThread)) {
3205
        $iframe = "<iframe style=\"border: 1px solid black\" src=\"iframe_thread.php?".api_get_cidreq()."&forum=".$forumId."&thread=".$myThread."#".$my_post."\" width=\"100%\"></iframe>";
3206
    }
3207
    if (!empty($iframe)) {
3208
        $form->addElement('label', get_lang('Thread'), $iframe);
3209
    }
3210
3211
    if (Gradebook::is_active() &&
3212
        (api_is_course_admin() || api_is_session_general_coach() || api_is_course_tutor()) && !($myThread)
3213
    ) {
3214
        $form->addElement('advanced_settings', 'advanced_params', get_lang('AdvancedParameters'));
3215
        $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3216
3217
        // Thread qualify
3218
        if (Gradebook::is_active()) {
3219
            //Loading gradebook select
3220
            GradebookUtils::load_gradebook_select_in_tool($form);
3221
            $form->addElement(
3222
                'checkbox',
3223
                'thread_qualify_gradebook',
3224
                '',
3225
                get_lang('QualifyThreadGradebook'),
3226
                'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"'
3227
            );
3228
        } else {
3229
            $form->addElement('hidden', 'thread_qualify_gradebook', false);
3230
        }
3231
3232
        $form->addElement('html', '<div id="options_field" style="display:none">');
3233
        $form->addElement('text', 'numeric_calification', get_lang('QualificationNumeric'));
3234
        $form->applyFilter('numeric_calification', 'html_filter');
3235
        $form->addElement('text', 'calification_notebook_title', get_lang('TitleColumnGradebook'));
3236
        $form->applyFilter('calification_notebook_title', 'html_filter');
3237
3238
        $form->addElement(
3239
            'text',
3240
            'weight_calification',
3241
            get_lang('QualifyWeight'),
3242
            ['value' => '0.00', 'onfocus' => "javascript: this.select();"]
3243
        );
3244
        $form->applyFilter('weight_calification', 'html_filter');
3245
3246
        $group = [];
3247
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('Yes'), 1);
3248
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('No'), 0);
3249
        $form->addGroup(
3250
            $group,
3251
            '',
3252
            [
3253
                get_lang('ForumThreadPeerScoring'),
3254
                get_lang('ForumThreadPeerScoringComment'),
3255
            ]
3256
        );
3257
        $form->addElement('html', '</div>');
3258
        $form->addElement('html', '</div>');
3259
    }
3260
3261
    if ($action == 'newthread') {
3262
        Skill::addSkillsToForm($form, ITEM_TYPE_FORUM_THREAD, 0);
3263
    }
3264
3265
    if (api_is_allowed_to_edit(null, true) && $action == 'newthread') {
3266
        $form->addElement('checkbox', 'thread_sticky', '', get_lang('StickyPost'));
3267
    }
3268
3269
    if (in_array($action, ['quote', 'replymessage'])) {
3270
        $form->addFile('user_upload[]', get_lang('Attachment'));
3271
        $form->addButton(
3272
            'add_attachment',
3273
            get_lang('AddAttachment'),
3274
            'paperclip',
3275
            'default',
3276
            'default',
3277
            null,
3278
            ['id' => 'reply-add-attachment']
3279
        );
3280
    } else {
3281
        $form->addFile('user_upload', get_lang('Attachment'));
3282
    }
3283
3284
    if ($giveRevision) {
3285
        $form->addHidden('give_revision', 1);
3286
        $extraField = new ExtraField('forum_post');
3287
        $returnParams = $extraField->addElements(
3288
            $form,
3289
            null,
3290
            [], //exclude
3291
            false, // filter
3292
            false, // tag as select
3293
            ['revision_language'], //show only fields
3294
            [], // order fields
3295
            [] // extra data
3296
        );
3297
    }
3298
3299
    // Setting the class and text of the form title and submit button.
3300
    if ($action == 'quote') {
3301
        $form->addButtonCreate(get_lang('QuoteMessage'), 'SubmitPost');
3302
    } elseif ($action == 'replythread') {
3303
        $form->addButtonCreate(get_lang('ReplyToThread'), 'SubmitPost');
3304
    } elseif ($action == 'replymessage') {
3305
        $form->addButtonCreate(get_lang('ReplyToMessage'), 'SubmitPost');
3306
    } else {
3307
        $form->addButtonCreate(get_lang('CreateThread'), 'SubmitPost');
3308
    }
3309
3310
    $defaults['thread_peer_qualify'] = 0;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$defaults was never initialized. Although not strictly required by PHP, it is generally a good practice to add $defaults = array(); before regardless.
Loading history...
3311
    if (!empty($form_values)) {
3312
        $defaults['post_title'] = prepare4display($form_values['post_title']);
3313
        $defaults['post_text'] = prepare4display($form_values['post_text']);
3314
        $defaults['post_notification'] = (int) $form_values['post_notification'];
3315
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
3316
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
3317
    }
3318
3319
    // If we are quoting a message we have to retrieve the information of the post we are quoting so that
3320
    // we can add this as default to the textarea.
3321
    // We also need to put the parent_id of the post in a hidden form when
3322
    if (($action == 'quote' || $action == 'replymessage' || $giveRevision) && !empty($my_post)) {
3323
        // we are quoting or replying to a message (<> reply to a thread !!!)
3324
        $form->addHidden('post_parent_id', $my_post);
3325
3326
        // If we are replying or are quoting then we display a default title.
3327
        $values = get_post_information($my_post);
0 ignored issues
show
Bug introduced by
It seems like $my_post can also be of type string; however, parameter $post_id of get_post_information() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3327
        $values = get_post_information(/** @scrutinizer ignore-type */ $my_post);
Loading history...
3328
        $posterInfo = api_get_user_info($values['poster_id']);
3329
        $posterName = '';
3330
        if ($posterInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $posterInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
3331
            $posterName = $posterInfo['complete_name'];
3332
        }
3333
        $defaults['post_title'] = get_lang('ReplyShort').api_html_entity_decode($values['post_title'], ENT_QUOTES);
3334
        // When we are quoting a message then we have to put that message into the wysiwyg editor.
3335
        // Note: The style has to be hardcoded here because using class="quote" didn't work.
3336
        if ($action == 'quote') {
3337
            $defaults['post_text'] = '<div>&nbsp;</div>
3338
                <div style="margin: 5px;">
3339
                    <div style="font-size: 90%; font-style: italic;">'.
3340
                        get_lang('Quoting').' '.$posterName.':</div>
3341
                        <div style="color: #006600; font-size: 90%;  font-style: italic; background-color: #FAFAFA; border: #D1D7DC 1px solid; padding: 3px;">'.
3342
                            prepare4display($values['post_text']).'
3343
                        </div>
3344
                    </div>
3345
                <div>&nbsp;</div>
3346
                <div>&nbsp;</div>
3347
            ';
3348
        }
3349
        if ($giveRevision) {
3350
            $defaults['post_text'] = prepare4display($values['post_text']);
3351
        }
3352
    }
3353
3354
    $form->setDefaults(isset($defaults) ? $defaults : []);
3355
3356
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3357
    $form->addRule('post_title', get_lang('ThisFieldIsRequired'), 'required');
3358
    if ($current_forum['allow_anonymous'] == 1 && !isset($_user['user_id'])) {
3359
        $form->addRule(
3360
            'poster_name',
3361
            get_lang('ThisFieldIsRequired'),
3362
            'required'
3363
        );
3364
    }
3365
3366
    // Validation or display
3367
    if ($form->validate()) {
3368
        $check = Security::check_token('post');
3369
        if ($check) {
3370
            $values = $form->getSubmitValues();
3371
            if (isset($values['thread_qualify_gradebook']) &&
3372
                $values['thread_qualify_gradebook'] == '1' &&
3373
                empty($values['weight_calification'])
3374
            ) {
3375
                Display::addFlash(
3376
                    Display::return_message(
3377
                        get_lang('YouMustAssignWeightOfQualification').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
3378
                        'error',
3379
                        false
3380
                    )
3381
                );
3382
3383
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type FormValidator.
Loading history...
3384
            }
3385
3386
            $postId = 0;
3387
            $threadId = 0;
3388
3389
            switch ($action) {
3390
                case 'newthread':
3391
                    $myThread = store_thread($current_forum, $values);
3392
                    if ($myThread) {
0 ignored issues
show
introduced by
$myThread is of type Chamilo\CourseBundle\Entity\CForumThread, thus it always evaluated to true.
Loading history...
3393
                        $threadId = $myThread->getIid();
3394
                        Skill::saveSkills($form, ITEM_TYPE_FORUM_THREAD, $threadId);
3395
                        $postId = $myThread->getThreadLastPost();
3396
                    }
3397
                    break;
3398
                case 'quote':
3399
                case 'replythread':
3400
                case 'replymessage':
3401
                    $postId = store_reply($current_forum, $values);
3402
                    break;
3403
            }
3404
3405
            if ($postId) {
3406
                if (isset($values['give_revision']) && $values['give_revision'] == 1) {
3407
                    $extraFieldValues = new ExtraFieldValue('forum_post');
3408
                    $params = [
3409
                        'item_id' => $postId,
3410
                        'extra_revision_language' => $values['extra_revision_language'],
3411
                    ];
3412
                    $extraFieldValues->saveFieldValues(
3413
                        $params,
3414
                        false,
3415
                        false,
3416
                        ['revision_language']
3417
                    );
3418
                }
3419
3420
                if (in_array($action, ['newthread', 'replythread', 'replymessage', 'quote'])) {
3421
                    $extraFieldValues = new ExtraFieldValue('forum_post');
3422
                    $params = [
3423
                        'item_id' => $postId,
3424
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
3425
                    ];
3426
                    $extraFieldValues->saveFieldValues(
3427
                        $params,
3428
                        false,
3429
                        false,
3430
                        ['ask_for_revision']
3431
                    );
3432
                }
3433
            }
3434
3435
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
3436
                [
3437
                    'forum' => $forumId,
3438
                    'thread' => $threadId,
3439
                ]
3440
            );
3441
3442
            Security::clear_token();
3443
            header('Location: '.$url);
3444
            exit;
3445
        }
3446
    } else {
3447
        $token = Security::get_token();
3448
        $form->addElement('hidden', 'sec_token');
3449
        $form->setConstants(['sec_token' => $token]);
3450
3451
        // Delete from $_SESSION forum attachment from other posts
3452
        // and keep only attachments for new post
3453
        clearAttachedFiles(FORUM_NEW_POST);
3454
        // Get forum attachment ajax table to add it to form
3455
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $current_forum['forum_id']);
3456
        $ajaxHtml = $attachmentAjaxTable;
3457
        $form->addElement('html', $ajaxHtml);
3458
3459
        return $form;
3460
    }
3461
}
3462
3463
/**
3464
 * @param array $threadInfo
3465
 * @param int   $user_id
3466
 * @param int   $thread_id
3467
 * @param int   $thread_qualify
3468
 * @param int   $qualify_time
3469
 * @param int   $session_id
3470
 *
3471
 * @return array optional
3472
 *
3473
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3474
 *
3475
 * @version October 2008, dokeos  1.8.6
3476
 */
3477
function saveThreadScore(
3478
    $threadInfo,
3479
    $user_id,
3480
    $thread_id,
3481
    $thread_qualify = 0,
3482
    $qualify_time,
3483
    $session_id = 0
3484
) {
3485
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3486
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3487
3488
    $course_id = api_get_course_int_id();
3489
    $session_id = intval($session_id);
3490
    $currentUserId = api_get_user_id();
3491
3492
    if ($user_id == strval(intval($user_id)) &&
3493
        $thread_id == strval(intval($thread_id)) &&
3494
        $thread_qualify == strval(floatval($thread_qualify))
3495
    ) {
3496
        // Testing
3497
        $sql = "SELECT thread_qualify_max FROM $table_threads
3498
                WHERE c_id = $course_id AND thread_id=".$thread_id;
3499
        $res_string = Database::query($sql);
3500
        $row_string = Database::fetch_array($res_string);
3501
        if ($thread_qualify <= $row_string[0]) {
3502
            if ($threadInfo['thread_peer_qualify'] == 0) {
3503
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3504
                        WHERE
3505
                            c_id = $course_id AND
3506
                            user_id = $user_id AND
3507
                            thread_id = ".$thread_id;
3508
            } else {
3509
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3510
                        WHERE
3511
                            c_id = $course_id AND
3512
                            user_id = $user_id AND
3513
                            qualify_user_id = $currentUserId AND
3514
                            thread_id = ".$thread_id;
3515
            }
3516
3517
            $result = Database::query($sql);
3518
            $row = Database::fetch_array($result);
3519
3520
            if ($row[0] == 0) {
3521
                $sql = "INSERT INTO $table_threads_qualify (c_id, user_id, thread_id,qualify,qualify_user_id,qualify_time,session_id)
3522
                        VALUES (".$course_id.", '".$user_id."','".$thread_id."',".(float) $thread_qualify.", '".$currentUserId."','".$qualify_time."','".$session_id."')";
3523
                Database::query($sql);
3524
                $insertId = Database::insert_id();
3525
                if ($insertId) {
3526
                    $sql = "UPDATE $table_threads_qualify SET id = iid
3527
                            WHERE iid = $insertId";
3528
                    Database::query($sql);
3529
                }
3530
3531
                return 'insert';
0 ignored issues
show
Bug Best Practice introduced by
The expression return 'insert' returns the type string which is incompatible with the documented return type array.
Loading history...
3532
            } else {
3533
                saveThreadScoreHistory(
3534
                    '1',
3535
                    $course_id,
3536
                    $user_id,
3537
                    $thread_id
3538
                );
3539
3540
                // Update
3541
                $sql = "UPDATE $table_threads_qualify
3542
                        SET
3543
                            qualify = '".$thread_qualify."',
3544
                            qualify_time = '".$qualify_time."'
3545
                        WHERE
3546
                            c_id = $course_id AND
3547
                            user_id=".$user_id." AND
3548
                            thread_id=".$thread_id." AND
3549
                            qualify_user_id = $currentUserId
3550
                        ";
3551
                Database::query($sql);
3552
3553
                return 'update';
0 ignored issues
show
Bug Best Practice introduced by
The expression return 'update' returns the type string which is incompatible with the documented return type array.
Loading history...
3554
            }
3555
        } else {
3556
            return null;
3557
        }
3558
    }
3559
}
3560
3561
/**
3562
 * This function shows qualify.
3563
 *
3564
 * @param string $option    contains the information of option to run
3565
 * @param int    $user_id   contains the information the current user id
3566
 * @param int    $thread_id contains the information the current thread id
3567
 *
3568
 * @return int qualify
3569
 *             <code> $option=1 obtained the qualification of the current thread</code>
3570
 *
3571
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3572
 *
3573
 * @version October 2008, dokeos  1.8.6
3574
 */
3575
function showQualify($option, $user_id, $thread_id)
3576
{
3577
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3578
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3579
3580
    $course_id = api_get_course_int_id();
3581
    $user_id = (int) $user_id;
3582
    $thread_id = (int) $thread_id;
3583
3584
    if (empty($user_id) || empty($thread_id)) {
3585
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
3586
    }
3587
3588
    $sql = '';
3589
    switch ($option) {
3590
        case 1:
3591
            $sql = "SELECT qualify FROM $table_threads_qualify
3592
                    WHERE
3593
                        c_id = $course_id AND
3594
                        user_id=".$user_id." AND
3595
                        thread_id=".$thread_id;
3596
            break;
3597
        case 2:
3598
            $sql = "SELECT thread_qualify_max FROM $table_threads
3599
                    WHERE c_id = $course_id AND thread_id=".$thread_id;
3600
            break;
3601
    }
3602
3603
    if (!empty($sql)) {
3604
        $rs = Database::query($sql);
3605
        $row = Database::fetch_array($rs);
3606
3607
        return $row[0];
3608
    }
3609
3610
    return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the documented return type integer.
Loading history...
3611
}
3612
3613
/**
3614
 * This function gets qualify historical.
3615
 *
3616
 * @param int  $user_id   contains the information the current user id
3617
 * @param int  $thread_id contains the information the current thread id
3618
 * @param bool $opt       contains the information of option to run
3619
 *
3620
 * @return array
3621
 *
3622
 * @author Christian Fasanando <[email protected]>,
3623
 * @author Isaac Flores <[email protected]>,
3624
 *
3625
 * @version October 2008, dokeos  1.8.6
3626
 */
3627
function getThreadScoreHistory($user_id, $thread_id, $opt)
3628
{
3629
    $user_id = (int) $user_id;
3630
    $thread_id = (int) $thread_id;
3631
3632
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3633
    $course_id = api_get_course_int_id();
3634
3635
    if ($opt == 'false') {
3636
        $sql = "SELECT * FROM $table_threads_qualify_log
3637
                WHERE
3638
                    c_id = $course_id AND
3639
                    thread_id='".$thread_id."' AND
3640
                    user_id='".$user_id."'
3641
                ORDER BY qualify_time";
3642
    } else {
3643
        $sql = "SELECT * FROM $table_threads_qualify_log
3644
                WHERE
3645
                    c_id = $course_id AND
3646
                    thread_id='".$thread_id."' AND
3647
                    user_id='".$user_id."'
3648
                ORDER BY qualify_time DESC";
3649
    }
3650
    $rs = Database::query($sql);
3651
    $log = [];
3652
    while ($row = Database::fetch_array($rs, 'ASSOC')) {
3653
        $log[] = $row;
3654
    }
3655
3656
    return $log;
3657
}
3658
3659
/**
3660
 * This function stores qualify historical.
3661
 *
3662
 * @param bool contains the information of option to run
3663
 * @param string contains the information the current course id
3664
 * @param int contains the information the current forum id
3665
 * @param int contains the information the current user id
3666
 * @param int contains the information the current thread id
3667
 * @param int contains the information the current qualify
3668
 * @param string $option
3669
 * @param int    $course_id
3670
 * @param int    $user_id
3671
 * @param int    $thread_id
3672
 *
3673
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3674
 *
3675
 * @version October 2008, dokeos  1.8.6
3676
 */
3677
function saveThreadScoreHistory(
3678
    $option,
3679
    $course_id,
3680
    $user_id,
3681
    $thread_id
3682
) {
3683
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3684
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3685
3686
    $course_id = intval($course_id);
3687
    $qualify_user_id = api_get_user_id();
3688
3689
    if ($user_id == strval(intval($user_id)) &&
3690
        $thread_id == strval(intval($thread_id)) && $option == 1
3691
    ) {
3692
        // Extract information of thread_qualify.
3693
        $sql = "SELECT qualify, qualify_time
3694
                FROM $table_threads_qualify
3695
                WHERE
3696
                    c_id = $course_id AND
3697
                    user_id = ".$user_id." AND
3698
                    thread_id = ".$thread_id." AND
3699
                    qualify_user_id = $qualify_user_id
3700
                ";
3701
        $rs = Database::query($sql);
3702
        $row = Database::fetch_array($rs);
3703
3704
        // Insert thread_historical.
3705
        $sql = "INSERT INTO $table_threads_qualify_log (c_id, user_id, thread_id, qualify, qualify_user_id,qualify_time,session_id)
3706
                VALUES(".$course_id.", '".$user_id."','".$thread_id."',".(float) $row[0].", '".$qualify_user_id."','".$row[1]."','')";
3707
        Database::query($sql);
3708
3709
        $insertId = Database::insert_id();
3710
        if ($insertId) {
3711
            $sql = "UPDATE $table_threads_qualify_log SET id = iid
3712
                    WHERE iid = $insertId";
3713
            Database::query($sql);
3714
        }
3715
    }
3716
}
3717
3718
/**
3719
 * This function shows current thread qualify .
3720
 *
3721
 * @param int $threadId
3722
 * @param int $sessionId
3723
 * @param int $userId
3724
 *
3725
 * @return array or null if is empty
3726
 *
3727
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3728
 *
3729
 * @version December 2008, dokeos  1.8.6
3730
 */
3731
function current_qualify_of_thread($threadId, $sessionId, $userId)
3732
{
3733
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3734
3735
    $course_id = api_get_course_int_id();
3736
    $currentUserId = api_get_user_id();
3737
    $sessionId = intval($sessionId);
3738
    $threadId = intval($threadId);
3739
3740
    $sql = "SELECT qualify FROM $table_threads_qualify
3741
            WHERE
3742
                c_id = $course_id AND
3743
                thread_id = $threadId AND
3744
                session_id = $sessionId AND
3745
                qualify_user_id = $currentUserId AND
3746
                user_id = $userId
3747
            ";
3748
    $res = Database::query($sql);
3749
    $row = Database::fetch_array($res, 'ASSOC');
3750
3751
    return $row['qualify'];
3752
}
3753
3754
/**
3755
 * This function stores a reply in the forum_post table.
3756
 * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date).
3757
 *
3758
 * @param array $current_forum
3759
 * @param array $values
3760
 * @param int   $courseId      Optional
3761
 * @param int   $userId        Optional
3762
 *
3763
 * @return int post id
3764
 *
3765
 * @author Patrick Cool <[email protected]>, Ghent University
3766
 *
3767
 * @version february 2006, dokeos 1.8
3768
 */
3769
function store_reply($current_forum, $values, $courseId = 0, $userId = 0)
3770
{
3771
    $courseId = !empty($courseId) ? $courseId : api_get_course_int_id();
3772
    $_course = api_get_course_info_by_id($courseId);
3773
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3774
    $post_date = api_get_utc_datetime();
3775
    $userId = $userId ?: api_get_user_id();
3776
3777
    if ($current_forum['allow_anonymous'] == 1) {
3778
        if (api_is_anonymous() && empty($userId)) {
3779
            $userId = api_get_anonymous_id();
3780
        }
3781
    }
3782
3783
    if (empty($userId)) {
3784
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
3785
    }
3786
3787
    $visible = 1;
3788
    if ($current_forum['approval_direct_post'] == '1' &&
3789
        !api_is_allowed_to_edit(null, true)
3790
    ) {
3791
        $visible = 0;
3792
    }
3793
3794
    $upload_ok = 1;
3795
    $new_post_id = 0;
3796
3797
    if ($upload_ok) {
3798
        // We first store an entry in the forum_post table.
3799
        $new_post_id = Database::insert(
3800
            $table_posts,
3801
            [
3802
                'c_id' => $courseId,
3803
                'post_title' => $values['post_title'],
3804
                'post_text' => isset($values['post_text']) ? ($values['post_text']) : null,
3805
                'thread_id' => $values['thread_id'],
3806
                'forum_id' => $values['forum_id'],
3807
                'poster_id' => $userId,
3808
                'post_id' => 0,
3809
                'post_date' => $post_date,
3810
                'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : null,
3811
                'post_parent_id' => isset($values['post_parent_id']) ? $values['post_parent_id'] : null,
3812
                'visible' => $visible,
3813
            ]
3814
        );
3815
3816
        if ($new_post_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $new_post_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
3817
            $sql = "UPDATE $table_posts SET post_id = iid WHERE iid = $new_post_id";
3818
            Database::query($sql);
3819
3820
            $values['new_post_id'] = $new_post_id;
3821
            $message = get_lang('ReplyAdded');
3822
3823
            if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3824
                foreach ($_POST['file_ids'] as $key => $id) {
3825
                    editAttachedFile(
3826
                        [
3827
                            'comment' => $_POST['file_comments'][$key],
3828
                            'post_id' => $new_post_id,
3829
                        ],
3830
                        $id
3831
                    );
3832
                }
3833
            }
3834
3835
            // Update the thread.
3836
            updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
3837
3838
            // Update the forum.
3839
            api_item_property_update(
3840
                $_course,
3841
                TOOL_FORUM,
3842
                $values['forum_id'],
3843
                'NewMessageInForum',
3844
                $userId
3845
            );
3846
3847
            // Insert post
3848
            api_item_property_update(
3849
                $_course,
3850
                TOOL_FORUM_POST,
3851
                $new_post_id,
3852
                'NewPost',
3853
                $userId
3854
            );
3855
3856
            if ($current_forum['approval_direct_post'] == '1' &&
3857
                !api_is_allowed_to_edit(null, true)
3858
            ) {
3859
                $message .= '<br />'.get_lang('MessageHasToBeApproved').'<br />';
3860
            }
3861
3862
            if ($current_forum['moderated'] &&
3863
                !api_is_allowed_to_edit(null, true)
3864
            ) {
3865
                $message .= '<br />'.get_lang('MessageHasToBeApproved').'<br />';
3866
            }
3867
3868
            // Setting the notification correctly.
3869
            $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
3870
            if ($my_post_notification == 1) {
3871
                set_notification('thread', $values['thread_id'], true);
3872
            }
3873
3874
            send_notification_mails(
3875
                $values['forum_id'],
3876
                $values['thread_id'],
3877
                $values
3878
            );
3879
            add_forum_attachment_file('', $new_post_id);
3880
3881
            $logInfo = [
3882
                'tool' => TOOL_FORUM,
3883
                'tool_id' => $values['forum_id'],
3884
                'tool_id_detail' => $values['thread_id'],
3885
                'action' => 'new-post',
3886
                'action_details' => $values['action'],
3887
                'info' => $values['post_title'],
3888
            ];
3889
            Event::registerLog($logInfo);
3890
        }
3891
3892
        Session::erase('formelements');
3893
        Session::erase('origin');
3894
        Session::erase('breadcrumbs');
3895
        Session::erase('addedresource');
3896
        Session::erase('addedresourceid');
3897
3898
        Display::addFlash(Display::return_message($message, 'confirmation', false));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $message does not seem to be defined for all execution paths leading up to this point.
Loading history...
3899
    } else {
3900
        Display::addFlash(
3901
            Display::return_message(
3902
                get_lang('UplNoFileUploaded').' '.get_lang('UplSelectFileFirst'),
3903
                'error'
3904
            )
3905
        );
3906
    }
3907
3908
    return $new_post_id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $new_post_id could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
3909
}
3910
3911
/**
3912
 * This function displays the form that is used to edit a post. This can be a new thread or a reply.
3913
 *
3914
 * @param array contains all the information about the current post
3915
 * @param array contains all the information about the current thread
3916
 * @param array contains all info about the current forum (to check if attachments are allowed)
3917
 * @param array contains the default values to fill the form
3918
 *
3919
 * @author Patrick Cool <[email protected]>, Ghent University
3920
 *
3921
 * @version february 2006, dokeos 1.8
3922
 */
3923
function show_edit_post_form(
3924
    $current_post,
3925
    $current_thread,
3926
    $current_forum,
3927
    $form_values = '',
3928
    $id_attach = 0
3929
) {
3930
    // Initialize the object.
3931
    $form = new FormValidator(
3932
        'edit_post',
3933
        'post',
3934
        api_get_self().'?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&post='.intval($_GET['post'])
3935
    );
3936
    $form->addElement('header', get_lang('EditPost'));
3937
    // Setting the form elements.
3938
    $form->addElement('hidden', 'post_id', $current_post['post_id']);
3939
    $form->addElement('hidden', 'thread_id', $current_thread['thread_id']);
3940
    $form->addElement('hidden', 'id_attach', $id_attach);
3941
3942
    if (empty($current_post['post_parent_id'])) {
3943
        $form->addElement('hidden', 'is_first_post_of_thread', '1');
3944
    }
3945
3946
    $form->addElement('text', 'post_title', get_lang('Title'));
3947
    $form->applyFilter('post_title', 'html_filter');
3948
    $form->addElement(
3949
        'html_editor',
3950
        'post_text',
3951
        get_lang('Text'),
3952
        null,
3953
        api_is_allowed_to_edit(null, true) ? [
3954
            'ToolbarSet' => 'Forum',
3955
            'Width' => '100%',
3956
            'Height' => '400',
3957
        ] : [
3958
            'ToolbarSet' => 'ForumStudent',
3959
            'Width' => '100%',
3960
            'Height' => '400',
3961
            'UserStatus' => 'student',
3962
        ]
3963
    );
3964
    $form->addRule('post_text', get_lang('ThisFieldIsRequired'), 'required');
3965
3966
    $extraFields = new ExtraField('forum_post');
3967
    $extraFields->addElements($form, $current_post['post_id']);
3968
3969
    $form->addButtonAdvancedSettings('advanced_params');
3970
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3971
3972
    if ($current_forum['moderated'] && api_is_allowed_to_edit(null, true)) {
3973
        $group = [];
3974
        $group[] = $form->createElement(
3975
            'radio',
3976
            'status',
3977
            null,
3978
            get_lang('Validated'),
3979
            1
3980
        );
3981
        $group[] = $form->createElement(
3982
            'radio',
3983
            'status',
3984
            null,
3985
            get_lang('WaitingModeration'),
3986
            2
3987
        );
3988
        $group[] = $form->createElement(
3989
            'radio',
3990
            'status',
3991
            null,
3992
            get_lang('Rejected'),
3993
            3
3994
        );
3995
        $form->addGroup($group, 'status', get_lang('Status'));
3996
    }
3997
3998
    $defaults['status']['status'] = isset($current_post['status']) && !empty($current_post['status']) ? $current_post['status'] : 2;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$defaults was never initialized. Although not strictly required by PHP, it is generally a good practice to add $defaults = array(); before regardless.
Loading history...
3999
    $form->addElement(
4000
        'checkbox',
4001
        'post_notification',
4002
        '',
4003
        get_lang('NotifyByEmail').' ('.$current_post['email'].')'
4004
    );
4005
4006
    if (api_is_allowed_to_edit(null, true) &&
4007
        empty($current_post['post_parent_id'])
4008
    ) {
4009
        // The sticky checkbox only appears when it is the first post of a thread.
4010
        $form->addElement('checkbox', 'thread_sticky', '', get_lang('StickyPost'));
4011
        if ($current_thread['thread_sticky'] == 1) {
4012
            $defaults['thread_sticky'] = true;
4013
        }
4014
    }
4015
4016
    $form->addElement('html', '</div>');
4017
4018
    $form->addFile('user_upload[]', get_lang('Attachment'));
4019
    $form->addButton(
4020
        'add_attachment',
4021
        get_lang('AddAttachment'),
4022
        'paperclip',
4023
        'default',
4024
        'default',
4025
        null,
4026
        ['id' => 'reply-add-attachment']
4027
    );
4028
4029
    $form->addButtonUpdate(get_lang('Modify'), 'SubmitPost');
4030
4031
    // Setting the default values for the form elements.
4032
    $defaults['post_title'] = $current_post['post_title'];
4033
    $defaults['post_text'] = $current_post['post_text'];
4034
4035
    if ($current_post['post_notification'] == 1) {
4036
        $defaults['post_notification'] = true;
4037
    }
4038
4039
    if (!empty($form_values)) {
4040
        $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
4041
        $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
4042
    }
4043
4044
    $form->setDefaults($defaults);
4045
4046
    // The course admin can make a thread sticky (=appears with special icon and always on top).
4047
4048
    $form->addRule('post_title', get_lang('ThisFieldIsRequired'), 'required');
4049
4050
    // Validation or display
4051
    if ($form->validate()) {
4052
        $values = $form->exportValues();
4053
4054
        $values['item_id'] = $current_post['post_id'];
4055
        $extraFieldValues = new ExtraFieldValue('forum_post');
4056
        $extraFieldValues->saveFieldValues($values);
4057
4058
        store_edit_post($current_forum, $values);
4059
    } else {
4060
        // Delete from $_SESSION forum attachment from other posts
4061
        clearAttachedFiles($current_post['post_id']);
4062
        // Get forum attachment ajax table to add it to form
4063
        $fileData = getAttachmentsAjaxTable($current_post['post_id'], $current_forum['forum_id']);
4064
        $form->addElement('html', $fileData);
4065
        $form->display();
4066
    }
4067
}
4068
4069
/**
4070
 * This function stores the edit of a post in the forum_post table.
4071
 *
4072
 * @param array
4073
 *
4074
 * @author Patrick Cool <[email protected]>, Ghent University
4075
 *
4076
 * @version february 2006, dokeos 1.8
4077
 */
4078
function store_edit_post($forumInfo, $values)
4079
{
4080
    $logInfo = [
4081
        'tool' => TOOL_FORUM,
4082
        'tool_id' => $_GET['forum'],
4083
        'tool_id_detail' => $values['thread_id'],
4084
        'action' => 'edit-post',
4085
        'action_details' => 'post',
4086
        'info' => $values['post_title'],
4087
    ];
4088
    Event::registerLog($logInfo);
4089
4090
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
4091
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4092
    $course_id = api_get_course_int_id();
4093
4094
    //check if this post is the first of the thread
4095
    // First we check if the change affects the thread and if so we commit
4096
    // the changes (sticky and post_title=thread_title are relevant).
4097
4098
    $posts = getPosts($forumInfo, $values['thread_id']);
4099
    $first_post = null;
4100
    if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
4101
        $first_post = $posts[0];
4102
    }
4103
4104
    if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
4105
        // Simple edit
4106
        $params = [
4107
            'thread_title' => $values['post_title'],
4108
            'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
4109
        ];
4110
        $where = ['c_id = ? AND thread_id = ?' => [$course_id, $values['thread_id']]];
4111
        Database::update($threadTable, $params, $where);
4112
    }
4113
4114
    $status = '';
4115
    $updateStatus = false;
4116
    if ($forumInfo['moderated']) {
4117
        if (api_is_allowed_to_edit(null, true)) {
4118
            $status = $values['status']['status'];
4119
            $updateStatus = true;
4120
        } else {
4121
            $status = CForumPost::STATUS_WAITING_MODERATION;
4122
            $updateStatus = true;
4123
        }
4124
    }
4125
4126
    // Update the post_title and the post_text.
4127
    $params = [
4128
        'post_title' => $values['post_title'],
4129
        'post_text' => $values['post_text'],
4130
        'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : '',
4131
    ];
4132
4133
    if ($updateStatus) {
4134
        $params['status'] = $status;
4135
    }
4136
4137
    $where = ['c_id = ? AND post_id = ?' => [$course_id, $values['post_id']]];
4138
    Database::update($table_posts, $params, $where);
4139
4140
    // Update attached files
4141
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
4142
        foreach ($_POST['file_ids'] as $key => $id) {
4143
            editAttachedFile(
4144
                [
4145
                    'comment' => $_POST['file_comments'][$key],
4146
                    'post_id' => $values['post_id'],
4147
                ],
4148
                $id
4149
            );
4150
        }
4151
    }
4152
4153
    if (!empty($values['remove_attach'])) {
4154
        delete_attachment($values['post_id']);
4155
    }
4156
4157
    if (empty($values['id_attach'])) {
4158
        add_forum_attachment_file(
4159
            isset($values['file_comment']) ? $values['file_comment'] : null,
4160
            $values['post_id']
4161
        );
4162
    } else {
4163
        edit_forum_attachment_file(
4164
            isset($values['file_comment']) ? $values['file_comment'] : null,
4165
            $values['post_id'],
4166
            $values['id_attach']
4167
        );
4168
    }
4169
4170
    $message = get_lang('EditPostStored').'<br />';
4171
    $message .= get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&">'.get_lang('Forum').'</a><br />';
4172
    $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>';
4173
4174
    Session::erase('formelements');
4175
    Session::erase('origin');
4176
    Session::erase('breadcrumbs');
4177
    Session::erase('addedresource');
4178
    Session::erase('addedresourceid');
4179
4180
    echo Display::return_message($message, 'confirmation', false);
4181
}
4182
4183
/**
4184
 * This function displays the firstname and lastname of the user as a link to the user tool.
4185
 *
4186
 * @param string names
4187
 * @ in_title : title tootip
4188
 *
4189
 * @return string HTML
4190
 *
4191
 * @author Patrick Cool <[email protected]>, Ghent University
4192
 *
4193
 * @version february 2006, dokeos 1.8
4194
 */
4195
function display_user_link($user_id, $name, $origin = '', $in_title = '')
4196
{
4197
    if ($user_id != 0) {
4198
        $userInfo = api_get_user_info($user_id);
4199
4200
        return '<a href="'.$userInfo['profile_url'].'">'.Security::remove_XSS($userInfo['complete_name']).'</a>';
4201
    } else {
4202
        return $name.' ('.get_lang('Anonymous').')';
4203
    }
4204
}
4205
4206
/**
4207
 * This function displays the user image from the profile, with a link to the user's details.
4208
 *
4209
 * @param   int     User's database ID
0 ignored issues
show
Documentation Bug introduced by
The doc comment User's at position 0 could not be parsed: Unknown type name 'User's' at position 0 in User's.
Loading history...
4210
 * @param   string  User's name
4211
 * @param   string  the origin where the forum is called (example : learnpath)
4212
 *
4213
 * @return string An HTML with the anchor and the image of the user
4214
 *
4215
 * @author Julio Montoya <[email protected]>
4216
 */
4217
function display_user_image($user_id, $name, $origin = '')
4218
{
4219
    $userInfo = api_get_user_info($user_id);
4220
    $link = '<a href="'.(!empty($origin) ? '#' : $userInfo['profile_url']).'" '.(!empty($origin) ? 'target="_self"' : '').'>';
4221
4222
    if ($user_id != 0) {
4223
        return $link.'<img src="'.$userInfo['avatar'].'"  alt="'.$name.'"  title="'.$name.'" /></a>';
4224
    } else {
4225
        return $link.Display::return_icon('unknown.jpg', $name).'</a>';
4226
    }
4227
}
4228
4229
/**
4230
 * The thread view counter gets increased every time someone looks at the thread.
4231
 *
4232
 * @param int
4233
 *
4234
 * @author Patrick Cool <[email protected]>, Ghent University
4235
 *
4236
 * @version february 2006, dokeos 1.8
4237
 */
4238
function increase_thread_view($thread_id)
4239
{
4240
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4241
    $course_id = api_get_course_int_id();
4242
4243
    $sql = "UPDATE $table_threads 
4244
            SET thread_views = thread_views + 1
4245
            WHERE 
4246
                c_id = $course_id AND  
4247
                thread_id = '".intval($thread_id)."'";
4248
    Database::query($sql);
4249
}
4250
4251
/**
4252
 * The relies counter gets increased every time somebody replies to the thread.
4253
 *
4254
 * @author Patrick Cool <[email protected]>, Ghent University
4255
 *
4256
 * @version february 2006, dokeos 1.8
4257
 *
4258
 * @param int    $threadId
4259
 * @param string $lastPostId
4260
 * @param string $post_date
4261
 */
4262
function updateThreadInfo($threadId, $lastPostId, $post_date)
4263
{
4264
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4265
    $course_id = api_get_course_int_id();
4266
    $sql = "UPDATE $table_threads SET 
4267
            thread_replies = thread_replies+1,
4268
            thread_last_post = '".Database::escape_string($lastPostId)."',
4269
            thread_date = '".Database::escape_string($post_date)."'
4270
            WHERE 
4271
                c_id = $course_id AND  
4272
                thread_id='".Database::escape_string($threadId)."'"; // this needs to be cleaned first
4273
    Database::query($sql);
4274
}
4275
4276
/**
4277
 * This function is used to find all the information about what's new in the forum tool.
4278
 *
4279
 * @author Patrick Cool <[email protected]>, Ghent University
4280
 *
4281
 * @version february 2006, dokeos 1.8
4282
 */
4283
function get_whats_new()
4284
{
4285
    $userId = api_get_user_id();
4286
    $course_id = api_get_course_int_id();
4287
4288
    if (empty($course_id) || empty($userId)) {
4289
        return false;
4290
    }
4291
4292
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4293
    $tracking_last_tool_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4294
4295
    $tool = TOOL_FORUM;
4296
    $lastForumAccess = Session::read('last_forum_access');
4297
4298
    if (!$lastForumAccess) {
4299
        $sql = "SELECT * FROM $tracking_last_tool_access
4300
                WHERE
4301
                    access_user_id = $userId AND
4302
                    c_id = $course_id AND
4303
                    access_tool = '".Database::escape_string($tool)."'";
4304
        $result = Database::query($sql);
4305
        $row = Database::fetch_array($result);
4306
        Session::write('last_forum_access', $row['access_date']);
4307
        $lastForumAccess = $row['access_date'];
4308
    }
4309
4310
    $whatsNew = Session::read('whatsnew_post_info');
4311
4312
    if (!$whatsNew) {
4313
        if ($lastForumAccess != '') {
4314
            $postInfo = [];
4315
            $sql = "SELECT * FROM $table_posts
4316
                    WHERE
4317
                        c_id = $course_id AND
4318
                        visible = 1 AND                        
4319
                        post_date > '".Database::escape_string($lastForumAccess)."'";
4320
            $result = Database::query($sql);
4321
            while ($row = Database::fetch_array($result)) {
4322
                $postInfo[$row['forum_id']][$row['thread_id']][$row['post_id']] = $row['post_date'];
4323
            }
4324
            Session::write('whatsnew_post_info', $postInfo);
4325
        }
4326
    }
4327
}
4328
4329
/**
4330
 * This function approves a post = change.
4331
 *
4332
 * @param int    $post_id the id of the post that will be deleted
4333
 * @param string $action  make the post visible or invisible
4334
 *
4335
 * @return string language variable
4336
 *
4337
 * @author Patrick Cool <[email protected]>, Ghent University
4338
 *
4339
 * @version february 2006, dokeos 1.8
4340
 */
4341
function approve_post($post_id, $action)
4342
{
4343
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4344
    $course_id = api_get_course_int_id();
4345
4346
    if ($action == 'invisible') {
4347
        $visibility_value = 0;
4348
    }
4349
4350
    if ($action == 'visible') {
4351
        $visibility_value = 1;
4352
        handle_mail_cue('post', $post_id);
4353
    }
4354
4355
    $sql = "UPDATE $table_posts SET
4356
            visible='".Database::escape_string($visibility_value)."'
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $visibility_value does not seem to be defined for all execution paths leading up to this point.
Loading history...
4357
            WHERE c_id = $course_id AND post_id='".Database::escape_string($post_id)."'";
4358
    $return = Database::query($sql);
4359
4360
    if ($return) {
0 ignored issues
show
introduced by
$return is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
4361
        return 'PostVisibilityChanged';
4362
    }
4363
}
4364
4365
/**
4366
 * This function retrieves all the unapproved messages for a given forum
4367
 * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see this).
4368
 *
4369
 * @param $forum_id the forum where we want to know the unapproved messages of
4370
 *
4371
 * @return array returns
4372
 *
4373
 * @author Patrick Cool <[email protected]>, Ghent University
4374
 *
4375
 * @version february 2006, dokeos 1.8
4376
 */
4377
function get_unaproved_messages($forum_id)
4378
{
4379
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4380
    $course_id = api_get_course_int_id();
4381
4382
    $return_array = [];
4383
    $sql = "SELECT DISTINCT thread_id FROM $table_posts
4384
            WHERE 
4385
                c_id = $course_id AND 
4386
                forum_id='".Database::escape_string($forum_id)."' AND 
4387
                visible='0' ";
4388
    $result = Database::query($sql);
4389
    while ($row = Database::fetch_array($result)) {
4390
        $return_array[] = $row['thread_id'];
4391
    }
4392
4393
    return $return_array;
4394
}
4395
4396
/**
4397
 * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
4398
 * was added to a given thread.
4399
 *
4400
 * @param array reply information
4401
 *
4402
 * @author Patrick Cool <[email protected]>, Ghent University
4403
 *
4404
 * @version february 2006, dokeos 1.8
4405
 */
4406
function send_notification_mails($forumId, $thread_id, $reply_info)
4407
{
4408
    $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4409
4410
    // First we need to check if
4411
    // 1. the forum category is visible
4412
    // 2. the forum is visible
4413
    // 3. the thread is visible
4414
    // 4. the reply is visible (=when there is)
4415
    $current_thread = get_thread_information($forumId, $thread_id);
4416
    $current_forum = get_forum_information($current_thread['forum_id'], $current_thread['c_id']);
0 ignored issues
show
Deprecated Code introduced by
The function get_forum_information() has been deprecated: this functionality is now moved to get_forums($forum_id) ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

4416
    $current_forum = /** @scrutinizer ignore-deprecated */ get_forum_information($current_thread['forum_id'], $current_thread['c_id']);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
4417
4418
    $current_forum_category = null;
4419
    if (isset($current_forum['forum_category'])) {
4420
        $current_forum_category = get_forumcategory_information(
4421
            $current_forum['forum_category']
4422
        );
4423
    }
4424
4425
    if ($current_thread['visibility'] == '1' &&
4426
        $current_forum['visibility'] == '1' &&
4427
        ($current_forum_category && $current_forum_category['visibility'] == '1') &&
4428
        $current_forum['approval_direct_post'] != '1'
4429
    ) {
4430
        $send_mails = true;
4431
    } else {
4432
        $send_mails = false;
4433
    }
4434
4435
    // The forum category, the forum, the thread and the reply are visible to the user
4436
    if ($send_mails) {
4437
        if (!empty($forumId)) {
4438
            send_notifications($forumId, $thread_id);
4439
        }
4440
    } else {
4441
        $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4442
        if (isset($current_forum['forum_id'])) {
4443
            $sql = "SELECT * FROM $table_notification
4444
                    WHERE
4445
                        c_id = ".api_get_course_int_id()." AND
4446
                        (
4447
                            forum_id = '".intval($current_forum['forum_id'])."' OR
4448
                            thread_id = '".intval($thread_id)."'
4449
                        ) ";
4450
4451
            $result = Database::query($sql);
4452
            $user_id = api_get_user_id();
4453
            while ($row = Database::fetch_array($result)) {
4454
                $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
4455
                        VALUES (".api_get_course_int_id().", '".intval($thread_id)."', '".intval($reply_info['new_post_id'])."', '$user_id' )";
4456
                Database::query($sql);
4457
            }
4458
        }
4459
    }
4460
}
4461
4462
/**
4463
 * This function is called whenever something is made visible because there might
4464
 * be new posts and the user might have indicated that (s)he wanted to be
4465
 * informed about the new posts by mail.
4466
 *
4467
 * @param string $content Content type (post, thread, forum, forum_category)
4468
 * @param int    $id      Item DB ID of the corresponding content type
4469
 *
4470
 * @return string language variable
4471
 *
4472
 * @author Patrick Cool <[email protected]>, Ghent University
4473
 *
4474
 * @version february 2006, dokeos 1.8
4475
 */
4476
function handle_mail_cue($content, $id)
4477
{
4478
    $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4479
    $table_forums = Database::get_course_table(TABLE_FORUM);
4480
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4481
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4482
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4483
4484
    $course_id = api_get_course_int_id();
4485
    $id = (int) $id;
4486
4487
    /* If the post is made visible we only have to send mails to the people
4488
     who indicated that they wanted to be informed for that thread.*/
4489
    if ($content == 'post') {
4490
        // Getting the information about the post (need the thread_id).
4491
        $post_info = get_post_information($id);
4492
        $thread_id = (int) $post_info['thread_id'];
4493
4494
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4495
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email
4496
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4497
                WHERE
4498
                    posts.c_id = $course_id AND
4499
                    mailcue.c_id = $course_id AND
4500
                    posts.thread_id = $thread_id AND
4501
                    posts.post_notification = '1' AND
4502
                    mailcue.thread_id = $thread_id AND
4503
                    users.user_id = posts.poster_id AND
4504
                    users.active = 1
4505
                GROUP BY users.email";
4506
4507
        $result = Database::query($sql);
4508
        while ($row = Database::fetch_array($result)) {
4509
            send_mail($row, get_thread_information($post_info['forum_id'], $post_info['thread_id']));
4510
        }
4511
    } elseif ($content == 'thread') {
4512
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4513
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
4514
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4515
                WHERE
4516
                    posts.c_id = $course_id AND
4517
                    mailcue.c_id = $course_id AND
4518
                    posts.thread_id = $id AND
4519
                    posts.post_notification = '1' AND
4520
                    mailcue.thread_id = $id AND
4521
                    users.user_id = posts.poster_id AND
4522
                    users.active = 1
4523
                GROUP BY users.email";
4524
        $result = Database::query($sql);
4525
        while ($row = Database::fetch_array($result)) {
4526
            send_mail($row, get_thread_information($row['forum_id'], $id));
4527
        }
4528
4529
        // Deleting the relevant entries from the mailcue.
4530
        $sql = "DELETE FROM $table_mailcue
4531
                WHERE c_id = $course_id AND thread_id = $id";
4532
        Database::query($sql);
4533
    } elseif ($content == 'forum') {
4534
        $sql = "SELECT thread_id FROM $table_threads
4535
                WHERE c_id = $course_id AND forum_id = $id";
4536
        $result = Database::query($sql);
4537
        while ($row = Database::fetch_array($result)) {
4538
            handle_mail_cue('thread', $row['thread_id']);
4539
        }
4540
    } elseif ($content == 'forum_category') {
4541
        $sql = "SELECT forum_id FROM $table_forums
4542
                WHERE c_id = $course_id AND forum_category = $id";
4543
        $result = Database::query($sql);
4544
        while ($row = Database::fetch_array($result)) {
4545
            handle_mail_cue('forum', $row['forum_id']);
4546
        }
4547
    } else {
4548
        return get_lang('Error');
4549
    }
4550
}
4551
4552
/**
4553
 * This function sends the mails for the mail notification.
4554
 *
4555
 * @param array
4556
 * @param array
4557
 *
4558
 * @author Patrick Cool <[email protected]>, Ghent University
4559
 *
4560
 * @version february 2006, dokeos 1.8
4561
 */
4562
function send_mail($user_info = [], $thread_information = [])
4563
{
4564
    $_course = api_get_course_info();
4565
    $user_id = api_get_user_id();
4566
    $subject = get_lang('NewForumPost').' - '.$_course['official_code'];
4567
    if (isset($thread_information) && is_array($thread_information)) {
4568
        $thread_link = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&forum='.$thread_information['forum_id'].'&thread='.$thread_information['thread_id'];
4569
    }
4570
    $email_body = get_lang('Dear').' '.api_get_person_name($user_info['firstname'], $user_info['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
4571
    $email_body .= get_lang('NewForumPost')."\n";
4572
    $email_body .= get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
4573
    $email_body .= get_lang('YouWantedToStayInformed')."<br />\n";
4574
    $email_body .= get_lang('ThreadCanBeFoundHere')." : <br /><a href=\"".$thread_link."\">".$thread_link."</a>\n";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $thread_link does not seem to be defined for all execution paths leading up to this point.
Loading history...
4575
4576
    if ($user_info['user_id'] != $user_id) {
4577
        MessageManager::send_message(
4578
            $user_info['user_id'],
4579
            $subject,
4580
            $email_body,
4581
            [],
4582
            [],
4583
            null,
4584
            null,
4585
            null,
4586
            null,
4587
            $user_id
4588
        );
4589
    }
4590
}
4591
4592
/**
4593
 * This function displays the form for moving a thread to a different (already existing) forum.
4594
 *
4595
 * @author Patrick Cool <[email protected]>, Ghent University
4596
 *
4597
 * @version february 2006, dokeos 1.8
4598
 */
4599
function move_thread_form()
4600
{
4601
    $form = new FormValidator(
4602
        'movepost',
4603
        'post',
4604
        api_get_self().'?forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
4605
    );
4606
    // The header for the form
4607
    $form->addElement('header', get_lang('MoveThread'));
4608
    // Invisible form: the thread_id
4609
    $form->addElement('hidden', 'thread_id', intval($_GET['thread']));
4610
    // the fora
4611
    $forum_categories = get_forum_categories();
4612
    $forums = get_forums();
4613
4614
    $htmlcontent = '<div class="row">
4615
        <div class="label">
4616
            <span class="form_required">*</span>'.get_lang('MoveTo').'
4617
        </div>
4618
        <div class="formw">';
4619
    $htmlcontent .= '<select name="forum">';
4620
    foreach ($forum_categories as $key => $category) {
4621
        $htmlcontent .= '<optgroup label="'.$category['cat_title'].'">';
4622
        foreach ($forums as $key => $forum) {
0 ignored issues
show
Comprehensibility Bug introduced by
$key is overwriting a variable from outer foreach loop.
Loading history...
4623
            if (isset($forum['forum_category'])) {
4624
                if ($forum['forum_category'] == $category['cat_id']) {
4625
                    $htmlcontent .= '<option value="'.$forum['forum_id'].'">'.$forum['forum_title'].'</option>';
4626
                }
4627
            }
4628
        }
4629
        $htmlcontent .= '</optgroup>';
4630
    }
4631
    $htmlcontent .= "</select>";
4632
    $htmlcontent .= '   </div>
4633
                    </div>';
4634
4635
    $form->addElement('html', $htmlcontent);
4636
4637
    // The OK button
4638
    $form->addButtonSave(get_lang('MoveThread'), 'SubmitForum');
4639
4640
    // Validation or display
4641
    if ($form->validate()) {
4642
        $values = $form->exportValues();
4643
        if (isset($_POST['forum'])) {
4644
            store_move_thread($values);
4645
        }
4646
    } else {
4647
        $form->display();
4648
    }
4649
}
4650
4651
/**
4652
 * This function displays the form for moving a post message to a different (already existing) or a new thread.
4653
 *
4654
 * @author Patrick Cool <[email protected]>, Ghent University
4655
 *
4656
 * @version february 2006, dokeos 1.8
4657
 */
4658
function move_post_form()
4659
{
4660
    $form = new FormValidator(
4661
        'movepost',
4662
        'post',
4663
        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'])
4664
    );
4665
    // The header for the form
4666
    $form->addElement('header', '', get_lang('MovePost'));
4667
4668
    // Invisible form: the post_id
4669
    $form->addElement('hidden', 'post_id', intval($_GET['post']));
4670
4671
    // Dropdown list: Threads of this forum
4672
    $threads = get_threads($_GET['forum']);
4673
    //my_print_r($threads);
4674
    $threads_list[0] = get_lang('ANewThread');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$threads_list was never initialized. Although not strictly required by PHP, it is generally a good practice to add $threads_list = array(); before regardless.
Loading history...
4675
    foreach ($threads as $key => $value) {
4676
        $threads_list[$value['thread_id']] = $value['thread_title'];
4677
    }
4678
    $form->addElement('select', 'thread', get_lang('MoveToThread'), $threads_list);
4679
    $form->applyFilter('thread', 'html_filter');
4680
4681
    // The OK button
4682
    $form->addButtonSave(get_lang('MovePost'), 'submit');
4683
4684
    // Setting the rules
4685
    $form->addRule('thread', get_lang('ThisFieldIsRequired'), 'required');
4686
4687
    // Validation or display
4688
    if ($form->validate()) {
4689
        $values = $form->exportValues();
4690
        store_move_post($values);
4691
    } else {
4692
        $form->display();
4693
    }
4694
}
4695
4696
/**
4697
 * @param array
4698
 *
4699
 * @return string HTML language variable
4700
 *
4701
 * @author Patrick Cool <[email protected]>, Ghent University
4702
 *
4703
 * @version february 2006, dokeos 1.8
4704
 */
4705
function store_move_post($values)
4706
{
4707
    $_course = api_get_course_info();
4708
    $course_id = api_get_course_int_id();
4709
4710
    $table_forums = Database::get_course_table(TABLE_FORUM);
4711
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4712
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4713
4714
    if ($values['thread'] == '0') {
4715
        $current_post = get_post_information($values['post_id']);
4716
4717
        // Storing a new thread.
4718
        $params = [
4719
            'c_id' => $course_id,
4720
            'thread_title' => $current_post['post_title'],
4721
            'forum_id' => $current_post['forum_id'],
4722
            'thread_poster_id' => $current_post['poster_id'],
4723
            'thread_poster_name' => $current_post['poster_name'],
4724
            'thread_last_post' => $values['post_id'],
4725
            'thread_date' => $current_post['post_date'],
4726
        ];
4727
4728
        $new_thread_id = Database::insert($table_threads, $params);
4729
4730
        api_item_property_update(
4731
            $_course,
4732
            TOOL_FORUM_THREAD,
4733
            $new_thread_id,
0 ignored issues
show
Bug introduced by
It seems like $new_thread_id can also be of type false; however, parameter $item_id of api_item_property_update() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4733
            /** @scrutinizer ignore-type */ $new_thread_id,
Loading history...
4734
            'visible',
4735
            $current_post['poster_id']
4736
        );
4737
4738
        // Moving the post to the newly created thread.
4739
        $sql = "UPDATE $table_posts SET thread_id='".intval($new_thread_id)."', post_parent_id = NULL
4740
                WHERE c_id = $course_id AND post_id='".intval($values['post_id'])."'";
4741
        Database::query($sql);
4742
4743
        // Resetting the parent_id of the thread to 0 for all those who had this moved post as parent.
4744
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4745
                WHERE c_id = $course_id AND post_parent_id='".intval($values['post_id'])."'";
4746
        Database::query($sql);
4747
4748
        // Updating updating the number of threads in the forum.
4749
        $sql = "UPDATE $table_forums SET forum_threads=forum_threads+1
4750
                WHERE c_id = $course_id AND forum_id='".intval($current_post['forum_id'])."'";
4751
        Database::query($sql);
4752
4753
        // Resetting the last post of the old thread and decreasing the number of replies and the thread.
4754
        $sql = "SELECT * FROM $table_posts
4755
                WHERE c_id = $course_id AND thread_id='".intval($current_post['thread_id'])."'
4756
                ORDER BY post_id DESC";
4757
        $result = Database::query($sql);
4758
        $row = Database::fetch_array($result);
4759
        $sql = "UPDATE $table_threads SET
4760
                    thread_last_post='".$row['post_id']."',
4761
                    thread_replies=thread_replies-1
4762
                WHERE
4763
                    c_id = $course_id AND
4764
                    thread_id='".intval($current_post['thread_id'])."'";
4765
        Database::query($sql);
4766
    } else {
4767
        // Moving to the chosen thread.
4768
        $sql = "SELECT thread_id FROM ".$table_posts."
4769
                WHERE c_id = $course_id AND post_id = '".$values['post_id']."' ";
4770
        $result = Database::query($sql);
4771
        $row = Database::fetch_array($result);
4772
4773
        $original_thread_id = $row['thread_id'];
4774
4775
        $sql = "SELECT thread_last_post FROM ".$table_threads."
4776
                WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
4777
4778
        $result = Database::query($sql);
4779
        $row = Database::fetch_array($result);
4780
        $thread_is_last_post = $row['thread_last_post'];
4781
        // If is this thread, update the thread_last_post with the last one.
4782
4783
        if ($thread_is_last_post == $values['post_id']) {
4784
            $sql = "SELECT post_id FROM ".$table_posts."
4785
                    WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' AND post_id <> '".$values['post_id']."'
4786
                    ORDER BY post_date DESC LIMIT 1";
4787
            $result = Database::query($sql);
4788
4789
            $row = Database::fetch_array($result);
4790
            $thread_new_last_post = $row['post_id'];
4791
4792
            $sql = "UPDATE ".$table_threads." SET thread_last_post = '".$thread_new_last_post."'
4793
                    WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
4794
            Database::query($sql);
4795
        }
4796
4797
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies-1
4798
                WHERE c_id = $course_id AND thread_id='".$original_thread_id."'";
4799
        Database::query($sql);
4800
4801
        // moving to the chosen thread
4802
        $sql = "UPDATE $table_posts SET thread_id='".intval($_POST['thread'])."', post_parent_id = NULL
4803
                WHERE c_id = $course_id AND post_id='".intval($values['post_id'])."'";
4804
        Database::query($sql);
4805
4806
        // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
4807
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4808
                WHERE c_id = $course_id AND post_parent_id='".intval($values['post_id'])."'";
4809
        Database::query($sql);
4810
4811
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies+1
4812
                WHERE c_id = $course_id AND thread_id='".intval($_POST['thread'])."'";
4813
        Database::query($sql);
4814
    }
4815
4816
    return get_lang('ThreadMoved');
4817
}
4818
4819
/**
4820
 * @param array
4821
 *
4822
 * @return string HTML language variable
4823
 *
4824
 * @author Patrick Cool <[email protected]>, Ghent University
4825
 *
4826
 * @version february 2006, dokeos 1.8
4827
 */
4828
function store_move_thread($values)
4829
{
4830
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4831
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4832
4833
    $courseId = api_get_course_int_id();
4834
    $sessionId = api_get_session_id();
4835
4836
    $forumId = intval($_POST['forum']);
4837
    $threadId = intval($_POST['thread_id']);
4838
    $forumInfo = get_forums($forumId);
4839
4840
    // Change the thread table: Setting the forum_id to the new forum.
4841
    $sql = "UPDATE $table_threads SET forum_id = $forumId
4842
            WHERE c_id = $courseId AND thread_id = $threadId";
4843
    Database::query($sql);
4844
4845
    // Changing all the posts of the thread: setting the forum_id to the new forum.
4846
    $sql = "UPDATE $table_posts SET forum_id = $forumId
4847
            WHERE c_id = $courseId AND thread_id= $threadId";
4848
    Database::query($sql);
4849
    // Fix group id, if forum is moved to a different group
4850
    if (!empty($forumInfo['to_group_id'])) {
4851
        $groupId = $forumInfo['to_group_id'];
4852
        $item = api_get_item_property_info(
4853
            $courseId,
4854
            TABLE_FORUM_THREAD,
4855
            $threadId,
4856
            $sessionId,
4857
            $groupId
4858
        );
4859
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4860
        $sessionCondition = api_get_session_condition($sessionId);
4861
4862
        if (!empty($item)) {
4863
            if ($item['to_group_id'] != $groupId) {
4864
                $sql = "UPDATE $table
4865
                    SET to_group_id = $groupId
4866
                    WHERE
4867
                      tool = '".TABLE_FORUM_THREAD."' AND
4868
                      c_id = $courseId AND
4869
                      ref = ".$item['ref']."
4870
                      $sessionCondition
4871
                ";
4872
                Database::query($sql);
4873
            }
4874
        } else {
4875
            $sql = "UPDATE $table
4876
                    SET to_group_id = $groupId
4877
                    WHERE
4878
                      tool = '".TABLE_FORUM_THREAD."' AND
4879
                      c_id = $courseId AND
4880
                      ref = ".$threadId."
4881
                      $sessionCondition
4882
            ";
4883
            Database::query($sql);
4884
        }
4885
    }
4886
4887
    return get_lang('ThreadMoved');
4888
}
4889
4890
/**
4891
 * Prepares a string for displaying by highlighting the search results inside, if any.
4892
 *
4893
 * @param string $input the input string
4894
 *
4895
 * @return string the same string with highlighted hits inside
4896
 *
4897
 * @author Patrick Cool <[email protected]>, Ghent University, February 2006 - the initial version.
4898
 * @author Ivan Tcholakov, March 2011 - adaptation for Chamilo LMS.
4899
 */
4900
function prepare4display($input)
4901
{
4902
    static $highlightcolors = ['yellow', '#33CC33', '#3399CC', '#9999FF', '#33CC33'];
4903
    static $search;
4904
4905
    if (!isset($search)) {
4906
        if (isset($_POST['search_term'])) {
4907
            $search = $_POST['search_term']; // No html at all.
4908
        } elseif (isset($_GET['search'])) {
4909
            $search = $_GET['search'];
4910
        } else {
4911
            $search = '';
4912
        }
4913
    }
4914
4915
    if (!empty($search)) {
4916
        if (strstr($search, '+')) {
4917
            $search_terms = explode('+', $search);
4918
        } else {
4919
            $search_terms[] = trim($search);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$search_terms was never initialized. Although not strictly required by PHP, it is generally a good practice to add $search_terms = array(); before regardless.
Loading history...
4920
        }
4921
        $counter = 0;
4922
        foreach ($search_terms as $key => $search_term) {
4923
            $input = api_preg_replace(
4924
                '/'.preg_quote(trim($search_term), '/').'/i',
4925
                '<span style="background-color: '.$highlightcolors[$counter].'">$0</span>',
4926
                $input
4927
            );
4928
            $counter++;
4929
        }
4930
    }
4931
4932
    // TODO: Security should be implemented outside this function.
4933
    // Change this to COURSEMANAGERLOWSECURITY or COURSEMANAGER to lower filtering and allow more styles
4934
    // (see comments of Security::remove_XSS() method to learn about other levels).
4935
4936
    return Security::remove_XSS($input, STUDENT, true);
4937
}
4938
4939
/**
4940
 * Display the search form for the forum and display the search results.
4941
 *
4942
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4943
 *
4944
 * @version march 2008, dokeos 1.8.5
4945
 */
4946
function forum_search()
4947
{
4948
    $form = new FormValidator(
4949
        'forumsearch',
4950
        'post',
4951
        'forumsearch.php?'.api_get_cidreq()
4952
    );
4953
4954
    // Setting the form elements.
4955
    $form->addElement('header', '', get_lang('ForumSearch'));
4956
    $form->addElement('text', 'search_term', get_lang('SearchTerm'), ['autofocus']);
4957
    $form->applyFilter('search_term', 'html_filter');
4958
    $form->addElement('static', 'search_information', '', get_lang('ForumSearchInformation'));
4959
    $form->addButtonSearch(get_lang('Search'));
4960
4961
    // Setting the rules.
4962
    $form->addRule('search_term', get_lang('ThisFieldIsRequired'), 'required');
4963
    $form->addRule('search_term', get_lang('TooShort'), 'minlength', 3);
4964
4965
    // Validation or display.
4966
    if ($form->validate()) {
4967
        $values = $form->exportValues();
4968
        $form->setDefaults($values);
4969
        $form->display();
4970
        // Display the search results.
4971
        display_forum_search_results(stripslashes($values['search_term']));
4972
    } else {
4973
        $form->display();
4974
    }
4975
}
4976
4977
/**
4978
 * Display the search results.
4979
 *
4980
 * @param string
4981
 * @param string $search_term
4982
 *
4983
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4984
 *
4985
 * @version march 2008, dokeos 1.8.5
4986
 */
4987
function display_forum_search_results($search_term)
4988
{
4989
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4990
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4991
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
4992
    $session_id = api_get_session_id();
4993
    $course_id = api_get_course_int_id();
4994
4995
    // Defining the search strings as an array.
4996
    if (strstr($search_term, '+')) {
4997
        $search_terms = explode('+', $search_term);
4998
    } else {
4999
        $search_terms[] = $search_term;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$search_terms was never initialized. Although not strictly required by PHP, it is generally a good practice to add $search_terms = array(); before regardless.
Loading history...
5000
    }
5001
5002
    // Search restriction.
5003
    foreach ($search_terms as $value) {
5004
        $search_restriction[] = "
5005
        (
5006
            posts.post_title LIKE '%".Database::escape_string(trim($value))."%' OR 
5007
            posts.post_text LIKE '%".Database::escape_string(trim($value))."%' 
5008
        )";
5009
    }
5010
5011
    $sessionCondition = api_get_session_condition(
5012
        $session_id,
5013
        true,
5014
        false,
5015
        'item_property.session_id'
5016
    );
5017
5018
    $sql = "SELECT posts.*
5019
            FROM $table_posts posts 
5020
            INNER JOIN $table_threads threads
5021
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
5022
            INNER JOIN $table_item_property item_property
5023
            ON (item_property.ref = threads.thread_id AND item_property.c_id = threads.c_id)
5024
            WHERE
5025
                posts.c_id = $course_id AND 
5026
                item_property.c_id = $course_id AND 
5027
                item_property.visibility = 1  
5028
                $sessionCondition AND
5029
                posts.visible = 1 AND 
5030
                item_property.tool = '".TOOL_FORUM_THREAD."' AND 
5031
                ".implode(' AND ', $search_restriction)."
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $search_restriction seems to be defined by a foreach iteration on line 5003. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
5032
            GROUP BY posts.post_id";
5033
5034
    // Getting all the information of the forum categories.
5035
    $forum_categories_list = get_forum_categories();
5036
5037
    // Getting all the information of the forums.
5038
    $forum_list = get_forums();
5039
5040
    $result = Database::query($sql);
5041
    $search_results = [];
5042
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5043
        $forumId = $row['forum_id'];
5044
        $forumData = get_forums($forumId);
5045
        $category = isset($forum_categories_list[$forumData['forum_category']]) ? $forum_categories_list[$forumData['forum_category']] : null;
5046
        $display_result = false;
5047
        /*
5048
          We only show it when
5049
          1. forum category is visible
5050
          2. forum is visible
5051
          3. thread is visible (to do)
5052
          4. post is visible
5053
         */
5054
        if (!api_is_allowed_to_edit(null, true)) {
5055
            if (!empty($category)) {
5056
                if ($category['visibility'] == '1' && $forumData['visibility'] == '1') {
5057
                    $display_result = true;
5058
                }
5059
            } else {
5060
                if ($forumData['visible'] == '1') {
5061
                    $display_result = true;
5062
                }
5063
            }
5064
        } else {
5065
            $display_result = true;
5066
        }
5067
5068
        if ($display_result) {
5069
            $categoryName = !empty($category) ? $category['cat_title'] : '';
5070
            $search_results_item = '<li><a href="viewforumcategory.php?'.api_get_cidreq().'&forumcategory='.$forumData['forum_category'].'&search='.urlencode($search_term).'">'.
5071
                prepare4display($categoryName).'</a> &gt; ';
5072
            $search_results_item .= '<a href="viewforum.php?'.api_get_cidreq().'&forum='.$forumId.'&search='.urlencode($search_term).'">'.
5073
                prepare4display($forum_list[$row['forum_id']]['forum_title']).'</a> &gt; ';
5074
            $search_results_item .= '<a href="viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$row['thread_id'].'&search='.urlencode($search_term).'">'.
5075
                prepare4display($row['post_title']).'</a>';
5076
            $search_results_item .= '<br />';
5077
            if (api_strlen($row['post_title']) > 200) {
5078
                $search_results_item .= prepare4display(api_substr(strip_tags($row['post_title']), 0, 200)).'...';
5079
            } else {
5080
                $search_results_item .= prepare4display($row['post_title']);
5081
            }
5082
            $search_results_item .= '</li>';
5083
            $search_results[] = $search_results_item;
5084
        }
5085
    }
5086
    echo '<legend>'.count($search_results).' '.get_lang('ForumSearchResults').'</legend>';
5087
    echo '<ol>';
5088
    if ($search_results) {
5089
        echo implode($search_results);
5090
    }
5091
    echo '</ol>';
5092
}
5093
5094
/**
5095
 * Return the link to the forum search page.
5096
 *
5097
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5098
 *
5099
 * @version April 2008, dokeos 1.8.5
5100
 */
5101
function search_link()
5102
{
5103
    $return = '';
5104
    $origin = api_get_origin();
5105
    if ($origin != 'learnpath') {
5106
        $return = '<a href="forumsearch.php?'.api_get_cidreq().'&action=search"> ';
5107
        $return .= Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
5108
5109
        if (!empty($_GET['search'])) {
5110
            $return .= ': '.Security::remove_XSS($_GET['search']).' ';
5111
            $url = api_get_self().'?';
5112
            $url_parameter = [];
5113
            foreach ($_GET as $key => $value) {
5114
                if ($key != 'search') {
5115
                    $url_parameter[] = Security::remove_XSS($key).'='.Security::remove_XSS($value);
5116
                }
5117
            }
5118
            $url = $url.implode('&', $url_parameter);
5119
            $return .= '<a href="'.$url.'">'.Display::return_icon('delete.gif', get_lang('RemoveSearchResults')).'</a>';
5120
        }
5121
    }
5122
5123
    return $return;
5124
}
5125
5126
/**
5127
 * This function adds an attachment file into a forum.
5128
 *
5129
 * @param string $file_comment a comment about file
5130
 * @param int    $last_id      from forum_post table
5131
 *
5132
 * @return false|null
5133
 */
5134
function add_forum_attachment_file($file_comment, $last_id)
5135
{
5136
    $_course = api_get_course_info();
5137
    $agenda_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5138
5139
    if (empty($_FILES['user_upload'])) {
5140
        return false;
5141
    }
5142
5143
    $filesData = [];
5144
5145
    if (!is_array($_FILES['user_upload']['name'])) {
5146
        $filesData[] = $_FILES['user_upload'];
5147
    } else {
5148
        $fileCount = count($_FILES['user_upload']['name']);
5149
        $fileKeys = array_keys($_FILES['user_upload']);
5150
        for ($i = 0; $i < $fileCount; $i++) {
5151
            foreach ($fileKeys as $key) {
5152
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
5153
            }
5154
        }
5155
    }
5156
5157
    foreach ($filesData as $attachment) {
5158
        if (empty($attachment['name'])) {
5159
            continue;
5160
        }
5161
5162
        $upload_ok = process_uploaded_file($attachment);
5163
5164
        if (!$upload_ok) {
5165
            continue;
5166
        }
5167
5168
        $course_dir = $_course['path'].'/upload/forum';
5169
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
5170
        $updir = $sys_course_path.$course_dir;
5171
5172
        // Try to add an extension to the file if it hasn't one.
5173
        $new_file_name = add_ext_on_mime(
5174
            stripslashes($attachment['name']),
5175
            $attachment['type']
5176
        );
5177
        // User's file name
5178
        $file_name = $attachment['name'];
5179
5180
        if (!filter_extension($new_file_name)) {
5181
            Display::addFlash(
5182
                Display::return_message(
5183
                    get_lang('UplUnableToSaveFileFilteredExtension'),
5184
                    'error'
5185
                )
5186
            );
5187
5188
            return;
5189
        }
5190
5191
        $new_file_name = uniqid('');
5192
        $new_path = $updir.'/'.$new_file_name;
5193
        $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5194
        $safe_file_comment = Database::escape_string($file_comment);
5195
        $safe_file_name = Database::escape_string($file_name);
5196
        $safe_new_file_name = Database::escape_string($new_file_name);
5197
        $last_id = intval($last_id);
5198
        // Storing the attachments if any.
5199
        if (!$result) {
5200
            return;
5201
        }
5202
5203
        $last_id_file = Database::insert(
5204
            $agenda_forum_attachment,
5205
            [
5206
                'c_id' => api_get_course_int_id(),
5207
                'filename' => $safe_file_name,
5208
                'comment' => $safe_file_comment,
5209
                'path' => $safe_new_file_name,
5210
                'post_id' => $last_id,
5211
                'size' => intval($attachment['size']),
5212
            ]
5213
        );
5214
5215
        api_item_property_update(
5216
            $_course,
5217
            TOOL_FORUM_ATTACH,
5218
            $last_id_file,
0 ignored issues
show
Bug introduced by
It seems like $last_id_file can also be of type false; however, parameter $item_id of api_item_property_update() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

5218
            /** @scrutinizer ignore-type */ $last_id_file,
Loading history...
5219
            'ForumAttachmentAdded',
5220
            api_get_user_id()
5221
        );
5222
    }
5223
}
5224
5225
/**
5226
 * This function edits an attachment file into a forum.
5227
 *
5228
 * @param string $file_comment a comment about file
5229
 * @param int    $post_id
5230
 * @param int    $id_attach    attachment file Id
5231
 */
5232
function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
5233
{
5234
    $_course = api_get_course_info();
5235
    $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5236
    $course_id = api_get_course_int_id();
5237
5238
    $filesData = [];
5239
5240
    if (!is_array($_FILES['user_upload']['name'])) {
5241
        $filesData[] = $_FILES['user_upload'];
5242
    } else {
5243
        $fileCount = count($_FILES['user_upload']['name']);
5244
        $fileKeys = array_keys($_FILES['user_upload']);
5245
5246
        for ($i = 0; $i < $fileCount; $i++) {
5247
            foreach ($fileKeys as $key) {
5248
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
5249
            }
5250
        }
5251
    }
5252
5253
    foreach ($filesData as $attachment) {
5254
        if (empty($attachment['name'])) {
5255
            continue;
5256
        }
5257
5258
        $upload_ok = process_uploaded_file($attachment);
5259
5260
        if (!$upload_ok) {
5261
            continue;
5262
        }
5263
5264
        $course_dir = $_course['path'].'/upload/forum';
5265
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
5266
        $updir = $sys_course_path.$course_dir;
5267
5268
        // Try to add an extension to the file if it hasn't one.
5269
        $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
5270
        // User's file name
5271
        $file_name = $attachment['name'];
5272
5273
        if (!filter_extension($new_file_name)) {
5274
            Display::addFlash(
5275
                Display::return_message(
5276
                    get_lang('UplUnableToSaveFileFilteredExtension'),
5277
                    'error'
5278
                )
5279
            );
5280
        } else {
5281
            $new_file_name = uniqid('');
5282
            $new_path = $updir.'/'.$new_file_name;
5283
            $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5284
            $safe_file_comment = Database::escape_string($file_comment);
5285
            $safe_file_name = Database::escape_string($file_name);
5286
            $safe_new_file_name = Database::escape_string($new_file_name);
5287
            $safe_post_id = (int) $post_id;
5288
            $safe_id_attach = (int) $id_attach;
5289
            // Storing the attachments if any.
5290
            if ($result) {
5291
                $sql = "UPDATE $table_forum_attachment 
5292
                        SET 
5293
                            filename = '$safe_file_name', 
5294
                            comment = '$safe_file_comment', 
5295
                            path = '$safe_new_file_name', 
5296
                            post_id = '$safe_post_id', 
5297
                            size ='".$attachment['size']."'
5298
                        WHERE c_id = $course_id AND id = '$safe_id_attach'";
5299
                Database::query($sql);
5300
                api_item_property_update(
5301
                    $_course,
5302
                    TOOL_FORUM_ATTACH,
5303
                    $safe_id_attach,
5304
                    'ForumAttachmentUpdated',
5305
                    api_get_user_id()
5306
                );
5307
            }
5308
        }
5309
    }
5310
}
5311
5312
/**
5313
 * Show a list with all the attachments according to the post's id.
5314
 *
5315
 * @param int $postId
5316
 *
5317
 * @return array with the post info
5318
 *
5319
 * @author Julio Montoya
5320
 *
5321
 * @version avril 2008, dokeos 1.8.5
5322
 */
5323
function get_attachment($postId)
5324
{
5325
    $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5326
    $course_id = api_get_course_int_id();
5327
    $row = [];
5328
    $postId = (int) $postId;
5329
5330
    if (empty($postId)) {
5331
        return [];
5332
    }
5333
5334
    $sql = "SELECT iid, path, filename, comment 
5335
            FROM $table
5336
            WHERE c_id = $course_id AND post_id = $postId";
5337
    $result = Database::query($sql);
5338
    if (Database::num_rows($result) != 0) {
5339
        $row = Database::fetch_array($result);
5340
    }
5341
5342
    return $row;
5343
}
5344
5345
/**
5346
 * @param int $postId
5347
 *
5348
 * @return array
5349
 */
5350
function getAllAttachment($postId)
5351
{
5352
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5353
    $courseId = api_get_course_int_id();
5354
    $postId = (int) $postId;
5355
5356
    if (empty($postId)) {
5357
        return [];
5358
    }
5359
5360
    $columns = ['iid', 'path', 'filename', 'comment'];
5361
    $conditions = [
5362
        'where' => [
5363
            'c_id = ? AND post_id = ?' => [$courseId, $postId],
5364
        ],
5365
    ];
5366
    $array = Database::select(
5367
        $columns,
5368
        $forumAttachmentTable,
5369
        $conditions,
5370
        'all',
5371
        'ASSOC'
5372
    );
5373
5374
    return $array;
5375
}
5376
5377
/**
5378
 * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
5379
 *
5380
 * @param int  $post_id
5381
 * @param int  $id_attach
5382
 *
5383
 * @return int
5384
 *
5385
 * @author Julio Montoya
5386
 *
5387
 * @version october 2014, chamilo 1.9.8
5388
 */
5389
function delete_attachment($post_id, $id_attach = 0)
5390
{
5391
    $_course = api_get_course_info();
5392
5393
    $forum_table_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5394
    $course_id = api_get_course_int_id();
5395
5396
    $cond = (!empty($id_attach)) ? " iid = ".(int) $id_attach."" : " post_id = ".(int) $post_id."";
5397
    $sql = "SELECT path FROM $forum_table_attachment WHERE c_id = $course_id AND $cond";
5398
    $res = Database::query($sql);
5399
    $row = Database::fetch_array($res);
5400
5401
    $course_dir = $_course['path'].'/upload/forum';
5402
    $sys_course_path = api_get_path(SYS_COURSE_PATH);
5403
    $updir = $sys_course_path.$course_dir;
5404
    $my_path = isset($row['path']) ? $row['path'] : null;
5405
    $file = $updir.'/'.$my_path;
5406
    if (Security::check_abs_path($file, $updir)) {
5407
        @unlink($file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

5407
        /** @scrutinizer ignore-unhandled */ @unlink($file);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
5408
    }
5409
5410
    // Delete from forum_attachment table.
5411
    $sql = "DELETE FROM $forum_table_attachment 
5412
            WHERE c_id = $course_id AND $cond ";
5413
    $result = Database::query($sql);
5414
    if ($result !== false) {
5415
        $affectedRows = Database::affected_rows($result);
5416
    } else {
5417
        $affectedRows = 0;
5418
    }
5419
5420
    // Update item_property.
5421
    api_item_property_update(
5422
        $_course,
5423
        TOOL_FORUM_ATTACH,
5424
        $id_attach,
5425
        'ForumAttachmentDelete',
5426
        api_get_user_id()
5427
    );
5428
5429
    if (!empty($result) && !empty($id_attach)) {
5430
        Display::addFlash(Display::return_message(get_lang('AttachmentFileDeleteSuccess'), 'confirmation'));
5431
    }
5432
5433
    return $affectedRows;
5434
}
5435
5436
/**
5437
 * This function gets all the forum information of the all the forum of the group.
5438
 *
5439
 * @param array $groupInfo the id of the group we need the fora of (see forum.forum_of_group)
5440
 *
5441
 * @return array
5442
 *
5443
 * @todo this is basically the same code as the get_forums function. Consider merging the two.
5444
 */
5445
function get_forums_of_group($groupInfo)
5446
{
5447
    $table_forums = Database::get_course_table(TABLE_FORUM);
5448
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
5449
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5450
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
5451
    $course_id = api_get_course_int_id();
5452
    $groupId = (int) $groupInfo['id'];
5453
5454
    // Student
5455
    // Select all the forum information of all forums (that are visible to students).
5456
    $sql = "SELECT * FROM $table_forums forum 
5457
            INNER JOIN $table_item_property item_properties
5458
            ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5459
            WHERE
5460
                forum.forum_of_group = $groupId AND
5461
                forum.c_id = $course_id AND
5462
                item_properties.c_id = $course_id AND                
5463
                item_properties.visibility = 1 AND
5464
                item_properties.tool = '".TOOL_FORUM."'
5465
            ORDER BY forum.forum_order ASC";
5466
5467
    // Select the number of threads of the forums (only the threads that are visible).
5468
    $sql2 = "SELECT 
5469
                count(thread_id) AS number_of_threads, 
5470
                threads.forum_id
5471
            FROM $table_threads threads 
5472
            INNER JOIN $table_item_property item_properties
5473
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5474
            WHERE                
5475
                threads.c_id = $course_id AND
5476
                item_properties.c_id = $course_id AND
5477
                item_properties.visibility = 1 AND
5478
                item_properties.tool='".TOOL_FORUM_THREAD."'
5479
            GROUP BY threads.forum_id";
5480
5481
    // Select the number of posts of the forum (post that are visible and that are in a thread that is visible).
5482
    $sql3 = "SELECT count(post_id) AS number_of_posts, posts.forum_id
5483
            FROM $table_posts posts 
5484
            INNER JOIN $table_threads threads 
5485
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
5486
            INNER JOIN $table_item_property item_properties
5487
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5488
            WHERE 
5489
                posts.visible=1 AND
5490
                posts.c_id = $course_id AND
5491
                item_properties.c_id = $course_id AND
5492
                threads.c_id = $course_id AND 
5493
                item_properties.visibility = 1 AND 
5494
                item_properties.tool='".TOOL_FORUM_THREAD."'
5495
            GROUP BY threads.forum_id";
5496
5497
    // Course Admin
5498
    if (api_is_allowed_to_edit()) {
5499
        // Select all the forum information of all forums (that are not deleted).
5500
        $sql = "SELECT *
5501
                FROM $table_forums forum 
5502
                INNER JOIN $table_item_property item_properties
5503
                ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5504
                WHERE
5505
                    forum.forum_of_group = $groupId AND
5506
                    forum.c_id = $course_id AND
5507
                    item_properties.c_id = $course_id AND                    
5508
                    item_properties.visibility <> 2 AND
5509
                    item_properties.tool = '".TOOL_FORUM."'
5510
                ORDER BY forum_order ASC";
5511
5512
        // Select the number of threads of the forums (only the threads that are not deleted).
5513
        $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id
5514
                 FROM $table_threads threads 
5515
                 INNER JOIN $table_item_property item_properties
5516
                 ON (threads.thread_id=item_properties.ref AND item_properties.c_id = threads.c_id)
5517
                 WHERE
5518
                    threads.c_id = $course_id AND
5519
                    item_properties.c_id = $course_id AND
5520
                    item_properties.visibility <> 2 AND
5521
                    item_properties.tool='".TOOL_FORUM_THREAD."'
5522
                GROUP BY threads.forum_id";
5523
        // Select the number of posts of the forum.
5524
        $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id
5525
                FROM $table_posts
5526
                WHERE c_id = $course_id 
5527
                GROUP BY forum_id";
5528
    }
5529
5530
    // Handling all the forum information.
5531
    $result = Database::query($sql);
5532
    $forum_list = [];
5533
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5534
        $forum_list[$row['forum_id']] = $row;
5535
    }
5536
5537
    // Handling the thread count information.
5538
    $result2 = Database::query($sql2);
5539
    while ($row2 = Database::fetch_array($result2, 'ASSOC')) {
5540
        if (is_array($forum_list)) {
5541
            if (array_key_exists($row2['forum_id'], $forum_list)) {
5542
                $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
5543
            }
5544
        }
5545
    }
5546
5547
    // Handling the post count information.
5548
    $result3 = Database::query($sql3);
5549
    while ($row3 = Database::fetch_array($result3, 'ASSOC')) {
5550
        if (is_array($forum_list)) {
5551
            if (array_key_exists($row3['forum_id'], $forum_list)) {
5552
                // This is needed because sql3 takes also the deleted forums into account.
5553
                $forum_list[$row3['forum_id']]['number_of_posts'] = $row3['number_of_posts'];
5554
            }
5555
        }
5556
    }
5557
5558
    // Finding the last post information
5559
    // (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname).
5560
    if (!empty($forum_list)) {
5561
        foreach ($forum_list as $key => $value) {
5562
            $last_post_info_of_forum = get_last_post_information($key, api_is_allowed_to_edit());
5563
            if ($last_post_info_of_forum) {
5564
                $forum_list[$key]['last_post_id'] = $last_post_info_of_forum['last_post_id'];
5565
                $forum_list[$key]['last_poster_id'] = $last_post_info_of_forum['last_poster_id'];
5566
                $forum_list[$key]['last_post_date'] = $last_post_info_of_forum['last_post_date'];
5567
                $forum_list[$key]['last_poster_name'] = $last_post_info_of_forum['last_poster_name'];
5568
                $forum_list[$key]['last_poster_lastname'] = $last_post_info_of_forum['last_poster_lastname'];
5569
                $forum_list[$key]['last_poster_firstname'] = $last_post_info_of_forum['last_poster_firstname'];
5570
            }
5571
        }
5572
    }
5573
5574
    return $forum_list;
5575
}
5576
5577
/**
5578
 * This function stores which users have to be notified of which forums or threads.
5579
 *
5580
 * @param string $content does the user want to be notified about a forum or about a thread
5581
 * @param int    $id      the id of the forum or thread
5582
 *
5583
 * @return string language variable
5584
 *
5585
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5586
 *
5587
 * @version May 2008, dokeos 1.8.5
5588
 *
5589
 * @since May 2008, dokeos 1.8.5
5590
 */
5591
function set_notification($content, $id, $add_only = false)
5592
{
5593
    $_user = api_get_user_info();
5594
    // Database table definition
5595
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5596
5597
    $course_id = api_get_course_int_id();
5598
5599
    // Which database field do we have to store the id in?
5600
    if ($content == 'forum') {
5601
        $database_field = 'forum_id';
5602
    } else {
5603
        $database_field = 'thread_id';
5604
    }
5605
5606
    // First we check if the notification is already set for this.
5607
    $sql = "SELECT * FROM $table_notification
5608
            WHERE
5609
                c_id = $course_id AND
5610
                $database_field = '".Database::escape_string($id)."' AND
5611
                user_id = '".intval($_user['user_id'])."'";
5612
    $result = Database::query($sql);
5613
    $total = Database::num_rows($result);
5614
5615
    // If the user did not indicate that (s)he wanted to be notified already
5616
    // then we store the notification request (to prevent double notification requests).
5617
    if ($total <= 0) {
5618
        $sql = "INSERT INTO $table_notification (c_id, $database_field, user_id)
5619
                VALUES (".$course_id.", '".Database::escape_string($id)."','".intval($_user['user_id'])."')";
5620
        Database::query($sql);
5621
        Session::erase('forum_notification');
5622
        getNotificationsPerUser(0, true);
5623
5624
        return get_lang('YouWillBeNotifiedOfNewPosts');
5625
    } else {
5626
        if (!$add_only) {
5627
            $sql = "DELETE FROM $table_notification
5628
                    WHERE
5629
                        c_id = $course_id AND
5630
                        $database_field = '".Database::escape_string($id)."' AND
5631
                        user_id = '".intval($_user['user_id'])."'";
5632
            Database::query($sql);
5633
            Session::erase('forum_notification');
5634
            getNotificationsPerUser(0, true);
5635
5636
            return get_lang('YouWillNoLongerBeNotifiedOfNewPosts');
5637
        }
5638
    }
5639
}
5640
5641
/**
5642
 * This function retrieves all the email adresses of the users who wanted to be notified
5643
 * about a new post in a certain forum or thread.
5644
 *
5645
 * @param string $content does the user want to be notified about a forum or about a thread
5646
 * @param int    $id      the id of the forum or thread
5647
 *
5648
 * @return array returns
5649
 *
5650
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5651
 *
5652
 * @version May 2008, dokeos 1.8.5
5653
 *
5654
 * @since May 2008, dokeos 1.8.5
5655
 */
5656
function get_notifications($content, $id)
5657
{
5658
    // Database table definition
5659
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5660
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5661
    $course_id = api_get_course_int_id();
5662
5663
    // Which database field contains the notification?
5664
    if ($content == 'forum') {
5665
        $database_field = 'forum_id';
5666
    } else {
5667
        $database_field = 'thread_id';
5668
    }
5669
5670
    $sql = "SELECT user.user_id, user.firstname, user.lastname, user.email, user.user_id user
5671
            FROM $table_users user, $table_notification notification
5672
            WHERE 
5673
                notification.c_id = $course_id AND user.active = 1 AND
5674
                user.user_id = notification.user_id AND
5675
                notification.$database_field= '".Database::escape_string($id)."'";
5676
5677
    $result = Database::query($sql);
5678
    $return = [];
5679
5680
    while ($row = Database::fetch_array($result)) {
5681
        $return['user'.$row['user_id']] = ['email' => $row['email'], 'user_id' => $row['user_id']];
5682
    }
5683
5684
    return $return;
5685
}
5686
5687
/**
5688
 * Get all the users who need to receive a notification of a new post (those subscribed to
5689
 * the forum or the thread).
5690
 *
5691
 * @param int $forum_id  the id of the forum
5692
 * @param int $thread_id the id of the thread
5693
 * @param int $post_id   the id of the post
5694
 *
5695
 * @return false|null
5696
 *
5697
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5698
 *
5699
 * @version May 2008, dokeos 1.8.5
5700
 *
5701
 * @since May 2008, dokeos 1.8.5
5702
 */
5703
function send_notifications($forum_id = 0, $thread_id = 0, $post_id = 0)
5704
{
5705
    $_course = api_get_course_info();
5706
5707
    $forumCourseId = api_get_configuration_value('global_forums_course_id');
5708
    if (!empty($forumCourseId)) {
5709
        if ($_course['real_id'] == $forumCourseId) {
5710
            return false;
5711
        }
5712
    }
5713
5714
    $forum_id = (int) $forum_id;
5715
5716
    // The content of the mail
5717
    $thread_link = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&forum='.$forum_id.'&thread='.$thread_id;
5718
5719
    // Users who subscribed to the forum
5720
    if ($forum_id != 0) {
5721
        $users_to_be_notified_by_forum = get_notifications('forum', $forum_id);
5722
    } else {
5723
        return false;
5724
    }
5725
5726
    $current_thread = get_thread_information($forum_id, $thread_id);
5727
    $current_forum = get_forum_information($current_thread['forum_id']);
0 ignored issues
show
Deprecated Code introduced by
The function get_forum_information() has been deprecated: this functionality is now moved to get_forums($forum_id) ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

5727
    $current_forum = /** @scrutinizer ignore-deprecated */ get_forum_information($current_thread['forum_id']);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
5728
    $subject = get_lang('NewForumPost').' - '.$_course['official_code'].' - '.$current_forum['forum_title'].' - '.$current_thread['thread_title'];
5729
5730
    // User who subscribed to the thread
5731
    if ($thread_id != 0) {
5732
        $users_to_be_notified_by_thread = get_notifications('thread', $thread_id);
5733
    }
5734
5735
    // Merging the two
5736
    $users_to_be_notified = array_merge($users_to_be_notified_by_forum, $users_to_be_notified_by_thread);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $users_to_be_notified_by_thread does not seem to be defined for all execution paths leading up to this point.
Loading history...
5737
    $sender_id = api_get_user_id();
5738
5739
    if (is_array($users_to_be_notified)) {
5740
        foreach ($users_to_be_notified as $value) {
5741
            $user_info = api_get_user_info($value['user_id']);
5742
            $email_body = get_lang('Dear').' '.api_get_person_name($user_info['firstname'], $user_info['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
5743
            $email_body .= get_lang('NewForumPost').": ".$current_forum['forum_title'].' - '.$current_thread['thread_title']." <br />\n";
5744
            $email_body .= get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."]  <br />\n";
5745
            $email_body .= get_lang('YouWantedToStayInformed')."<br />\n";
5746
            $email_body .= get_lang('ThreadCanBeFoundHere').': <br /> <a href="'.$thread_link.'">'.$thread_link."</a>\n";
5747
5748
            MessageManager::send_message_simple(
5749
                $value['user_id'],
5750
                $subject,
5751
                $email_body,
5752
                $sender_id
5753
            );
5754
        }
5755
    }
5756
}
5757
5758
/**
5759
 * Get all the notification subscriptions of the user
5760
 * = which forums and which threads does the user wants to be informed of when a new
5761
 * post is added to this thread.
5762
 *
5763
 * @param int  $user_id the user_id of a user (default = 0 => the current user)
5764
 * @param bool $force   force get the notification subscriptions (even if the information is already in the session
5765
 *
5766
 * @return array returns
5767
 *
5768
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5769
 *
5770
 * @version May 2008, dokeos 1.8.5
5771
 *
5772
 * @since May 2008, dokeos 1.8.5
5773
 */
5774
function getNotificationsPerUser($user_id = 0, $force = false, $course_id = 0)
5775
{
5776
    // Database table definition
5777
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5778
    $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
5779
    if (empty($course_id) || $course_id == -1) {
5780
        return null;
5781
    }
5782
    if ($user_id == 0) {
5783
        $user_id = api_get_user_id();
5784
    }
5785
5786
    if (!isset($_SESSION['forum_notification']) ||
5787
        $_SESSION['forum_notification']['course'] != $course_id ||
5788
        $force == true
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
5789
    ) {
5790
        $_SESSION['forum_notification']['course'] = $course_id;
5791
5792
        $sql = "SELECT * FROM $table_notification
5793
                WHERE c_id = $course_id AND user_id='".intval($user_id)."'";
5794
5795
        $result = Database::query($sql);
5796
        while ($row = Database::fetch_array($result)) {
5797
            if (!is_null($row['forum_id'])) {
5798
                $_SESSION['forum_notification']['forum'][] = $row['forum_id'];
5799
            }
5800
            if (!is_null($row['thread_id'])) {
5801
                $_SESSION['forum_notification']['thread'][] = $row['thread_id'];
5802
            }
5803
        }
5804
    }
5805
}
5806
5807
/**
5808
 * This function counts the number of post inside a thread.
5809
 *
5810
 * @param int $thread_id
5811
 *
5812
 * @return int the number of post inside a thread
5813
 *
5814
 * @author Jhon Hinojosa <[email protected]>,
5815
 *
5816
 * @version octubre 2008, dokeos 1.8
5817
 */
5818
function count_number_of_post_in_thread($thread_id)
5819
{
5820
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5821
    $course_id = api_get_course_int_id();
5822
    if (empty($course_id)) {
5823
        return 0;
5824
    }
5825
    $sql = "SELECT count(*) count FROM $table_posts
5826
            WHERE 
5827
                c_id = $course_id AND 
5828
                thread_id='".intval($thread_id)."' ";
5829
    $result = Database::query($sql);
5830
5831
    $count = 0;
5832
    if (Database::num_rows($result) > 0) {
5833
        $row = Database::fetch_array($result);
5834
        $count = $row['count'];
5835
    }
5836
5837
    return $count;
5838
}
5839
5840
/**
5841
 * This function counts the number of post inside a thread user.
5842
 *
5843
 * @param int $thread_id
5844
 * @param int $user_id
5845
 *
5846
 * @return int the number of post inside a thread user
5847
 */
5848
function count_number_of_post_for_user_thread($thread_id, $user_id)
5849
{
5850
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5851
    $course_id = api_get_course_int_id();
5852
    $sql = "SELECT count(iid) as count 
5853
            FROM $table_posts
5854
            WHERE c_id = $course_id AND
5855
                  thread_id=".intval($thread_id)." AND
5856
                  poster_id = ".intval($user_id)." AND visible = 1 ";
5857
    $result = Database::query($sql);
5858
    $count = 0;
5859
    if (Database::num_rows($result) > 0) {
5860
        $count = Database::fetch_array($result);
5861
        $count = $count['count'];
5862
    }
5863
5864
    return $count;
5865
}
5866
5867
/**
5868
 * This function retrieves information of statistical.
5869
 *
5870
 * @param int $thread_id
5871
 * @param int $user_id
5872
 * @param int $course_id
5873
 *
5874
 * @return array the information of statistical
5875
 *
5876
 * @author Jhon Hinojosa <[email protected]>,
5877
 *
5878
 * @version oct 2008, dokeos 1.8
5879
 */
5880
function get_statistical_information($thread_id, $user_id, $course_id)
5881
{
5882
    $result = [];
5883
    $courseInfo = api_get_course_info_by_id($course_id);
5884
    $result['user_course'] = CourseManager::get_users_count_in_course($courseInfo['code']);
5885
    $result['post'] = count_number_of_post_in_thread($thread_id);
5886
    $result['user_post'] = count_number_of_post_for_user_thread($thread_id, $user_id);
5887
5888
    return $result;
5889
}
5890
5891
/**
5892
 * This function return the posts inside a thread from a given user.
5893
 *
5894
 * @param string $course_code
5895
 * @param int    $thread_id
5896
 * @param int    $user_id
5897
 *
5898
 * @return array posts inside a thread
5899
 *
5900
 * @author Jhon Hinojosa <[email protected]>,
5901
 *
5902
 * @version oct 2008, dokeos 1.8
5903
 */
5904
function get_thread_user_post($course_code, $thread_id, $user_id)
5905
{
5906
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5907
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5908
    $thread_id = intval($thread_id);
5909
    $user_id = intval($user_id);
5910
    $course_info = api_get_user_info($course_code);
5911
    $course_id = $course_info['real_id'];
5912
5913
    if (empty($course_id)) {
5914
        $course_id = api_get_course_int_id();
5915
    }
5916
    $sql = "SELECT * FROM $table_posts posts
5917
            LEFT JOIN  $table_users users
5918
                ON posts.poster_id=users.user_id
5919
            WHERE
5920
                posts.c_id = $course_id AND
5921
                posts.thread_id='$thread_id'
5922
                AND posts.poster_id='$user_id'
5923
            ORDER BY posts.post_id ASC";
5924
5925
    $result = Database::query($sql);
5926
    $post_list = [];
5927
    while ($row = Database::fetch_array($result)) {
5928
        $row['status'] = '1';
5929
        $post_list[] = $row;
5930
        $sql = "SELECT * FROM $table_posts posts
5931
                LEFT JOIN $table_users users
5932
                ON (posts.poster_id=users.user_id)
5933
                WHERE
5934
                    posts.c_id = $course_id AND
5935
                    posts.thread_id='$thread_id'
5936
                    AND posts.post_parent_id='".$row['post_id']."'
5937
                ORDER BY posts.post_id ASC";
5938
        $result2 = Database::query($sql);
5939
        while ($row2 = Database::fetch_array($result2)) {
5940
            $row2['status'] = '0';
5941
            $post_list[] = $row2;
5942
        }
5943
    }
5944
5945
    return $post_list;
5946
}
5947
5948
/**
5949
 * This function get the name of an thread by id.
5950
 *
5951
 * @param int thread_id
5952
 *
5953
 * @return string
5954
 *
5955
 * @author Christian Fasanando
5956
 * @author Julio Montoya <[email protected]> Adding security
5957
 */
5958
function get_name_thread_by_id($thread_id)
5959
{
5960
    $t_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
5961
    $course_id = api_get_course_int_id();
5962
    $sql = "SELECT thread_title 
5963
            FROM $t_forum_thread
5964
            WHERE c_id = $course_id AND thread_id = '".intval($thread_id)."' ";
5965
    $result = Database::query($sql);
5966
    $row = Database::fetch_array($result);
5967
5968
    return $row[0];
5969
}
5970
5971
/**
5972
 * This function gets all the post written by an user.
5973
 *
5974
 * @param int    $user_id
5975
 * @param string $course_code
5976
 *
5977
 * @return string
5978
 */
5979
function get_all_post_from_user($user_id, $course_code)
5980
{
5981
    $j = 0;
5982
    $forums = get_forums('', $course_code);
5983
    krsort($forums);
5984
    $forum_results = '';
5985
5986
    foreach ($forums as $forum) {
5987
        if ($forum['visibility'] == 0) {
5988
            continue;
5989
        }
5990
        if ($j <= 4) {
5991
            $threads = get_threads($forum['forum_id']);
5992
5993
            if (is_array($threads)) {
5994
                $i = 0;
5995
                $hand_forums = '';
5996
                $post_counter = 0;
5997
                foreach ($threads as $thread) {
5998
                    if ($thread['visibility'] == 0) {
5999
                        continue;
6000
                    }
6001
                    if ($i <= 4) {
6002
                        $post_list = get_thread_user_post_limit(
6003
                            $course_code,
6004
                            $thread['thread_id'],
6005
                            $user_id,
6006
                            1
6007
                        );
6008
                        $post_counter = count($post_list);
6009
                        if (is_array($post_list) && count($post_list) > 0) {
6010
                            $hand_forums .= '<div id="social-thread">';
6011
                            $hand_forums .= Display::return_icon(
6012
                                'thread.png',
6013
                                get_lang('Thread'),
6014
                                '',
6015
                                ICON_SIZE_MEDIUM
6016
                            );
6017
                            $hand_forums .= '&nbsp;'.Security::remove_XSS($thread['thread_title'], STUDENT);
6018
                            $hand_forums .= '</div>';
6019
6020
                            foreach ($post_list as $posts) {
6021
                                $hand_forums .= '<div id="social-post">';
6022
                                $hand_forums .= '<strong>'.Security::remove_XSS($posts['post_title'], STUDENT).'</strong>';
6023
                                $hand_forums .= '<br / >';
6024
                                $hand_forums .= Security::remove_XSS($posts['post_text'], STUDENT);
6025
                                $hand_forums .= '</div>';
6026
                                $hand_forums .= '<br / >';
6027
                            }
6028
                        }
6029
                    }
6030
                    $i++;
6031
                }
6032
                $forum_results .= '<div id="social-forum">';
6033
                $forum_results .= '<div class="clear"></div><br />';
6034
                $forum_results .= '<div id="social-forum-title">'.
6035
                    Display::return_icon('forum.gif', get_lang('Forum')).'&nbsp;'.Security::remove_XSS($forum['forum_title'], STUDENT).
6036
                    '<div style="float:right;margin-top:-35px">
6037
                        <a href="../forum/viewforum.php?'.api_get_cidreq_params($course_code).'&forum='.$forum['forum_id'].' " >'.
6038
                            get_lang('SeeForum').'    
6039
                        </a>
6040
                     </div></div>';
6041
                $forum_results .= '<br / >';
6042
                if ($post_counter > 0) {
6043
                    $forum_results .= $hand_forums;
6044
                }
6045
                $forum_results .= '</div>';
6046
            }
6047
            $j++;
6048
        }
6049
    }
6050
6051
    return $forum_results;
6052
}
6053
6054
/**
6055
 * @param string $course_code
6056
 * @param int    $thread_id
6057
 * @param int    $user_id
6058
 * @param int    $limit
6059
 *
6060
 * @return array
6061
 */
6062
function get_thread_user_post_limit($course_code, $thread_id, $user_id, $limit = 10)
6063
{
6064
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
6065
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
6066
6067
    $course_info = api_get_course_info($course_code);
6068
    $course_id = $course_info['real_id'];
6069
6070
    $sql = "SELECT * FROM $table_posts posts
6071
            LEFT JOIN  $table_users users
6072
                ON posts.poster_id=users.user_id
6073
            WHERE
6074
                posts.c_id = $course_id AND
6075
                posts.thread_id='".Database::escape_string($thread_id)."' AND 
6076
                posts.poster_id='".Database::escape_string($user_id)."'
6077
            ORDER BY posts.post_id DESC LIMIT $limit ";
6078
    $result = Database::query($sql);
6079
    $post_list = [];
6080
    while ($row = Database::fetch_array($result)) {
6081
        $row['status'] = '1';
6082
        $post_list[] = $row;
6083
    }
6084
6085
    return $post_list;
6086
}
6087
6088
/**
6089
 * @param string $user_id
6090
 * @param int    $courseId
6091
 * @param int    $sessionId
6092
 *
6093
 * @return array
6094
 */
6095
function getForumCreatedByUser($user_id, $courseId, $sessionId)
6096
{
6097
    $items = api_get_item_property_list_by_tool_by_user(
6098
        $user_id,
6099
        'forum',
6100
        $courseId,
6101
        $sessionId
6102
    );
6103
6104
    $courseInfo = api_get_course_info_by_id($courseId);
6105
    $forumList = [];
6106
    if (!empty($items)) {
6107
        foreach ($items as $forum) {
6108
            $forumInfo = get_forums(
6109
                $forum['ref'],
6110
                $courseInfo['code'],
6111
                true,
6112
                $sessionId
6113
            );
6114
            if (!empty($forumInfo)) {
6115
                $forumList[] = [
6116
                    $forumInfo['forum_title'],
6117
                    api_get_local_time($forum['insert_date']),
6118
                    api_get_local_time($forum['lastedit_date']),
6119
                ];
6120
            }
6121
        }
6122
    }
6123
6124
    return $forumList;
6125
}
6126
6127
/**
6128
 * This function builds an array of all the posts in a given thread
6129
 * where the key of the array is the post_id
6130
 * It also adds an element children to the array which itself is an array
6131
 * that contains all the id's of the first-level children.
6132
 *
6133
 * @return array $rows containing all the information on the posts of a thread
6134
 *
6135
 * @author Patrick Cool <[email protected]>, Ghent University
6136
 */
6137
function calculate_children($rows)
6138
{
6139
    $sorted_rows = [0 => []];
6140
    if (!empty($rows)) {
6141
        foreach ($rows as $row) {
6142
            $rows_with_children[$row['post_id']] = $row;
6143
            $rows_with_children[$row['post_parent_id']]['children'][] = $row['post_id'];
6144
        }
6145
6146
        $rows = $rows_with_children;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $rows_with_children seems to be defined by a foreach iteration on line 6141. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
6147
        forumRecursiveSort($rows, $sorted_rows);
6148
        unset($sorted_rows[0]);
6149
    }
6150
6151
    return $sorted_rows;
6152
}
6153
6154
/**
6155
 * @param $rows
6156
 * @param $threads
6157
 * @param int $seed
6158
 * @param int $indent
6159
 */
6160
function forumRecursiveSort($rows, &$threads, $seed = 0, $indent = 0)
6161
{
6162
    if ($seed > 0) {
6163
        $threads[$rows[$seed]['post_id']] = $rows[$seed];
6164
        $threads[$rows[$seed]['post_id']]['indent_cnt'] = $indent;
6165
        $indent++;
6166
    }
6167
6168
    if (isset($rows[$seed]['children'])) {
6169
        foreach ($rows[$seed]['children'] as $child) {
6170
            forumRecursiveSort($rows, $threads, $child, $indent);
6171
        }
6172
    }
6173
}
6174
6175
/**
6176
 * Update forum attachment data, used to update comment and post ID.
6177
 *
6178
 * @param $array array (field => value) to update forum attachment row
6179
 * @param $id attach ID to find row to update
6180
 * @param null $courseId course ID to find row to update
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $courseId is correct as it would always require null to be passed?
Loading history...
6181
 *
6182
 * @return int number of affected rows
6183
 */
6184
function editAttachedFile($array, $id, $courseId = null)
6185
{
6186
    // Init variables
6187
    $setString = '';
6188
    $id = intval($id);
6189
    $courseId = intval($courseId);
6190
    if (empty($courseId)) {
6191
        // $courseId can be null, use api method
6192
        $courseId = api_get_course_int_id();
6193
    }
6194
    /*
6195
     * Check if Attachment ID and Course ID are greater than zero
6196
     * and array of field values is not empty
6197
     */
6198
    if ($id > 0 && $courseId > 0 && !empty($array) && is_array($array)) {
6199
        foreach ($array as $key => &$item) {
6200
            $item = Database::escape_string($item);
6201
            $setString .= $key.' = "'.$item.'", ';
6202
        }
6203
        // Delete last comma
6204
        $setString = substr($setString, 0, strlen($setString) - 2);
6205
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6206
        $sql = "UPDATE $forumAttachmentTable 
6207
                SET $setString WHERE c_id = $courseId AND id = $id";
6208
        $result = Database::query($sql);
6209
        if ($result !== false) {
6210
            $affectedRows = Database::affected_rows($result);
6211
            if ($affectedRows > 0) {
6212
                /*
6213
                 * If exist in $_SESSION variable, then delete them from it
6214
                 * because they would be deprecated
6215
                 */
6216
                if (!empty($_SESSION['forum']['upload_file'][$courseId][$id])) {
6217
                    unset($_SESSION['forum']['upload_file'][$courseId][$id]);
6218
                }
6219
            }
6220
6221
            return $affectedRows;
6222
        }
6223
    }
6224
6225
    return 0;
6226
}
6227
6228
/**
6229
 * Return a table where the attachments will be set.
6230
 *
6231
 * @param int $postId Forum Post ID
6232
 *
6233
 * @return string The Forum Attachments Ajax Table
6234
 */
6235
function getAttachmentsAjaxTable($postId = 0)
6236
{
6237
    // Init variables
6238
    $postId = intval($postId);
6239
    $courseId = api_get_course_int_id();
6240
    $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6241
    $fileDataContent = '';
6242
    // Update comment to show if form did not pass validation
6243
    if (!empty($_REQUEST['file_ids']) && is_array($_REQUEST['file_ids'])) {
6244
        // 'file_ids is the name from forum attachment ajax form
6245
        foreach ($_REQUEST['file_ids'] as $key => $attachId) {
6246
            if (!empty($_SESSION['forum']['upload_file'][$courseId][$attachId]) &&
6247
                is_array($_SESSION['forum']['upload_file'][$courseId][$attachId])
6248
            ) {
6249
                // If exist forum attachment then update into $_SESSION data
6250
                $_SESSION['forum']['upload_file'][$courseId][$attachId]['comment'] = $_POST['file_comments'][$key];
6251
            }
6252
        }
6253
    }
6254
6255
    // Get data to fill into attachment files table
6256
    if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6257
        is_array($_SESSION['forum']['upload_file'][$courseId])
6258
    ) {
6259
        $uploadedFiles = $_SESSION['forum']['upload_file'][$courseId];
6260
        foreach ($uploadedFiles as $k => $uploadedFile) {
6261
            if (!empty($uploadedFile) && in_array($uploadedFile['id'], $attachIds)) {
6262
                // Buil html table including an input with attachmentID
6263
                $fileDataContent .= '<tr id="'.$uploadedFile['id'].'" ><td>'.$uploadedFile['name'].'</td><td>'.$uploadedFile['size'].'</td><td>&nbsp;'.$uploadedFile['result'].
6264
                    ' </td><td> <input style="width:90%;" type="text" value="'.$uploadedFile['comment'].'" name="file_comments[]"> </td><td>'.
6265
                    $uploadedFile['delete'].'</td>'.
6266
                    '<input type="hidden" value="'.$uploadedFile['id'].'" name="file_ids[]">'.'</tr>';
6267
            } else {
6268
                /*
6269
                 * If attachment data is empty, then delete it from $_SESSION
6270
                 * because could generate and empty row into html table
6271
                 */
6272
                unset($_SESSION['forum']['upload_file'][$courseId][$k]);
6273
            }
6274
        }
6275
    }
6276
    $style = empty($fileDataContent) ? 'display: none;' : '';
6277
    // Forum attachment Ajax table
6278
    $fileData = '
6279
    <div class="control-group " style="'.$style.'">
6280
        <label class="control-label">'.get_lang('AttachmentList').'</label>
6281
        <div class="controls">
6282
            <table id="attachmentFileList" class="files data_table span10">
6283
                <tr>
6284
                    <th>'.get_lang('FileName').'</th>
6285
                    <th>'.get_lang('Size').'</th>
6286
                    <th>'.get_lang('Status').'</th>
6287
                    <th>'.get_lang('Comment').'</th>
6288
                    <th>'.get_lang('Delete').'</th>
6289
                </tr>
6290
                '.$fileDataContent.'
6291
            </table>
6292
        </div>
6293
    </div>';
6294
6295
    return $fileData;
6296
}
6297
6298
/**
6299
 * Return an array of prepared attachment data to build forum attachment table
6300
 * Also, save this array into $_SESSION to do available the attachment data.
6301
 *
6302
 * @param int $forumId
6303
 * @param int $threadId
6304
 * @param int $postId
6305
 * @param int $attachId
6306
 * @param int $courseId
6307
 *
6308
 * @return array
6309
 */
6310
function getAttachedFiles(
6311
    $forumId,
6312
    $threadId,
6313
    $postId = 0,
6314
    $attachId = 0,
6315
    $courseId = 0
6316
) {
6317
    $forumId = intval($forumId);
6318
    $courseId = intval($courseId);
6319
    $attachId = intval($attachId);
6320
    $postId = intval($postId);
6321
    $threadId = !empty($threadId) ? intval($threadId) : isset($_REQUEST['thread']) ? intval($_REQUEST['thread']) : '';
6322
    if (empty($courseId)) {
6323
        // $courseId can be null, use api method
6324
        $courseId = api_get_course_int_id();
6325
    }
6326
    if (empty($forumId)) {
6327
        if (!empty($_REQUEST['forum'])) {
6328
            $forumId = intval($_REQUEST['forum']);
6329
        } else {
6330
            // if forum ID is empty, cannot generate delete url
6331
6332
            return [];
6333
        }
6334
    }
6335
    // Check if exist at least one of them to filter forum attachment select query
6336
    if (empty($postId) && empty($attachId)) {
6337
        return [];
6338
    } elseif (empty($postId)) {
6339
        $filter = "AND iid = $attachId";
6340
    } elseif (empty($attachId)) {
6341
        $filter = "AND post_id = $postId";
6342
    } else {
6343
        $filter = "AND post_id = $postId AND iid = $attachId";
6344
    }
6345
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6346
    $sql = "SELECT iid, comment, filename, path, size
6347
            FROM $forumAttachmentTable
6348
            WHERE c_id = $courseId $filter";
6349
    $result = Database::query($sql);
6350
    $json = [];
6351
    if ($result !== false && Database::num_rows($result) > 0) {
6352
        while ($row = Database::fetch_array($result, 'ASSOC')) {
6353
            // name contains an URL to download attachment file and its filename
6354
            $json['name'] = Display::url(
6355
                api_htmlentities($row['filename']),
6356
                api_get_path(WEB_CODE_PATH).'forum/download.php?file='.$row['path'].'&'.api_get_cidreq(),
6357
                ['target' => '_blank', 'class' => 'attachFilename']
6358
            );
6359
            $json['id'] = $row['iid'];
6360
            $json['comment'] = $row['comment'];
6361
            // Format file size
6362
            $json['size'] = format_file_size($row['size']);
6363
            // Check if $row is consistent
6364
            if (!empty($row) && is_array($row)) {
6365
                // Set result as success and bring delete URL
6366
                $json['result'] = Display::return_icon('accept.png', get_lang('Uploaded'));
6367
                $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&action=delete_attach&forum='.$forumId.'&thread='.$threadId.'&id_attach='.$row['iid'];
6368
                $json['delete'] = Display::url(
6369
                    Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL),
6370
                    $url,
6371
                    ['class' => 'deleteLink']
6372
                );
6373
            } else {
6374
                // If not, set an exclamation result
6375
                $json['result'] = Display::return_icon('exclamation.png', get_lang('Error'));
6376
            }
6377
            // Store array data into $_SESSION
6378
            $_SESSION['forum']['upload_file'][$courseId][$json['id']] = $json;
6379
        }
6380
    }
6381
6382
    return $json;
6383
}
6384
6385
/**
6386
 * Clear forum attachment data stored in $_SESSION,
6387
 * If is not defined post, it will clear all forum attachment data from course.
6388
 *
6389
 * @param int $postId   -1 : Clear all attachments from course stored in $_SESSION
6390
 *                      0 : Clear attachments from course, except from temporal post "0"
6391
 *                      but without delete them from file system and database
6392
 *                      Other values : Clear attachments from course except specified post
6393
 *                      and delete them from file system and database
6394
 * @param int $courseId : Course ID, if it is null, will use api_get_course_int_id()
6395
 *
6396
 * @return array
6397
 */
6398
function clearAttachedFiles($postId = null, $courseId = null)
6399
{
6400
    // Init variables
6401
    $courseId = intval($courseId);
6402
    $postId = intval($postId);
6403
    $array = [];
6404
    if (empty($courseId)) {
6405
        // $courseId can be null, use api method
6406
        $courseId = api_get_course_int_id();
6407
    }
6408
    if ($postId === -1) {
6409
        // If post ID is -1 then delete course's attachment data from $_SESSION
6410
        if (!empty($_SESSION['forum']['upload_file'][$courseId])) {
6411
            $array = array_keys($_SESSION['forum']['upload_file'][$courseId]);
6412
            unset($_SESSION['forum']['upload_file'][$courseId]);
6413
        }
6414
    } else {
6415
        $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6416
        if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6417
            is_array($_SESSION['forum']['upload_file'][$courseId])) {
6418
            foreach ($_SESSION['forum']['upload_file'][$courseId] as $attachId => $attach) {
6419
                if (!in_array($attachId, $attachIds)) {
6420
                    // If attach ID is not into specified post, delete attachment
6421
                    // Save deleted attachment ID
6422
                    $array[] = $attachId;
6423
                    if ($postId !== 0) {
6424
                        // Post 0 is temporal, delete them from file system and DB
6425
                        delete_attachment(0, $attachId);
6426
                    }
6427
                    // Delete attachment data from $_SESSION
6428
                    unset($_SESSION['forum']['upload_file'][$courseId][$attachId]);
6429
                }
6430
            }
6431
        }
6432
    }
6433
6434
    return $array;
6435
}
6436
6437
/**
6438
 * Returns an array of forum attachment ids into a course and forum post.
6439
 *
6440
 * @param int $postId
6441
 * @param int $courseId
6442
 *
6443
 * @return array
6444
 */
6445
function getAttachmentIdsByPostId($postId, $courseId = 0)
6446
{
6447
    $array = [];
6448
    $courseId = intval($courseId);
6449
    $postId = intval($postId);
6450
    if (empty($courseId)) {
6451
        // $courseId can be null, use api method
6452
        $courseId = api_get_course_int_id();
6453
    }
6454
    if ($courseId > 0) {
6455
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6456
        $sql = "SELECT id FROM $forumAttachmentTable
6457
                WHERE c_id = $courseId AND post_id = $postId";
6458
        $result = Database::query($sql);
6459
        if ($result !== false && Database::num_rows($result) > 0) {
6460
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6461
                $array[] = $row['id'];
6462
            }
6463
        }
6464
    }
6465
6466
    return $array;
6467
}
6468
6469
/**
6470
 * Check if the forum category exists looking for its title.
6471
 *
6472
 * @param string $title     The forum category title
6473
 * @param int    $courseId  The course ID
6474
 * @param int    $sessionId Optional. The session ID
6475
 *
6476
 * @return bool
6477
 */
6478
function getForumCategoryByTitle($title, $courseId, $sessionId = 0)
6479
{
6480
    $sessionId = intval($sessionId);
6481
    $forumCategoryTable = Database::get_course_table(TABLE_FORUM_CATEGORY);
6482
    $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6483
6484
    $fakeFrom = "$forumCategoryTable fc
6485
        INNER JOIN $itemProperty ip ";
6486
6487
    if ($sessionId === 0) {
6488
        $fakeFrom .= "
6489
            ON (
6490
                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)
6491
            )
6492
        ";
6493
    } else {
6494
        $fakeFrom .= "
6495
            ON (
6496
                fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND fc.session_id = ip.session_id
6497
            )
6498
        ";
6499
    }
6500
6501
    $resultData = Database::select(
6502
        'fc.*',
6503
        $fakeFrom,
6504
        [
6505
            'where' => [
6506
                'ip.visibility != ? AND ' => 2,
6507
                'ip.tool = ? AND ' => TOOL_FORUM_CATEGORY,
6508
                'fc.session_id = ? AND ' => $sessionId,
6509
                'fc.cat_title = ? AND ' => $title,
6510
                'fc.c_id = ?' => intval($courseId),
6511
            ],
6512
        ],
6513
        'first'
6514
    );
6515
6516
    if (empty($resultData)) {
6517
        return false;
6518
    }
6519
6520
    return $resultData;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $resultData returns the type array which is incompatible with the documented return type boolean.
Loading history...
6521
}
6522
6523
/**
6524
 * @param array $current_forum
6525
 * @param array $row
6526
 * @param bool  $addWrapper
6527
 *
6528
 * @return string
6529
 */
6530
function getPostStatus($current_forum, $row, $addWrapper = true)
6531
{
6532
    $statusIcon = '';
6533
    if ($current_forum['moderated']) {
6534
        if ($addWrapper) {
6535
            $statusIcon = '<br /><br /><span id="status_post_'.$row['iid'].'">';
6536
        }
6537
        $row['status'] = empty($row['status']) ? 2 : $row['status'];
6538
6539
        $addUrl = false;
6540
        $showStatus = false;
6541
        if (api_is_allowed_to_edit(false, true)) {
6542
            $addUrl = true;
6543
        } else {
6544
            if ($row['user_id'] == api_get_user_id()) {
6545
                $showStatus = true;
6546
            }
6547
        }
6548
6549
        $label = '';
6550
        $icon = '';
6551
        $buttonType = '';
6552
        switch ($row['status']) {
6553
            case CForumPost::STATUS_VALIDATED:
6554
                $label = get_lang('Validated');
6555
                $icon = 'check-circle';
6556
                $buttonType = 'success';
6557
                break;
6558
            case CForumPost::STATUS_WAITING_MODERATION:
6559
                $label = get_lang('WaitingModeration');
6560
                $icon = 'warning';
6561
                $buttonType = 'warning';
6562
                break;
6563
            case CForumPost::STATUS_REJECTED:
6564
                $label = get_lang('Rejected');
6565
                $icon = 'minus-circle';
6566
                $buttonType = 'danger';
6567
                break;
6568
        }
6569
6570
        if ($addUrl) {
6571
            $statusIcon .= Display::toolbarButton(
6572
                $label.'&nbsp;',
6573
                'javascript:void(0)',
6574
                $icon,
6575
                $buttonType,
6576
                ['class' => 'change_post_status']
6577
            );
6578
        } else {
6579
            if ($showStatus) {
6580
                $statusIcon .= Display::label(
6581
                    Display::returnFontAwesomeIcon($icon).$label,
6582
                    $buttonType
6583
                );
6584
            }
6585
        }
6586
6587
        if ($addWrapper) {
6588
            $statusIcon .= '</span>';
6589
        }
6590
    }
6591
6592
    return $statusIcon;
6593
}
6594
6595
/**
6596
 * @param array $forumInfo
6597
 * @param int   $threadId
6598
 * @param int   $status
6599
 *
6600
 * @return mixed
6601
 */
6602
function getCountPostsWithStatus($status, $forumInfo, $threadId = null)
6603
{
6604
    $em = Database::getManager();
6605
    $criteria = Criteria::create();
6606
    $criteria
6607
        ->where(Criteria::expr()->eq('status', $status))
6608
        ->andWhere(Criteria::expr()->eq('cId', $forumInfo['c_id']))
6609
        ->andWhere(Criteria::expr()->eq('visible', 1))
6610
    ;
6611
6612
    if (!empty($threadId)) {
6613
        $criteria->andWhere(Criteria::expr()->eq('threadId', $threadId));
6614
    }
6615
6616
    $qb = $em->getRepository('ChamiloCourseBundle:CForumPost')->createQueryBuilder('p');
6617
    $qb->select('count(p.iid)')
6618
        ->addCriteria($criteria);
6619
6620
    return $qb->getQuery()->getSingleScalarResult();
6621
}
6622
6623
/**
6624
 * @param array $forum
6625
 * @param array $post
6626
 *
6627
 * @return bool
6628
 */
6629
function postIsEditableByStudent($forum, $post)
6630
{
6631
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
6632
        return true;
6633
    }
6634
6635
    if ($forum['moderated'] == 1) {
6636
        if (is_null($post['status'])) {
6637
            return true;
6638
        } else {
6639
            return in_array(
6640
                $post['status'],
6641
                [
6642
                    CForumPost::STATUS_WAITING_MODERATION,
6643
                    CForumPost::STATUS_REJECTED,
6644
                ]
6645
            );
6646
        }
6647
    } else {
6648
        return true;
6649
    }
6650
}
6651
6652
/**
6653
 * @param int $postId
6654
 *
6655
 * @return bool
6656
 */
6657
function savePostRevision($postId)
6658
{
6659
    $postData = get_post_information($postId);
6660
6661
    if (empty($postData)) {
6662
        return false;
6663
    }
6664
6665
    $userId = api_get_user_id();
6666
6667
    if ($postData['poster_id'] != $userId) {
6668
        return false;
6669
    }
6670
6671
    $status = (int) !postNeedsRevision($postId);
6672
    $extraFieldValue = new ExtraFieldValue('forum_post');
6673
    $params = [
6674
        'item_id' => $postId,
6675
        'extra_ask_for_revision' => ['extra_ask_for_revision' => $status],
6676
    ];
6677
    if (empty($status)) {
6678
        unset($params['extra_ask_for_revision']);
6679
    }
6680
    $extraFieldValue->saveFieldValues(
6681
        $params,
6682
        true,
6683
        false,
6684
        ['ask_for_revision']
6685
    );
6686
}
6687
6688
/**
6689
 * @param int $postId
6690
 *
6691
 * @return string
6692
 */
6693
function getPostRevision($postId)
6694
{
6695
    $extraFieldValue = new ExtraFieldValue('forum_post');
6696
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6697
        $postId,
6698
        'revision_language'
6699
    );
6700
    $revision = '';
6701
    if ($value && isset($value['value'])) {
6702
        $revision = $value['value'];
6703
    }
6704
6705
    return $revision;
6706
}
6707
6708
/**
6709
 * @param int $postId
6710
 *
6711
 * @return bool
6712
 */
6713
function postNeedsRevision($postId)
6714
{
6715
    $extraFieldValue = new ExtraFieldValue('forum_post');
6716
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6717
        $postId,
6718
        'ask_for_revision'
6719
    );
6720
    $hasRevision = false;
6721
    if ($value && isset($value['value'])) {
6722
        return $value['value'] == 1;
6723
    }
6724
6725
    return $hasRevision;
6726
}
6727
6728
/**
6729
 * @param int   $postId
6730
 * @param array $threadInfo
6731
 *
6732
 * @return string
6733
 */
6734
function getAskRevisionButton($postId, $threadInfo)
6735
{
6736
    if (api_get_configuration_value('allow_forum_post_revisions') === false) {
6737
        return '';
6738
    }
6739
6740
    $postId = (int) $postId;
6741
6742
    $status = 'btn-default';
6743
    if (postNeedsRevision($postId)) {
6744
        $status = 'btn-success';
6745
    }
6746
6747
    return Display::url(
6748
        get_lang('AskRevision'),
6749
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6750
        api_get_cidreq().'&action=ask_revision&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6751
        ['class' => "btn $status", 'title' => get_lang('AskRevision')]
6752
    );
6753
}
6754
6755
/**
6756
 * @param int   $postId
6757
 * @param array $threadInfo
6758
 *
6759
 * @return string
6760
 */
6761
function giveRevisionButton($postId, $threadInfo)
6762
{
6763
    $postId = (int) $postId;
6764
6765
    return Display::toolbarButton(
6766
        get_lang('GiveRevision'),
6767
        api_get_path(WEB_CODE_PATH).'forum/reply.php?'.api_get_cidreq().'&'.http_build_query(
6768
            [
6769
                'forum' => $threadInfo['forum_id'],
6770
                'thread' => $threadInfo['thread_id'],
6771
                'post' => $postId = (int) $postId,
6772
                'action' => 'replymessage',
6773
                'give_revision' => 1,
6774
            ]
6775
        ),
6776
        'reply',
6777
        'primary',
6778
        ['id' => "reply-to-post-{$postId}"]
6779
    );
6780
}
6781
6782
/**
6783
 * @param int   $postId
6784
 * @param array $threadInfo
6785
 *
6786
 * @return string
6787
 */
6788
function getReportButton($postId, $threadInfo)
6789
{
6790
    $postId = (int) $postId;
6791
6792
    return Display::url(
6793
        Display::returnFontAwesomeIcon('flag'),
6794
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6795
        api_get_cidreq().'&action=report&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6796
        ['class' => 'btn btn-danger', 'title' => get_lang('Report')]
6797
    );
6798
}
6799
6800
/**
6801
 * @return bool
6802
 */
6803
function reportAvailable()
6804
{
6805
    $extraFieldValue = new ExtraFieldValue('course');
6806
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6807
        api_get_course_int_id(),
6808
        'allow_forum_report_button'
6809
    );
6810
    $allowReport = false;
6811
    if ($value && isset($value['value']) && $value['value'] == 1) {
6812
        $allowReport = true;
6813
    }
6814
6815
    return $allowReport;
6816
}
6817
6818
/**
6819
 * @return array
6820
 */
6821
function getReportRecipients()
6822
{
6823
    $extraFieldValue = new ExtraFieldValue('course');
6824
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6825
        api_get_course_int_id(),
6826
        'forum_report_recipients'
6827
    );
6828
    $users = [];
6829
    if ($value && isset($value['value'])) {
6830
        $usersType = explode(';', $value['value']);
6831
6832
        foreach ($usersType as $type) {
6833
            switch ($type) {
6834
                case 'teachers':
6835
                    $teachers = CourseManager::get_teacher_list_from_course_code(api_get_course_id());
6836
                    if (!empty($teachers)) {
6837
                        $users = array_merge($users, array_column($teachers, 'user_id'));
6838
                    }
6839
                break;
6840
                case 'admins':
6841
                    $admins = UserManager::get_all_administrators();
6842
                    if (!empty($admins)) {
6843
                        $users = array_merge($users, array_column($admins, 'user_id'));
6844
                    }
6845
                    break;
6846
                case 'community_managers':
6847
                    $managers = api_get_configuration_value('community_managers_user_list');
6848
                    if (!empty($managers) && isset($managers['users'])) {
6849
                        $users = array_merge($users, $managers['users']);
6850
                    }
6851
                    break;
6852
            }
6853
        }
6854
6855
        $users = array_unique(array_filter($users));
6856
    }
6857
6858
    return $users;
6859
}
6860
6861
/**
6862
 * @param int   $postId
6863
 * @param array $forumInfo
6864
 * @param array $threadInfo
6865
 *
6866
 * @return bool
6867
 */
6868
function reportPost($postId, $forumInfo, $threadInfo)
6869
{
6870
    if (!reportAvailable()) {
6871
        return false;
6872
    }
6873
6874
    if (empty($forumInfo) || empty($threadInfo)) {
6875
        return false;
6876
    }
6877
6878
    $postId = (int) $postId;
6879
6880
    $postData = get_post_information($postId);
6881
    $currentUser = api_get_user_info();
6882
6883
    if (!empty($postData)) {
6884
        $users = getReportRecipients();
6885
        if (!empty($users)) {
6886
            $url = api_get_path(WEB_CODE_PATH).
6887
                'forum/viewthread.php?forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'].'&'.api_get_cidreq().'&post_id='.$postId.'#post_id_'.$postId;
6888
            $postLink = Display::url(
6889
                $postData['post_title'],
6890
                $url
6891
            );
6892
            $subject = get_lang('ForumPostReported');
6893
            $content = sprintf(
6894
                get_lang('UserXReportedPostXInForumX'),
6895
                $currentUser['complete_name'],
6896
                $postLink,
6897
                $forumInfo['forum_title']
6898
            );
6899
            foreach ($users as $userId) {
6900
                MessageManager::send_message_simple($userId, $subject, $content);
6901
            }
6902
        }
6903
    }
6904
}
6905
6906
/**
6907
 * @return array
6908
 */
6909
function getLanguageListForFlag()
6910
{
6911
    $languages = api_get_languages();
6912
    $languages = array_column($languages, 'english_name', 'isocode');
6913
    unset($languages['en']);
6914
    $languages['gb'] = 'english';
6915
    $languages = array_flip($languages);
6916
6917
    return $languages;
6918
}
6919