Passed
Push — master ( f437d8...92f70a )
by Julito
10:14
created

send_notifications()   A

Complexity

Conditions 6
Paths 13

Size

Total Lines 45
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 17
nc 13
nop 3
dl 0
loc 45
rs 9.0777
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
                $postInfo = get_post_information($postId);
3407
                if ($postInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $postInfo 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...
3408
                    $threadId = $postInfo['thread_id'];
3409
                }
3410
3411
                if (isset($values['give_revision']) && $values['give_revision'] == 1) {
3412
                    $extraFieldValues = new ExtraFieldValue('forum_post');
3413
                    $params = [
3414
                        'item_id' => $postId,
3415
                        'extra_revision_language' => $values['extra_revision_language'],
3416
                    ];
3417
                    $extraFieldValues->saveFieldValues(
3418
                        $params,
3419
                        false,
3420
                        false,
3421
                        ['revision_language']
3422
                    );
3423
                }
3424
3425
                if (in_array($action, ['newthread', 'replythread', 'replymessage', 'quote'])) {
3426
                    $extraFieldValues = new ExtraFieldValue('forum_post');
3427
                    $params = [
3428
                        'item_id' => $postId,
3429
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
3430
                    ];
3431
                    $extraFieldValues->saveFieldValues(
3432
                        $params,
3433
                        false,
3434
                        false,
3435
                        ['ask_for_revision']
3436
                    );
3437
                }
3438
            }
3439
3440
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
3441
                [
3442
                    'forum' => $forumId,
3443
                    'thread' => $threadId,
3444
                ]
3445
            );
3446
3447
            Security::clear_token();
3448
            header('Location: '.$url);
3449
            exit;
3450
        }
3451
    } else {
3452
        $token = Security::get_token();
3453
        $form->addElement('hidden', 'sec_token');
3454
        $form->setConstants(['sec_token' => $token]);
3455
3456
        // Delete from $_SESSION forum attachment from other posts
3457
        // and keep only attachments for new post
3458
        clearAttachedFiles(FORUM_NEW_POST);
3459
        // Get forum attachment ajax table to add it to form
3460
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $current_forum['forum_id']);
3461
        $ajaxHtml = $attachmentAjaxTable;
3462
        $form->addElement('html', $ajaxHtml);
3463
3464
        return $form;
3465
    }
3466
}
3467
3468
/**
3469
 * @param array $threadInfo
3470
 * @param int   $user_id
3471
 * @param int   $thread_id
3472
 * @param int   $thread_qualify
3473
 * @param int   $qualify_time
3474
 * @param int   $session_id
3475
 *
3476
 * @return array optional
3477
 *
3478
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3479
 *
3480
 * @version October 2008, dokeos  1.8.6
3481
 */
3482
function saveThreadScore(
3483
    $threadInfo,
3484
    $user_id,
3485
    $thread_id,
3486
    $thread_qualify = 0,
3487
    $qualify_time,
3488
    $session_id = 0
3489
) {
3490
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3491
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3492
3493
    $course_id = api_get_course_int_id();
3494
    $session_id = intval($session_id);
3495
    $currentUserId = api_get_user_id();
3496
3497
    if ($user_id == strval(intval($user_id)) &&
3498
        $thread_id == strval(intval($thread_id)) &&
3499
        $thread_qualify == strval(floatval($thread_qualify))
3500
    ) {
3501
        // Testing
3502
        $sql = "SELECT thread_qualify_max FROM $table_threads
3503
                WHERE c_id = $course_id AND thread_id=".$thread_id;
3504
        $res_string = Database::query($sql);
3505
        $row_string = Database::fetch_array($res_string);
3506
        if ($thread_qualify <= $row_string[0]) {
3507
            if ($threadInfo['thread_peer_qualify'] == 0) {
3508
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3509
                        WHERE
3510
                            c_id = $course_id AND
3511
                            user_id = $user_id AND
3512
                            thread_id = ".$thread_id;
3513
            } else {
3514
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3515
                        WHERE
3516
                            c_id = $course_id AND
3517
                            user_id = $user_id AND
3518
                            qualify_user_id = $currentUserId AND
3519
                            thread_id = ".$thread_id;
3520
            }
3521
3522
            $result = Database::query($sql);
3523
            $row = Database::fetch_array($result);
3524
3525
            if ($row[0] == 0) {
3526
                $sql = "INSERT INTO $table_threads_qualify (c_id, user_id, thread_id,qualify,qualify_user_id,qualify_time,session_id)
3527
                        VALUES (".$course_id.", '".$user_id."','".$thread_id."',".(float) $thread_qualify.", '".$currentUserId."','".$qualify_time."','".$session_id."')";
3528
                Database::query($sql);
3529
                $insertId = Database::insert_id();
3530
                if ($insertId) {
3531
                    $sql = "UPDATE $table_threads_qualify SET id = iid
3532
                            WHERE iid = $insertId";
3533
                    Database::query($sql);
3534
                }
3535
3536
                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...
3537
            } else {
3538
                saveThreadScoreHistory(
3539
                    '1',
3540
                    $course_id,
3541
                    $user_id,
3542
                    $thread_id
3543
                );
3544
3545
                // Update
3546
                $sql = "UPDATE $table_threads_qualify
3547
                        SET
3548
                            qualify = '".$thread_qualify."',
3549
                            qualify_time = '".$qualify_time."'
3550
                        WHERE
3551
                            c_id = $course_id AND
3552
                            user_id=".$user_id." AND
3553
                            thread_id=".$thread_id." AND
3554
                            qualify_user_id = $currentUserId
3555
                        ";
3556
                Database::query($sql);
3557
3558
                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...
3559
            }
3560
        } else {
3561
            return null;
3562
        }
3563
    }
3564
}
3565
3566
/**
3567
 * This function shows qualify.
3568
 *
3569
 * @param string $option    contains the information of option to run
3570
 * @param int    $user_id   contains the information the current user id
3571
 * @param int    $thread_id contains the information the current thread id
3572
 *
3573
 * @return int qualify
3574
 *             <code> $option=1 obtained the qualification of the current thread</code>
3575
 *
3576
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3577
 *
3578
 * @version October 2008, dokeos  1.8.6
3579
 */
