Passed
Push — master ( d9f8b0...e02700 )
by Julito
09:47
created

getForumCreatedByUser()   B

Complexity

Conditions 7
Paths 3

Size

Total Lines 34
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 22
c 0
b 0
f 0
nc 3
nop 3
dl 0
loc 34
rs 8.6346
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-fluid']
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
    $form->setDefaults($defaults);
458
    // Validation or display
459
    if ($form->validate()) {
460
        $check = Security::check_token('post');
461
        if ($check) {
462
            $values = $form->getSubmitValues();
463
            $forumId = store_forum($values, '', true);
464
            if ($forumId) {
465
                // Skill::saveSkills($form, ITEM_TYPE_FORUM, $forumId);
466
                if (isset($values['forum_id'])) {
467
                    Display::addFlash(Display::return_message(get_lang('ForumEdited'), 'confirmation'));
468
                } else {
469
                    Display::addFlash(Display::return_message(get_lang('ForumAdded'), 'confirmation'));
470
                }
471
            }
472
        }
473
        Security::clear_token();
474
    } else {
475
        $token = Security::get_token();
476
        $form->addElement('hidden', 'sec_token');
477
        $form->setConstants(['sec_token' => $token]);
478
479
        return $form->returnForm();
480
    }
481
}
482
483
/**
484
 * This function deletes the forum image if exists.
485
 *
486
 * @param int forum id
487
 *
488
 * @return bool true if success
489
 *
490
 * @author Julio Montoya <[email protected]>
491
 *
492
 * @version february 2006, dokeos 1.8
493
 */
494
function delete_forum_image($forum_id)
495
{
496
    $table_forums = Database::get_course_table(TABLE_FORUM);
497
    $course_id = api_get_course_int_id();
498
    $forum_id = intval($forum_id);
499
500
    $sql = "SELECT forum_image FROM $table_forums
501
            WHERE forum_id = $forum_id AND c_id = $course_id";
502
    $result = Database::query($sql);
503
    $row = Database::fetch_array($result);
504
    if ($row['forum_image'] != '') {
505
        $file = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/forum/images/'.$row['forum_image'];
506
        if (file_exists($file)) {
507
            unlink($file);
508
        }
509
510
        return true;
511
    } else {
512
        return false;
513
    }
514
}
515
516
/**
517
 * This function displays the form that is used to edit a forum category.
518
 *
519
 * @param array
520
 *
521
 * @return string
522
 *
523
 * @author Patrick Cool <[email protected]>, Ghent University
524
 *
525
 * @version february 2006, dokeos 1.8
526
 */
527
function show_edit_forumcategory_form($inputvalues = [])
528
{
529
    $categoryId = $inputvalues['cat_id'];
530
    $form = new FormValidator('forumcategory', 'post', 'index.php?'.api_get_cidreq().'&id='.$categoryId);
531
532
    // Setting the form elements.
533
    $form->addElement('header', '', get_lang('EditForumCategory'));
534
    $form->addElement('hidden', 'forum_category_id');
535
    $form->addElement('text', 'forum_category_title', get_lang('Title'));
536
537
    $form->addElement(
538
        'html_editor',
539
        'forum_category_comment',
540
        get_lang('Comment'),
541
        null,
542
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
543
    );
544
545
    $extraField = new ExtraField('forum_category');
546
    $returnParams = $extraField->addElements(
547
        $form,
548
        $categoryId,
549
        [], //exclude
550
        false, // filter
551
        false, // tag as select
552
        [], //show only fields
553
        [], // order fields
554
        [] // extra data
555
    );
556
557
    $form->addButtonUpdate(get_lang('ModifyCategory'), 'SubmitEditForumCategory');
558
559
    // Setting the default values.
560
    $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...
561
    $defaultvalues['forum_category_title'] = $inputvalues['cat_title'];
562
    $defaultvalues['forum_category_comment'] = $inputvalues['cat_comment'];
563
    $form->setDefaults($defaultvalues);
564
565
    // Setting the rules.
566
    $form->addRule('forum_category_title', get_lang('ThisFieldIsRequired'), 'required');
567
568
    // Validation or display
569
    if ($form->validate()) {
570
        $check = Security::check_token('post');
571
        if ($check) {
572
            $values = $form->exportValues();
573
            store_forumcategory($values);
574
        }
575
        Security::clear_token();
576
    } else {
577
        $token = Security::get_token();
578
        $form->addElement('hidden', 'sec_token');
579
        $form->setConstants(['sec_token' => $token]);
580
581
        return $form->returnForm();
582
    }
583
}
584
585
/**
586
 * This function stores the forum category in the database.
587
 * The new category is added to the end.
588
 *
589
 * @param array $values
590
 * @param array $courseInfo
591
 * @param bool  $showMessage
592
 *
593
 * @author Patrick Cool <[email protected]>, Ghent University
594
 *
595
 * @version february 2006, dokeos 1.8
596
 */
597
function store_forumcategory($values, $courseInfo = [], $showMessage = true)
598
{
599
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
600
    $course_id = $courseInfo['real_id'];
601
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
602
603
    // Find the max cat_order. The new forum category is added at the end => max cat_order + &
604
    $sql = "SELECT MAX(cat_order) as sort_max
605
            FROM $table_categories
606
            WHERE c_id = $course_id";
607
    $result = Database::query($sql);
608
    $row = Database::fetch_array($result);
609
    $new_max = $row['sort_max'] + 1;
610
    $session_id = api_get_session_id();
611
    $clean_cat_title = $values['forum_category_title'];
612
    $last_id = null;
613
614
    if (isset($values['forum_category_id'])) {
615
        // Storing after edition.
616
        $params = [
617
            'cat_title' => $clean_cat_title,
618
            'cat_comment' => isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '',
619
        ];
620
621
        Database::update(
622
            $table_categories,
623
            $params,
624
            [
625
                'c_id = ? AND cat_id = ?' => [
626
                    $course_id,
627
                    $values['forum_category_id'],
628
                ],
629
            ]
630
        );
631
632
        api_item_property_update(
633
            $courseInfo,
634
            TOOL_FORUM_CATEGORY,
635
            $values['forum_category_id'],
636
            'ForumCategoryUpdated',
637
            api_get_user_id()
638
        );
639
        $return_message = get_lang('ForumCategoryEdited');
640
641
        $logInfo = [
642
            'tool' => TOOL_FORUM,
643
            'tool_id' => 0,
644
            'tool_id_detail' => 0,
645
            'action' => 'update-forumcategory',
646
            'action_details' => 'forumcategory',
647
            'info' => $clean_cat_title,
648
        ];
649
        Event::registerLog($logInfo);
0 ignored issues
show
Bug introduced by
The method registerLog() does not exist on Event. ( Ignorable by Annotation )

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

649
        Event::/** @scrutinizer ignore-call */ 
650
               registerLog($logInfo);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
650
651
        $values['item_id'] = $values['forum_category_id'];
652
    } else {
653
        $params = [
654
            'c_id' => $course_id,
655
            'cat_title' => $clean_cat_title,
656
            'cat_comment' => isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '',
657
            'cat_order' => $new_max,
658
            'session_id' => $session_id,
659
            'locked' => 0,
660
            'cat_id' => 0,
661
        ];
662
        $last_id = Database::insert($table_categories, $params);
663
664
        if ($last_id > 0) {
665
            $sql = "UPDATE $table_categories SET cat_id = $last_id WHERE iid = $last_id";
666
            Database::query($sql);
667
668
            api_item_property_update(
669
                $courseInfo,
670
                TOOL_FORUM_CATEGORY,
671
                $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

671
                /** @scrutinizer ignore-type */ $last_id,
Loading history...
672
                'ForumCategoryAdded',
673
                api_get_user_id()
674
            );
675
            api_set_default_visibility(
676
                $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

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

938
                /** @scrutinizer ignore-type */ $forumId,
Loading history...
939
                'ForumAdded',
940
                api_get_user_id(),
941
                $groupInfo
942
            );
943
944
            api_set_default_visibility(
945
                $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

945
                /** @scrutinizer ignore-type */ $forumId,
Loading history...
946
                TOOL_FORUM,
947
                $group_id,
948
                $courseInfo
949
            );
950
951
            $logInfo = [
952
                'tool' => TOOL_FORUM,
953
                'tool_id' => $forumId,
954
                'tool_id_detail' => 0,
955
                'action' => 'new-forum',
956
                'action_details' => 'forum',
957
                'info' => $values['forum_title'],
958
            ];
959
            Event::registerLog($logInfo);
960
        }
961
        $return_message = get_lang('ForumAdded');
962
    }
963
964
    if ($returnId) {
965
        return $forumId;
966
    }
967
968
    return $return_message;
969
}
970
971
/**
972
 * This function deletes a forum or a forum category
973
 * This function currently does not delete the forums inside the category,
974
 * nor the threads and replies inside these forums.
975
 * For the moment this is the easiest method and it has the advantage that it
976
 * allows to recover fora that were acidently deleted
977
 * when the forum category got deleted.
978
 *
979
 * @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...
980
 * @param $id the id of the forum category that has to be deleted
981
 *
982
 * @todo write the code for the cascading deletion of the forums inside a
983
 * forum category and also the threads and replies inside these forums
984
 * @todo config setting for recovery or not
985
 * (see also the documents tool: real delete or not).
986
 *
987
 * @return string
988
 *
989
 * @author Patrick Cool <[email protected]>, Ghent University
990
 *
991
 * @version february 2006, dokeos 1.8
992
 */