3580
function showQualify($option, $user_id, $thread_id)
3581
{
3582
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3583
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3584
3585
    $course_id = api_get_course_int_id();
3586
    $user_id = (int) $user_id;
3587
    $thread_id = (int) $thread_id;
3588
3589
    if (empty($user_id) || empty($thread_id)) {
3590
        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...
3591
    }
3592
3593
    $sql = '';
3594
    switch ($option) {
3595
        case 1:
3596
            $sql = "SELECT qualify FROM $table_threads_qualify
3597
                    WHERE
3598
                        c_id = $course_id AND
3599
                        user_id=".$user_id." AND
3600
                        thread_id=".$thread_id;
3601
            break;
3602
        case 2:
3603
            $sql = "SELECT thread_qualify_max FROM $table_threads
3604
                    WHERE c_id = $course_id AND thread_id=".$thread_id;
3605
            break;
3606
    }
3607
3608
    if (!empty($sql)) {
3609
        $rs = Database::query($sql);
3610
        $row = Database::fetch_array($rs);
3611
3612
        return $row[0];
3613
    }
3614
3615
    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...
3616
}
3617
3618
/**
3619
 * This function gets qualify historical.
3620
 *
3621
 * @param int  $user_id   contains the information the current user id
3622
 * @param int  $thread_id contains the information the current thread id
3623
 * @param bool $opt       contains the information of option to run
3624
 *
3625
 * @return array
3626
 *
3627
 * @author Christian Fasanando <[email protected]>,
3628
 * @author Isaac Flores <[email protected]>,
3629
 *
3630
 * @version October 2008, dokeos  1.8.6
3631
 */
3632
function getThreadScoreHistory($user_id, $thread_id, $opt)
3633
{
3634
    $user_id = (int) $user_id;
3635
    $thread_id = (int) $thread_id;
3636
3637
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3638
    $course_id = api_get_course_int_id();
3639
3640
    if ($opt == 'false') {
3641
        $sql = "SELECT * FROM $table_threads_qualify_log
3642
                WHERE
3643
                    c_id = $course_id AND
3644
                    thread_id='".$thread_id."' AND
3645
                    user_id='".$user_id."'
3646
                ORDER BY qualify_time";
3647
    } else {
3648
        $sql = "SELECT * FROM $table_threads_qualify_log
3649
                WHERE
3650
                    c_id = $course_id AND
3651
                    thread_id='".$thread_id."' AND
3652
                    user_id='".$user_id."'
3653
                ORDER BY qualify_time DESC";
3654
    }
3655
    $rs = Database::query($sql);
3656
    $log = [];
3657
    while ($row = Database::fetch_array($rs, 'ASSOC')) {
3658
        $log[] = $row;
3659
    }
3660
3661
    return $log;
3662
}
3663
3664
/**
3665
 * This function stores qualify historical.
3666
 *
3667
 * @param bool contains the information of option to run
3668
 * @param string contains the information the current course id
3669
 * @param int contains the information the current forum id
3670
 * @param int contains the information the current user id
3671
 * @param int contains the information the current thread id
3672
 * @param int contains the information the current qualify
3673
 * @param string $option
3674
 * @param int    $course_id
3675
 * @param int    $user_id
3676
 * @param int    $thread_id
3677
 *
3678
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3679
 *
3680
 * @version October 2008, dokeos  1.8.6
3681
 */
3682
function saveThreadScoreHistory(
3683
    $option,
3684
    $course_id,
3685
    $user_id,
3686
    $thread_id
3687
) {
3688
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3689
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3690
3691
    $course_id = intval($course_id);
3692
    $qualify_user_id = api_get_user_id();
3693
3694
    if ($user_id == strval(intval($user_id)) &&
3695
        $thread_id == strval(intval($thread_id)) && $option == 1
3696
    ) {
3697
        // Extract information of thread_qualify.
3698
        $sql = "SELECT qualify, qualify_time
3699
                FROM $table_threads_qualify
3700
                WHERE
3701
                    c_id = $course_id AND
3702
                    user_id = ".$user_id." AND
3703
                    thread_id = ".$thread_id." AND
3704
                    qualify_user_id = $qualify_user_id
3705
                ";
3706
        $rs = Database::query($sql);
3707
        $row = Database::fetch_array($rs);
3708
3709
        // Insert thread_historical.
3710
        $sql = "INSERT INTO $table_threads_qualify_log (c_id, user_id, thread_id, qualify, qualify_user_id,qualify_time,session_id)
3711
                VALUES(".$course_id.", '".$user_id."','".$thread_id."',".(float) $row[0].", '".$qualify_user_id."','".$row[1]."','')";
3712
        Database::query($sql);
3713
3714
        $insertId = Database::insert_id();
3715
        if ($insertId) {
3716
            $sql = "UPDATE $table_threads_qualify_log SET id = iid
3717
                    WHERE iid = $insertId";
3718
            Database::query($sql);
3719
        }
3720
    }
3721
}
3722
3723
/**
3724
 * This function shows current thread qualify .
3725
 *
3726
 * @param int $threadId
3727
 * @param int $sessionId
3728
 * @param int $userId
3729
 *
3730
 * @return array or null if is empty
3731
 *
3732
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3733
 *
3734
 * @version December 2008, dokeos  1.8.6
3735
 */
3736
function current_qualify_of_thread($threadId, $sessionId, $userId)
3737
{
3738
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3739
3740
    $course_id = api_get_course_int_id();
3741
    $currentUserId = api_get_user_id();
3742
    $sessionId = intval($sessionId);
3743
    $threadId = intval($threadId);
3744
3745
    $sql = "SELECT qualify FROM $table_threads_qualify
3746
            WHERE
3747
                c_id = $course_id AND
3748
                thread_id = $threadId AND
3749
                session_id = $sessionId AND
3750
                qualify_user_id = $currentUserId AND
3751
                user_id = $userId
3752
            ";
3753
    $res = Database::query($sql);
3754
    $row = Database::fetch_array($res, 'ASSOC');
3755
3756
    return $row['qualify'];
3757
}
3758
3759
/**
3760
 * This function stores a reply in the forum_post table.
3761
 * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date).
3762
 *
3763
 * @param array $current_forum
3764
 * @param array $values
3765
 * @param int   $courseId      Optional
3766
 * @param int   $userId        Optional
3767
 *
3768
 * @return int post id
3769
 *
3770
 * @author Patrick Cool <[email protected]>, Ghent University
3771
 *
3772
 * @version february 2006, dokeos 1.8
3773
 */