993
function deleteForumCategoryThread($content, $id)
994
{
995
    $_course = api_get_course_info();
996
    $table_forums = Database::get_course_table(TABLE_FORUM);
997
    $table_forums_post = Database::get_course_table(TABLE_FORUM_POST);
998
    $table_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
999
    $course_id = api_get_course_int_id();
1000
    $groupId = api_get_group_id();
1001
    $groupInfo = GroupManager::get_group_properties($groupId);
1002
    $userId = api_get_user_id();
1003
    $id = intval($id);
1004
1005
    // Delete all attachment file about this tread id.
1006
    $sql = "SELECT post_id FROM $table_forums_post
1007
            WHERE c_id = $course_id AND thread_id = '".$id."' ";
1008
    $res = Database::query($sql);
1009
    while ($poster_id = Database::fetch_row($res)) {
1010
        delete_attachment($poster_id[0]);
1011
    }
1012
1013
    $tool_constant = null;
1014
    $return_message = '';
1015
    if ($content == 'forumcategory') {
1016
        $tool_constant = TOOL_FORUM_CATEGORY;
1017
        $return_message = get_lang('ForumCategoryDeleted');
1018
1019
        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...
1020
            $sql = "SELECT forum_id FROM $table_forums
1021
                    WHERE c_id = $course_id AND forum_category='".$id."'";
1022
            $result = Database::query($sql);
1023
            $row = Database::fetch_array($result);
1024
            foreach ($row as $arr_forum) {
1025
                $forum_id = $arr_forum['forum_id'];
1026
                api_item_property_update(
1027
                    $_course,
1028
                    'forum',
1029
                    $forum_id,
1030
                    'delete',
1031
                    api_get_user_id()
1032
                );
1033
            }
1034
        }
1035
    }
1036
1037
    if ($content == 'forum') {
1038
        $tool_constant = TOOL_FORUM;
1039
        $return_message = get_lang('ForumDeleted');
1040
1041
        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...
1042
            $sql = "SELECT thread_id FROM $table_forum_thread 
1043
                    WHERE c_id = $course_id AND forum_id = $id ";
1044
            $result = Database::query($sql);
1045
            $row = Database::fetch_array($result);
1046
            foreach ($row as $arr_forum) {
1047
                $forum_id = $arr_forum['thread_id'];
1048
                api_item_property_update(
1049
                    $_course,
1050
                    'forum_thread',
1051
                    $forum_id,
1052
                    'delete',
1053
                    api_get_user_id()
1054
                );
1055
            }
1056
        }
1057
    }
1058
1059
    if ($content == 'thread') {
1060
        $tool_constant = TOOL_FORUM_THREAD;
1061
        $return_message = get_lang('ThreadDeleted');
1062
        Skill::deleteSkillsFromItem($id, ITEM_TYPE_FORUM_THREAD);
1063
    }
1064
1065
    api_item_property_update(
1066
        $_course,
1067
        $tool_constant,
1068
        $id,
1069
        'delete',
1070
        $userId,
1071
        $groupInfo
1072
    );
1073
1074
    // Check if this returns a true and if so => return $return_message, if not => return false;
1075
    if (!empty($return_message)) {
1076
        Display::addFlash(Display::return_message($return_message, 'confirmation', false));
1077
    }
1078
1079
    return $return_message;
1080
}
1081
1082
/**
1083
 * This function deletes a forum post. This separate function is needed because forum posts do not appear
1084
 * in the item_property table (yet)
1085
 * and because deleting a post also has consequence on the posts that have this post as parent_id
1086
 * (they are also deleted).
1087
 * an alternative would be to store the posts also in item_property and mark this post as deleted (visibility = 2).
1088
 * We also have to decrease the number of replies in the thread table.
1089
 *
1090
 * @param $post_id the id of the post that will be deleted
1091
 *
1092
 * @todo write recursive function that deletes all the posts that have this message as parent
1093
 *
1094
 * @return string language variable
1095
 *
1096
 * @author Patrick Cool <[email protected]>, Ghent University
1097
 * @author Hubert Borderiou Function cleanead and fixed
1098
 *
1099
 * @version february 2006
1100
 */
1101
function delete_post($post_id)
1102
{
1103
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1104
    $post_id = intval($post_id);
1105
    $course_id = api_get_course_int_id();
1106
    $em = Database::getManager();
1107
1108
    $post = $em
1109
        ->getRepository('ChamiloCourseBundle:CForumPost')
1110
        ->findOneBy(['cId' => $course_id, 'postId' => $post_id]);
1111
1112
    if ($post) {
1113
        $em
1114
            ->createQuery('
1115
                UPDATE ChamiloCourseBundle:CForumPost p
1116
                SET p.postParentId = :parent_of_deleted_post
1117
                WHERE
1118
                    p.cId = :course AND
1119
                    p.postParentId = :post AND
1120
                    p.threadId = :thread_of_deleted_post AND
1121
                    p.forumId = :forum_of_deleted_post
1122
            ')
1123
            ->execute([
1124
                'parent_of_deleted_post' => $post->getPostParentId(),
1125
                'course' => $course_id,
1126
                'post' => $post->getPostId(),
1127
                'thread_of_deleted_post' => $post->getThread() ? $post->getThread()->getIid() : 0,
1128
                'forum_of_deleted_post' => $post->getForumId(),
1129
            ]);
1130
1131
        $em->remove($post);
1132
        $em->flush();
1133
1134
        // Delete attachment file about this post id.
1135
        delete_attachment($post_id);
1136
    }
1137
1138
    $last_post_of_thread = check_if_last_post_of_thread($_GET['thread']);
1139
1140
    if (is_array($last_post_of_thread)) {
1141
        // Decreasing the number of replies for this thread and also changing the last post information.
1142
        $sql = "UPDATE $table_threads
1143
                SET
1144
                    thread_replies = thread_replies - 1,
1145
                    thread_last_post = ".intval($last_post_of_thread['post_id']).",
1146
                    thread_date='".Database::escape_string($last_post_of_thread['post_date'])."'
1147
                WHERE c_id = $course_id AND thread_id = ".intval($_GET['thread']);
1148
        Database::query($sql);
1149
1150
        return 'PostDeleted';
1151
    }
1152
    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...
1153
        // We deleted the very single post of the thread so we need to delete the entry in the thread table also.
1154
        $sql = "DELETE FROM $table_threads
1155
                WHERE c_id = $course_id AND thread_id = ".intval($_GET['thread']);
1156
        Database::query($sql);
1157
1158
        return 'PostDeletedSpecial';
1159
    }
1160
}
1161
1162
/**
1163
 * This function gets the all information of the last (=most recent) post of the thread
1164
 * This can be done by sorting the posts that have the field thread_id=$thread_id and sort them by post_date.
1165
 *
1166
 * @param $thread_id the id of the thread we want to know the last post of
1167
 *
1168
 * @return an array or bool if there is a last post found, false if there is
1169
 *            no post entry linked to that thread => thread will be deleted
1170
 *
1171
 * @author Patrick Cool <[email protected]>, Ghent University
1172
 *
1173
 * @version february 2006, dokeos 1.8
1174
 */
1175
function check_if_last_post_of_thread($thread_id)
1176
{
1177
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1178
    $course_id = api_get_course_int_id();
1179
    $sql = "SELECT * FROM $table_posts
1180
            WHERE c_id = $course_id AND thread_id = ".intval($thread_id)."
1181
            ORDER BY post_date DESC";
1182
    $result = Database::query($sql);
1183
    if (Database::num_rows($result) > 0) {
1184
        $row = Database::fetch_array($result);
1185
1186
        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...
1187
    } else {
1188
        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...
1189
    }
1190
}
1191
1192
/**
1193
 * @param string $content                   Type of content forum category, forum, thread, post
1194
 * @param int    $id                        the id of the content we want to make invisible
1195
 * @param int    $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
1196
 * @param array  $additional_url_parameters
1197
 *
1198
 * @return string HTML
1199
 */
1200
function return_visible_invisible_icon(
1201
    $content,
1202
    $id,
1203
    $current_visibility_status,
1204
    $additional_url_parameters = ''
1205
) {
1206
    $html = '';
1207
    $id = (int) $id;
1208
    $current_visibility_status = (int) $current_visibility_status;
1209
1210
    if ($current_visibility_status == 1) {
1211
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1212
        if (is_array($additional_url_parameters)) {
1213
            foreach ($additional_url_parameters as $key => $value) {
1214
                $html .= $key.'='.$value.'&';
1215
            }
1216
        }
1217
        $html .= 'action=invisible&content='.$content.'&id='.$id.'">'.
1218
            Display::return_icon('visible.png', get_lang('MakeInvisible'), [], ICON_SIZE_SMALL).'</a>';
1219
    }
1220
    if ($current_visibility_status == 0) {
1221
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1222
        if (is_array($additional_url_parameters)) {
1223
            foreach ($additional_url_parameters as $key => $value) {
1224
                $html .= $key.'='.$value.'&';
1225
            }
1226
        }
1227
        $html .= 'action=visible&content='.$content.'&id='.$id.'">'.
1228
            Display::return_icon('invisible.png', get_lang('MakeVisible'), [], ICON_SIZE_SMALL).'</a>';
1229
    }
1230
1231
    return $html;
1232
}
1233
1234
/**
1235
 * @param $content
1236
 * @param $id
1237
 * @param $current_lock_status
1238
 * @param string $additional_url_parameters
1239
 *
1240
 * @return string
1241
 */
1242
function return_lock_unlock_icon($content, $id, $current_lock_status, $additional_url_parameters = '')
1243
{
1244
    $html = '';
1245
    $id = intval($id);
1246
    //check if the forum is blocked due
1247
    if ($content == 'thread') {
1248
        if (api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD)) {
1249
            $html .= Display::return_icon(
1250
                'lock_na.png',
1251
                get_lang('ResourceLockedByGradebook'),
1252
                [],
1253
                ICON_SIZE_SMALL
1254
            );
1255
1256
            return $html;
1257
        }
1258
    }
1259
    if ($current_lock_status == '1') {
1260
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1261
        if (is_array($additional_url_parameters)) {
1262
            foreach ($additional_url_parameters as $key => $value) {
1263
                $html .= $key.'='.$value.'&';
1264
            }
1265
        }
1266
        $html .= 'action=unlock&content='.$content.'&id='.$id.'">'.
1267
            Display::return_icon('lock.png', get_lang('Unlock'), [], ICON_SIZE_SMALL).'</a>';
1268
    }
1269
    if ($current_lock_status == '0') {
1270
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1271
        if (is_array($additional_url_parameters)) {
1272
            foreach ($additional_url_parameters as $key => $value) {
1273
                $html .= $key.'='.$value.'&';
1274
            }
1275
        }
1276
        $html .= 'action=lock&content='.$content.'&id='.$id.'">'.
1277
            Display::return_icon('unlock.png', get_lang('Lock'), [], ICON_SIZE_SMALL).'</a>';
1278
    }