3774
function store_reply($current_forum, $values, $courseId = 0, $userId = 0)
3775
{
3776
    $courseId = !empty($courseId) ? $courseId : api_get_course_int_id();
3777
    $_course = api_get_course_info_by_id($courseId);
3778
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3779
    $post_date = api_get_utc_datetime();
3780
    $userId = $userId ?: api_get_user_id();
3781
3782
    if ($current_forum['allow_anonymous'] == 1) {
3783
        if (api_is_anonymous() && empty($userId)) {
3784
            $userId = api_get_anonymous_id();
3785
        }
3786
    }
3787
3788
    if (empty($userId)) {
3789
        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...
3790
    }
3791
3792
    $visible = 1;
3793
    if ($current_forum['approval_direct_post'] == '1' &&
3794
        !api_is_allowed_to_edit(null, true)
3795
    ) {
3796
        $visible = 0;
3797
    }
3798
3799
    $upload_ok = 1;
3800
    $new_post_id = 0;
3801
3802
    if ($upload_ok) {
3803
        // We first store an entry in the forum_post table.
3804
        $new_post_id = Database::insert(
3805
            $table_posts,
3806
            [
3807
                'c_id' => $courseId,
3808
                'post_title' => $values['post_title'],
3809
                'post_text' => isset($values['post_text']) ? ($values['post_text']) : null,
3810
                'thread_id' => $values['thread_id'],
3811
                'forum_id' => $values['forum_id'],
3812
                'poster_id' => $userId,
3813
                'post_id' => 0,
3814
                'post_date' => $post_date,
3815
                'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : null,
3816
                'post_parent_id' => isset($values['post_parent_id']) ? $values['post_parent_id'] : null,
3817
                'visible' => $visible,
3818
            ]
3819
        );
3820
3821
        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...
3822
            $sql = "UPDATE $table_posts SET post_id = iid WHERE iid = $new_post_id";
3823
            Database::query($sql);
3824
3825
            $values['new_post_id'] = $new_post_id;
3826
            $message = get_lang('ReplyAdded');
3827
3828
            if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3829
                foreach ($_POST['file_ids'] as $key => $id) {
3830
                    editAttachedFile(
3831
                        [
3832
                            'comment' => $_POST['file_comments'][$key],
3833
                            'post_id' => $new_post_id,
3834
                        ],
3835
                        $id
3836
                    );
3837
                }
3838
            }
3839
3840
            // Update the thread.
3841
            updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
3842
3843
            // Update the forum.
3844
            api_item_property_update(
3845
                $_course,
3846
                TOOL_FORUM,
3847
                $values['forum_id'],
3848
                'NewMessageInForum',
3849
                $userId
3850
            );
3851
3852
            // Insert post
3853
            api_item_property_update(
3854
                $_course,
3855
                TOOL_FORUM_POST,
3856
                $new_post_id,
3857
                'NewPost',
3858
                $userId
3859
            );
3860
3861
            if ($current_forum['approval_direct_post'] == '1' &&
3862
                !api_is_allowed_to_edit(null, true)
3863
            ) {
3864
                $message .= '<br />'.get_lang('MessageHasToBeApproved').'<br />';
3865
            }
3866
3867
            if ($current_forum['moderated'] &&
3868
                !api_is_allowed_to_edit(null, true)
3869
            ) {
3870
                $message .= '<br />'.get_lang('MessageHasToBeApproved').'<br />';
3871
            }
3872
3873
            // Setting the notification correctly.
3874
            $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
3875
            if ($my_post_notification == 1) {
3876
                set_notification('thread', $values['thread_id'], true);
3877
            }
3878
3879
            send_notification_mails(
3880
                $values['forum_id'],
3881
                $values['thread_id'],
3882
                $values
3883
            );
3884
            add_forum_attachment_file('', $new_post_id);
3885
3886
            $logInfo = [
3887
                'tool' => TOOL_FORUM,
3888
                'tool_id' => $values['forum_id'],
3889
                'tool_id_detail' => $values['thread_id'],
3890
                'action' => 'new-post',
3891
                'action_details' => $values['action'],
3892
                'info' => $values['post_title'],
3893
            ];
3894
            Event::registerLog($logInfo);
3895
        }
3896
3897
        Session::erase('formelements');
3898
        Session::erase('origin');
3899
        Session::erase('breadcrumbs');
3900
        Session::erase('addedresource');
3901
        Session::erase('addedresourceid');
3902
3903
        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...
3904
    } else {
3905
        Display::addFlash(
3906
            Display::return_message(
3907
                get_lang('UplNoFileUploaded').' '.get_lang('UplSelectFileFirst'),
3908
                'error'
3909
            )
3910
        );
3911
    }
3912
3913
    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...
3914
}
3915
3916
/**
3917
 * This function displays the form that is used to edit a post. This can be a new thread or a reply.
3918
 *
3919
 * @param array contains all the information about the current post
3920
 * @param array contains all the information about the current thread
3921
 * @param array contains all info about the current forum (to check if attachments are allowed)
3922
 * @param array contains the default values to fill the form
3923
 *
3924
 * @author Patrick Cool <[email protected]>, Ghent University
3925
 *
3926
 * @version february 2006, dokeos 1.8
3927
 */
3928
function show_edit_post_form(
3929
    $current_post,
3930
    $current_thread,
3931
    $current_forum,
3932
    $form_values = '',
3933
    $id_attach = 0
3934
) {
3935
    // Initialize the object.
3936
    $form = new FormValidator(
3937
        'edit_post',
3938
        'post',
3939
        api_get_self().'?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&post='.intval($_GET['post'])
3940
    );
3941
    $form->addElement('header', get_lang('EditPost'));
3942
    // Setting the form elements.
3943
    $form->addElement('hidden', 'post_id', $current_post['post_id']);
3944
    $form->addElement('hidden', 'thread_id', $current_thread['thread_id']);
3945
    $form->addElement('hidden', 'id_attach', $id_attach);
3946
3947
    if (empty($current_post['post_parent_id'])) {
3948
        $form->addElement('hidden', 'is_first_post_of_thread', '1');
3949
    }
3950
3951
    $form->addElement('text', 'post_title', get_lang('Title'));
3952
    $form->applyFilter('post_title', 'html_filter');
3953
    $form->addElement(
3954
        'html_editor',
3955
        'post_text',
3956
        get_lang('Text'),
3957
        null,
3958
        api_is_allowed_to_edit(null, true) ? [
3959
            'ToolbarSet' => 'Forum',
3960
            'Width' => '100%',
3961
            'Height' => '400',
3962
        ] : [
3963
            'ToolbarSet' => 'ForumStudent',
3964
            'Width' => '100%',
3965
            'Height' => '400',
3966
            'UserStatus' => 'student',
3967
        ]
3968
    );
3969
    $form->addRule('post_text', get_lang('ThisFieldIsRequired'), 'required');
3970
3971
    $extraFields = new ExtraField('forum_post');
3972
    $extraFields->addElements($form, $current_post['post_id']);
3973
3974
    $form->addButtonAdvancedSettings('advanced_params');
3975
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3976
3977
    if ($current_forum['moderated'] && api_is_allowed_to_edit(null, true)) {
3978
        $group = [];
3979
        $group[] = $form->createElement(
3980
            'radio',
3981
            'status',
3982
            null,
3983
            get_lang('Validated'),
3984
            1
3985
        );
3986
        $group[] = $form->createElement(
3987
            'radio',
3988
            'status',
3989
            null,
3990
            get_lang('WaitingModeration'),
3991
            2
3992
        );
3993
        $group[] = $form->createElement(
3994
            'radio',
3995
            'status',
3996
            null,
3997
            get_lang('Rejected'),
3998
            3
3999
        );
4000
        $form->addGroup($group, 'status', get_lang('Status'));
4001
    }
4002
4003
    $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...
4004
    $form->addElement(
4005
        'checkbox',
4006
        'post_notification',
4007
        '',
4008
        get_lang('NotifyByEmail').' ('.$current_post['email'].')'
4009
    );
4010
4011
    if (api_is_allowed_to_edit(null, true) &&
4012
        empty($current_post['post_parent_id'])
4013
    ) {
4014
        // The sticky checkbox only appears when it is the first post of a thread.
4015
        $form->addElement('checkbox', 'thread_sticky', '', get_lang('StickyPost'));
4016
        if ($current_thread['thread_sticky'] == 1) {
4017
            $defaults['thread_sticky'] = true;
4018
        }
4019
    }
4020
4021
    $form->addElement('html', '</div>');
4022
4023
    $form->addFile('user_upload[]', get_lang('Attachment'));
4024
    $form->addButton(
4025
        'add_attachment',
4026
        get_lang('AddAttachment'),
4027
        'paperclip',
4028
        'default',
4029
        'default',
4030
        null,
4031
        ['id' => 'reply-add-attachment']
4032
    );
4033
4034
    $form->addButtonUpdate(get_lang('Modify'), 'SubmitPost');
4035
4036
    // Setting the default values for the form elements.
4037
    $defaults['post_title'] = $current_post['post_title'];
4038
    $defaults['post_text'] = $current_post['post_text'];
4039
4040
    if ($current_post['post_notification'] == 1) {
4041
        $defaults['post_notification'] = true;
4042
    }
4043
4044
    if (!empty($form_values)) {
4045
        $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
4046
        $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
4047
    }
4048
4049
    $form->setDefaults($defaults);
4050
4051
    // The course admin can make a thread sticky (=appears with special icon and always on top).
4052
4053
    $form->addRule('post_title', get_lang('ThisFieldIsRequired'), 'required');
4054
4055
    // Validation or display
4056
    if ($form->validate()) {
4057
        $values = $form->exportValues();
4058
4059
        $values['item_id'] = $current_post['post_id'];
4060
        $extraFieldValues = new ExtraFieldValue('forum_post');
4061
        $extraFieldValues->saveFieldValues($values);
4062
4063
        store_edit_post($current_forum, $values);
4064
    } else {
4065
        // Delete from $_SESSION forum attachment from other posts
4066
        clearAttachedFiles($current_post['post_id']);
4067
        // Get forum attachment ajax table to add it to form
4068
        $fileData = getAttachmentsAjaxTable($current_post['post_id'], $current_forum['forum_id']);
4069
        $form->addElement('html', $fileData);
4070
        $form->display();
4071
    }
4072
}
4073
4074
/**
4075
 * This function stores the edit of a post in the forum_post table.
4076
 *
4077
 * @param array
4078
 *
4079
 * @author Patrick Cool <[email protected]>, Ghent University
4080
 *
4081
 * @version february 2006, dokeos 1.8
4082
 */