1279
1280
    return $html;
1281
}
1282
1283
/**
1284
 * This function takes care of the display of the up and down icon.
1285
 *
1286
 * @param string $content what is it that we want to make (in)visible: forum category, forum, thread, post
1287
 * @param int    $id      is the id of the item we want to display the icons for
1288
 * @param array  $list    is an array of all the items. All items in this list should have
1289
 *                        an up and down icon except for the first (no up icon) and the last (no down icon)
1290
 *                        The key of this $list array is the id of the item.
1291
 *
1292
 * @return string HTML
1293
 */
1294
function return_up_down_icon($content, $id, $list)
1295
{
1296
    $id = (int) $id;
1297
    $total_items = count($list);
1298
    $position = 0;
1299
    $internal_counter = 0;
1300
    $forumCategory = isset($_GET['forumcategory']) ? Security::remove_XSS($_GET['forumcategory']) : null;
1301
1302
    if (is_array($list)) {
1303
        foreach ($list as $key => $listitem) {
1304
            $internal_counter++;
1305
            if ($id == $key) {
1306
                $position = $internal_counter;
1307
            }
1308
        }
1309
    }
1310
1311
    if ($position > 1) {
1312
        $return_value = '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=up&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('MoveUp').'">'.
1313
            Display::return_icon('up.png', get_lang('MoveUp'), [], ICON_SIZE_SMALL).'</a>';
1314
    } else {
1315
        $return_value = Display::return_icon('up_na.png', '-', [], ICON_SIZE_SMALL);
1316
    }
1317
1318
    if ($position < $total_items) {
1319
        $return_value .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=down&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('MoveDown').'" >'.
1320
            Display::return_icon('down.png', get_lang('MoveDown'), [], ICON_SIZE_SMALL).'</a>';
1321
    } else {
1322
        $return_value .= Display::return_icon('down_na.png', '-', [], ICON_SIZE_SMALL);
1323
    }
1324
1325
    return $return_value;
1326
}
1327
1328
/**
1329
 * This function changes the visibility in the database (item_property).
1330
 *
1331
 * @param string $content           what is it that we want to make (in)visible: forum category, forum, thread, post
1332
 * @param int    $id                the id of the content we want to make invisible
1333
 * @param string $target_visibility what is the current status of the visibility (0 = invisible, 1 = visible)
1334
 *
1335
 * @todo change the get parameter so that it matches the tool constants.
1336
 * @todo check if api_item_property_update returns true or false => returnmessage depends on it.
1337
 * @todo move to itemmanager
1338
 *
1339
 * @return string language variable
1340
 *
1341
 * @author Patrick Cool <[email protected]>, Ghent University
1342
 *
1343
 * @version february 2006, dokeos 1.8
1344
 */
1345
function change_visibility($content, $id, $target_visibility)
1346
{
1347
    $_course = api_get_course_info();
1348
    $constants = [
1349
        'forumcategory' => TOOL_FORUM_CATEGORY,
1350
        'forum' => TOOL_FORUM,
1351
        'thread' => TOOL_FORUM_THREAD,
1352
    ];
1353
    api_item_property_update(
1354
        $_course,
1355
        $constants[$content],
1356
        $id,
1357
        $target_visibility,
1358
        api_get_user_id()
1359
    );
1360
1361
    if ($target_visibility == 'visible') {
1362
        handle_mail_cue($content, $id);
1363
    }
1364
1365
    return get_lang('VisibilityChanged');
1366
}
1367
1368
/**
1369
 * This function changes the lock status in the database.
1370
 *
1371
 * @param string $content what is it that we want to (un)lock: forum category, forum, thread, post
1372
 * @param int    $id      the id of the content we want to (un)lock
1373
 * @param string $action  do we lock (=>locked value in db = 1) or unlock (=> locked value in db = 0)
1374
 *
1375
 * @return string language variable
1376
 *
1377
 * @todo move to item manager
1378
 *
1379
 * @author Patrick Cool <[email protected]>, Ghent University
1380
 *
1381
 * @version february 2006, dokeos 1.8
1382
 */
1383
function change_lock_status($content, $id, $action)
1384
{
1385
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1386
    $table_forums = Database::get_course_table(TABLE_FORUM);
1387
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1388
1389
    // Determine the relevant table.
1390
    if ($content == 'forumcategory') {
1391
        $table = $table_categories;
1392
        $id_field = 'cat_id';
1393
    } elseif ($content == 'forum') {
1394
        $table = $table_forums;
1395
        $id_field = 'forum_id';
1396
    } elseif ($content == 'thread') {
1397
        $table = $table_threads;
1398
        $id_field = 'thread_id';
1399
    } else {
1400
        return get_lang('Error');
1401
    }
1402
1403
    // Determine what we are doing => defines the value for the database and the return message.
1404
    if ($action == 'lock') {
1405
        $db_locked = 1;
1406
        $return_message = get_lang('Locked');
1407
    } elseif ($action == 'unlock') {
1408
        $db_locked = 0;
1409
        $return_message = get_lang('Unlocked');
1410
    } else {
1411
        return get_lang('Error');
1412
    }
1413
1414
    $course_id = api_get_course_int_id();
1415
1416
    // Doing the change in the database
1417
    $sql = "UPDATE $table SET locked='".Database::escape_string($db_locked)."'
1418
            WHERE c_id = $course_id AND $id_field='".Database::escape_string($id)."'";
1419
    if (Database::query($sql)) {
1420
        return $return_message;
1421
    } else {
1422
        return get_lang('Error');
1423
    }
1424
}
1425
1426
/**
1427
 * This function moves a forum or a forum category up or down.
1428
 *
1429
 * @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
1430
 * @param $direction do we want to move it up or down
1431
 * @param $id the id of the content we want to make invisible
1432
 *
1433
 * @todo consider removing the table_item_property calls here but this can
1434
 * prevent unwanted side effects when a forum does not have an entry in
1435
 * the item_property table but does have one in the forum table.
1436
 *
1437
 * @return string language variable
1438
 *
1439
 * @author Patrick Cool <[email protected]>, Ghent University
1440
 *
1441
 * @version february 2006, dokeos 1.8
1442
 */
1443
function move_up_down($content, $direction, $id)
1444
{
1445
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1446
    $table_forums = Database::get_course_table(TABLE_FORUM);
1447
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1448
    $course_id = api_get_course_int_id();
1449
    $id = intval($id);
1450
1451
    // Determine which field holds the sort order.
1452
    if ($content == 'forumcategory') {
1453
        $table = $table_categories;
1454
        $sort_column = 'cat_order';
1455
        $id_column = 'cat_id';
1456
        $sort_column = 'cat_order';
1457
    } elseif ($content == 'forum') {
1458
        $table = $table_forums;
1459
        $sort_column = 'forum_order';
1460
        $id_column = 'forum_id';
1461
        $sort_column = 'forum_order';
1462
        // We also need the forum_category of this forum.
1463
        $sql = "SELECT forum_category FROM $table_forums
1464
                WHERE c_id = $course_id AND forum_id = ".intval($id);
1465
        $result = Database::query($sql);
1466
        $row = Database::fetch_array($result);
1467
        $forum_category = $row['forum_category'];
1468
    } else {
1469
        return get_lang('Error');
1470
    }
1471
1472
    // Determine the need for sorting ascending or descending order.
1473
    if ($direction == 'down') {
1474
        $sort_direction = 'ASC';
1475
    } elseif ($direction == 'up') {
1476
        $sort_direction = 'DESC';
1477
    } else {
1478
        return get_lang('Error');
1479
    }
1480
1481
    // The SQL statement
1482
    if ($content == 'forumcategory') {
1483
        $sql = "SELECT *
1484
                FROM $table_categories forum_categories, $table_item_property item_properties
1485
                WHERE
1486
                    forum_categories.c_id = $course_id AND
1487
                    item_properties.c_id = $course_id AND
1488
                    forum_categories.cat_id=item_properties.ref AND
1489
                    item_properties.tool='".TOOL_FORUM_CATEGORY."'
1490
                ORDER BY forum_categories.cat_order $sort_direction";
1491
    }
1492
    if ($content == 'forum') {
1493
        $sql = "SELECT *
1494
            FROM $table
1495
            WHERE
1496
                c_id = $course_id AND
1497
                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...
1498
            ORDER BY forum_order $sort_direction";
1499
    }
1500
    // Finding the items that need to be switched.
1501
    $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...
1502
    $found = false;
1503
    while ($row = Database::fetch_array($result)) {
1504
        if ($found) {
1505
            $next_id = $row[$id_column];
1506
            $next_sort = $row[$sort_column];
1507
            $found = false;
1508
        }
1509
        if ($id == $row[$id_column]) {
1510
            $this_id = $id;
1511
            $this_sort = $row[$sort_column];
1512
            $found = true;
1513
        }
1514
    }
1515
1516
    // Committing the switch.
1517
    // We do an extra check if we do not have illegal values. If your remove this if statement you will
1518
    // be able to mess with the sorting by refreshing the page over and over again.
1519
    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 $this_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 $next_id does not seem to be defined for all execution paths leading up to this point.
Loading history...
1520
        $sql = "UPDATE $table SET $sort_column='".Database::escape_string($this_sort)."'
1521
                WHERE c_id = $course_id AND $id_column='".Database::escape_string($next_id)."'";
1522
        Database::query($sql);
1523
1524
        $sql = "UPDATE $table SET $sort_column='".Database::escape_string($next_sort)."'
1525
                WHERE c_id = $course_id AND $id_column='".Database::escape_string($this_id)."'";
1526
        Database::query($sql);
1527
    }
1528
1529
    return get_lang(ucfirst($content).'Moved');
1530
}
1531
1532
/**
1533
 * Retrieve all the information off the forum categories (or one specific) for the current course.
1534
 * The categories are sorted according to their sorting order (cat_order.
1535
 *
1536
 * @param int|string $id        default ''. When an id is passed we only find the information
1537
 *                              about that specific forum category. If no id is passed we get all the forum categories.
1538
 * @param int        $courseId  Optional. The course ID
1539
 * @param int        $sessionId Optional. The session ID
1540
 *
1541
 * @return array containing all the information about all the forum categories
1542
 *
1543
 * @author Patrick Cool <[email protected]>, Ghent University
1544
 *
1545
 * @version february 2006, dokeos 1.8
1546
 */