4083
function store_edit_post($forumInfo, $values)
4084
{
4085
    $logInfo = [
4086
        'tool' => TOOL_FORUM,
4087
        'tool_id' => $_GET['forum'],
4088
        'tool_id_detail' => $values['thread_id'],
4089
        'action' => 'edit-post',
4090
        'action_details' => 'post',
4091
        'info' => $values['post_title'],
4092
    ];
4093
    Event::registerLog($logInfo);
4094
4095
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
4096
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4097
    $course_id = api_get_course_int_id();
4098
4099
    //check if this post is the first of the thread
4100
    // First we check if the change affects the thread and if so we commit
4101
    // the changes (sticky and post_title=thread_title are relevant).
4102
4103
    $posts = getPosts($forumInfo, $values['thread_id']);
4104
    $first_post = null;
4105
    if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
4106
        $first_post = $posts[0];
4107
    }
4108
4109
    if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
4110
        // Simple edit
4111
        $params = [
4112
            'thread_title' => $values['post_title'],
4113
            'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
4114
        ];
4115
        $where = ['c_id = ? AND thread_id = ?' => [$course_id, $values['thread_id']]];
4116
        Database::update($threadTable, $params, $where);
4117
    }
4118
4119
    $status = '';
4120
    $updateStatus = false;
4121
    if ($forumInfo['moderated']) {
4122
        if (api_is_allowed_to_edit(null, true)) {
4123
            $status = $values['status']['status'];
4124
            $updateStatus = true;
4125
        } else {
4126
            $status = CForumPost::STATUS_WAITING_MODERATION;
4127
            $updateStatus = true;
4128
        }
4129
    }
4130
4131
    // Update the post_title and the post_text.
4132
    $params = [
4133
        'post_title' => $values['post_title'],
4134
        'post_text' => $values['post_text'],
4135
        'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : '',
4136
    ];
4137
4138
    if ($updateStatus) {
4139
        $params['status'] = $status;
4140
    }
4141
4142
    $where = ['c_id = ? AND post_id = ?' => [$course_id, $values['post_id']]];
4143
    Database::update($table_posts, $params, $where);
4144
4145
    // Update attached files
4146
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
4147
        foreach ($_POST['file_ids'] as $key => $id) {
4148
            editAttachedFile(
4149
                [
4150
                    'comment' => $_POST['file_comments'][$key],
4151
                    'post_id' => $values['post_id'],
4152
                ],
4153
                $id
4154
            );
4155
        }
4156
    }
4157
4158
    if (!empty($values['remove_attach'])) {
4159
        delete_attachment($values['post_id']);
4160
    }
4161
4162
    if (empty($values['id_attach'])) {
4163
        add_forum_attachment_file(
4164
            isset($values['file_comment']) ? $values['file_comment'] : null,
4165
            $values['post_id']
4166
        );
4167
    } else {
4168
        edit_forum_attachment_file(
4169
            isset($values['file_comment']) ? $values['file_comment'] : null,
4170
            $values['post_id'],
4171
            $values['id_attach']
4172
        );
4173
    }
4174
4175
    $message = get_lang('EditPostStored').'<br />';
4176
    $message .= get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&">'.get_lang('Forum').'</a><br />';
4177
    $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>';
4178
4179
    Session::erase('formelements');
4180
    Session::erase('origin');
4181
    Session::erase('breadcrumbs');
4182
    Session::erase('addedresource');
4183
    Session::erase('addedresourceid');
4184
4185
    echo Display::return_message($message, 'confirmation', false);
4186
}
4187
4188
/**
4189
 * This function displays the firstname and lastname of the user as a link to the user tool.
4190
 *
4191
 * @param string names
4192
 * @ in_title : title tootip
4193
 *
4194
 * @return string HTML
4195
 *
4196
 * @author Patrick Cool <[email protected]>, Ghent University
4197
 *
4198
 * @version february 2006, dokeos 1.8
4199
 */