1547
function get_forum_categories($id = '', $courseId = 0, $sessionId = 0)
1548
{
1549
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1550
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1551
1552
    // Condition for the session
1553
    $session_id = $sessionId ?: api_get_session_id();
1554
    $course_id = $courseId ?: api_get_course_int_id();
1555
1556
    $condition_session = api_get_session_condition(
1557
        $session_id,
1558
        true,
1559
        true,
1560
        'forum_categories.session_id'
1561
    );
1562
    $condition_session .= " AND forum_categories.c_id = $course_id AND item_properties.c_id = $course_id";
1563
1564
    if (empty($id)) {
1565
        $sql = "SELECT *
1566
                FROM $table_item_property item_properties 
1567
                INNER JOIN $table_categories forum_categories
1568
                ON (
1569
                    forum_categories.cat_id = item_properties.ref AND 
1570
                    item_properties.c_id = forum_categories.c_id
1571
                )
1572
                WHERE                    
1573
                    item_properties.visibility = 1 AND
1574
                    item_properties.tool = '".TOOL_FORUM_CATEGORY."'
1575
                    $condition_session
1576
                ORDER BY forum_categories.cat_order ASC";
1577
        if (api_is_allowed_to_edit()) {
1578
            $sql = "SELECT *
1579
                    FROM $table_item_property item_properties  
1580
                    INNER JOIN $table_categories forum_categories
1581
                    ON (
1582
                        forum_categories.cat_id = item_properties.ref AND 
1583
                        item_properties.c_id = forum_categories.c_id
1584
                    )
1585
                    WHERE                        
1586
                        item_properties.visibility<>2 AND
1587
                        item_properties.tool='".TOOL_FORUM_CATEGORY."'
1588
                        $condition_session
1589
                    ORDER BY forum_categories.cat_order ASC";
1590
        }
1591
    } else {
1592
        $sql = "SELECT *
1593
                FROM $table_item_property item_properties 
1594
                INNER JOIN $table_categories forum_categories
1595
                ON (
1596
                    forum_categories.cat_id = item_properties.ref AND 
1597
                    item_properties.c_id = forum_categories.c_id
1598
                )
1599
                WHERE                    
1600
                    item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
1601
                    forum_categories.cat_id = ".intval($id)."
1602
                    $condition_session
1603
                ORDER BY forum_categories.cat_order ASC";
1604
    }
1605
1606
    $result = Database::query($sql);
1607
    $forum_categories_list = [];
1608
    $extraFieldValue = new ExtraFieldValue('forum_category');
1609
    while ($row = Database::fetch_assoc($result)) {
1610
        $row['extra_fields'] = $extraFieldValue->getAllValuesByItem($row['cat_id']);
1611
1612
        if (empty($id)) {
1613
            $forum_categories_list[$row['cat_id']] = $row;
1614
        } else {
1615
            $forum_categories_list = $row;
1616
        }
1617
    }
1618
1619
    return $forum_categories_list;
1620
}
1621
1622
/**
1623
 * This function retrieves all the fora in a given forum category.
1624
 *
1625
 * @param int $cat_id   the id of the forum category
1626
 * @param int $courseId Optional. The course ID
1627
 *
1628
 * @return array containing all the information about the forums (regardless of their category)
1629
 *
1630
 * @author Patrick Cool <[email protected]>, Ghent University
1631
 *
1632
 * @version february 2006, dokeos 1.8
1633
 */
1634
function get_forums_in_category($cat_id, $courseId = 0)
1635
{
1636
    $table_forums = Database::get_course_table(TABLE_FORUM);
1637
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1638
1639
    $forum_list = [];
1640
    $course_id = $courseId ?: api_get_course_int_id();
1641
    $cat_id = (int) $cat_id;
1642
1643
    $sql = "SELECT * FROM $table_forums forum 
1644
            INNER JOIN $table_item_property item_properties
1645
            ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
1646
            WHERE
1647
                forum.forum_category = '".$cat_id."' AND                
1648
                item_properties.visibility = 1 AND
1649
                forum.c_id = $course_id AND
1650
                item_properties.c_id = $course_id AND
1651
                item_properties.tool = '".TOOL_FORUM."'                 
1652
            ORDER BY forum.forum_order ASC";
1653
    if (api_is_allowed_to_edit()) {
1654
        $sql = "SELECT * FROM $table_forums forum  
1655
                INNER JOIN $table_item_property item_properties
1656
                ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
1657
                WHERE
1658
                    forum.forum_category = '".$cat_id."' AND                    
1659
                    item_properties.visibility <> 2 AND
1660
                    item_properties.tool = '".TOOL_FORUM."' AND
1661
                    item_properties.c_id = $course_id AND
1662
                    forum.c_id = $course_id
1663
                ORDER BY forum_order ASC";
1664
    }
1665
    $result = Database::query($sql);
1666
    while ($row = Database::fetch_array($result)) {
1667
        $forum_list[$row['forum_id']] = $row;
1668
    }
1669
1670
    return $forum_list;
1671
}
1672
1673
/**
1674
 * Retrieve all the forums (regardless of their category) or of only one.
1675
 * The forums are sorted according to the forum_order.
1676
 * Since it does not take the forum category into account there probably
1677
 * will be two or more forums that have forum_order=1, ...
1678
 *
1679
 * @param int    $id                 forum id
1680
 * @param string $course_code
1681
 * @param bool   $includeGroupsForum
1682
 * @param int    $sessionId
1683
 *
1684
 * @return array an array containing all the information about the forums (regardless of their category)
1685
 *
1686
 * @todo check $sql4 because this one really looks fishy.
1687
 *
1688
 * @author Patrick Cool <[email protected]>, Ghent University
1689
 *
1690
 * @version february 2006, dokeos 1.8
1691
 */
1692
function get_forums(
1693
    $id = 0,
1694
    $course_code = '',
1695
    $includeGroupsForum = true,
1696
    $sessionId = 0
1697
) {
1698
    $id = (int) $id;
1699
    $course_info = api_get_course_info($course_code);
1700
1701
    $table_forums = Database::get_course_table(TABLE_FORUM);
1702
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1703
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1704
1705
    // Condition for the session
1706
    $session_id = intval($sessionId) ?: api_get_session_id();
1707
    $sessionIdLink = $session_id === 0 ? '' : ' AND threads.session_id = item_properties.session_id';
1708
1709
    $condition_session = api_get_session_condition(
1710
        $session_id,
1711
        true,
1712
        false,
1713
        'item_properties.session_id'
1714
    );
1715
1716
    $course_id = $course_info['real_id'];
1717
1718
    $forum_list = [];
1719
    $includeGroupsForumSelect = '';
1720
    if (!$includeGroupsForum) {
1721
        $includeGroupsForumSelect = " AND (forum_of_group = 0 OR forum_of_group IS NULL) ";
1722
    }
1723
1724
    $allowToEdit = api_is_allowed_to_edit();
1725
1726
    if (empty($id)) {
1727
        // Student
1728
        // Select all the forum information of all forums (that are visible to students).
1729
        $sql = "SELECT item_properties.*, forum.* 
1730
                FROM $table_forums forum
1731
                INNER JOIN $table_item_property item_properties
1732
                ON (
1733
                    forum.forum_id = item_properties.ref AND
1734
                    forum.c_id = item_properties.c_id
1735
                )
1736
                WHERE
1737
                    item_properties.visibility = 1 AND
1738
                    item_properties.tool = '".TOOL_FORUM."'
1739
                    $condition_session AND
1740
                    forum.c_id = $course_id AND
1741
                    item_properties.c_id = $course_id
1742
                    $includeGroupsForumSelect
1743
                ORDER BY forum.forum_order ASC";
1744
1745
        // Select the number of threads of the forums (only the threads that are visible).
1746
        $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1747
                FROM $table_threads threads
1748
                INNER JOIN $table_item_property item_properties
1749
                ON (
1750
                    threads.thread_id = item_properties.ref AND
1751
                    threads.c_id = item_properties.c_id
1752
                    $sessionIdLink
1753
                )
1754
                WHERE
1755
                    item_properties.visibility=1 AND
1756
                    item_properties.tool='".TOOL_FORUM_THREAD."' AND
1757
                    threads.c_id = $course_id AND
1758
                    item_properties.c_id = $course_id
1759
                GROUP BY threads.forum_id";
1760
1761
        // Course Admin
1762
        if ($allowToEdit) {
1763
            // Select all the forum information of all forums (that are not deleted).
1764
            $sql = "SELECT item_properties.*, forum.* 
1765
                    FROM $table_forums forum
1766
                    INNER JOIN $table_item_property item_properties
1767
                    ON (
1768
                        forum.forum_id = item_properties.ref AND
1769
                        forum.c_id = item_properties.c_id
1770
                    )
1771
                    WHERE
1772
                        item_properties.visibility <> 2 AND
1773
                        item_properties.tool = '".TOOL_FORUM."'
1774
                        $condition_session AND
1775
                        forum.c_id = $course_id AND
1776
                        item_properties.c_id = $course_id
1777
                        $includeGroupsForumSelect
1778
                    ORDER BY forum_order ASC";
1779
1780
            // Select the number of threads of the forums (only the threads that are not deleted).
1781
            $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1782
                    FROM $table_threads threads
1783
                    INNER JOIN $table_item_property item_properties
1784
                    ON (
1785
                        threads.thread_id = item_properties.ref AND
1786
                        threads.c_id = item_properties.c_id
1787
                        $sessionIdLink
1788
                    )
1789
                    WHERE
1790
                        item_properties.visibility<>2 AND
1791
                        item_properties.tool='".TOOL_FORUM_THREAD."' AND
1792
                        threads.c_id = $course_id AND
1793
                        item_properties.c_id = $course_id
1794
                    GROUP BY threads.forum_id";
1795
        }
1796
    } else {
1797
        // GETTING ONE SPECIFIC FORUM
1798
        /* We could do the splitup into student and course admin also but we want
1799
        to have as much as information about a certain forum as possible
1800
        so we do not take too much information into account. This function
1801
         (or this section of the function) is namely used to fill the forms
1802
        when editing a forum (and for the moment it is the only place where
1803
        we use this part of the function) */
1804
1805
        // Select all the forum information of the given forum (that is not deleted).
1806
        $sql = "SELECT * FROM $table_item_property item_properties 
1807
                INNER JOIN $table_forums forum
1808
                ON (forum.forum_id = item_properties.ref AND forum.c_id = item_properties.c_id)
1809
                WHERE
1810
                    forum.forum_id = $id AND
1811
                    forum.c_id = $course_id AND
1812
                    item_properties.visibility != 2 AND
1813
                    item_properties.tool = '".TOOL_FORUM."'
1814
                ORDER BY forum_order ASC";
1815
1816
        // Select the number of threads of the forum.
1817
        $sql2 = "SELECT count(*) AS number_of_threads, forum_id
1818
                FROM $table_threads
1819
                WHERE
1820
                    forum_id = $id
1821
                GROUP BY forum_id";
1822
    }
1823
1824
    // Handling all the forum information.
1825
    $result = Database::query($sql);
1826
    while ($row = Database::fetch_assoc($result)) {
1827
        if (empty($id)) {
1828
            $forum_list[$row['forum_id']] = $row;
1829
        } else {
1830
            $forum_list = $row;
1831
        }
1832
    }
1833
1834
    // Handling the thread count information.
1835
    $result2 = Database::query($sql2);
1836
    while ($row2 = Database::fetch_array($result2)) {
1837
        if (empty($id)) {
1838
            $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
1839
        } else {
1840
            $forum_list['number_of_threads'] = $row2['number_of_threads'];
1841
        }
1842
    }
1843
1844
    /* Finding the last post information
1845
    (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)*/
1846
    if (empty($id)) {
1847
        if (is_array($forum_list)) {
1848
            foreach ($forum_list as $key => $value) {
1849
                $lastPost = get_last_post_information(
1850
                    $key,
1851
                    $allowToEdit,
1852
                    $course_id
1853
                );
1854
1855
                if ($lastPost) {
1856
                    $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
1857
                    $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
1858
                    $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
1859
                    $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
1860
                    $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
1861
                    $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
1862
                    $forum_list[$key]['last_post_title'] = $lastPost['last_post_title'];
1863
                    $forum_list[$key]['last_post_text'] = $lastPost['last_post_text'];
1864
                }
1865
            }
1866
        } else {
1867
            $forum_list = [];
1868
        }
1869
    } else {
1870
        $lastPost = get_last_post_information(
1871
            $id,
1872
            $allowToEdit,
1873
            $course_id
1874
        );
1875
        if ($lastPost) {
1876
            $forum_list['last_post_id'] = $lastPost['last_post_id'];
1877
            $forum_list['last_poster_id'] = $lastPost['last_poster_id'];
1878
            $forum_list['last_post_date'] = $lastPost['last_post_date'];
1879
            $forum_list['last_poster_name'] = $lastPost['last_poster_name'];
1880
            $forum_list['last_poster_lastname'] = $lastPost['last_poster_lastname'];
1881
            $forum_list['last_poster_firstname'] = $lastPost['last_poster_firstname'];
1882
            $forum_list['last_post_title'] = $lastPost['last_post_title'];
1883
            $forum_list['last_post_text'] = $lastPost['last_post_text'];
1884
        }
1885
    }
1886
1887
    return $forum_list;
1888
}
1889
1890
/**
1891
 * @param int  $course_id
1892
 * @param int  $thread_id
1893
 * @param int  $forum_id
1894
 * @param bool $show_visible
1895
 *
1896
 * @return array|bool
1897
 */
1898
function get_last_post_by_thread($course_id, $thread_id, $forum_id, $show_visible = true)
1899
{
1900
    if (empty($thread_id) || empty($forum_id) || empty($course_id)) {
1901
        return false;
1902
    }
1903
1904
    $thread_id = intval($thread_id);
1905
    $forum_id = intval($forum_id);
1906
    $course_id = intval($course_id);
1907
1908
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1909
    $sql = "SELECT * FROM $table_posts
1910
            WHERE 
1911
                c_id = $course_id AND 
1912
                thread_id = $thread_id AND 
1913
                forum_id = $forum_id";
1914
1915
    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...
1916
        $sql .= " AND visible = 1 ";
1917
    }
1918
1919
    $sql .= " ORDER BY post_id DESC LIMIT 1";
1920
    $result = Database::query($sql);
1921
    if (Database::num_rows($result)) {
1922
        return Database::fetch_array($result, 'ASSOC');
1923
    } else {
1924
        return false;
1925
    }
1926
}
1927
1928
/**
1929
 * This function gets all the last post information of a certain forum.
1930
 *
1931
 * @param int  $forum_id        the id of the forum we want to know the last post information of
1932
 * @param bool $show_invisibles
1933
 * @param string course db name
1934
 * @param int $sessionId Optional. The session id
1935
 *
1936
 * @return array containing all the information about the last post
1937
 *               (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)
1938
 *
1939
 * @author Patrick Cool <[email protected]>, Ghent University
1940
 *
1941
 * @version february 2006, dokeos 1.8
1942
 */
1943
function get_last_post_information($forum_id, $show_invisibles = false, $course_id = null, $sessionId = 0)
1944
{
1945
    if (!isset($course_id)) {
1946
        $course_id = api_get_course_int_id();
1947
    } else {
1948
        $course_id = intval($course_id);
1949
    }
1950
    $sessionId = $sessionId ? intval($sessionId) : api_get_session_id();
1951
1952
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1953
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1954
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
1955
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1956
1957
    $forum_id = intval($forum_id);
1958
    $return_array = [];
1959
1960
    // First get the threads to make sure there is no inconsistency in the
1961
    // database between forum and thread
1962
    $sql = "SELECT thread_id FROM $table_threads 
1963
            WHERE 
1964
                forum_id = $forum_id AND 
1965
                c_id = $course_id AND 
1966
                session_id = $sessionId";
1967
    $result = Database::query($sql);
1968
    if (Database::num_rows($result) == 0) {
1969
        // If there are no threads in this forum, then there are no posts
1970
        return [];
1971
    }
1972
    $threads = [];
1973
    while ($row = Database::fetch_row($result)) {
1974
        $threads[] = $row[0];
1975
    }
1976
    $threadsList = implode(',', $threads);
1977
    // Now get the posts that are linked to these threads
1978
    $sql = "SELECT
1979
                post.post_id,
1980
                post.forum_id,
1981
                post.poster_id,
1982
                post.poster_name,
1983
                post.post_date,
1984
                users.lastname,
1985
                users.firstname,
1986
                post.visible,
1987
                thread_properties.visibility AS thread_visibility,
1988
                forum_properties.visibility AS forum_visibility,
1989
                post.post_title,
1990
                post.post_text
1991
            FROM
1992
                $table_posts post,
1993
                $table_users users,
1994
                $table_item_property thread_properties,
1995
                $table_item_property forum_properties
1996
            WHERE
1997
                post.forum_id = $forum_id
1998
                AND post.thread_id IN ($threadsList)
1999
                AND post.poster_id = users.user_id
2000
                AND post.thread_id = thread_properties.ref
2001
                AND thread_properties.tool='".TOOL_FORUM_THREAD."'
2002
                AND post.forum_id=forum_properties.ref
2003
                AND forum_properties.tool='".TOOL_FORUM."'
2004
                AND post.c_id = $course_id AND
2005
                thread_properties.c_id = $course_id AND
2006
                forum_properties.c_id = $course_id
2007
            ORDER BY post.post_id DESC";
2008
    $result = Database::query($sql);
2009
2010
    if ($show_invisibles) {
2011
        $row = Database::fetch_array($result);
2012
        $return_array['last_post_id'] = $row['post_id'];
2013
        $return_array['last_poster_id'] = $row['poster_id'];
2014
        $return_array['last_post_date'] = $row['post_date'];
2015
        $return_array['last_poster_name'] = $row['poster_name'];
2016
        $return_array['last_poster_lastname'] = $row['lastname'];
2017
        $return_array['last_poster_firstname'] = $row['firstname'];
2018
        $return_array['last_post_title'] = $row['post_title'];
2019
        $return_array['last_post_text'] = $row['post_text'];
2020
2021
        return $return_array;
2022
    } else {
2023
        // We have to loop through the results to find the first one that is
2024
        // actually visible to students (forum_category, forum, thread AND post are visible).
2025
        while ($row = Database::fetch_array($result)) {
2026
            if ($row['visible'] == '1' && $row['thread_visibility'] == '1' && $row['forum_visibility'] == '1') {
2027
                $return_array['last_post_id'] = $row['post_id'];
2028
                $return_array['last_poster_id'] = $row['poster_id'];
2029
                $return_array['last_post_date'] = $row['post_date'];
2030
                $return_array['last_poster_name'] = $row['poster_name'];
2031
                $return_array['last_poster_lastname'] = $row['lastname'];
2032
                $return_array['last_poster_firstname'] = $row['firstname'];
2033
                $return_array['last_post_title'] = $row['post_title'];
2034
                $return_array['last_post_text'] = $row['post_text'];
2035
2036
                return $return_array;
2037
            }
2038
        }
2039
    }
2040
}
2041
2042
/**
2043
 * Retrieve all the threads of a given forum.
2044
 *
2045
 * @param int      $forum_id
2046
 * @param int|null $courseId  Optional If is null then it is considered the current course
2047
 * @param int|null $sessionId Optional. If is null then it is considered the current session
2048
 *
2049
 * @return array containing all the information about the threads
2050
 *
2051
 * @author Patrick Cool <[email protected]>, Ghent University
2052
 *
2053
 * @version february 2006, dokeos 1.8
2054
 */