4200
function display_user_link($user_id, $name, $origin = '', $in_title = '')
4201
{
4202
    if ($user_id != 0) {
4203
        $userInfo = api_get_user_info($user_id);
4204
4205
        return '<a href="'.$userInfo['profile_url'].'">'.Security::remove_XSS($userInfo['complete_name']).'</a>';
4206
    } else {
4207
        return $name.' ('.get_lang('Anonymous').')';
4208
    }
4209
}
4210
4211
/**
4212
 * This function displays the user image from the profile, with a link to the user's details.
4213
 *
4214
 * @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...
4215
 * @param   string  User's name
4216
 * @param   string  the origin where the forum is called (example : learnpath)
4217
 *
4218
 * @return string An HTML with the anchor and the image of the user
4219
 *
4220
 * @author Julio Montoya <[email protected]>
4221
 */
4222
function display_user_image($user_id, $name, $origin = '')
4223
{
4224
    $userInfo = api_get_user_info($user_id);
4225
    $link = '<a href="'.(!empty($origin) ? '#' : $userInfo['profile_url']).'" '.(!empty($origin) ? 'target="_self"' : '').'>';
4226
4227
    if ($user_id != 0) {
4228
        return $link.'<img src="'.$userInfo['avatar'].'"  alt="'.$name.'"  title="'.$name.'" /></a>';
4229
    } else {
4230
        return $link.Display::return_icon('unknown.jpg', $name).'</a>';
4231
    }
4232
}
4233
4234
/**
4235
 * The thread view counter gets increased every time someone looks at the thread.
4236
 *
4237
 * @param int
4238
 *
4239
 * @author Patrick Cool <[email protected]>, Ghent University
4240
 *
4241
 * @version february 2006, dokeos 1.8
4242
 */
4243
function increase_thread_view($thread_id)
4244
{
4245
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4246
    $course_id = api_get_course_int_id();
4247
4248
    $sql = "UPDATE $table_threads 
4249
            SET thread_views = thread_views + 1
4250
            WHERE 
4251
                c_id = $course_id AND  
4252
                thread_id = '".intval($thread_id)."'";
4253
    Database::query($sql);
4254
}
4255
4256
/**
4257
 * The relies counter gets increased every time somebody replies to the thread.
4258
 *
4259
 * @author Patrick Cool <[email protected]>, Ghent University
4260
 *
4261
 * @version february 2006, dokeos 1.8
4262
 *
4263
 * @param int    $threadId
4264
 * @param string $lastPostId
4265
 * @param string $post_date
4266
 */
4267
function updateThreadInfo($threadId, $lastPostId, $post_date)
4268
{
4269
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4270
    $course_id = api_get_course_int_id();
4271
    $sql = "UPDATE $table_threads SET 
4272
            thread_replies = thread_replies+1,
4273
            thread_last_post = '".Database::escape_string($lastPostId)."',
4274
            thread_date = '".Database::escape_string($post_date)."'
4275
            WHERE 
4276
                c_id = $course_id AND  
4277
                thread_id='".Database::escape_string($threadId)."'"; // this needs to be cleaned first
4278
    Database::query($sql);
4279
}
4280
4281
/**
4282
 * This function is used to find all the information about what's new in the forum tool.
4283
 *
4284
 * @author Patrick Cool <[email protected]>, Ghent University
4285
 *
4286
 * @version february 2006, dokeos 1.8
4287
 */
4288
function get_whats_new()
4289
{
4290
    $userId = api_get_user_id();
4291
    $course_id = api_get_course_int_id();
4292
4293
    if (empty($course_id) || empty($userId)) {
4294
        return false;
4295
    }
4296
4297
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4298
    $tracking_last_tool_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4299
4300
    $tool = TOOL_FORUM;
4301
    $lastForumAccess = Session::read('last_forum_access');
4302
4303
    if (!$lastForumAccess) {
4304
        $sql = "SELECT * FROM $tracking_last_tool_access
4305
                WHERE
4306
                    access_user_id = $userId AND
4307
                    c_id = $course_id AND
4308
                    access_tool = '".Database::escape_string($tool)."'";
4309
        $result = Database::query($sql);
4310
        $row = Database::fetch_array($result);
4311
        Session::write('last_forum_access', $row['access_date']);
4312
        $lastForumAccess = $row['access_date'];
4313
    }
4314
4315
    $whatsNew = Session::read('whatsnew_post_info');
4316
4317
    if (!$whatsNew) {
4318
        if ($lastForumAccess != '') {
4319
            $postInfo = [];
4320
            $sql = "SELECT * FROM $table_posts
4321
                    WHERE
4322
                        c_id = $course_id AND
4323
                        visible = 1 AND                        
4324
                        post_date > '".Database::escape_string($lastForumAccess)."'";
4325
            $result = Database::query($sql);
4326
            while ($row = Database::fetch_array($result)) {
4327
                $postInfo[$row['forum_id']][$row['thread_id']][$row['post_id']] = $row['post_date'];
4328
            }
4329
            Session::write('whatsnew_post_info', $postInfo);
4330
        }
4331
    }
4332
}
4333
4334
/**
4335
 * This function approves a post = change.
4336
 *
4337
 * @param int    $post_id the id of the post that will be deleted
4338
 * @param string $action  make the post visible or invisible
4339
 *
4340
 * @return string language variable
4341
 *
4342
 * @author Patrick Cool <[email protected]>, Ghent University
4343
 *
4344
 * @version february 2006, dokeos 1.8
4345
 */
4346
function approve_post($post_id, $action)
4347
{
4348
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4349
    $course_id = api_get_course_int_id();
4350
4351
    if ($action == 'invisible') {
4352
        $visibility_value = 0;
4353
    }
4354
4355
    if ($action == 'visible') {
4356
        $visibility_value = 1;
4357
        handle_mail_cue('post', $post_id);
4358
    }
4359
4360
    $sql = "UPDATE $table_posts SET
4361
            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...
4362
            WHERE c_id = $course_id AND post_id='".Database::escape_string($post_id)."'";
4363
    $return = Database::query($sql);
4364
4365
    if ($return) {
0 ignored issues
show
introduced by
$return is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
4366
        return 'PostVisibilityChanged';
4367
    }
4368
}
4369
4370
/**
4371
 * This function retrieves all the unapproved messages for a given forum
4372
 * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see this).
4373
 *
4374
 * @param $forum_id the forum where we want to know the unapproved messages of
4375
 *
4376
 * @return array returns
4377
 *
4378
 * @author Patrick Cool <[email protected]>, Ghent University
4379
 *
4380
 * @version february 2006, dokeos 1.8
4381
 */
4382
function get_unaproved_messages($forum_id)
4383
{
4384
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4385
    $course_id = api_get_course_int_id();
4386
4387
    $return_array = [];
4388
    $sql = "SELECT DISTINCT thread_id FROM $table_posts
4389
            WHERE 
4390
                c_id = $course_id AND 
4391
                forum_id='".Database::escape_string($forum_id)."' AND 
4392
                visible='0' ";
4393
    $result = Database::query($sql);
4394
    while ($row = Database::fetch_array($result)) {
4395
        $return_array[] = $row['thread_id'];
4396
    }
4397
4398
    return $return_array;
4399
}
4400
4401
/**
4402
 * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
4403
 * was added to a given thread.
4404
 *
4405
 * @param array reply information
4406
 *
4407
 * @author Patrick Cool <[email protected]>, Ghent University
4408
 *
4409
 * @version february 2006, dokeos 1.8
4410
 */
4411
function send_notification_mails($forumId, $thread_id, $reply_info)
4412
{
4413
    $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4414
4415
    // First we need to check if
4416
    // 1. the forum category is visible
4417
    // 2. the forum is visible
4418
    // 3. the thread is visible
4419
    // 4. the reply is visible (=when there is)
4420
    $current_thread = get_thread_information($forumId, $thread_id);
4421
    $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

4421
    $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...
4422
4423
    $current_forum_category = null;
4424
    if (isset($current_forum['forum_category'])) {
4425
        $current_forum_category = get_forumcategory_information($current_forum['forum_category']);
4426
    }
4427
4428
    $send_mails = false;
4429
    if ($current_thread['visibility'] == '1' &&
4430
        $current_forum['visibility'] == '1' &&
4431
        ($current_forum_category && $current_forum_category['visibility'] == '1') &&
4432
        $current_forum['approval_direct_post'] != '1'
4433
    ) {
4434
        $send_mails = true;
4435
    }
4436
4437
    // The forum category, the forum, the thread and the reply are visible to the user
4438
    if ($send_mails && !empty($forumId)) {
4439
        $postId = isset($reply_info['new_post_id']) ? $reply_info['new_post_id'] : 0;
4440
        send_notifications($forumId, $thread_id, $postId);
4441
    } else {
4442
        $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4443
        if (isset($current_forum['forum_id'])) {
4444
            $sql = "SELECT * FROM $table_notification
4445
                    WHERE
4446
                        c_id = ".api_get_course_int_id()." AND
4447
                        (
4448
                            forum_id = '".intval($current_forum['forum_id'])."' OR
4449
                            thread_id = '".intval($thread_id)."'
4450
                        ) ";
4451
4452
            $result = Database::query($sql);
4453
            $user_id = api_get_user_id();
4454
            while ($row = Database::fetch_array($result)) {
4455
                $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
4456
                        VALUES (".api_get_course_int_id().", '".intval($thread_id)."', '".intval($reply_info['new_post_id'])."', '$user_id' )";
4457
                Database::query($sql);
4458
            }
4459
        }
4460
    }
4461
}
4462
4463
/**
4464
 * This function is called whenever something is made visible because there might
4465
 * be new posts and the user might have indicated that (s)he wanted to be
4466
 * informed about the new posts by mail.
4467
 *
4468
 * @param string $content Content type (post, thread, forum, forum_category)
4469
 * @param int    $id      Item DB ID of the corresponding content type
4470
 *
4471
 * @return string language variable
4472
 *
4473
 * @author Patrick Cool <[email protected]>, Ghent University
4474
 *
4475
 * @version february 2006, dokeos 1.8
4476
 */