2055
function get_threads($forum_id, $courseId = null, $sessionId = null)
2056
{
2057
    $groupId = api_get_group_id();
2058
    $sessionId = $sessionId !== null ? (int) $sessionId : api_get_session_id();
2059
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2060
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2061
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
2062
2063
    $courseId = $courseId !== null ? (int) $courseId : api_get_course_int_id();
2064
    $groupInfo = GroupManager::get_group_properties($groupId);
2065
    $groupCondition = '';
2066
2067
    if (!empty($groupInfo)) {
2068
        $groupIid = $groupInfo['iid'];
2069
        $groupCondition = " AND item_properties.to_group_id = '$groupIid' ";
2070
    }
2071
2072
    $sessionCondition = api_get_session_condition(
2073
        $sessionId,
2074
        true,
2075
        false,
2076
        'item_properties.session_id'
2077
    );
2078
2079
    // important note:  it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
2080
    // because we also have thread.* in it. This is because thread has a field locked and post also has the same field
2081
    // since we are merging these we would have the post.locked value but in fact we want the thread.locked value
2082
    // This is why it is added to the end of the field selection
2083
    $sql = "SELECT DISTINCT
2084
                item_properties.*,
2085
                users.firstname,
2086
                users.lastname,
2087
                users.user_id,
2088
                thread.locked as locked,
2089
                thread.*
2090
            FROM $table_threads thread
2091
            INNER JOIN $table_item_property item_properties
2092
            ON
2093
                thread.thread_id = item_properties.ref AND
2094
                item_properties.c_id = thread.c_id AND
2095
                item_properties.tool = '".TABLE_FORUM_THREAD."' 
2096
                $groupCondition
2097
                $sessionCondition
2098
            LEFT JOIN $table_users users
2099
                ON thread.thread_poster_id = users.user_id
2100
            WHERE
2101
                item_properties.visibility='1' AND
2102
                thread.forum_id = ".intval($forum_id)." AND
2103
                thread.c_id = $courseId 
2104
            ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
2105
2106
    if (api_is_allowed_to_edit()) {
2107
        $sql = "SELECT DISTINCT
2108
                    item_properties.*,
2109
                    users.firstname,
2110
                    users.lastname,
2111
                    users.user_id,
2112
                    thread.locked as locked,
2113
                    thread.*
2114
                FROM $table_threads thread
2115
                INNER JOIN $table_item_property item_properties
2116
                ON
2117
                    thread.thread_id = item_properties.ref AND
2118
                    item_properties.c_id = thread.c_id AND
2119
                    item_properties.tool = '".TABLE_FORUM_THREAD."'
2120
                    $groupCondition
2121
                    $sessionCondition
2122
                LEFT JOIN $table_users users
2123
                    ON thread.thread_poster_id=users.user_id
2124
                WHERE
2125
                    item_properties.visibility<>2 AND
2126
                    thread.forum_id = ".intval($forum_id)." AND
2127
                    thread.c_id = $courseId 
2128
                ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
2129
    }
2130
    $result = Database::query($sql);
2131
    $list = [];
2132
    $alreadyAdded = [];
2133
    while ($row = Database::fetch_array($result, 'ASSOC')) {
2134
        if (in_array($row['thread_id'], $alreadyAdded)) {
2135
            continue;
2136
        }
2137
        $list[] = $row;
2138
        $alreadyAdded[] = $row['thread_id'];
2139
    }
2140
2141
    return $list;
2142
}
2143
2144
/**
2145
 * Get a thread by Id and course id.
2146
 *
2147
 * @param int $threadId the thread Id
2148
 * @param int $cId      the course id
2149
 *
2150
 * @return array containing all the information about the thread
2151
 */
2152
function getThreadInfo($threadId, $cId)
2153
{
2154
    $repo = Database::getManager()->getRepository('ChamiloCourseBundle:CForumThread');
2155
    $forumThread = $repo->findOneBy(['threadId' => $threadId, 'cId' => $cId]);
2156
2157
    $thread = [];
2158
    if ($forumThread) {
2159
        $thread['threadId'] = $forumThread->getThreadId();
2160
        $thread['threadTitle'] = $forumThread->getThreadTitle();
2161
        $thread['forumId'] = $forumThread->getForum() ? $forumThread->getForum()->getIid() : 0;
2162
        $thread['sessionId'] = $forumThread->getSessionId();
2163
        $thread['threadSticky'] = $forumThread->getThreadSticky();
2164
        $thread['locked'] = $forumThread->getLocked();
2165
        $thread['threadTitleQualify'] = $forumThread->getThreadTitleQualify();
2166
        $thread['threadQualifyMax'] = $forumThread->getThreadQualifyMax();
2167
        $thread['threadCloseDate'] = $forumThread->getThreadCloseDate();
2168
        $thread['threadWeight'] = $forumThread->getThreadWeight();
2169
        $thread['threadPeerQualify'] = $forumThread->isThreadPeerQualify();
2170
    }
2171
2172
    return $thread;
2173
}
2174
2175
/**
2176
 * Retrieve all posts of a given thread.
2177
 *
2178
 * @param array  $forumInfo
2179
 * @param int    $threadId       The thread ID
2180
 * @param string $orderDirection Optional. The direction for sort the posts
2181
 * @param bool   $recursive      Optional. If the list is recursive
2182
 * @param int    $postId         Optional. The post ID for recursive list
2183
 * @param int    $depth          Optional. The depth to indicate the indent
2184
 *
2185
 * @todo move to a repository
2186
 *
2187
 * @return array containing all the information about the posts of a given thread
2188
 */
2189
function getPosts(
2190
    $forumInfo,
2191
    $threadId,
2192
    $orderDirection = 'ASC',
2193
    $recursive = false,
2194
    $postId = null,
2195
    $depth = -1
2196
) {
2197
    $em = Database::getManager();
2198
2199
    if (api_is_allowed_to_edit(false, true)) {
2200
        $visibleCriteria = Criteria::expr()->neq('visible', 2);
2201
    } else {
2202
        $visibleCriteria = Criteria::expr()->eq('visible', 1);
2203
    }
2204
2205
    $criteria = Criteria::create();
2206
    $criteria
2207
        ->where(Criteria::expr()->eq('thread', $threadId))
2208
        ->andWhere(Criteria::expr()->eq('cId', $forumInfo['c_id']))
2209
        ->andWhere($visibleCriteria)
2210
    ;
2211
2212
    $groupId = api_get_group_id();
2213
    $groupInfo = GroupManager::get_group_properties($groupId);
2214
    $filterModerated = true;
2215
2216
    if (empty($groupId)) {
2217
        if (api_is_allowed_to_edit()) {
2218
            $filterModerated = false;
2219
        }
2220
    } else {
2221
        if (GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo) ||
2222
            api_is_allowed_to_edit(false, true)
2223
        ) {
2224
            $filterModerated = false;
2225
        }
2226
    }
2227
2228
    if ($recursive) {
2229
        $criteria->andWhere(Criteria::expr()->eq('postParentId', $postId));
2230
    }
2231
2232
    $qb = $em->getRepository('ChamiloCourseBundle:CForumPost')->createQueryBuilder('p');
2233
    $qb->select('p')
2234
        ->addCriteria($criteria)
2235
        ->addOrderBy('p.postId', $orderDirection);
2236
2237
    if ($filterModerated && $forumInfo['moderated'] == 1) {
2238
        if (!api_is_allowed_to_edit(false, true)) {
2239
            $userId = api_get_user_id();
2240
            $qb->andWhere(
2241
                "p.status = 1 OR 
2242
                    (p.status = ".CForumPost::STATUS_WAITING_MODERATION." AND p.posterId = $userId) OR
2243
                    (p.status = ".CForumPost::STATUS_REJECTED." AND p.posterId = $userId) OR
2244
                    (p.status IS NULL AND p.posterId = $userId) 
2245
                    "
2246
            );
2247
        }
2248
    }
2249
2250
    $posts = $qb->getQuery()->getResult();
2251
    $depth++;
2252
2253
    $list = [];
2254
    /** @var CForumPost $post */
2255
    foreach ($posts as $post) {
2256
        $postInfo = [
2257
            'iid' => $post->getIid(),
2258
            'c_id' => $post->getCId(),
2259
            'post_id' => $post->getPostId(),
2260
            'post_title' => $post->getPostTitle(),
2261
            'post_text' => $post->getPostText(),
2262
            'thread_id' => $post->getThread() ? $post->getThread()->getIid() : 0,
2263
            'forum_id' => $post->getForumId(),
2264
            'poster_id' => $post->getPosterId(),
2265
            'poster_name' => $post->getPosterName(),
2266
            'post_date' => $post->getPostDate(),
2267
            'post_notification' => $post->getPostNotification(),
2268
            'post_parent_id' => $post->getPostParentId(),
2269
            'visible' => $post->getVisible(),
2270
            'status' => $post->getStatus(),
2271
            'indent_cnt' => $depth,
2272
        ];
2273
2274
        $posterId = $post->getPosterId();
2275
        if (!empty($posterId)) {
2276
            $user = api_get_user_entity($posterId);
2277
            if ($user) {
2278
                $postInfo['user_id'] = $user->getUserId();
2279
                $postInfo['username'] = $user->getUsername();
2280
                $postInfo['username_canonical'] = $user->getUsernameCanonical();
2281
                $postInfo['lastname'] = $user->getLastname();
2282
                $postInfo['firstname'] = $user->getFirstname();
2283
                $postInfo['complete_name'] = UserManager::formatUserFullName($user);
2284
            }
2285
        }
2286
2287
        $list[] = $postInfo;
2288
2289
        if (!$recursive) {
2290
            continue;
2291
        }
2292
        $list = array_merge(
2293
            $list,
2294
            getPosts(
2295
                $forumInfo,
2296
                $threadId,
2297
                $orderDirection,
2298
                $recursive,
2299
                $post->getPostId(),
2300
                $depth
2301
            )
2302
        );
2303
    }
2304
2305
    return $list;
2306
}
2307
2308
/**
2309
 * This function retrieves all the information of a post.
2310
 *
2311
 * @param int $post_id integer that indicates the forum
2312
 *
2313
 * @return array returns
2314
 *
2315
 * @author Patrick Cool <[email protected]>, Ghent University
2316
 *
2317
 * @version february 2006, dokeos 1.8
2318
 */