4477
function handle_mail_cue($content, $id)
4478
{
4479
    $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4480
    $table_forums = Database::get_course_table(TABLE_FORUM);
4481
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4482
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4483
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4484
4485
    $course_id = api_get_course_int_id();
4486
    $id = (int) $id;
4487
4488
    /* If the post is made visible we only have to send mails to the people
4489
     who indicated that they wanted to be informed for that thread.*/
4490
    if ($content == 'post') {
4491
        // Getting the information about the post (need the thread_id).
4492
        $post_info = get_post_information($id);
4493
        $thread_id = (int) $post_info['thread_id'];
4494
4495
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4496
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email
4497
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4498
                WHERE
4499
                    posts.c_id = $course_id AND
4500
                    mailcue.c_id = $course_id AND
4501
                    posts.thread_id = $thread_id AND
4502
                    posts.post_notification = '1' AND
4503
                    mailcue.thread_id = $thread_id AND
4504
                    users.user_id = posts.poster_id AND
4505
                    users.active = 1
4506
                GROUP BY users.email";
4507
4508
        $result = Database::query($sql);
4509
        while ($row = Database::fetch_array($result)) {
4510
            $forumInfo = get_forum_information($post_info['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

4510
            $forumInfo = /** @scrutinizer ignore-deprecated */ get_forum_information($post_info['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...
4511
            send_mail($row, $forumInfo, get_thread_information($post_info['forum_id'], $post_info['thread_id']), $post_info);
4512
        }
4513
    } elseif ($content == 'thread') {
4514
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4515
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
4516
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4517
                WHERE
4518
                    posts.c_id = $course_id AND
4519
                    mailcue.c_id = $course_id AND
4520
                    posts.thread_id = $id AND
4521
                    posts.post_notification = '1' AND
4522
                    mailcue.thread_id = $id AND
4523
                    users.user_id = posts.poster_id AND
4524
                    users.active = 1
4525
                GROUP BY users.email";
4526
        $result = Database::query($sql);
4527
        while ($row = Database::fetch_array($result)) {
4528
            $forumInfo = get_forum_information($row['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

4528
            $forumInfo = /** @scrutinizer ignore-deprecated */ get_forum_information($row['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...
4529
            send_mail($row, $forumInfo, get_thread_information($row['forum_id'], $id));
4530
        }
4531
4532
        // Deleting the relevant entries from the mailcue.
4533
        $sql = "DELETE FROM $table_mailcue
4534
                WHERE c_id = $course_id AND thread_id = $id";
4535
        Database::query($sql);
4536
    } elseif ($content == 'forum') {
4537
        $sql = "SELECT thread_id FROM $table_threads
4538
                WHERE c_id = $course_id AND forum_id = $id";
4539
        $result = Database::query($sql);
4540
        while ($row = Database::fetch_array($result)) {
4541
            handle_mail_cue('thread', $row['thread_id']);
4542
        }
4543
    } elseif ($content == 'forum_category') {
4544
        $sql = "SELECT forum_id FROM $table_forums
4545
                WHERE c_id = $course_id AND forum_category = $id";
4546
        $result = Database::query($sql);
4547
        while ($row = Database::fetch_array($result)) {
4548
            handle_mail_cue('forum', $row['forum_id']);
4549
        }
4550
    } else {
4551
        return get_lang('Error');
4552
    }
4553
}
4554
4555
/**
4556
 * This function sends the mails for the mail notification.
4557
 *
4558
 * @param array
4559
 * @param array
4560
 * @param array
4561
 * @param array
4562
 *
4563
 * @author Patrick Cool <[email protected]>, Ghent University
4564
 *
4565
 * @version february 2006, dokeos 1.8
4566
 */
4567
function send_mail($userInfo, $forumInfo, $thread_information, $postInfo = [])
4568
{
4569
    if (empty($userInfo) || empty($forumInfo) || empty($thread_information)) {
4570
        return false;
4571
    }
4572
4573
    $_course = api_get_course_info();
4574
    $user_id = api_get_user_id();
4575
4576
    $thread_link = '';
4577
    if (isset($thread_information) && is_array($thread_information)) {
4578
        $thread_link = api_get_path(WEB_CODE_PATH).
4579
            'forum/viewthread.php?'.api_get_cidreq().'&forum='.$thread_information['forum_id'].'&thread='.$thread_information['thread_id'];
4580
    }
4581
    $email_body = get_lang('Dear').' '.api_get_person_name($userInfo['firstname'], $userInfo['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
4582
    $email_body .= get_lang('NewForumPost').': '.$forumInfo['forum_title'].' - '.$thread_information['thread_title']." <br />\n";
4583
4584
    $courseId = api_get_configuration_value('global_forums_course_id');
4585
    $subject = get_lang('NewForumPost').' - '.$_course['official_code'].': '.$forumInfo['forum_title'].' - '.$thread_information['thread_title']." <br />\n";
4586
4587
    $courseInfoTitle = get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
4588
    if (!empty($courseId) && $_course['real_id'] == $courseId) {
4589
        $subject = get_lang('NewForumPost').': '.$forumInfo['forum_title'].' - '.$thread_information['thread_title']." <br />\n";
4590
        $courseInfoTitle = " <br />\n";
4591
    }
4592
    $email_body .= $courseInfoTitle;
4593
4594
    if (!empty($postInfo) && isset($postInfo['post_text'])) {
4595
        $text = cut(strip_tags($postInfo['post_text']), 100);
4596
        if (!empty($text)) {
4597
            $email_body .= get_lang('Message').": <br />\n ";
4598
            $email_body .= $text;
4599
            $email_body .= "<br /><br />\n";
4600
        }
4601
    }
4602
4603
    $email_body .= get_lang('YouWantedToStayInformed')."<br />\n";
4604
4605
    if (!empty($thread_link)) {
4606
        $email_body .= get_lang('ThreadCanBeFoundHere')." : <br /><a href=\"".$thread_link."\">".$thread_link."</a>\n";
4607
    }
4608
4609
    if ($userInfo['user_id'] != $user_id) {
4610
        MessageManager::send_message(
4611
            $userInfo['user_id'],
4612
            $subject,
4613
            $email_body,
4614
            [],
4615
            [],
4616
            null,
4617
            null,
4618
            null,
4619
            null,
4620
            $user_id
4621
        );
4622
    }
4623
}
4624
4625
/**
4626
 * This function displays the form for moving a thread to a different (already existing) forum.
4627
 *
4628
 * @author Patrick Cool <[email protected]>, Ghent University
4629
 *
4630
 * @version february 2006, dokeos 1.8
4631
 */
4632
function move_thread_form()
4633
{
4634
    $form = new FormValidator(
4635
        'movepost',
4636
        'post',
4637
        api_get_self().'?forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
4638
    );
4639
    // The header for the form
4640
    $form->addElement('header', get_lang('MoveThread'));
4641
    // Invisible form: the thread_id
4642
    $form->addElement('hidden', 'thread_id', intval($_GET['thread']));
4643
    // the fora
4644
    $forum_categories = get_forum_categories();
4645
    $forums = get_forums();
4646
4647
    $htmlcontent = '<div class="row">
4648
        <div class="label">
4649
            <span class="form_required">*</span>'.get_lang('MoveTo').'
4650
        </div>
4651
        <div class="formw">';
4652
    $htmlcontent .= '<select name="forum">';
4653
    foreach ($forum_categories as $key => $category) {
4654
        $htmlcontent .= '<optgroup label="'.$category['cat_title'].'">';
4655
        foreach ($forums as $key => $forum) {
0 ignored issues
show
Comprehensibility Bug introduced by
$key is overwriting a variable from outer foreach loop.
Loading history...
4656
            if (isset($forum['forum_category'])) {
4657
                if ($forum['forum_category'] == $category['cat_id']) {
4658
                    $htmlcontent .= '<option value="'.$forum['forum_id'].'">'.$forum['forum_title'].'</option>';
4659
                }
4660
            }
4661
        }
4662
        $htmlcontent .= '</optgroup>';
4663
    }
4664
    $htmlcontent .= "</select>";
4665
    $htmlcontent .= '   </div>
4666
                    </div>';
4667
4668
    $form->addElement('html', $htmlcontent);
4669
4670
    // The OK button
4671
    $form->addButtonSave(get_lang('MoveThread'), 'SubmitForum');
4672
4673
    // Validation or display
4674
    if ($form->validate()) {
4675
        $values = $form->exportValues();
4676
        if (isset($_POST['forum'])) {
4677
            store_move_thread($values);
4678
        }
4679
    } else {
4680
        $form->display();
4681
    }
4682
}
4683
4684
/**
4685
 * This function displays the form for moving a post message to a different (already existing) or a new thread.
4686
 *
4687
 * @author Patrick Cool <[email protected]>, Ghent University
4688
 *
4689
 * @version february 2006, dokeos 1.8
4690
 */
4691
function move_post_form()
4692
{
4693
    $form = new FormValidator(
4694
        'movepost',
4695
        'post',
4696
        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'])
4697
    );
4698
    // The header for the form
4699
    $form->addElement('header', '', get_lang('MovePost'));
4700
4701
    // Invisible form: the post_id
4702
    $form->addElement('hidden', 'post_id', intval($_GET['post']));
4703
4704
    // Dropdown list: Threads of this forum
4705
    $threads = get_threads($_GET['forum']);
4706
    //my_print_r($threads);
4707
    $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...
4708
    foreach ($threads as $key => $value) {
4709
        $threads_list[$value['thread_id']] = $value['thread_title'];
4710
    }
4711
    $form->addElement('select', 'thread', get_lang('MoveToThread'), $threads_list);
4712
    $form->applyFilter('thread', 'html_filter');
4713
4714
    // The OK button
4715
    $form->addButtonSave(get_lang('MovePost'), 'submit');
4716
4717
    // Setting the rules
4718
    $form->addRule('thread', get_lang('ThisFieldIsRequired'), 'required');
4719
4720
    // Validation or display
4721
    if ($form->validate()) {
4722
        $values = $form->exportValues();
4723
        store_move_post($values);
4724
    } else {
4725
        $form->display();
4726
    }
4727
}
4728
4729
/**
4730
 * @param array
4731
 *
4732
 * @return string HTML language variable
4733
 *
4734
 * @author Patrick Cool <[email protected]>, Ghent University
4735
 *
4736
 * @version february 2006, dokeos 1.8
4737
 */
4738
function store_move_post($values)
4739
{
4740
    $_course = api_get_course_info();
4741
    $course_id = api_get_course_int_id();
4742
4743
    $table_forums = Database::get_course_table(TABLE_FORUM);
4744
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4745
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4746
4747
    if ($values['thread'] == '0') {
4748
        $current_post = get_post_information($values['post_id']);
4749
4750
        // Storing a new thread.
4751
        $params = [
4752
            'c_id' => $course_id,
4753
            'thread_title' => $current_post['post_title'],
4754
            'forum_id' => $current_post['forum_id'],
4755
            'thread_poster_id' => $current_post['poster_id'],
4756
            'thread_poster_name' => $current_post['poster_name'],
4757
            'thread_last_post' => $values['post_id'],
4758
            'thread_date' => $current_post['post_date'],
4759
        ];
4760
4761
        $new_thread_id = Database::insert($table_threads, $params);
4762
4763
        api_item_property_update(
4764
            $_course,
4765
            TOOL_FORUM_THREAD,
4766
            $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

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

5251
            /** @scrutinizer ignore-type */ $last_id_file,
Loading history...
5252
            'ForumAttachmentAdded',
5253
            api_get_user_id()
5254
        );
5255
    }
5256
}
5257
5258
/**
5259
 * This function edits an attachment file into a forum.
5260
 *
5261
 * @param string $file_comment a comment about file
5262
 * @param int    $post_id
5263
 * @param int    $id_attach    attachment file Id
5264
 */
5265
function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
5266
{
5267
    $_course = api_get_course_info();
5268
    $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5269
    $course_id = api_get_course_int_id();
5270
5271
    $filesData = [];
5272
5273
    if (!is_array($_FILES['user_upload']['name'])) {
5274
        $filesData[] = $_FILES['user_upload'];
5275
    } else {
5276
        $fileCount = count($_FILES['user_upload']['name']);
5277
        $fileKeys = array_keys($_FILES['user_upload']);
5278
5279
        for ($i = 0; $i < $fileCount; $i++) {
5280
            foreach ($fileKeys as $key) {
5281
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
5282
            }
5283
        }
5284
    }
5285
5286
    foreach ($filesData as $attachment) {
5287
        if (empty($attachment['name'])) {
5288
            continue;
5289
        }
5290
5291
        $upload_ok = process_uploaded_file($attachment);
5292
5293
        if (!$upload_ok) {
5294
            continue;
5295
        }
5296
5297
        $course_dir = $_course['path'].'/upload/forum';
5298
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
5299
        $updir = $sys_course_path.$course_dir;
5300
5301
        // Try to add an extension to the file if it hasn't one.
5302
        $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
5303
        // User's file name
5304
        $file_name = $attachment['name'];
5305
5306
        if (!filter_extension($new_file_name)) {
5307
            Display::addFlash(
5308
                Display::return_message(
5309
                    get_lang('UplUnableToSaveFileFilteredExtension'),
5310
                    'error'
5311
                )
5312
            );
5313
        } else {
5314
            $new_file_name = uniqid('');
5315
            $new_path = $updir.'/'.$new_file_name;
5316
            $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5317
            $safe_file_comment = Database::escape_string($file_comment);
5318
            $safe_file_name = Database::escape_string($file_name);
5319
            $safe_new_file_name = Database::escape_string($new_file_name);
5320
            $safe_post_id = (int) $post_id;
5321
            $safe_id_attach = (int) $id_attach;
5322
            // Storing the attachments if any.
5323
            if ($result) {
5324
                $sql = "UPDATE $table_forum_attachment 
5325
                        SET 
5326
                            filename = '$safe_file_name', 
5327
                            comment = '$safe_file_comment', 
5328
                            path = '$safe_new_file_name', 
5329
                            post_id = '$safe_post_id', 
5330
                            size ='".$attachment['size']."'
5331
                        WHERE c_id = $course_id AND id = '$safe_id_attach'";
5332
                Database::query($sql);
5333
                api_item_property_update(
5334
                    $_course,
5335
                    TOOL_FORUM_ATTACH,
5336
                    $safe_id_attach,
5337
                    'ForumAttachmentUpdated',
5338
                    api_get_user_id()
5339
                );
5340
            }
5341
        }
5342
    }
5343
}
5344
5345
/**
5346
 * Show a list with all the attachments according to the post's id.
5347
 *
5348
 * @param int $postId
5349
 *
5350
 * @return array with the post info
5351
 *
5352
 * @author Julio Montoya
5353
 *
5354
 * @version avril 2008, dokeos 1.8.5
5355
 */
5356
function get_attachment($postId)
5357
{
5358
    $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5359
    $course_id = api_get_course_int_id();
5360
    $row = [];
5361
    $postId = (int) $postId;
5362
5363
    if (empty($postId)) {
5364
        return [];
5365
    }
5366
5367
    $sql = "SELECT iid, path, filename, comment 
5368
            FROM $table
5369
            WHERE c_id = $course_id AND post_id = $postId";
5370
    $result = Database::query($sql);
5371
    if (Database::num_rows($result) != 0) {
5372
        $row = Database::fetch_array($result);
5373
    }
5374
5375
    return $row;
5376
}
5377
5378
/**
5379
 * @param int $postId
5380
 *
5381
 * @return array
5382
 */
5383
function getAllAttachment($postId)
5384
{
5385
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5386
    $courseId = api_get_course_int_id();
5387
    $postId = (int) $postId;
5388
5389
    if (empty($postId)) {
5390
        return [];
5391
    }
5392
5393
    $columns = ['iid', 'path', 'filename', 'comment'];
5394
    $conditions = [
5395
        'where' => [
5396
            'c_id = ? AND post_id = ?' => [$courseId, $postId],
5397
        ],
5398
    ];
5399
    $array = Database::select(
5400
        $columns,
5401
        $forumAttachmentTable,
5402
        $conditions,
5403
        'all',
5404
        'ASSOC'
5405
    );
5406
5407
    return $array;
5408
}
5409
5410
/**
5411
 * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
5412
 *
5413
 * @param int $post_id
5414
 * @param int $id_attach
5415
 *
5416
 * @return int
5417
 *
5418
 * @author Julio Montoya
5419
 *
5420
 * @version october 2014, chamilo 1.9.8
5421
 */
5422
function delete_attachment($post_id, $id_attach = 0)
5423
{
5424
    $_course = api_get_course_info();
5425
5426
    $forum_table_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5427
    $course_id = api_get_course_int_id();
5428
5429
    $cond = (!empty($id_attach)) ? " iid = ".(int) $id_attach."" : " post_id = ".(int) $post_id."";
5430
    $sql = "SELECT path FROM $forum_table_attachment WHERE c_id = $course_id AND $cond";
5431
    $res = Database::query($sql);
5432
    $row = Database::fetch_array($res);
5433
5434
    $course_dir = $_course['path'].'/upload/forum';
5435
    $sys_course_path = api_get_path(SYS_COURSE_PATH);
5436
    $updir = $sys_course_path.$course_dir;
5437
    $my_path = isset($row['path']) ? $row['path'] : null;
5438
    $file = $updir.'/'.$my_path;
5439
    if (Security::check_abs_path($file, $updir)) {
5440
        @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

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

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