2319
function get_post_information($post_id)
2320
{
2321
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
2322
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
2323
    $course_id = api_get_course_int_id();
2324
    $post_id = (int) $post_id;
2325
2326
    if (empty($post_id)) {
2327
        return [];
2328
    }
2329
2330
    $sql = "SELECT posts.*, email FROM ".$table_posts." posts, ".$table_users." users
2331
            WHERE
2332
                c_id = $course_id AND
2333
                posts.poster_id=users.user_id AND
2334
                posts.post_id = ".$post_id;
2335
    $result = Database::query($sql);
2336
    $row = Database::fetch_array($result, 'ASSOC');
2337
2338
    return $row;
2339
}
2340
2341
/**
2342
 * This function retrieves all the information of a thread.
2343
 *
2344
 * @param int $forumId
2345
 * @param $thread_id integer that indicates the forum
2346
 * @param int|null $sessionId Optional. If is null then it is considered the current session
2347
 *
2348
 * @return array returns
2349
 *
2350
 * @author Patrick Cool <[email protected]>, Ghent University
2351
 *
2352
 * @version february 2006, dokeos 1.8
2353
 */
2354
function get_thread_information($forumId, $thread_id, $sessionId = null)
2355
{
2356
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2357
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2358
    $thread_id = intval($thread_id);
2359
    $sessionId = $sessionId !== null ? intval($sessionId) : api_get_session_id();
2360
    $sessionCondition = api_get_session_condition(
2361
        $sessionId,
2362
        true,
2363
        false,
2364
        'threads.session_id'
2365
    );
2366
    $forumCondition = '';
2367
    if (!empty($forumId)) {
2368
        $forumId = (int) $forumId;
2369
        $forumCondition = " threads.forum_id = $forumId AND ";
2370
    }
2371
    $sql = "SELECT * FROM $table_item_property item_properties
2372
            INNER JOIN
2373
            $table_threads threads
2374
            ON (item_properties.ref = threads.thread_id AND threads.c_id = item_properties.c_id)
2375
            WHERE
2376
                $forumCondition
2377
                item_properties.tool= '".TOOL_FORUM_THREAD."' AND                
2378
                threads.thread_id = $thread_id 
2379
                $sessionCondition
2380
            ";
2381
2382
    $result = Database::query($sql);
2383
    $row = Database::fetch_assoc($result);
2384
2385
    return $row;
2386
}
2387
2388
/**
2389
 * This function retrieves forum thread users details.
2390
 *
2391
 * @param   int Thread ID
2392
 * @param   string  Course DB name (optional)
2393
 *
2394
 * @return Doctrine\DBAL\Driver\Statement|null array Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2395
 *
2396
 * @author Christian Fasanando <[email protected]>,
2397
 *
2398
 * @todo     this function need to be improved
2399
 *
2400
 * @version octubre 2008, dokeos 1.8
2401
 */
2402
function get_thread_users_details($thread_id)
2403
{
2404
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2405
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2406
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2407
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2408
2409
    $course_id = api_get_course_int_id();
2410
2411
    $is_western_name_order = api_is_western_name_order();
2412
    if ($is_western_name_order) {
2413
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2414
    } else {
2415
        $orderby = 'ORDER BY user.lastname, user.firstname';
2416
    }
2417
2418
    if (api_get_session_id()) {
2419
        $session_info = api_get_session_info(api_get_session_id());
2420
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2421
        //not showing coaches
2422
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2423
                FROM $t_posts p, $t_users user, $t_session_rel_user session_rel_user_rel_course
2424
                WHERE 
2425
                    p.poster_id = user.id AND
2426
                    user.id = session_rel_user_rel_course.user_id AND
2427
                    session_rel_user_rel_course.status<>'2' AND
2428
                    session_rel_user_rel_course.user_id NOT IN ($user_to_avoid) AND
2429
                    p.thread_id = ".intval($thread_id)." AND
2430
                    session_id = ".api_get_session_id()." AND
2431
                    p.c_id = $course_id AND
2432
                    session_rel_user_rel_course.c_id = ".$course_id." $orderby ";
2433
    } else {
2434
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2435
                FROM $t_posts p, $t_users user, $t_course_user course_user
2436
                WHERE 
2437
                    p.poster_id = user.id
2438
                    AND user.id = course_user.user_id
2439
                    AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
2440
                    AND p.thread_id = ".intval($thread_id)."
2441
                    AND course_user.status NOT IN('1') AND
2442
                    p.c_id = $course_id AND
2443
                    course_user.c_id = ".$course_id." $orderby";
2444
    }
2445
    $result = Database::query($sql);
2446
2447
    return $result;
2448
}
2449
2450
/**
2451
 * This function retrieves forum thread users qualify.
2452
 *
2453
 * @param   int Thread ID
2454
 * @param   string  Course DB name (optional)
2455
 *
2456
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2457
 *
2458
 * @author Jhon Hinojosa
2459
 *
2460
 * @todo     this function need to be improved
2461
 */
2462
function get_thread_users_qualify($thread_id)
2463
{
2464
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2465
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2466
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2467
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2468
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2469
2470
    $course_id = api_get_course_int_id();
2471
    $sessionId = api_get_session_id();
2472
2473
    $is_western_name_order = api_is_western_name_order();
2474
    if ($is_western_name_order) {
2475
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2476
    } else {
2477
        $orderby = 'ORDER BY user.lastname, user.firstname';
2478
    }
2479
2480
    if ($sessionId) {
2481
        $session_info = api_get_session_info($sessionId);
2482
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2483
        //not showing coaches
2484
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2485
                FROM $t_posts post , $t_users user, $t_session_rel_user scu, $t_qualify qualify
2486
                WHERE poster_id = user.id
2487
                    AND post.poster_id = qualify.user_id
2488
                    AND user.id = scu.user_id
2489
                    AND scu.status<>'2'
2490
                    AND scu.user_id NOT IN ($user_to_avoid)
2491
                    AND qualify.thread_id = ".intval($thread_id)."
2492
                    AND post.thread_id = ".intval($thread_id)."
2493
                    AND scu.session_id = $sessionId
2494
                    AND scu.c_id = ".$course_id." AND
2495
                    qualify.c_id = $course_id AND
2496
                    post.c_id = $course_id
2497
                $orderby ";
2498
    } else {
2499
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2500
                FROM $t_posts post,
2501
                     $t_qualify qualify,
2502
                     $t_users user,
2503
                     $t_course_user course_user
2504
                WHERE
2505
                     post.poster_id = user.id
2506
                     AND post.poster_id = qualify.user_id
2507
                     AND user.id = course_user.user_id
2508
                     AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
2509
                     AND qualify.thread_id = ".intval($thread_id)."
2510
                     AND post.thread_id = ".intval($thread_id)."
2511
                     AND course_user.status not in('1')
2512
                     AND course_user.c_id = $course_id
2513
                     AND qualify.c_id = $course_id
2514
                     AND post.c_id = $course_id
2515
                 $orderby ";
2516
    }
2517
    $result = Database::query($sql);
2518
2519
    return $result;
2520
}
2521
2522
/**
2523
 * This function retrieves forum thread users not qualify.
2524
 *
2525
 * @param   int Thread ID
2526
 * @param   string  Course DB name (optional)
2527
 *
2528
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2529
 *
2530
 * @author   Jhon Hinojosa<[email protected]>,
2531
 *
2532
 * @version oct 2008, dokeos 1.8
2533
 */
2534
function get_thread_users_not_qualify($thread_id)
2535
{
2536
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2537
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2538
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2539
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2540
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2541
2542
    $is_western_name_order = api_is_western_name_order();
2543
    if ($is_western_name_order) {
2544
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2545
    } else {
2546
        $orderby = 'ORDER BY user.lastname, user.firstname';
2547
    }
2548
2549
    $course_id = api_get_course_int_id();
2550
2551
    $sql1 = "SELECT user_id FROM  $t_qualify
2552
             WHERE c_id = $course_id AND thread_id = '".$thread_id."'";
2553
    $result1 = Database::query($sql1);
2554
    $cad = '';
2555
    while ($row = Database::fetch_array($result1)) {
2556
        $cad .= $row['user_id'].',';
2557
    }
2558
    if ($cad == '') {
2559
        $cad = '0';
2560
    } else {
2561
        $cad = substr($cad, 0, strlen($cad) - 1);
2562
    }
2563
2564
    if (api_get_session_id()) {
2565
        $session_info = api_get_session_info(api_get_session_id());
2566
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2567
        //not showing coaches
2568
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2569
                FROM $t_posts post , $t_users user, $t_session_rel_user session_rel_user_rel_course
2570
                WHERE poster_id = user.id
2571
                    AND user.id NOT IN (".$cad.")
2572
                    AND user.id = session_rel_user_rel_course.user_id
2573
                    AND session_rel_user_rel_course.status<>'2'
2574
                    AND session_rel_user_rel_course.user_id NOT IN ($user_to_avoid)
2575
                    AND post.thread_id = ".intval($thread_id)."
2576
                    AND session_id = ".api_get_session_id()."
2577
                    AND session_rel_user_rel_course.c_id = $course_id AND post.c_id = $course_id $orderby ";
2578
    } else {
2579
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2580
                FROM $t_posts post, $t_users user,$t_course_user course_user
2581
                WHERE post.poster_id = user.id
2582
                AND user.id NOT IN (".$cad.")
2583
                AND user.id = course_user.user_id
2584
                AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
2585
                AND post.thread_id = ".intval($thread_id)."
2586
                AND course_user.status not in('1')
2587
                AND course_user.c_id = $course_id AND post.c_id = $course_id  $orderby";
2588
    }
2589
    $result = Database::query($sql);
2590
2591
    return $result;
2592
}
2593
2594
/**
2595
 * This function retrieves all the information of a given forum_id.
2596
 *
2597
 * @param $forum_id integer that indicates the forum
2598
 *
2599
 * @return array returns
2600
 *
2601
 * @author Patrick Cool <[email protected]>, Ghent University
2602
 *
2603
 * @version february 2006, dokeos 1.8
2604
 *
2605
 * @deprecated this functionality is now moved to get_forums($forum_id)
2606
 */
2607
function get_forum_information($forum_id, $courseId = 0)
2608
{
2609
    $table_forums = Database::get_course_table(TABLE_FORUM);
2610
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2611
    $courseId = empty($courseId) ? api_get_course_int_id() : intval($courseId);
2612
    $forum_id = intval($forum_id);
2613
2614
    $sql = "SELECT *
2615
            FROM $table_forums forums
2616
            INNER JOIN $table_item_property item_properties
2617
            ON (forums.c_id = item_properties.c_id)
2618
            WHERE
2619
                item_properties.tool = '".TOOL_FORUM."' AND
2620
                item_properties.ref = '".$forum_id."' AND
2621
                forums.forum_id = '".$forum_id."' AND
2622
                forums.c_id = ".$courseId."
2623
            ";
2624
2625
    $result = Database::query($sql);
2626
    $row = Database::fetch_array($result, 'ASSOC');
2627
    $row['approval_direct_post'] = 0;
2628
    // We can't anymore change this option, so it should always be activated.
2629
2630
    return $row;
2631
}
2632
2633
/**
2634
 * This function retrieves all the information of a given forumcategory id.
2635
 *
2636
 * @param $cat_id integer that indicates the forum
2637
 *
2638
 * @return array returns if there are category or bool returns if there aren't category
2639
 *
2640
 * @author Patrick Cool <[email protected]>, Ghent University
2641
 *
2642
 * @version february 2006, dokeos 1.8
2643
 */
2644
function get_forumcategory_information($cat_id)
2645
{
2646
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
2647
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2648
2649
    $course_id = api_get_course_int_id();
2650
    $sql = "SELECT *
2651
            FROM $table_categories forumcategories 
2652
            INNER JOIN $table_item_property item_properties
2653
            ON (forumcategories.c_id = item_properties.c_id)
2654
            WHERE
2655
                forumcategories.c_id = $course_id AND
2656
                item_properties.c_id = $course_id AND
2657
                item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
2658
                item_properties.ref='".Database::escape_string($cat_id)."' AND
2659
                forumcategories.cat_id='".Database::escape_string($cat_id)."'";
2660
    $result = Database::query($sql);
2661
    $row = Database::fetch_array($result);
2662
2663
    return $row;
2664
}
2665
2666
/**
2667
 * This function counts the number of forums inside a given category.
2668
 *
2669
 * @param int $cat_id the id of the forum category
2670
 *
2671
 * @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return the number
2672
 *      of visible forums, $countinvisible=1 would return the number of visible and invisible forums
2673
 *
2674
 * @return int the number of forums inside the given category
2675
 *
2676
 * @author Patrick Cool <[email protected]>, Ghent University
2677
 *
2678
 * @version february 2006, dokeos 1.8
2679
 */
2680
function count_number_of_forums_in_category($cat_id)
2681
{
2682
    $table_forums = Database::get_course_table(TABLE_FORUM);
2683
    $course_id = api_get_course_int_id();
2684
    $cat_id = (int) $cat_id;
2685
    $sql = "SELECT count(*) AS number_of_forums
2686
            FROM $table_forums
2687
            WHERE c_id = $course_id AND forum_category = $cat_id";
2688
    $result = Database::query($sql);
2689
    $row = Database::fetch_array($result);
2690
2691
    return $row['number_of_forums'];
2692
}
2693
2694
/**
2695
 * This function update a thread.
2696
 *
2697
 * @param array $values - The form Values
2698
 */
2699
function updateThread($values)
2700
{
2701
    if (!api_is_allowed_to_edit()) {
2702
        return '';
2703
    }
2704
2705
    $logInfo = [
2706
        'tool' => TOOL_FORUM,
2707
        'tool_id' => $values['forum_id'],
2708
        'tool_id_detail' => $values['thread_id'],
2709
        'action' => 'edit-thread',
2710
        'action_details' => 'thread',
2711
        'info' => $values['thread_title'],
2712
    ];
2713
    Event::registerLog($logInfo);
2714
2715
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
2716
    $courseId = api_get_course_int_id();
2717
    $courseCode = api_get_course_id();
2718
    $sessionId = api_get_session_id();
2719
2720
    // Simple update + set gradebook values to null
2721
    $params = [
2722
        'thread_title' => $values['thread_title'],
2723
        'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
2724
    ];
2725
    $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2726
    Database::update($threadTable, $params, $where);
2727
2728
    $id = $values['thread_id'];
2729
    $linkInfo = GradebookUtils::isResourceInCourseGradebook(
2730
        $courseCode,
2731
        LINK_FORUM_THREAD,
2732
        $id,
2733
        $sessionId
2734
    );
2735
    $linkId = $linkInfo['id'];
2736
    $em = Database::getManager();
2737
    $gradebookLink = null;
2738
    if (!empty($linkId)) {
2739
        $gradebookLink = $em->getRepository('ChamiloCoreBundle:GradebookLink')->find($linkId);
2740
    }
2741
2742
    // values 1 or 0
2743
    $check = isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : false;
2744
    if ($check) {
2745
        $title = Security::remove_XSS(stripslashes($values['calification_notebook_title']));
2746
        $value = isset($values['numeric_calification']) ? intval($values['numeric_calification']) : 0;
2747
        $weight = isset($values['weight_calification']) ? floatval($values['weight_calification']) : 0;
2748
        $description = '';
2749
        // Update title
2750
        $params = [
2751
            'thread_title_qualify' => $values['calification_notebook_title'],
2752
            'thread_qualify_max' => api_float_val($values['numeric_calification']),
2753
            'thread_weight' => api_float_val($values['weight_calification']),
2754
            'thread_peer_qualify' => $values['thread_peer_qualify'],
2755
        ];
2756
        $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2757
        Database::update($threadTable, $params, $where);
2758
2759
        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...
2760
            GradebookUtils::add_resource_to_course_gradebook(
2761
                $values['category_id'],
2762
                $courseCode,
2763
                LINK_FORUM_THREAD,
2764
                $id,
2765
                $title,
2766
                $weight,
2767
                $value,
2768
                $description,
2769
                1,
2770
                $sessionId
2771
            );
2772
        } else {
2773
            if ($gradebookLink) {
2774
                $gradebookLink->setWeight($weight);
2775
                $em->persist($gradebookLink);
2776
                $em->flush();
2777
            }
2778
        }
2779
    } else {
2780
        $params = [
2781
            'thread_title_qualify' => '',
2782
            'thread_qualify_max' => 0,
2783
            'thread_weight' => 0,
2784
            'thread_peer_qualify' => 0,
2785
        ];
2786
        $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2787
        Database::update($threadTable, $params, $where);
2788
2789
        if (!empty($linkInfo)) {
2790
            if ($gradebookLink) {
2791
                $em->remove($gradebookLink);
2792
                $em->flush();
2793
            }
2794
        }
2795
    }
2796
2797
    $message = get_lang('EditPostStored').'<br />';
2798
    Display::addFlash(Display::return_message($message, 'confirmation', false));
2799
}
2800
2801
/**
2802
 * This function stores a new thread. This is done through an entry in the forum_thread table AND
2803
 * in the forum_post table because. The threads are also stored in the item_property table. (forum posts are not (yet)).
2804
 *
2805
 * @param array $current_forum
2806
 * @param array $values
2807
 * @param array $courseInfo
2808
 * @param bool  $showMessage
2809
 * @param int   $userId        Optional. The user ID
2810
 * @param int   $sessionId
2811
 *
2812
 * @return CForumThread
2813
 *
2814
 * @author Patrick Cool <[email protected]>, Ghent University
2815
 *
2816
 * @version february 2006, dokeos 1.8
2817
 */
2818
function store_thread(
2819
    $current_forum,
2820
    $values,
2821
    $courseInfo = [],
2822
    $showMessage = true,
2823
    $userId = 0,
2824
    $sessionId = 0
2825
) {
2826
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
2827
    $userId = $userId ?: api_get_user_id();
2828
    $course_id = $courseInfo['real_id'];
2829
    $courseCode = $courseInfo['code'];
2830
    $groupId = api_get_group_id();
2831
    $groupInfo = GroupManager::get_group_properties($groupId);
2832
    $sessionId = $sessionId ?: api_get_session_id();
2833
2834
    $em = Database::getManager();
2835
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2836
    $upload_ok = 1;
2837
    $has_attachment = false;
2838
2839
    if (!empty($_FILES['user_upload']['name'])) {
2840
        $upload_ok = process_uploaded_file($_FILES['user_upload']);
2841
        $has_attachment = true;
2842
    }
2843
2844
    if (!$upload_ok) {
2845
        if ($showMessage) {
2846
            Display::addFlash(
2847
                Display::return_message(
2848
                    get_lang('UplNoFileUploaded'),
2849
                    'error',
2850
                    false
2851
                )
2852
            );
2853
        }
2854
2855
        return null;
2856
    }
2857
2858
    $post_date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
2859
    $visible = 1;
2860
    if ($current_forum['approval_direct_post'] == '1' && !api_is_allowed_to_edit(null, true)) {
2861
        $visible = 0; // The post has not been approved yet.
2862
    }
2863
    $clean_post_title = $values['post_title'];
2864
2865
    $forum = $em->find('ChamiloCourseBundle:CForumForum', $values['forum_id']);
2866
2867
    // We first store an entry in the forum_thread table because the thread_id is used in the forum_post table.
2868
    $lastThread = new CForumThread();
2869
    $lastThread
2870
        ->setCId($course_id)
2871
        ->setThreadTitle($clean_post_title)
2872
        ->setForum($forum)
2873
        ->setThreadPosterId($userId)
2874
        ->setThreadPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2875
        ->setThreadDate($post_date)
2876
        ->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

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

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

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

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

4524
            $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...
4525
            send_mail($row, $forumInfo, get_thread_information($post_info['forum_id'], $post_info['thread_id']), $post_info);
4526
        }
4527
    } elseif ($content == 'thread') {
4528
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4529
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
4530
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4531
                WHERE
4532
                    posts.c_id = $course_id AND
4533
                    mailcue.c_id = $course_id AND
4534
                    posts.thread_id = $id AND
4535
                    posts.post_notification = '1' AND
4536
                    mailcue.thread_id = $id AND
4537
                    users.user_id = posts.poster_id AND
4538
                    users.active = 1
4539
                GROUP BY users.email";
4540
        $result = Database::query($sql);
4541
        while ($row = Database::fetch_array($result)) {
4542
            $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

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

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

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

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

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