Test Failed
Push — master ( 482637...7bef58 )
by Julito
33:32
created

count_number_of_user_in_course()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CourseBundle\Entity\CForumPost;
5
use Chamilo\CourseBundle\Entity\CForumThread;
6
use Chamilo\UserBundle\Entity\User;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, User. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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

636
                /** @scrutinizer ignore-type */ $last_id,
Loading history...
637
                'ForumCategoryAdded',
638
                api_get_user_id()
639
            );
640
            api_set_default_visibility(
641
                $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

641
                /** @scrutinizer ignore-type */ $last_id,
Loading history...
642
                TOOL_FORUM_CATEGORY,
643
                0,
644
                $courseInfo
645
            );
646
        }
647
        $return_message = get_lang('ForumCategoryAdded');
648
    }
649
650
    if ($showMessage) {
651
        Display::addFlash(Display::return_message($return_message, 'confirmation'));
652
    }
653
654
    return $last_id;
655
}
656
657
/**
658
 * This function stores the forum in the database. The new forum is added to the end.
659
 *
660
 * @param array $values
661
 * @param array $courseInfo
662
 * @param bool  $returnId
663
 *
664
 * @return string language variable
665
 *
666
 * @author Patrick Cool <[email protected]>, Ghent University
667
 *
668
 * @version february 2006, dokeos 1.8
669
 */
670
function store_forum($values, $courseInfo = [], $returnId = false)
671
{
672
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
673
    $course_id = $courseInfo['real_id'];
674
    $session_id = api_get_session_id();
675
    $group_id = api_get_group_id();
676
    if (isset($values['group_id']) && !empty($values['group_id'])) {
677
        $group_id = $values['group_id'];
678
    }
679
    $groupInfo = [];
680
    if (!empty($group_id)) {
681
        $groupInfo = GroupManager::get_group_properties($group_id);
682
    }
683
684
    $table_forums = Database::get_course_table(TABLE_FORUM);
685
686
    // Find the max forum_order for the given category. The new forum is added at the end => max cat_order + &
687
    if (is_null($values['forum_category'])) {
688
        $new_max = null;
689
    } else {
690
        $sql = "SELECT MAX(forum_order) as sort_max
691
                FROM $table_forums
692
                WHERE
693
                    c_id = $course_id AND
694
                    forum_category='".Database::escape_string($values['forum_category'])."'";
695
        $result = Database::query($sql);
696
        $row = Database::fetch_array($result);
697
        $new_max = $row['sort_max'] + 1;
698
    }
699
700
    // Forum images
701
    $has_attachment = false;
702
    $image_moved = true;
703
    if (!empty($_FILES['picture']['name'])) {
704
        $upload_ok = process_uploaded_file($_FILES['picture']);
705
        $has_attachment = true;
706
    }
707
708
    // Remove existing picture if it was requested.
709
    if (!empty($_POST['remove_picture'])) {
710
        delete_forum_image($values['forum_id']);
711
    }
712
713
    $new_file_name = '';
714
    if (isset($upload_ok)) {
715
        if ($has_attachment) {
716
            $course_dir = $courseInfo['path'].'/upload/forum/images';
717
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
718
            $updir = $sys_course_path.$course_dir;
719
            // Try to add an extension to the file if it hasn't one.
720
            $new_file_name = add_ext_on_mime(
721
                Database::escape_string($_FILES['picture']['name']),
722
                $_FILES['picture']['type']
723
            );
724
            if (!filter_extension($new_file_name)) {
725
                //Display::addFlash(Display::return_message(get_lang('UplUnableToSaveFileFilteredExtension'), 'error'));
726
                $image_moved = false;
727
            } else {
728
                $file_extension = explode('.', $_FILES['picture']['name']);
729
                $file_extension = strtolower($file_extension[sizeof($file_extension) - 1]);
730
                $new_file_name = uniqid('').'.'.$file_extension;
731
                $new_path = $updir.'/'.$new_file_name;
732
                $result = @move_uploaded_file($_FILES['picture']['tmp_name'], $new_path);
733
                // Storing the attachments if any
734
                if ($result) {
735
                    $image_moved = true;
736
                }
737
            }
738
        }
739
    }
740
741
    if (isset($values['forum_id'])) {
742
        // Storing after edition.
743
        $params = [
744
            'forum_title' => $values['forum_title'],
745
            'forum_comment' => isset($values['forum_comment']) ? $values['forum_comment'] : null,
746
            'forum_category' => isset($values['forum_category']) ? $values['forum_category'] : null,
747
            'allow_anonymous' => isset($values['allow_anonymous_group']['allow_anonymous']) ? $values['allow_anonymous_group']['allow_anonymous'] : null,
748
            'allow_edit' => isset($values['students_can_edit_group']['students_can_edit']) ? $values['students_can_edit_group']['students_can_edit'] : null,
749
            'approval_direct_post' => isset($values['approval_direct_group']['approval_direct']) ? $values['approval_direct_group']['approval_direct'] : null,
750
            'allow_attachments' => isset($values['allow_attachments_group']['allow_attachments']) ? $values['allow_attachments_group']['allow_attachments'] : null,
751
            'allow_new_threads' => isset($values['allow_new_threads_group']['allow_new_threads']) ? $values['allow_new_threads_group']['allow_new_threads'] : null,
752
            'default_view' => isset($values['default_view_type_group']['default_view_type']) ? $values['default_view_type_group']['default_view_type'] : null,
753
            'forum_of_group' => isset($values['group_forum']) ? $values['group_forum'] : null,
754
            '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,
755
            'moderated' => $values['moderated']['moderated'],
756
            'start_time' => !empty($values['start_time']) ? api_get_utc_datetime($values['start_time']) : null,
757
            'end_time' => !empty($values['end_time']) ? api_get_utc_datetime($values['end_time']) : null,
758
            'session_id' => $session_id,
759
            'lp_id' => isset($values['lp_id']) ? intval($values['lp_id']) : 0,
760
        ];
761
762
        if (isset($upload_ok)) {
763
            if ($has_attachment) {
764
                $params['forum_image'] = $new_file_name;
765
            }
766
        }
767
768
        if (isset($values['remove_picture']) && $values['remove_picture'] == 1) {
769
            $params['forum_image'] = '';
770
            delete_forum_image($values['forum_id']);
771
        }
772
773
        Database::update(
774
            $table_forums,
775
            $params,
776
            ['c_id = ? AND forum_id = ?' => [$course_id, $values['forum_id']]]
777
        );
778
779
        api_item_property_update(
780
            $courseInfo,
781
            TOOL_FORUM,
782
            Database::escape_string($values['forum_id']),
783
            'ForumUpdated',
784
            api_get_user_id(),
785
            $groupInfo
786
        );
787
788
        $return_message = get_lang('ForumEdited');
789
        $forumId = $values['forum_id'];
790
    } else {
791
        if ($image_moved) {
792
            $new_file_name = isset($new_file_name) ? $new_file_name : '';
793
        }
794
        $params = [
795
            'c_id' => $course_id,
796
            'forum_title' => $values['forum_title'],
797
            'forum_image' => $new_file_name,
798
            'forum_comment' => isset($values['forum_comment']) ? $values['forum_comment'] : null,
799
            'forum_category' => isset($values['forum_category']) ? $values['forum_category'] : null,
800
            'allow_anonymous' => isset($values['allow_anonymous_group']['allow_anonymous']) ? $values['allow_anonymous_group']['allow_anonymous'] : null,
801
            'allow_edit' => isset($values['students_can_edit_group']['students_can_edit']) ? $values['students_can_edit_group']['students_can_edit'] : null,
802
            'approval_direct_post' => isset($values['approval_direct_group']['approval_direct']) ? $values['approval_direct_group']['approval_direct'] : null,
803
            'allow_attachments' => isset($values['allow_attachments_group']['allow_attachments']) ? $values['allow_attachments_group']['allow_attachments'] : null,
804
            'allow_new_threads' => isset($values['allow_new_threads_group']['allow_new_threads']) ? $values['allow_new_threads_group']['allow_new_threads'] : null,
805
            'default_view' => isset($values['default_view_type_group']['default_view_type']) ? $values['default_view_type_group']['default_view_type'] : null,
806
            'forum_of_group' => isset($values['group_forum']) ? $values['group_forum'] : null,
807
            '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,
808
            'moderated' => isset($values['moderated']['moderated']) ? (int) $values['moderated']['moderated'] : 0,
809
            'start_time' => !empty($values['start_time']) ? api_get_utc_datetime($values['start_time']) : null,
810
            'end_time' => !empty($values['end_time']) ? api_get_utc_datetime($values['end_time']) : null,
811
            'forum_order' => isset($new_max) ? $new_max : null,
812
            'session_id' => $session_id,
813
            'lp_id' => isset($values['lp_id']) ? intval($values['lp_id']) : 0,
814
            'locked' => 0,
815
            'forum_id' => 0,
816
        ];
817
818
        $forumId = Database::insert($table_forums, $params);
819
        if ($forumId > 0) {
820
            $sql = "UPDATE $table_forums SET forum_id = iid WHERE iid = $forumId";
821
            Database::query($sql);
822
823
            api_item_property_update(
824
                $courseInfo,
825
                TOOL_FORUM,
826
                $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

826
                /** @scrutinizer ignore-type */ $forumId,
Loading history...
827
                'ForumAdded',
828
                api_get_user_id(),
829
                $groupInfo
830
            );
831
832
            api_set_default_visibility(
833
                $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

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

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

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

2720
        ->setThreadSticky(/** @scrutinizer ignore-type */ isset($values['thread_sticky']) ? $values['thread_sticky'] : 0)
Loading history...
2721
        ->setThreadTitleQualify(
2722
            isset($values['calification_notebook_title']) ? $values['calification_notebook_title'] : null
2723
        )
2724
        ->setThreadQualifyMax(isset($values['numeric_calification']) ? (int) $values['numeric_calification'] : 0)
2725
        ->setThreadWeight(isset($values['weight_calification']) ? (int) $values['weight_calification'] : 0)
2726
        ->setThreadPeerQualify(isset($values['thread_peer_qualify']) ? (bool) $values['thread_peer_qualify'] : false)
2727
        ->setSessionId($sessionId)
2728
        ->setLpItemId(isset($values['lp_item_id']) ? (int) $values['lp_item_id'] : 0)
2729
        ->setThreadId(0)
2730
        ->setLocked(0)
2731
    ;
2732
2733
    $em->persist($lastThread);
2734
    $em->flush();
2735
2736
    // Add option gradebook qualify.
2737
    if (isset($values['thread_qualify_gradebook']) &&
2738
        1 == $values['thread_qualify_gradebook']
2739
    ) {
2740
        // Add function gradebook.
2741
        $resourcename = stripslashes($values['calification_notebook_title']);
2742
        GradebookUtils::add_resource_to_course_gradebook(
2743
            $values['category_id'],
2744
            $courseCode,
2745
            5,
2746
            $lastThread->getIid(),
2747
            $resourcename,
2748
            $values['weight_calification'],
2749
            $values['numeric_calification'],
2750
            '',
2751
            0,
2752
            $sessionId
2753
        );
2754
    }
2755
2756
    if ($lastThread->getIid()) {
2757
        $lastThread->setThreadId($lastThread->getIid());
2758
2759
        $em->merge($lastThread);
2760
        $em->flush();
2761
2762
        api_item_property_update(
2763
            $courseInfo,
2764
            TOOL_FORUM_THREAD,
2765
            $lastThread->getIid(),
2766
            'ForumThreadAdded',
2767
            $userId,
2768
            $groupInfo,
2769
            null,
2770
            null,
2771
            null,
2772
            $sessionId
2773
        );
2774
2775
        // If the forum properties tell that the posts have to be approved
2776
        // we have to put the whole thread invisible,
2777
        // because otherwise the students will see the thread and not the post
2778
        // in the thread.
2779
        // We also have to change $visible because the post itself has to be
2780
        // visible in this case (otherwise the teacher would have
2781
        // to make the thread visible AND the post.
2782
        // Default behaviour
2783
        api_set_default_visibility(
2784
            $lastThread->getIid(),
2785
            TOOL_FORUM_THREAD,
2786
            $groupId,
2787
            $courseInfo,
2788
            $sessionId,
2789
            $userId
2790
        );
2791
2792
        if ($visible == 0) {
2793
            api_item_property_update(
2794
                $courseInfo,
2795
                TOOL_FORUM_THREAD,
2796
                $lastThread->getIid(),
2797
                'invisible',
2798
                $userId,
2799
                $groupInfo
2800
            );
2801
            $visible = 1;
2802
        }
2803
    }
2804
2805
    // We now store the content in the table_post table.
2806
    $lastPost = new CForumPost();
2807
    $lastPost
2808
        ->setCId($course_id)
2809
        ->setPostTitle($clean_post_title)
2810
        ->setPostText($values['post_text'])
2811
        ->setThreadId($lastThread->getIid())
2812
        ->setForumId($values['forum_id'])
2813
        ->setPosterId($userId)
2814
        ->setPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2815
        ->setPostDate($post_date)
2816
        ->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

2816
        ->setPostNotification(/** @scrutinizer ignore-type */ isset($values['post_notification']) ? (int) $values['post_notification'] : null)
Loading history...
2817
        ->setPostParentId(null)
2818
        ->setVisible($visible)
2819
        ->setPostId(0)
2820
        ->setStatus(CForumPost::STATUS_VALIDATED);
2821
2822
    if ($current_forum['moderated']) {
2823
        $lastPost->setStatus(
2824
            api_is_course_admin() ? CForumPost::STATUS_VALIDATED : CForumPost::STATUS_WAITING_MODERATION
2825
        );
2826
    }
2827
2828
    $em->persist($lastPost);
2829
    $em->flush();
2830
2831
    $lastPostId = $lastPost->getIid();
2832
2833
    if ($lastPostId) {
2834
        $lastPost->setPostId($lastPostId);
2835
        $em->merge($lastPost);
2836
        $em->flush();
2837
    }
2838
2839
    // Update attached files
2840
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
2841
        foreach ($_POST['file_ids'] as $key => $id) {
2842
            editAttachedFile(
2843
                [
2844
                    'comment' => $_POST['file_comments'][$key],
2845
                    'post_id' => $lastPostId,
2846
                ],
2847
                $id
2848
            );
2849
        }
2850
    }
2851
2852
    // Now we have to update the thread table to fill the thread_last_post
2853
    // field (so that we know when the thread has been updated for the last time).
2854
    $sql = "UPDATE $table_threads
2855
            SET thread_last_post = '".Database::escape_string($lastPostId)."'
2856
            WHERE
2857
                c_id = $course_id AND
2858
                thread_id='".Database::escape_string($lastThread->getIid())."'";
2859
    $result = Database::query($sql);
2860
    $message = get_lang('NewThreadStored');
2861
2862
    // Overwrite default message.
2863
    if ($current_forum['moderated'] &&
2864
        !api_is_allowed_to_edit(null, true)
2865
    ) {
2866
        $message = get_lang('MessageHasToBeApproved');
2867
    }
2868
2869
    // Storing the attachments if any.
2870
    if ($has_attachment) {
2871
        // Try to add an extension to the file if it hasn't one.
2872
        $new_file_name = add_ext_on_mime(
2873
            stripslashes($_FILES['user_upload']['name']),
2874
            $_FILES['user_upload']['type']
2875
        );
2876
2877
        if (!filter_extension($new_file_name)) {
2878
            if ($showMessage) {
2879
                Display::addFlash(Display::return_message(
2880
                    get_lang('UplUnableToSaveFileFilteredExtension'),
2881
                    'error'
2882
                ));
2883
            }
2884
        } else {
2885
            if ($result) {
2886
                add_forum_attachment_file(
2887
                    isset($values['file_comment']) ? $values['file_comment'] : null,
2888
                    $lastPostId
2889
                );
2890
            }
2891
        }
2892
    } else {
2893
        $message .= '<br />';
2894
    }
2895
2896
    if ($current_forum['approval_direct_post'] == '1' &&
2897
        !api_is_allowed_to_edit(null, true)
2898
    ) {
2899
        $message .= get_lang('MessageHasToBeApproved').'<br />';
2900
        $message .= get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2901
            get_lang('Forum').'</a><br />';
2902
    } else {
2903
        $message .= get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2904
            get_lang('Forum').'</a><br />';
2905
        $message .= get_lang('ReturnTo').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&thread='.$lastThread->getIid().'">'.
2906
            get_lang('Message').'</a>';
2907
    }
2908
    $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...
2909
    $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
2910
2911
    if ($my_post_notification == 1) {
2912
        set_notification('thread', $lastThread->getIid(), true);
2913
    }
2914
2915
    send_notification_mails(
2916
        $current_forum['forum_id'],
2917
        $lastThread->getIid(),
2918
        $reply_info,
2919
        $courseInfo['code']
2920
    );
2921
2922
    Session::erase('formelements');
2923
    Session::erase('origin');
2924
    Session::erase('breadcrumbs');
2925
    Session::erase('addedresource');
2926
    Session::erase('addedresourceid');
2927
2928
    if ($showMessage) {
2929
        Display::addFlash(Display::return_message($message, 'success', false));
2930
    }
2931
2932
    return $lastThread->getIid();
2933
}
2934
2935
/**
2936
 * This function displays the form that is used to add a post. This can be a new thread or a reply.
2937
 *
2938
 * @param array  $current_forum
2939
 * @param array  $forum_setting
2940
 * @param string $action        is the parameter that determines if we are
2941
 *                              1. newthread: adding a new thread (both empty) => No I-frame
2942
 *                              2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete thread (if enabled)
2943
 *                              3. replymessage: Replying to a message ($action =replymessage) => I-frame with the complete thread (if enabled)
2944
 *                              (I first thought to put and I-frame with the message only)
2945
 *                              4. quote: Quoting a message ($action= quotemessage) => I-frame with the complete thread (if enabled).
2946
 *                              The message will be in the reply. (I first thought not to put an I-frame here)
2947
 *
2948
 * @return FormValidator
2949
 *
2950
 * @author Patrick Cool <[email protected]>, Ghent University
2951
 *
2952
 * @version february 2006, dokeos 1.8
2953
 */
2954
function show_add_post_form($current_forum, $forum_setting, $action, $id = '', $form_values = '')
2955
{
2956
    $_user = api_get_user_info();
2957
    $action = isset($action) ? Security::remove_XSS($action) : '';
2958
    $myThread = isset($_GET['thread']) ? (int) $_GET['thread'] : '';
2959
    $forumId = isset($_GET['forum']) ? (int) $_GET['forum'] : '';
2960
    $my_post = isset($_GET['post']) ? (int) $_GET['post'] : '';
2961
2962
    $url = api_get_self().'?'.http_build_query([
2963
        'action' => $action,
2964
        'forum' => $forumId,
2965
        'thread' => $myThread,
2966
        'post' => $my_post,
2967
    ]).'&'.api_get_cidreq();
2968
2969
    $form = new FormValidator(
2970
        'thread',
2971
        'post',
2972
        $url
2973
    );
2974
2975
    $form->setConstants(['forum' => '5']);
2976
2977
    // Setting the form elements.
2978
    $form->addElement('hidden', 'forum_id', $forumId);
2979
    $form->addElement('hidden', 'thread_id', $myThread);
2980
    $form->addElement('hidden', 'action', $action);
2981
2982
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2983
    if ($current_forum['allow_anonymous'] == 1 && !isset($_user['user_id'])) {
2984
        $form->addElement('text', 'poster_name', get_lang('Name'));
2985
        $form->applyFilter('poster_name', 'html_filter');
2986
    }
2987
2988
    $form->addElement('text', 'post_title', get_lang('Title'));
2989
    $form->addHtmlEditor(
2990
        'post_text',
2991
        get_lang('Text'),
2992
        true,
2993
        false,
2994
        api_is_allowed_to_edit(null, true) ? [
2995
            'ToolbarSet' => 'Forum',
2996
            'Width' => '100%',
2997
            'Height' => '300',
2998
        ] : [
2999
            'ToolbarSet' => 'ForumStudent',
3000
            'Width' => '100%',
3001
            'Height' => '300',
3002
            'UserStatus' => 'student',
3003
        ]
3004
    );
3005
3006
    $form->addRule('post_text', get_lang('ThisFieldIsRequired'), 'required');
3007
    $iframe = null;
3008
    $myThread = Security::remove_XSS($myThread);
3009
    if ($forum_setting['show_thread_iframe_on_reply'] && $action != 'newthread' && !empty($myThread)) {
3010
        $iframe = "<iframe style=\"border: 1px solid black\" src=\"iframe_thread.php?".api_get_cidreq()."&forum=".intval($forumId)."&thread=".$myThread."#".Security::remove_XSS($my_post)."\" width=\"100%\"></iframe>";
3011
    }
3012
    if (!empty($iframe)) {
3013
        $form->addElement('label', get_lang('Thread'), $iframe);
3014
    }
3015
3016
    if (Gradebook::is_active() &&
3017
        (api_is_course_admin() || api_is_session_general_coach() || api_is_course_tutor()) && !($myThread)
3018
    ) {
3019
        $form->addElement('advanced_settings', 'advanced_params', get_lang('AdvancedParameters'));
3020
        $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3021
3022
        // Thread qualify
3023
        if (Gradebook::is_active()) {
3024
            //Loading gradebook select
3025
            GradebookUtils::load_gradebook_select_in_tool($form);
3026
            $form->addElement(
3027
                'checkbox',
3028
                'thread_qualify_gradebook',
3029
                '',
3030
                get_lang('QualifyThreadGradebook'),
3031
                'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"'
3032
            );
3033
        } else {
3034
            $form->addElement('hidden', 'thread_qualify_gradebook', false);
3035
        }
3036
3037
        $form->addElement('html', '<div id="options_field" style="display:none">');
3038
        $form->addElement('text', 'numeric_calification', get_lang('QualificationNumeric'));
3039
        $form->applyFilter('numeric_calification', 'html_filter');
3040
        $form->addElement('text', 'calification_notebook_title', get_lang('TitleColumnGradebook'));
3041
        $form->applyFilter('calification_notebook_title', 'html_filter');
3042
3043
        $form->addElement(
3044
            'text',
3045
            'weight_calification',
3046
            get_lang('QualifyWeight'),
3047
            ['value' => '0.00', 'onfocus' => "javascript: this.select();"]
3048
        );
3049
        $form->applyFilter('weight_calification', 'html_filter');
3050
3051
        $group = [];
3052
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('Yes'), 1);
3053
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('No'), 0);
3054
        $form->addGroup(
3055
            $group,
3056
            '',
3057
            [
3058
                get_lang('ForumThreadPeerScoring'),
3059
                get_lang('ForumThreadPeerScoringComment'),
3060
            ]
3061
        );
3062
        $form->addElement('html', '</div>');
3063
        $form->addElement('html', '</div>');
3064
    }
3065
3066
    if ($action == 'newthread') {
3067
        Skill::addSkillsToForm($form, ITEM_TYPE_FORUM_THREAD, 0);
3068
    }
3069
3070
    if ($forum_setting['allow_sticky'] && api_is_allowed_to_edit(null, true) && $action == 'newthread') {
3071
        $form->addElement('checkbox', 'thread_sticky', '', get_lang('StickyPost'));
3072
    }
3073
3074
    if (in_array($action, ['quote', 'replymessage'])) {
3075
        $form->addFile('user_upload[]', get_lang('Attachment'));
3076
        $form->addButton(
3077
            'add_attachment',
3078
            get_lang('AddAttachment'),
3079
            'paperclip',
3080
            'default',
3081
            'default',
3082
            null,
3083
            ['id' => 'reply-add-attachment']
3084
        );
3085
    } else {
3086
        $form->addFile('user_upload', get_lang('Attachment'));
3087
    }
3088
3089
    // Setting the class and text of the form title and submit button.
3090
    if ($action == 'quote') {
3091
        $form->addButtonCreate(get_lang('QuoteMessage'), 'SubmitPost');
3092
    } elseif ($action == 'replythread') {
3093
        $form->addButtonCreate(get_lang('ReplyToThread'), 'SubmitPost');
3094
    } elseif ($action == 'replymessage') {
3095
        $form->addButtonCreate(get_lang('ReplyToMessage'), 'SubmitPost');
3096
    } else {
3097
        $form->addButtonCreate(get_lang('CreateThread'), 'SubmitPost');
3098
    }
3099
3100
    if (!empty($form_values)) {
3101
        $defaults['post_title'] = prepare4display($form_values['post_title']);
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...
3102
        $defaults['post_text'] = prepare4display($form_values['post_text']);
3103
        $defaults['post_notification'] = (int) $form_values['post_notification'];
3104
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
3105
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
3106
    } else {
3107
        $defaults['thread_peer_qualify'] = 0;
3108
    }
3109
3110
    // If we are quoting a message we have to retrieve the information of the post we are quoting so that
3111
    // we can add this as default to the textarea.
3112
    if (($action == 'quote' || $action == 'replymessage') && isset($my_post)) {
3113
        // We also need to put the parent_id of the post in a hidden form when
3114
        // we are quoting or replying to a message (<> reply to a thread !!!)
3115
        $form->addHidden('post_parent_id', intval($my_post));
3116
3117
        // If we are replying or are quoting then we display a default title.
3118
        $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

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

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

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

Loading history...
3122
            $posterName = $posterInfo['complete_name'];
3123
        }
3124
        $defaults['post_title'] = get_lang('ReplyShort').api_html_entity_decode($values['post_title'], ENT_QUOTES);
3125
        // When we are quoting a message then we have to put that message into the wysiwyg editor.
3126
        // Note: The style has to be hardcoded here because using class="quote" didn't work.
3127
        if ($action == 'quote') {
3128
            $defaults['post_text'] = '<div>&nbsp;</div>
3129
                <div style="margin: 5px;">
3130
                    <div style="font-size: 90%; font-style: italic;">'.
3131
                        get_lang('Quoting').' '.$posterName.':</div>
3132
                        <div style="color: #006600; font-size: 90%;  font-style: italic; background-color: #FAFAFA; border: #D1D7DC 1px solid; padding: 3px;">'.
3133
                            prepare4display($values['post_text']).'
3134
                        </div>
3135
                    </div>
3136
                <div>&nbsp;</div>
3137
                <div>&nbsp;</div>
3138
            ';
3139
        }
3140
    }
3141
3142
    $form->setDefaults(isset($defaults) ? $defaults : []);
3143
3144
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3145
    $form->addRule('post_title', get_lang('ThisFieldIsRequired'), 'required');
3146
    if ($current_forum['allow_anonymous'] == 1 && !isset($_user['user_id'])) {
3147
        $form->addRule(
3148
            'poster_name',
3149
            get_lang('ThisFieldIsRequired'),
3150
            'required'
3151
        );
3152
    }
3153
3154
    // Validation or display
3155
    if ($form->validate()) {
3156
        $check = Security::check_token('post');
3157
        if ($check) {
3158
            $values = $form->exportValues();
3159
            if (isset($values['thread_qualify_gradebook']) &&
3160
                $values['thread_qualify_gradebook'] == '1' &&
3161
                empty($values['weight_calification'])
3162
            ) {
3163
                Display::addFlash(
3164
                    Display::return_message(
3165
                        get_lang('YouMustAssignWeightOfQualification').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
3166
                        'error',
3167
                        false
3168
                    )
3169
                );
3170
3171
                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...
3172
            }
3173
3174
            switch ($action) {
3175
                case 'newthread':
3176
                    $myThread = store_thread($current_forum, $values);
3177
                    Skill::saveSkills($form, ITEM_TYPE_FORUM_THREAD, $myThread);
3178
                    break;
3179
                case 'quote':
3180
                case 'replythread':
3181
                case 'replymessage':
3182
                    store_reply($current_forum, $values);
3183
3184
                    break;
3185
            }
3186
3187
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
3188
                [
3189
                    'forum' => $forumId,
3190
                    'thread' => $myThread,
3191
                ]
3192
            );
3193
3194
            Security::clear_token();
3195
            header('Location: '.$url);
3196
            exit;
3197
        }
3198
    } else {
3199
        $token = Security::get_token();
3200
        $form->addElement('hidden', 'sec_token');
3201
        $form->setConstants(['sec_token' => $token]);
3202
3203
        // Delete from $_SESSION forum attachment from other posts
3204
        // and keep only attachments for new post
3205
        clearAttachedFiles(FORUM_NEW_POST);
3206
        // Get forum attachment ajax table to add it to form
3207
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $current_forum['forum_id']);
3208
        $ajaxHtml = $attachmentAjaxTable;
3209
        $form->addElement('html', $ajaxHtml);
3210
3211
        return $form;
3212
    }
3213
}
3214
3215
/**
3216
 * @param array $threadInfo
3217
 * @param int   $user_id
3218
 * @param int   $thread_id
3219
 * @param int   $thread_qualify
3220
 * @param int   $qualify_time
3221
 * @param int   $session_id
3222
 *
3223
 * @return array optional
3224
 *
3225
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3226
 *
3227
 * @version October 2008, dokeos  1.8.6
3228
 */
3229
function saveThreadScore(
3230
    $threadInfo,
3231
    $user_id,
3232
    $thread_id,
3233
    $thread_qualify = 0,
3234
    $qualify_time,
3235
    $session_id = 0
3236
) {
3237
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3238
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3239
3240
    $course_id = api_get_course_int_id();
3241
    $session_id = intval($session_id);
3242
    $currentUserId = api_get_user_id();
3243
3244
    if ($user_id == strval(intval($user_id)) &&
3245
        $thread_id == strval(intval($thread_id)) &&
3246
        $thread_qualify == strval(floatval($thread_qualify))
3247
    ) {
3248
        // Testing
3249
        $sql = "SELECT thread_qualify_max FROM $table_threads
3250
                WHERE c_id = $course_id AND thread_id=".$thread_id;
3251
        $res_string = Database::query($sql);
3252
        $row_string = Database::fetch_array($res_string);
3253
        if ($thread_qualify <= $row_string[0]) {
3254
            if ($threadInfo['thread_peer_qualify'] == 0) {
3255
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3256
                        WHERE
3257
                            c_id = $course_id AND
3258
                            user_id = $user_id AND
3259
                            thread_id = ".$thread_id;
3260
            } else {
3261
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3262
                        WHERE
3263
                            c_id = $course_id AND
3264
                            user_id = $user_id AND
3265
                            qualify_user_id = $currentUserId AND
3266
                            thread_id = ".$thread_id;
3267
            }
3268
3269
            $result = Database::query($sql);
3270
            $row = Database::fetch_array($result);
3271
3272
            if ($row[0] == 0) {
3273
                $sql = "INSERT INTO $table_threads_qualify (c_id, user_id, thread_id,qualify,qualify_user_id,qualify_time,session_id)
3274
                        VALUES (".$course_id.", '".$user_id."','".$thread_id."',".(float) $thread_qualify.", '".$currentUserId."','".$qualify_time."','".$session_id."')";
3275
                Database::query($sql);
3276
                $insertId = Database::insert_id();
3277
                if ($insertId) {
3278
                    $sql = "UPDATE $table_threads_qualify SET id = iid
3279
                            WHERE iid = $insertId";
3280
                    Database::query($sql);
3281
                }
3282
3283
                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...
3284
            } else {
3285
                saveThreadScoreHistory(
3286
                    '1',
3287
                    $course_id,
3288
                    $user_id,
3289
                    $thread_id
3290
                );
3291
3292
                // Update
3293
                $sql = "UPDATE $table_threads_qualify
3294
                        SET
3295
                            qualify = '".$thread_qualify."',
3296
                            qualify_time = '".$qualify_time."'
3297
                        WHERE
3298
                            c_id = $course_id AND
3299
                            user_id=".$user_id." AND
3300
                            thread_id=".$thread_id." AND
3301
                            qualify_user_id = $currentUserId
3302
                        ";
3303
                Database::query($sql);
3304
3305
                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...
3306
            }
3307
        } else {
3308
            return null;
3309
        }
3310
    }
3311
}
3312
3313
/**
3314
 * This function shows qualify.
3315
 *
3316
 * @param string $option    contains the information of option to run
3317
 * @param int    $user_id   contains the information the current user id
3318
 * @param int    $thread_id contains the information the current thread id
3319
 *
3320
 * @return int qualify
3321
 *             <code> $option=1 obtained the qualification of the current thread</code>
3322
 *
3323
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3324
 *
3325
 * @version October 2008, dokeos  1.8.6
3326
 */
3327
function showQualify($option, $user_id, $thread_id)
3328
{
3329
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3330
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3331
3332
    $course_id = api_get_course_int_id();
3333
    $user_id = intval($user_id);
3334
    $thread_id = intval($thread_id);
3335
3336
    if (empty($user_id) || empty($thread_id)) {
3337
        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...
3338
    }
3339
3340
    $sql = '';
3341
    switch ($option) {
3342
        case 1:
3343
            $sql = "SELECT qualify FROM $table_threads_qualify
3344
                    WHERE
3345
                        c_id = $course_id AND
3346
                        user_id=".$user_id." AND
3347
                        thread_id=".$thread_id;
3348
            break;
3349
        case 2:
3350
            $sql = "SELECT thread_qualify_max FROM $table_threads
3351
                    WHERE c_id = $course_id AND thread_id=".$thread_id;
3352
            break;
3353
    }
3354
3355
    if (!empty($sql)) {
3356
        $rs = Database::query($sql);
3357
        $row = Database::fetch_array($rs);
3358
3359
        return $row[0];
3360
    }
3361
3362
    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...
3363
}
3364
3365
/**
3366
 * This function gets qualify historical.
3367
 *
3368
 * @param int  $user_id   contains the information the current user id
3369
 * @param int  $thread_id contains the information the current thread id
3370
 * @param bool $opt       contains the information of option to run
3371
 *
3372
 * @return array
3373
 *
3374
 * @author Christian Fasanando <[email protected]>,
3375
 * @author Isaac Flores <[email protected]>,
3376
 *
3377
 * @version October 2008, dokeos  1.8.6
3378
 */
3379
function getThreadScoreHistory($user_id, $thread_id, $opt)
3380
{
3381
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3382
    $course_id = api_get_course_int_id();
3383
3384
    if ($opt == 'false') {
3385
        $sql = "SELECT * FROM $table_threads_qualify_log
3386
                WHERE
3387
                    c_id = $course_id AND
3388
                    thread_id='".Database::escape_string($thread_id)."' AND
3389
                    user_id='".Database::escape_string($user_id)."'
3390
                ORDER BY qualify_time";
3391
    } else {
3392
        $sql = "SELECT * FROM $table_threads_qualify_log
3393
                WHERE
3394
                    c_id = $course_id AND
3395
                    thread_id='".Database::escape_string($thread_id)."' AND
3396
                    user_id='".Database::escape_string($user_id)."'
3397
                ORDER BY qualify_time DESC";
3398
    }
3399
    $rs = Database::query($sql);
3400
    $log = [];
3401
    while ($row = Database::fetch_array($rs, 'ASSOC')) {
3402
        $log[] = $row;
3403
    }
3404
3405
    return $log;
3406
}
3407
3408
/**
3409
 * This function stores qualify historical.
3410
 *
3411
 * @param bool contains the information of option to run
3412
 * @param string contains the information the current course id
3413
 * @param int contains the information the current forum id
3414
 * @param int contains the information the current user id
3415
 * @param int contains the information the current thread id
3416
 * @param int contains the information the current qualify
3417
 * @param string $option
3418
 * @param int    $course_id
3419
 * @param int    $user_id
3420
 * @param int    $thread_id
3421
 *
3422
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3423
 *
3424
 * @version October 2008, dokeos  1.8.6
3425
 */
3426
function saveThreadScoreHistory(
3427
    $option,
3428
    $course_id,
3429
    $user_id,
3430
    $thread_id
3431
) {
3432
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3433
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3434
3435
    $course_id = intval($course_id);
3436
    $qualify_user_id = api_get_user_id();
3437
3438
    if ($user_id == strval(intval($user_id)) &&
3439
        $thread_id == strval(intval($thread_id)) && $option == 1
3440
    ) {
3441
        // Extract information of thread_qualify.
3442
        $sql = "SELECT qualify, qualify_time
3443
                FROM $table_threads_qualify
3444
                WHERE
3445
                    c_id = $course_id AND
3446
                    user_id = ".$user_id." AND
3447
                    thread_id = ".$thread_id." AND
3448
                    qualify_user_id = $qualify_user_id
3449
                ";
3450
        $rs = Database::query($sql);
3451
        $row = Database::fetch_array($rs);
3452
3453
        // Insert thread_historical.
3454
        $sql = "INSERT INTO $table_threads_qualify_log (c_id, user_id, thread_id, qualify, qualify_user_id,qualify_time,session_id)
3455
                VALUES(".$course_id.", '".$user_id."','".$thread_id."',".(float) $row[0].", '".$qualify_user_id."','".$row[1]."','')";
3456
        Database::query($sql);
3457
3458
        $insertId = Database::insert_id();
3459
        if ($insertId) {
3460
            $sql = "UPDATE $table_threads_qualify_log SET id = iid
3461
                    WHERE iid = $insertId";
3462
            Database::query($sql);
3463
        }
3464
    }
3465
}
3466
3467
/**
3468
 * This function shows current thread qualify .
3469
 *
3470
 * @param int $threadId
3471
 * @param int $sessionId
3472
 * @param int $userId
3473
 *
3474
 * @return array or null if is empty
3475
 *
3476
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3477
 *
3478
 * @version December 2008, dokeos  1.8.6
3479
 */
3480
function current_qualify_of_thread($threadId, $sessionId, $userId)
3481
{
3482
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3483
3484
    $course_id = api_get_course_int_id();
3485
    $currentUserId = api_get_user_id();
3486
    $sessionId = intval($sessionId);
3487
    $threadId = intval($threadId);
3488
3489
    $sql = "SELECT qualify FROM $table_threads_qualify
3490
            WHERE
3491
                c_id = $course_id AND
3492
                thread_id = $threadId AND
3493
                session_id = $sessionId AND
3494
                qualify_user_id = $currentUserId AND
3495
                user_id = $userId
3496
            ";
3497
    $res = Database::query($sql);
3498
    $row = Database::fetch_array($res, 'ASSOC');
3499
3500
    return $row['qualify'];
3501
}
3502
3503
/**
3504
 * This function stores a reply in the forum_post table.
3505
 * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date).
3506
 *
3507
 * @param array $current_forum
3508
 * @param array $values
3509
 * @param int   $courseId      Optional
3510
 * @param int   $userId        Optional
3511
 *
3512
 * @return array
3513
 *
3514
 * @author Patrick Cool <[email protected]>, Ghent University
3515
 *
3516
 * @version february 2006, dokeos 1.8
3517
 */
3518
function store_reply($current_forum, $values, $courseId = 0, $userId = 0)
3519
{
3520
    $courseId = !empty($courseId) ? $courseId : api_get_course_int_id();
3521
    $_course = api_get_course_info_by_id($courseId);
3522
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3523
    $post_date = api_get_utc_datetime();
3524
    $userId = $userId ?: api_get_user_id();
3525
3526
    if ($current_forum['allow_anonymous'] == 1) {
3527
        if (api_is_anonymous() && empty($userId)) {
3528
            $userId = api_get_anonymous_id();
3529
        }
3530
    }
3531
3532
    if (empty($userId)) {
3533
        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 array.
Loading history...
3534
    }
3535
3536
    if ($current_forum['approval_direct_post'] == '1' &&
3537
        !api_is_allowed_to_edit(null, true)
3538
    ) {
3539
        $visible = 0;
3540
    } else {
3541
        $visible = 1;
3542
    }
3543
3544
    $upload_ok = 1;
3545
    $return = [];
3546
3547
    if ($upload_ok) {
3548
        // We first store an entry in the forum_post table.
3549
        $new_post_id = Database::insert(
3550
            $table_posts,
3551
            [
3552
                'c_id' => $courseId,
3553
                'post_title' => $values['post_title'],
3554
                'post_text' => isset($values['post_text']) ? ($values['post_text']) : null,
3555
                'thread_id' => $values['thread_id'],
3556
                'forum_id' => $values['forum_id'],
3557
                'poster_id' => $userId,
3558
                'post_id' => 0,
3559
                'post_date' => $post_date,
3560
                'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : null,
3561
                'post_parent_id' => isset($values['post_parent_id']) ? $values['post_parent_id'] : null,
3562
                'visible' => $visible,
3563
            ]
3564
        );
3565
3566
        if ($new_post_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $new_post_id of type integer|false 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...
3567
            $sql = "UPDATE $table_posts SET post_id = iid WHERE iid = $new_post_id";
3568
            Database::query($sql);
3569
3570
            $values['new_post_id'] = $new_post_id;
3571
            $message = get_lang('ReplyAdded');
3572
3573
            if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3574
                foreach ($_POST['file_ids'] as $key => $id) {
3575
                    editAttachedFile(
3576
                        [
3577
                            'comment' => $_POST['file_comments'][$key],
3578
                            'post_id' => $new_post_id,
3579
                        ],
3580
                        $id
3581
                    );
3582
                }
3583
            }
3584
3585
            // Update the thread.
3586
            updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
3587
3588
            // Update the forum.
3589
            api_item_property_update(
3590
                $_course,
3591
                TOOL_FORUM,
3592
                $values['forum_id'],
3593
                'NewMessageInForum',
3594
                $userId
3595
            );
3596
3597
            // Insert post
3598
            api_item_property_update(
3599
                $_course,
3600
                TOOL_FORUM_POST,
3601
                $new_post_id,
3602
                'NewPost',
3603
                $userId
3604
            );
3605
3606
            if ($current_forum['approval_direct_post'] == '1' &&
3607
                !api_is_allowed_to_edit(null, true)
3608
            ) {
3609
                $message .= '<br />'.get_lang('MessageHasToBeApproved').'<br />';
3610
            }
3611
3612
            if ($current_forum['moderated'] &&
3613
                !api_is_allowed_to_edit(null, true)
3614
            ) {
3615
                $message .= '<br />'.get_lang('MessageHasToBeApproved').'<br />';
3616
            }
3617
3618
            // Setting the notification correctly.
3619
            $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
3620
            if ($my_post_notification == 1) {
3621
                set_notification('thread', $values['thread_id'], true);
3622
            }
3623
3624
            send_notification_mails(
3625
                $values['forum_id'],
3626
                $values['thread_id'],
3627
                $values
3628
            );
3629
            add_forum_attachment_file('', $new_post_id);
3630
        }
3631
3632
        Session::erase('formelements');
3633
        Session::erase('origin');
3634
        Session::erase('breadcrumbs');
3635
        Session::erase('addedresource');
3636
        Session::erase('addedresourceid');
3637
3638
        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...
3639
    } else {
3640
        Display::addFlash(
3641
            Display::return_message(
3642
                get_lang('UplNoFileUploaded').' '.get_lang('UplSelectFileFirst'),
3643
                'error'
3644
            )
3645
        );
3646
    }
3647
3648
    return $return;
3649
}
3650
3651
/**
3652
 * This function displays the form that is used to edit a post. This can be a new thread or a reply.
3653
 *
3654
 * @param array contains all the information about the current post
3655
 * @param array contains all the information about the current thread
3656
 * @param array contains all info about the current forum (to check if attachments are allowed)
3657
 * @param array contains the default values to fill the form
3658
 *
3659
 * @author Patrick Cool <[email protected]>, Ghent University
3660
 *
3661
 * @version february 2006, dokeos 1.8
3662
 */
3663
function show_edit_post_form(
3664
    $forum_setting,
3665
    $current_post,
3666
    $current_thread,
3667
    $current_forum,
3668
    $form_values = '',
3669
    $id_attach = 0
3670
) {
3671
    // Initialize the object.
3672
    $form = new FormValidator(
3673
        'edit_post',
3674
        'post',
3675
        api_get_self().'?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&post='.intval($_GET['post'])
3676
    );
3677
    $form->addElement('header', get_lang('EditPost'));
3678
    // Setting the form elements.
3679
    $form->addElement('hidden', 'post_id', $current_post['post_id']);
3680
    $form->addElement('hidden', 'thread_id', $current_thread['thread_id']);
3681
    $form->addElement('hidden', 'id_attach', $id_attach);
3682
3683
    if (empty($current_post['post_parent_id'])) {
3684
        $form->addElement('hidden', 'is_first_post_of_thread', '1');
3685
    }
3686
3687
    $form->addElement('text', 'post_title', get_lang('Title'));
3688
    $form->applyFilter('post_title', 'html_filter');
3689
    $form->addElement(
3690
        'html_editor',
3691
        'post_text',
3692
        get_lang('Text'),
3693
        null,
3694
        api_is_allowed_to_edit(null, true) ? [
3695
            'ToolbarSet' => 'Forum',
3696
            'Width' => '100%',
3697
            'Height' => '400',
3698
        ] : [
3699
            'ToolbarSet' => 'ForumStudent',
3700
            'Width' => '100%',
3701
            'Height' => '400',
3702
            'UserStatus' => 'student',
3703
        ]
3704
    );
3705
    $form->addRule('post_text', get_lang('ThisFieldIsRequired'), 'required');
3706
3707
    $form->addButtonAdvancedSettings('advanced_params');
3708
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3709
3710
    if ($current_forum['moderated'] && api_is_allowed_to_edit(null, true)) {
3711
        $group = [];
3712
        $group[] = $form->createElement(
3713
            'radio',
3714
            'status',
3715
            null,
3716
            get_lang('Validated'),
3717
            1
3718
        );
3719
        $group[] = $form->createElement(
3720
            'radio',
3721
            'status',
3722
            null,
3723
            get_lang('WaitingModeration'),
3724
            2
3725
        );
3726
        $group[] = $form->createElement(
3727
            'radio',
3728
            'status',
3729
            null,
3730
            get_lang('Rejected'),
3731
            3
3732
        );
3733
        $form->addGroup($group, 'status', get_lang('Status'));
3734
    }
3735
3736
    $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...
3737
3738
    if ($forum_setting['allow_post_notification']) {
3739
        $form->addElement(
3740
            'checkbox',
3741
            'post_notification',
3742
            '',
3743
            get_lang('NotifyByEmail').' ('.$current_post['email'].')'
3744
        );
3745
    }
3746
3747
    if ($forum_setting['allow_sticky'] &&
3748
        api_is_allowed_to_edit(null, true) &&
3749
        empty($current_post['post_parent_id'])
3750
    ) {
3751
        // The sticky checkbox only appears when it is the first post of a thread.
3752
        $form->addElement('checkbox', 'thread_sticky', '', get_lang('StickyPost'));
3753
        if ($current_thread['thread_sticky'] == 1) {
3754
            $defaults['thread_sticky'] = true;
3755
        }
3756
    }
3757
3758
    $form->addElement('html', '</div>');
3759
3760
    $form->addFile('user_upload[]', get_lang('Attachment'));
3761
    $form->addButton(
3762
        'add_attachment',
3763
        get_lang('AddAttachment'),
3764
        'paperclip',
3765
        'default',
3766
        'default',
3767
        null,
3768
        ['id' => 'reply-add-attachment']
3769
    );
3770
3771
    $form->addButtonUpdate(get_lang('Modify'), 'SubmitPost');
3772
3773
    // Setting the default values for the form elements.
3774
    $defaults['post_title'] = $current_post['post_title'];
3775
    $defaults['post_text'] = $current_post['post_text'];
3776
3777
    if ($current_post['post_notification'] == 1) {
3778
        $defaults['post_notification'] = true;
3779
    }
3780
3781
    if (!empty($form_values)) {
3782
        $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
3783
        $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
3784
    }
3785
3786
    $form->setDefaults($defaults);
3787
3788
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3789
3790
    $form->addRule('post_title', get_lang('ThisFieldIsRequired'), 'required');
3791
3792
    // Validation or display
3793
    if ($form->validate()) {
3794
        $values = $form->exportValues();
3795
        store_edit_post($current_forum, $values);
3796
    } else {
3797
        // Delete from $_SESSION forum attachment from other posts
3798
        clearAttachedFiles($current_post['post_id']);
3799
        // Get forum attachment ajax table to add it to form
3800
        $fileData = getAttachmentsAjaxTable($current_post['post_id'], $current_forum['forum_id']);
3801
        $form->addElement('html', $fileData);
3802
        $form->display();
3803
    }
3804
}
3805
3806
/**
3807
 * This function stores the edit of a post in the forum_post table.
3808
 *
3809
 * @param array
3810
 *
3811
 * @author Patrick Cool <[email protected]>, Ghent University
3812
 *
3813
 * @version february 2006, dokeos 1.8
3814
 */
3815
function store_edit_post($forumInfo, $values)
3816
{
3817
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
3818
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3819
    $course_id = api_get_course_int_id();
3820
3821
    //check if this post is the first of the thread
3822
    // First we check if the change affects the thread and if so we commit
3823
    // the changes (sticky and post_title=thread_title are relevant).
3824
3825
    $posts = getPosts($forumInfo, $values['thread_id']);
3826
    $first_post = null;
3827
    if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
3828
        $first_post = $posts[0];
3829
    }
3830
3831
    if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
3832
        // Simple edit
3833
        $params = [
3834
            'thread_title' => $values['post_title'],
3835
            'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
3836
        ];
3837
        $where = ['c_id = ? AND thread_id = ?' => [$course_id, $values['thread_id']]];
3838
        Database::update($threadTable, $params, $where);
3839
    }
3840
3841
    $status = '';
3842
    $updateStatus = false;
3843
    if ($forumInfo['moderated']) {
3844
        if (api_is_allowed_to_edit(null, true)) {
3845
            $status = $values['status']['status'];
3846
            $updateStatus = true;
3847
        } else {
3848
            $status = CForumPost::STATUS_WAITING_MODERATION;
3849
            $updateStatus = true;
3850
        }
3851
    }
3852
3853
    // Update the post_title and the post_text.
3854
    $params = [
3855
        'post_title' => $values['post_title'],
3856
        'post_text' => $values['post_text'],
3857
        'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : '',
3858
    ];
3859
3860
    if ($updateStatus) {
3861
        $params['status'] = $status;
3862
    }
3863
3864
    $where = ['c_id = ? AND post_id = ?' => [$course_id, $values['post_id']]];
3865
    Database::update($table_posts, $params, $where);
3866
3867
    // Update attached files
3868
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3869
        foreach ($_POST['file_ids'] as $key => $id) {
3870
            editAttachedFile(
3871
                [
3872
                    'comment' => $_POST['file_comments'][$key],
3873
                    'post_id' => $values['post_id'],
3874
                ],
3875
                $id
3876
            );
3877
        }
3878
    }
3879
3880
    if (!empty($values['remove_attach'])) {
3881
        delete_attachment($values['post_id']);
3882
    }
3883
3884
    if (empty($values['id_attach'])) {
3885
        add_forum_attachment_file(
3886
            isset($values['file_comment']) ? $values['file_comment'] : null,
3887
            $values['post_id']
3888
        );
3889
    } else {
3890
        edit_forum_attachment_file(
3891
            isset($values['file_comment']) ? $values['file_comment'] : null,
3892
            $values['post_id'],
3893
            $values['id_attach']
3894
        );
3895
    }
3896
3897
    $message = get_lang('EditPostStored').'<br />';
3898
    $message .= get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&">'.get_lang('Forum').'</a><br />';
3899
    $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>';
3900
3901
    Session::erase('formelements');
3902
    Session::erase('origin');
3903
    Session::erase('breadcrumbs');
3904
    Session::erase('addedresource');
3905
    Session::erase('addedresourceid');
3906
3907
    echo Display::return_message($message, 'confirmation', false);
3908
}
3909
3910
/**
3911
 * This function displays the firstname and lastname of the user as a link to the user tool.
3912
 *
3913
 * @param string names
3914
 * @ in_title : title tootip
3915
 *
3916
 * @return string HTML
3917
 *
3918
 * @author Patrick Cool <[email protected]>, Ghent University
3919
 *
3920
 * @version february 2006, dokeos 1.8
3921
 */
3922
function display_user_link($user_id, $name, $origin = '', $in_title = '')
3923
{
3924
    if ($user_id != 0) {
3925
        $userInfo = api_get_user_info($user_id);
3926
3927
        return '<a href="'.$userInfo['profile_url'].'">'.Security::remove_XSS($userInfo['complete_name']).'</a>';
3928
    } else {
3929
        return $name.' ('.get_lang('Anonymous').')';
3930
    }
3931
}
3932
3933
/**
3934
 * This function displays the user image from the profile, with a link to the user's details.
3935
 *
3936
 * @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...
3937
 * @param   string  User's name
3938
 * @param   string  the origin where the forum is called (example : learnpath)
3939
 *
3940
 * @return string An HTML with the anchor and the image of the user
3941
 *
3942
 * @author Julio Montoya <[email protected]>
3943
 */
3944
function display_user_image($user_id, $name, $origin = '')
3945
{
3946
    $userInfo = api_get_user_info($user_id);
3947
    $link = '<a href="'.(!empty($origin) ? '#' : $userInfo['profile_url']).'" '.(!empty($origin) ? 'target="_self"' : '').'>';
3948
3949
    if ($user_id != 0) {
3950
        return $link.'<img src="'.$userInfo['avatar'].'"  alt="'.$name.'"  title="'.$name.'" /></a>';
3951
    } else {
3952
        return $link.Display::return_icon('unknown.jpg', $name).'</a>';
3953
    }
3954
}
3955
3956
/**
3957
 * The thread view counter gets increased every time someone looks at the thread.
3958
 *
3959
 * @param int
3960
 *
3961
 * @author Patrick Cool <[email protected]>, Ghent University
3962
 *
3963
 * @version february 2006, dokeos 1.8
3964
 */
3965
function increase_thread_view($thread_id)
3966
{
3967
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3968
    $course_id = api_get_course_int_id();
3969
3970
    $sql = "UPDATE $table_threads 
3971
            SET thread_views = thread_views + 1
3972
            WHERE 
3973
                c_id = $course_id AND  
3974
                thread_id = '".intval($thread_id)."'";
3975
    Database::query($sql);
3976
}
3977
3978
/**
3979
 * The relies counter gets increased every time somebody replies to the thread.
3980
 *
3981
 * @author Patrick Cool <[email protected]>, Ghent University
3982
 *
3983
 * @version february 2006, dokeos 1.8
3984
 *
3985
 * @param string $lastPostId
3986
 * @param string $post_date
3987
 */
3988
function updateThreadInfo($thread_id, $lastPostId, $post_date)
3989
{
3990
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3991
    $course_id = api_get_course_int_id();
3992
    $sql = "UPDATE $table_threads SET 
3993
            thread_replies = thread_replies+1,
3994
            thread_last_post = '".Database::escape_string($lastPostId)."',
3995
            thread_date = '".Database::escape_string($post_date)."'
3996
            WHERE 
3997
                c_id = $course_id AND  
3998
                thread_id='".Database::escape_string($thread_id)."'"; // this needs to be cleaned first
3999
    Database::query($sql);
4000
}
4001
4002
/**
4003
 * This function is used to find all the information about what's new in the forum tool.
4004
 *
4005
 * @author Patrick Cool <[email protected]>, Ghent University
4006
 *
4007
 * @version february 2006, dokeos 1.8
4008
 */
4009
function get_whats_new()
4010
{
4011
    $userId = api_get_user_id();
4012
    $course_id = api_get_course_int_id();
4013
4014
    if (empty($course_id) || empty($userId)) {
4015
        return false;
4016
    }
4017
4018
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4019
    $tracking_last_tool_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4020
4021
    $tool = TOOL_FORUM;
4022
    $lastForumAccess = Session::read('last_forum_access');
4023
4024
    if (!$lastForumAccess) {
4025
        $sql = "SELECT * FROM $tracking_last_tool_access
4026
                WHERE
4027
                    access_user_id = $userId AND
4028
                    c_id = $course_id AND
4029
                    access_tool = '".Database::escape_string($tool)."'";
4030
        $result = Database::query($sql);
4031
        $row = Database::fetch_array($result);
4032
        Session::write('last_forum_access', $row['access_date']);
4033
        $lastForumAccess = $row['access_date'];
4034
    }
4035
4036
    $whatsNew = Session::read('whatsnew_post_info');
4037
4038
    if (!$whatsNew) {
4039
        if ($lastForumAccess != '') {
4040
            $postInfo = [];
4041
            $sql = "SELECT * FROM $table_posts
4042
                    WHERE
4043
                        c_id = $course_id AND
4044
                        visible = 1 AND                        
4045
                        post_date > '".Database::escape_string($lastForumAccess)."'";
4046
            $result = Database::query($sql);
4047
            while ($row = Database::fetch_array($result)) {
4048
                $postInfo[$row['forum_id']][$row['thread_id']][$row['post_id']] = $row['post_date'];
4049
            }
4050
            Session::write('whatsnew_post_info', $postInfo);
4051
        }
4052
    }
4053
}
4054
4055
/**
4056
 * This function approves a post = change.
4057
 *
4058
 * @param int    $post_id the id of the post that will be deleted
4059
 * @param string $action  make the post visible or invisible
4060
 *
4061
 * @return string language variable
4062
 *
4063
 * @author Patrick Cool <[email protected]>, Ghent University
4064
 *
4065
 * @version february 2006, dokeos 1.8
4066
 */
4067
function approve_post($post_id, $action)
4068
{
4069
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4070
    $course_id = api_get_course_int_id();
4071
4072
    if ($action == 'invisible') {
4073
        $visibility_value = 0;
4074
    }
4075
4076
    if ($action == 'visible') {
4077
        $visibility_value = 1;
4078
        handle_mail_cue('post', $post_id);
4079
    }
4080
4081
    $sql = "UPDATE $table_posts SET
4082
            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...
4083
            WHERE c_id = $course_id AND post_id='".Database::escape_string($post_id)."'";
4084
    $return = Database::query($sql);
4085
4086
    if ($return) {
4087
        return 'PostVisibilityChanged';
4088
    }
4089
}
4090
4091
/**
4092
 * This function retrieves all the unapproved messages for a given forum
4093
 * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see this).
4094
 *
4095
 * @param $forum_id the forum where we want to know the unapproved messages of
4096
 *
4097
 * @return array returns
4098
 *
4099
 * @author Patrick Cool <[email protected]>, Ghent University
4100
 *
4101
 * @version february 2006, dokeos 1.8
4102
 */
4103
function get_unaproved_messages($forum_id)
4104
{
4105
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4106
    $course_id = api_get_course_int_id();
4107
4108
    $return_array = [];
4109
    $sql = "SELECT DISTINCT thread_id FROM $table_posts
4110
            WHERE 
4111
                c_id = $course_id AND 
4112
                forum_id='".Database::escape_string($forum_id)."' AND 
4113
                visible='0' ";
4114
    $result = Database::query($sql);
4115
    while ($row = Database::fetch_array($result)) {
4116
        $return_array[] = $row['thread_id'];
4117
    }
4118
4119
    return $return_array;
4120
}
4121
4122
/**
4123
 * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
4124
 * was added to a given thread.
4125
 *
4126
 * @param array reply information
4127
 *
4128
 * @author Patrick Cool <[email protected]>, Ghent University
4129
 *
4130
 * @version february 2006, dokeos 1.8
4131
 */
4132
function send_notification_mails($forumId, $thread_id, $reply_info)
4133
{
4134
    $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4135
4136
    // First we need to check if
4137
    // 1. the forum category is visible
4138
    // 2. the forum is visible
4139
    // 3. the thread is visible
4140
    // 4. the reply is visible (=when there is)
4141
    $current_thread = get_thread_information($forumId, $thread_id);
4142
    $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

4142
    $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...
4143
4144
    $current_forum_category = null;
4145
    if (isset($current_forum['forum_category'])) {
4146
        $current_forum_category = get_forumcategory_information(
4147
            $current_forum['forum_category']
4148
        );
4149
    }
4150
4151
    if ($current_thread['visibility'] == '1' &&
4152
        $current_forum['visibility'] == '1' &&
4153
        ($current_forum_category && $current_forum_category['visibility'] == '1') &&
4154
        $current_forum['approval_direct_post'] != '1'
4155
    ) {
4156
        $send_mails = true;
4157
    } else {
4158
        $send_mails = false;
4159
    }
4160
4161
    // The forum category, the forum, the thread and the reply are visible to the user
4162
    if ($send_mails) {
4163
        if (!empty($forumId)) {
4164
            send_notifications($forumId, $thread_id);
4165
        }
4166
    } else {
4167
        $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4168
        if (isset($current_forum['forum_id'])) {
4169
            $sql = "SELECT * FROM $table_notification
4170
                    WHERE
4171
                        c_id = ".api_get_course_int_id()." AND
4172
                        (
4173
                            forum_id = '".intval($current_forum['forum_id'])."' OR
4174
                            thread_id = '".intval($thread_id)."'
4175
                        ) ";
4176
4177
            $result = Database::query($sql);
4178
            $user_id = api_get_user_id();
4179
            while ($row = Database::fetch_array($result)) {
4180
                $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
4181
                        VALUES (".api_get_course_int_id().", '".intval($thread_id)."', '".intval($reply_info['new_post_id'])."', '$user_id' )";
4182
                Database::query($sql);
4183
            }
4184
        }
4185
    }
4186
}
4187
4188
/**
4189
 * This function is called whenever something is made visible because there might
4190
 * be new posts and the user might have indicated that (s)he wanted to be
4191
 * informed about the new posts by mail.
4192
 *
4193
 * @param string  Content type (post, thread, forum, forum_category)
4194
 * @param int     Item DB ID
4195
 * @param string $content
4196
 * @param int    $id
4197
 *
4198
 * @return string language variable
4199
 *
4200
 * @author Patrick Cool <[email protected]>, Ghent University
4201
 *
4202
 * @version february 2006, dokeos 1.8
4203
 */
4204
function handle_mail_cue($content, $id)
4205
{
4206
    $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4207
    $table_forums = Database::get_course_table(TABLE_FORUM);
4208
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4209
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4210
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4211
4212
    $course_id = api_get_course_int_id();
4213
4214
    /* If the post is made visible we only have to send mails to the people
4215
     who indicated that they wanted to be informed for that thread.*/
4216
    if ($content == 'post') {
4217
        // Getting the information about the post (need the thread_id).
4218
        $post_info = get_post_information($id);
4219
        $thread_id = intval($post_info['thread_id']);
4220
4221
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4222
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email
4223
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4224
                WHERE
4225
                    posts.c_id = $course_id AND
4226
                    mailcue.c_id = $course_id AND
4227
                    posts.thread_id='$thread_id'
4228
                    AND posts.post_notification='1'
4229
                    AND mailcue.thread_id='$thread_id'
4230
                    AND users.user_id=posts.poster_id
4231
                    AND users.active=1
4232
                GROUP BY users.email";
4233
4234
        $result = Database::query($sql);
4235
        while ($row = Database::fetch_array($result)) {
4236
            send_mail($row, get_thread_information($post_info['forum_id'], $post_info['thread_id']));
4237
        }
4238
    } elseif ($content == 'thread') {
4239
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4240
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
4241
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4242
                WHERE
4243
                    posts.c_id = $course_id AND
4244
                    mailcue.c_id = $course_id AND
4245
                    posts.thread_id = ".intval($id)."
4246
                    AND posts.post_notification='1'
4247
                    AND mailcue.thread_id = ".intval($id)."
4248
                    AND users.user_id=posts.poster_id
4249
                    AND users.active=1
4250
                GROUP BY users.email";
4251
        $result = Database::query($sql);
4252
        while ($row = Database::fetch_array($result)) {
4253
            send_mail($row, get_thread_information($row['forum_id'], $id));
4254
        }
4255
4256
        // Deleting the relevant entries from the mailcue.
4257
        $sql = "DELETE FROM $table_mailcue
4258
                WHERE c_id = $course_id AND thread_id='".Database::escape_string($id)."'";
4259
        Database::query($sql);
4260
    } elseif ($content == 'forum') {
4261
        $sql = "SELECT thread_id FROM $table_threads
4262
                WHERE c_id = $course_id AND forum_id='".Database::escape_string($id)."'";
4263
        $result = Database::query($sql);
4264
        while ($row = Database::fetch_array($result)) {
4265
            handle_mail_cue('thread', $row['thread_id']);
4266
        }
4267
    } elseif ($content == 'forum_category') {
4268
        $sql = "SELECT forum_id FROM $table_forums
4269
                WHERE c_id = $course_id AND forum_category ='".Database::escape_string($id)."'";
4270
        $result = Database::query($sql);
4271
        while ($row = Database::fetch_array($result)) {
4272
            handle_mail_cue('forum', $row['forum_id']);
4273
        }
4274
    } else {
4275
        return get_lang('Error');
4276
    }
4277
}
4278
4279
/**
4280
 * This function sends the mails for the mail notification.
4281
 *
4282
 * @param array
4283
 * @param array
4284
 *
4285
 * @author Patrick Cool <[email protected]>, Ghent University
4286
 *
4287
 * @version february 2006, dokeos 1.8
4288
 */
4289
function send_mail($user_info = [], $thread_information = [])
4290
{
4291
    $_course = api_get_course_info();
4292
    $user_id = api_get_user_id();
4293
    $subject = get_lang('NewForumPost').' - '.$_course['official_code'];
4294
    if (isset($thread_information) && is_array($thread_information)) {
4295
        $thread_link = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&forum='.$thread_information['forum_id'].'&thread='.$thread_information['thread_id'];
4296
    }
4297
    $email_body = get_lang('Dear').' '.api_get_person_name($user_info['firstname'], $user_info['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
4298
    $email_body .= get_lang('NewForumPost')."\n";
4299
    $email_body .= get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
4300
    $email_body .= get_lang('YouWantedToStayInformed')."<br />\n";
4301
    $email_body .= get_lang('ThreadCanBeFoundHere')." : <br /><a href=\"".$thread_link."\">".$thread_link."</a>\n";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $thread_link does not seem to be defined for all execution paths leading up to this point.
Loading history...
4302
4303
    if ($user_info['user_id'] != $user_id) {
4304
        MessageManager::send_message(
4305
            $user_info['user_id'],
4306
            $subject,
4307
            $email_body,
4308
            [],
4309
            [],
4310
            null,
4311
            null,
4312
            null,
4313
            null,
4314
            $user_id
4315
        );
4316
    }
4317
}
4318
4319
/**
4320
 * This function displays the form for moving a thread to a different (already existing) forum.
4321
 *
4322
 * @author Patrick Cool <[email protected]>, Ghent University
4323
 *
4324
 * @version february 2006, dokeos 1.8
4325
 */
4326
function move_thread_form()
4327
{
4328
    $form = new FormValidator(
4329
        'movepost',
4330
        'post',
4331
        api_get_self().'?forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
4332
    );
4333
    // The header for the form
4334
    $form->addElement('header', get_lang('MoveThread'));
4335
    // Invisible form: the thread_id
4336
    $form->addElement('hidden', 'thread_id', intval($_GET['thread']));
4337
    // the fora
4338
    $forum_categories = get_forum_categories();
4339
    $forums = get_forums();
4340
4341
    $htmlcontent = '<div class="row">
4342
        <div class="label">
4343
            <span class="form_required">*</span>'.get_lang('MoveTo').'
4344
        </div>
4345
        <div class="formw">';
4346
    $htmlcontent .= '<select name="forum">';
4347
    foreach ($forum_categories as $key => $category) {
4348
        $htmlcontent .= '<optgroup label="'.$category['cat_title'].'">';
4349
        foreach ($forums as $key => $forum) {
0 ignored issues
show
Comprehensibility Bug introduced by
$key is overwriting a variable from outer foreach loop.
Loading history...
4350
            if (isset($forum['forum_category'])) {
4351
                if ($forum['forum_category'] == $category['cat_id']) {
4352
                    $htmlcontent .= '<option value="'.$forum['forum_id'].'">'.$forum['forum_title'].'</option>';
4353
                }
4354
            }
4355
        }
4356
        $htmlcontent .= '</optgroup>';
4357
    }
4358
    $htmlcontent .= "</select>";
4359
    $htmlcontent .= '   </div>
4360
                    </div>';
4361
4362
    $form->addElement('html', $htmlcontent);
4363
4364
    // The OK button
4365
    $form->addButtonSave(get_lang('MoveThread'), 'SubmitForum');
4366
4367
    // Validation or display
4368
    if ($form->validate()) {
4369
        $values = $form->exportValues();
4370
        if (isset($_POST['forum'])) {
4371
            store_move_thread($values);
4372
        }
4373
    } else {
4374
        $form->display();
4375
    }
4376
}
4377
4378
/**
4379
 * This function displays the form for moving a post message to a different (already existing) or a new thread.
4380
 *
4381
 * @author Patrick Cool <[email protected]>, Ghent University
4382
 *
4383
 * @version february 2006, dokeos 1.8
4384
 */
4385
function move_post_form()
4386
{
4387
    $form = new FormValidator(
4388
        'movepost',
4389
        'post',
4390
        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'])
4391
    );
4392
    // The header for the form
4393
    $form->addElement('header', '', get_lang('MovePost'));
4394
4395
    // Invisible form: the post_id
4396
    $form->addElement('hidden', 'post_id', intval($_GET['post']));
4397
4398
    // Dropdown list: Threads of this forum
4399
    $threads = get_threads($_GET['forum']);
4400
    //my_print_r($threads);
4401
    $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...
4402
    foreach ($threads as $key => $value) {
4403
        $threads_list[$value['thread_id']] = $value['thread_title'];
4404
    }
4405
    $form->addElement('select', 'thread', get_lang('MoveToThread'), $threads_list);
4406
    $form->applyFilter('thread', 'html_filter');
4407
4408
    // The OK button
4409
    $form->addButtonSave(get_lang('MovePost'), 'submit');
4410
4411
    // Setting the rules
4412
    $form->addRule('thread', get_lang('ThisFieldIsRequired'), 'required');
4413
4414
    // Validation or display
4415
    if ($form->validate()) {
4416
        $values = $form->exportValues();
4417
        store_move_post($values);
4418
    } else {
4419
        $form->display();
4420
    }
4421
}
4422
4423
/**
4424
 * @param array
4425
 *
4426
 * @return string HTML language variable
4427
 *
4428
 * @author Patrick Cool <[email protected]>, Ghent University
4429
 *
4430
 * @version february 2006, dokeos 1.8
4431
 */
4432
function store_move_post($values)
4433
{
4434
    $_course = api_get_course_info();
4435
    $course_id = api_get_course_int_id();
4436
4437
    $table_forums = Database::get_course_table(TABLE_FORUM);
4438
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4439
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4440
4441
    if ($values['thread'] == '0') {
4442
        $current_post = get_post_information($values['post_id']);
4443
4444
        // Storing a new thread.
4445
        $params = [
4446
            'c_id' => $course_id,
4447
            'thread_title' => $current_post['post_title'],
4448
            'forum_id' => $current_post['forum_id'],
4449
            'thread_poster_id' => $current_post['poster_id'],
4450
            'thread_poster_name' => $current_post['poster_name'],
4451
            'thread_last_post' => $values['post_id'],
4452
            'thread_date' => $current_post['post_date'],
4453
        ];
4454
4455
        $new_thread_id = Database::insert($table_threads, $params);
4456
4457
        api_item_property_update(
4458
            $_course,
4459
            TOOL_FORUM_THREAD,
4460
            $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

4460
            /** @scrutinizer ignore-type */ $new_thread_id,
Loading history...
4461
            'visible',
4462
            $current_post['poster_id']
4463
        );
4464
4465
        // Moving the post to the newly created thread.
4466
        $sql = "UPDATE $table_posts SET thread_id='".intval($new_thread_id)."', post_parent_id = NULL
4467
                WHERE c_id = $course_id AND post_id='".intval($values['post_id'])."'";
4468
        Database::query($sql);
4469
4470
        // Resetting the parent_id of the thread to 0 for all those who had this moved post as parent.
4471
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4472
                WHERE c_id = $course_id AND post_parent_id='".intval($values['post_id'])."'";
4473
        Database::query($sql);
4474
4475
        // Updating updating the number of threads in the forum.
4476
        $sql = "UPDATE $table_forums SET forum_threads=forum_threads+1
4477
                WHERE c_id = $course_id AND forum_id='".intval($current_post['forum_id'])."'";
4478
        Database::query($sql);
4479
4480
        // Resetting the last post of the old thread and decreasing the number of replies and the thread.
4481
        $sql = "SELECT * FROM $table_posts
4482
                WHERE c_id = $course_id AND thread_id='".intval($current_post['thread_id'])."'
4483
                ORDER BY post_id DESC";
4484
        $result = Database::query($sql);
4485
        $row = Database::fetch_array($result);
4486
        $sql = "UPDATE $table_threads SET
4487
                    thread_last_post='".$row['post_id']."',
4488
                    thread_replies=thread_replies-1
4489
                WHERE
4490
                    c_id = $course_id AND
4491
                    thread_id='".intval($current_post['thread_id'])."'";
4492
        Database::query($sql);
4493
    } else {
4494
        // Moving to the chosen thread.
4495
        $sql = "SELECT thread_id FROM ".$table_posts."
4496
                WHERE c_id = $course_id AND post_id = '".$values['post_id']."' ";
4497
        $result = Database::query($sql);
4498
        $row = Database::fetch_array($result);
4499
4500
        $original_thread_id = $row['thread_id'];
4501
4502
        $sql = "SELECT thread_last_post FROM ".$table_threads."
4503
                WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
4504
4505
        $result = Database::query($sql);
4506
        $row = Database::fetch_array($result);
4507
        $thread_is_last_post = $row['thread_last_post'];
4508
        // If is this thread, update the thread_last_post with the last one.
4509
4510
        if ($thread_is_last_post == $values['post_id']) {
4511
            $sql = "SELECT post_id FROM ".$table_posts."
4512
                    WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' AND post_id <> '".$values['post_id']."'
4513
                    ORDER BY post_date DESC LIMIT 1";
4514
            $result = Database::query($sql);
4515
4516
            $row = Database::fetch_array($result);
4517
            $thread_new_last_post = $row['post_id'];
4518
4519
            $sql = "UPDATE ".$table_threads." SET thread_last_post = '".$thread_new_last_post."'
4520
                    WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
4521
            Database::query($sql);
4522
        }
4523
4524
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies-1
4525
                WHERE c_id = $course_id AND thread_id='".$original_thread_id."'";
4526
        Database::query($sql);
4527
4528
        // moving to the chosen thread
4529
        $sql = "UPDATE $table_posts SET thread_id='".intval($_POST['thread'])."', post_parent_id = NULL
4530
                WHERE c_id = $course_id AND post_id='".intval($values['post_id'])."'";
4531
        Database::query($sql);
4532
4533
        // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
4534
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4535
                WHERE c_id = $course_id AND post_parent_id='".intval($values['post_id'])."'";
4536
        Database::query($sql);
4537
4538
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies+1
4539
                WHERE c_id = $course_id AND thread_id='".intval($_POST['thread'])."'";
4540
        Database::query($sql);
4541
    }
4542
4543
    return get_lang('ThreadMoved');
4544
}
4545
4546
/**
4547
 * @param array
4548
 *
4549
 * @return string HTML language variable
4550
 *
4551
 * @author Patrick Cool <[email protected]>, Ghent University
4552
 *
4553
 * @version february 2006, dokeos 1.8
4554
 */
4555
function store_move_thread($values)
4556
{
4557
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4558
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4559
4560
    $courseId = api_get_course_int_id();
4561
    $sessionId = api_get_session_id();
4562
4563
    $forumId = intval($_POST['forum']);
4564
    $threadId = intval($_POST['thread_id']);
4565
    $forumInfo = get_forums($forumId);
4566
4567
    // Change the thread table: Setting the forum_id to the new forum.
4568
    $sql = "UPDATE $table_threads SET forum_id = $forumId
4569
            WHERE c_id = $courseId AND thread_id = $threadId";
4570
    Database::query($sql);
4571
4572
    // Changing all the posts of the thread: setting the forum_id to the new forum.
4573
    $sql = "UPDATE $table_posts SET forum_id = $forumId
4574
            WHERE c_id = $courseId AND thread_id= $threadId";
4575
    Database::query($sql);
4576
    // Fix group id, if forum is moved to a different group
4577
    if (!empty($forumInfo['to_group_id'])) {
4578
        $groupId = $forumInfo['to_group_id'];
4579
        $item = api_get_item_property_info(
4580
            $courseId,
4581
            TABLE_FORUM_THREAD,
4582
            $threadId,
4583
            $sessionId,
4584
            $groupId
4585
        );
4586
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4587
        $sessionCondition = api_get_session_condition($sessionId);
4588
4589
        if (!empty($item)) {
4590
            if ($item['to_group_id'] != $groupId) {
4591
                $sql = "UPDATE $table
4592
                    SET to_group_id = $groupId
4593
                    WHERE
4594
                      tool = '".TABLE_FORUM_THREAD."' AND
4595
                      c_id = $courseId AND
4596
                      ref = ".$item['ref']."
4597
                      $sessionCondition
4598
                ";
4599
                Database::query($sql);
4600
            }
4601
        } else {
4602
            $sql = "UPDATE $table
4603
                    SET to_group_id = $groupId
4604
                    WHERE
4605
                      tool = '".TABLE_FORUM_THREAD."' AND
4606
                      c_id = $courseId AND
4607
                      ref = ".$threadId."
4608
                      $sessionCondition
4609
            ";
4610
            Database::query($sql);
4611
        }
4612
    }
4613
4614
    return get_lang('ThreadMoved');
4615
}
4616
4617
/**
4618
 * Prepares a string for displaying by highlighting the search results inside, if any.
4619
 *
4620
 * @param string $input the input string
4621
 *
4622
 * @return string the same string with highlighted hits inside
4623
 *
4624
 * @author Patrick Cool <[email protected]>, Ghent University, February 2006 - the initial version.
4625
 * @author Ivan Tcholakov, March 2011 - adaptation for Chamilo LMS.
4626
 */
4627
function prepare4display($input)
4628
{
4629
    static $highlightcolors = ['yellow', '#33CC33', '#3399CC', '#9999FF', '#33CC33'];
4630
    static $search;
4631
4632
    if (!isset($search)) {
4633
        if (isset($_POST['search_term'])) {
4634
            $search = $_POST['search_term']; // No html at all.
4635
        } elseif (isset($_GET['search'])) {
4636
            $search = $_GET['search'];
4637
        } else {
4638
            $search = '';
4639
        }
4640
    }
4641
4642
    if (!empty($search)) {
4643
        if (strstr($search, '+')) {
4644
            $search_terms = explode('+', $search);
4645
        } else {
4646
            $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...
4647
        }
4648
        $counter = 0;
4649
        foreach ($search_terms as $key => $search_term) {
4650
            $input = api_preg_replace(
4651
                '/'.preg_quote(trim($search_term), '/').'/i',
4652
                '<span style="background-color: '.$highlightcolors[$counter].'">$0</span>',
4653
                $input
4654
            );
4655
            $counter++;
4656
        }
4657
    }
4658
4659
    // TODO: Security should be implemented outside this function.
4660
    // Change this to COURSEMANAGERLOWSECURITY or COURSEMANAGER to lower filtering and allow more styles
4661
    // (see comments of Security::remove_XSS() method to learn about other levels).
4662
4663
    return Security::remove_XSS($input, STUDENT, true);
4664
}
4665
4666
/**
4667
 * Display the search form for the forum and display the search results.
4668
 *
4669
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4670
 *
4671
 * @version march 2008, dokeos 1.8.5
4672
 */
4673
function forum_search()
4674
{
4675
    $form = new FormValidator(
4676
        'forumsearch',
4677
        'post',
4678
        'forumsearch.php?'.api_get_cidreq()
4679
    );
4680
4681
    // Setting the form elements.
4682
    $form->addElement('header', '', get_lang('ForumSearch'));
4683
    $form->addElement('text', 'search_term', get_lang('SearchTerm'), ['autofocus']);
4684
    $form->applyFilter('search_term', 'html_filter');
4685
    $form->addElement('static', 'search_information', '', get_lang('ForumSearchInformation'));
4686
    $form->addButtonSearch(get_lang('Search'));
4687
4688
    // Setting the rules.
4689
    $form->addRule('search_term', get_lang('ThisFieldIsRequired'), 'required');
4690
    $form->addRule('search_term', get_lang('TooShort'), 'minlength', 3);
4691
4692
    // Validation or display.
4693
    if ($form->validate()) {
4694
        $values = $form->exportValues();
4695
        $form->setDefaults($values);
4696
        $form->display();
4697
        // Display the search results.
4698
        display_forum_search_results(stripslashes($values['search_term']));
4699
    } else {
4700
        $form->display();
4701
    }
4702
}
4703
4704
/**
4705
 * Display the search results.
4706
 *
4707
 * @param string
4708
 * @param string $search_term
4709
 *
4710
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4711
 *
4712
 * @version march 2008, dokeos 1.8.5
4713
 */
4714
function display_forum_search_results($search_term)
4715
{
4716
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4717
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4718
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
4719
    $session_id = api_get_session_id();
4720
    $course_id = api_get_course_int_id();
4721
4722
    // Defining the search strings as an array.
4723
    if (strstr($search_term, '+')) {
4724
        $search_terms = explode('+', $search_term);
4725
    } else {
4726
        $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...
4727
    }
4728
4729
    // Search restriction.
4730
    foreach ($search_terms as $value) {
4731
        $search_restriction[] = "
4732
        (
4733
            posts.post_title LIKE '%".Database::escape_string(trim($value))."%' OR 
4734
            posts.post_text LIKE '%".Database::escape_string(trim($value))."%' 
4735
        )";
4736
    }
4737
4738
    $sessionCondition = api_get_session_condition(
4739
        $session_id,
4740
        true,
4741
        false,
4742
        'item_property.session_id'
4743
    );
4744
4745
    $sql = "SELECT posts.*
4746
            FROM $table_posts posts 
4747
            INNER JOIN $table_threads threads
4748
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
4749
            INNER JOIN $table_item_property item_property
4750
            ON (item_property.ref = threads.thread_id AND item_property.c_id = threads.c_id)
4751
            WHERE
4752
                posts.c_id = $course_id AND 
4753
                item_property.c_id = $course_id AND 
4754
                item_property.visibility = 1  
4755
                $sessionCondition AND
4756
                posts.visible = 1 AND 
4757
                item_property.tool = '".TOOL_FORUM_THREAD."' AND 
4758
                ".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 4730. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
4759
            GROUP BY posts.post_id";
4760
4761
    // Getting all the information of the forum categories.
4762
    $forum_categories_list = get_forum_categories();
4763
4764
    // Getting all the information of the forums.
4765
    $forum_list = get_forums();
4766
4767
    $result = Database::query($sql);
4768
    $search_results = [];
4769
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4770
        $forumId = $row['forum_id'];
4771
        $forumData = get_forums($forumId);
4772
        $category = isset($forum_categories_list[$forumData['forum_category']]) ? $forum_categories_list[$forumData['forum_category']] : null;
4773
        $display_result = false;
4774
        /*
4775
          We only show it when
4776
          1. forum category is visible
4777
          2. forum is visible
4778
          3. thread is visible (to do)
4779
          4. post is visible
4780
         */
4781
        if (!api_is_allowed_to_edit(null, true)) {
4782
            if (!empty($category)) {
4783
                if ($category['visibility'] == '1' && $forumData['visibility'] == '1') {
4784
                    $display_result = true;
4785
                }
4786
            } else {
4787
                if ($forumData['visible'] == '1') {
4788
                    $display_result = true;
4789
                }
4790
            }
4791
        } else {
4792
            $display_result = true;
4793
        }
4794
4795
        if ($display_result) {
4796
            $categoryName = !empty($category) ? $category['cat_title'] : '';
4797
            $search_results_item = '<li><a href="viewforumcategory.php?'.api_get_cidreq().'&forumcategory='.$forumData['forum_category'].'&search='.urlencode($search_term).'">'.
4798
                prepare4display($categoryName).'</a> &gt; ';
4799
            $search_results_item .= '<a href="viewforum.php?'.api_get_cidreq().'&forum='.$forumId.'&search='.urlencode($search_term).'">'.
4800
                prepare4display($forum_list[$row['forum_id']]['forum_title']).'</a> &gt; ';
4801
            $search_results_item .= '<a href="viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$row['thread_id'].'&search='.urlencode($search_term).'">'.
4802
                prepare4display($row['post_title']).'</a>';
4803
            $search_results_item .= '<br />';
4804
            if (api_strlen($row['post_title']) > 200) {
4805
                $search_results_item .= prepare4display(api_substr(strip_tags($row['post_title']), 0, 200)).'...';
4806
            } else {
4807
                $search_results_item .= prepare4display($row['post_title']);
4808
            }
4809
            $search_results_item .= '</li>';
4810
            $search_results[] = $search_results_item;
4811
        }
4812
    }
4813
    echo '<legend>'.count($search_results).' '.get_lang('ForumSearchResults').'</legend>';
4814
    echo '<ol>';
4815
    if ($search_results) {
4816
        echo implode($search_results);
4817
    }
4818
    echo '</ol>';
4819
}
4820
4821
/**
4822
 * Return the link to the forum search page.
4823
 *
4824
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4825
 *
4826
 * @version April 2008, dokeos 1.8.5
4827
 */
4828
function search_link()
4829
{
4830
    $return = '';
4831
    $origin = api_get_origin();
4832
    if ($origin != 'learnpath') {
4833
        $return = '<a href="forumsearch.php?'.api_get_cidreq().'&action=search"> ';
4834
        $return .= Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
4835
4836
        if (!empty($_GET['search'])) {
4837
            $return .= ': '.Security::remove_XSS($_GET['search']).' ';
4838
            $url = api_get_self().'?';
4839
            $url_parameter = [];
4840
            foreach ($_GET as $key => $value) {
4841
                if ($key != 'search') {
4842
                    $url_parameter[] = Security::remove_XSS($key).'='.Security::remove_XSS($value);
4843
                }
4844
            }
4845
            $url = $url.implode('&', $url_parameter);
4846
            $return .= '<a href="'.$url.'">'.Display::return_icon('delete.gif', get_lang('RemoveSearchResults')).'</a>';
4847
        }
4848
    }
4849
4850
    return $return;
4851
}
4852
4853
/**
4854
 * This function adds an attachment file into a forum.
4855
 *
4856
 * @param string $file_comment a comment about file
4857
 * @param int    $last_id      from forum_post table
4858
 *
4859
 * @return false|null
4860
 */
4861
function add_forum_attachment_file($file_comment, $last_id)
4862
{
4863
    $_course = api_get_course_info();
4864
    $agenda_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
4865
4866
    if (!isset($_FILES['user_upload'])) {
4867
        return false;
4868
    }
4869
4870
    $fileCount = count($_FILES['user_upload']['name']);
4871
    $filesData = [];
4872
4873
    if (!is_array($_FILES['user_upload']['name'])) {
4874
        $filesData[] = $_FILES['user_upload'];
4875
    } else {
4876
        $fileKeys = array_keys($_FILES['user_upload']);
4877
        for ($i = 0; $i < $fileCount; $i++) {
4878
            foreach ($fileKeys as $key) {
4879
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
4880
            }
4881
        }
4882
    }
4883
4884
    foreach ($filesData as $attachment) {
4885
        if (empty($attachment['name'])) {
4886
            continue;
4887
        }
4888
4889
        $upload_ok = process_uploaded_file($attachment);
4890
4891
        if (!$upload_ok) {
4892
            continue;
4893
        }
4894
4895
        $course_dir = $_course['path'].'/upload/forum';
4896
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
4897
        $updir = $sys_course_path.$course_dir;
4898
4899
        // Try to add an extension to the file if it hasn't one.
4900
        $new_file_name = add_ext_on_mime(
4901
            stripslashes($attachment['name']),
4902
            $attachment['type']
4903
        );
4904
        // User's file name
4905
        $file_name = $attachment['name'];
4906
4907
        if (!filter_extension($new_file_name)) {
4908
            Display::addFlash(
4909
                Display::return_message(
4910
                    get_lang('UplUnableToSaveFileFilteredExtension'),
4911
                    'error'
4912
                )
4913
            );
4914
4915
            return;
4916
        }
4917
4918
        $new_file_name = uniqid('');
4919
        $new_path = $updir.'/'.$new_file_name;
4920
        $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
4921
        $safe_file_comment = Database::escape_string($file_comment);
4922
        $safe_file_name = Database::escape_string($file_name);
4923
        $safe_new_file_name = Database::escape_string($new_file_name);
4924
        $last_id = intval($last_id);
4925
        // Storing the attachments if any.
4926
        if (!$result) {
4927
            return;
4928
        }
4929
4930
        $last_id_file = Database::insert(
4931
            $agenda_forum_attachment,
4932
            [
4933
                'c_id' => api_get_course_int_id(),
4934
                'filename' => $safe_file_name,
4935
                'comment' => $safe_file_comment,
4936
                'path' => $safe_new_file_name,
4937
                'post_id' => $last_id,
4938
                'size' => intval($attachment['size']),
4939
            ]
4940
        );
4941
4942
        api_item_property_update(
4943
            $_course,
4944
            TOOL_FORUM_ATTACH,
4945
            $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

4945
            /** @scrutinizer ignore-type */ $last_id_file,
Loading history...
4946
            'ForumAttachmentAdded',
4947
            api_get_user_id()
4948
        );
4949
    }
4950
}
4951
4952
/**
4953
 * This function edits an attachment file into a forum.
4954
 *
4955
 * @param string $file_comment a comment about file
4956
 * @param int    $post_id
4957
 * @param int    $id_attach    attachment file Id
4958
 */
4959
function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
4960
{
4961
    $_course = api_get_course_info();
4962
    $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
4963
    $course_id = api_get_course_int_id();
4964
4965
    $fileCount = count($_FILES['user_upload']['name']);
4966
    $filesData = [];
4967
4968
    if (!is_array($_FILES['user_upload']['name'])) {
4969
        $filesData[] = $_FILES['user_upload'];
4970
    } else {
4971
        $fileKeys = array_keys($_FILES['user_upload']);
4972
4973
        for ($i = 0; $i < $fileCount; $i++) {
4974
            foreach ($fileKeys as $key) {
4975
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
4976
            }
4977
        }
4978
    }
4979
4980
    foreach ($filesData as $attachment) {
4981
        if (empty($attachment['name'])) {
4982
            continue;
4983
        }
4984
4985
        $upload_ok = process_uploaded_file($attachment);
4986
4987
        if (!$upload_ok) {
4988
            continue;
4989
        }
4990
4991
        $course_dir = $_course['path'].'/upload/forum';
4992
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
4993
        $updir = $sys_course_path.$course_dir;
4994
4995
        // Try to add an extension to the file if it hasn't one.
4996
        $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
4997
        // User's file name
4998
        $file_name = $attachment['name'];
4999
5000
        if (!filter_extension($new_file_name)) {
5001
            Display::addFlash(
5002
                Display::return_message(
5003
                    get_lang('UplUnableToSaveFileFilteredExtension'),
5004
                    'error'
5005
                )
5006
            );
5007
        } else {
5008
            $new_file_name = uniqid('');
5009
            $new_path = $updir.'/'.$new_file_name;
5010
            $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5011
            $safe_file_comment = Database::escape_string($file_comment);
5012
            $safe_file_name = Database::escape_string($file_name);
5013
            $safe_new_file_name = Database::escape_string($new_file_name);
5014
            $safe_post_id = (int) $post_id;
5015
            $safe_id_attach = (int) $id_attach;
5016
            // Storing the attachments if any.
5017
            if ($result) {
5018
                $sql = "UPDATE $table_forum_attachment 
5019
                        SET 
5020
                            filename = '$safe_file_name', 
5021
                            comment = '$safe_file_comment', 
5022
                            path = '$safe_new_file_name', 
5023
                            post_id = '$safe_post_id', 
5024
                            size ='".$attachment['size']."'
5025
                        WHERE c_id = $course_id AND id = '$safe_id_attach'";
5026
                Database::query($sql);
5027
                api_item_property_update(
5028
                    $_course,
5029
                    TOOL_FORUM_ATTACH,
5030
                    $safe_id_attach,
5031
                    'ForumAttachmentUpdated',
5032
                    api_get_user_id()
5033
                );
5034
            }
5035
        }
5036
    }
5037
}
5038
5039
/**
5040
 * Show a list with all the attachments according to the post's id.
5041
 *
5042
 * @param int $post_id
5043
 *
5044
 * @return array with the post info
5045
 *
5046
 * @author Julio Montoya
5047
 *
5048
 * @version avril 2008, dokeos 1.8.5
5049
 */
5050
function get_attachment($post_id)
5051
{
5052
    $forum_table_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5053
    $course_id = api_get_course_int_id();
5054
    $row = [];
5055
    $post_id = intval($post_id);
5056
    $sql = "SELECT iid, path, filename, comment 
5057
            FROM $forum_table_attachment
5058
            WHERE c_id = $course_id AND post_id = $post_id";
5059
    $result = Database::query($sql);
5060
    if (Database::num_rows($result) != 0) {
5061
        $row = Database::fetch_array($result);
5062
    }
5063
5064
    return $row;
5065
}
5066
5067
/**
5068
 * @param int $postId
5069
 *
5070
 * @return array
5071
 */
5072
function getAllAttachment($postId)
5073
{
5074
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5075
    $courseId = api_get_course_int_id();
5076
    $postId = intval($postId);
5077
    $columns = ['iid', 'path', 'filename', 'comment'];
5078
    $conditions = [
5079
        'where' => [
5080
            'c_id = ? AND post_id = ?' => [$courseId, $postId],
5081
        ],
5082
    ];
5083
    $array = Database::select(
5084
        $columns,
5085
        $forumAttachmentTable,
5086
        $conditions,
5087
        'all',
5088
        'ASSOC'
5089
    );
5090
5091
    return $array;
5092
}
5093
5094
/**
5095
 * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
5096
 *
5097
 * @param int  $post_id
5098
 * @param int  $id_attach
5099
 * @param bool $display   to show or not result message
5100
 *
5101
 * @return int
5102
 *
5103
 * @author Julio Montoya
5104
 *
5105
 * @version october 2014, chamilo 1.9.8
5106
 */
5107
function delete_attachment($post_id, $id_attach = 0, $display = true)
5108
{
5109
    $_course = api_get_course_info();
5110
5111
    $forum_table_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5112
    $course_id = api_get_course_int_id();
5113
5114
    $cond = (!empty($id_attach)) ? " iid = ".(int) $id_attach."" : " post_id = ".(int) $post_id."";
5115
    $sql = "SELECT path FROM $forum_table_attachment WHERE c_id = $course_id AND $cond";
5116
    $res = Database::query($sql);
5117
    $row = Database::fetch_array($res);
5118
5119
    $course_dir = $_course['path'].'/upload/forum';
5120
    $sys_course_path = api_get_path(SYS_COURSE_PATH);
5121
    $updir = $sys_course_path.$course_dir;
5122
    $my_path = isset($row['path']) ? $row['path'] : null;
5123
    $file = $updir.'/'.$my_path;
5124
    if (Security::check_abs_path($file, $updir)) {
5125
        @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

5125
        /** @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...
5126
    }
5127
5128
    // Delete from forum_attachment table.
5129
    $sql = "DELETE FROM $forum_table_attachment 
5130
            WHERE c_id = $course_id AND $cond ";
5131
    $result = Database::query($sql);
5132
    if ($result !== false) {
5133
        $affectedRows = Database::affected_rows($result);
5134
    } else {
5135
        $affectedRows = 0;
5136
    }
5137
5138
    // Update item_property.
5139
    api_item_property_update(
5140
        $_course,
5141
        TOOL_FORUM_ATTACH,
5142
        $id_attach,
5143
        'ForumAttachmentDelete',
5144
        api_get_user_id()
5145
    );
5146
5147
    if (!empty($result) && !empty($id_attach) && $display) {
5148
        $message = get_lang('AttachmentFileDeleteSuccess');
5149
        echo Display::return_message($message, 'confirmation');
5150
    }
5151
5152
    return $affectedRows;
5153
}
5154
5155
/**
5156
 * This function gets all the forum information of the all the forum of the group.
5157
 *
5158
 * @param array $groupInfo the id of the group we need the fora of (see forum.forum_of_group)
5159
 *
5160
 * @return array
5161
 *
5162
 * @todo this is basically the same code as the get_forums function. Consider merging the two.
5163
 */
5164
function get_forums_of_group($groupInfo)
5165
{
5166
    $table_forums = Database::get_course_table(TABLE_FORUM);
5167
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
5168
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5169
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
5170
    $course_id = api_get_course_int_id();
5171
    $groupId = (int) $groupInfo['id'];
5172
5173
    // Student
5174
    // Select all the forum information of all forums (that are visible to students).
5175
    $sql = "SELECT * FROM $table_forums forum 
5176
            INNER JOIN $table_item_property item_properties
5177
            ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5178
            WHERE
5179
                forum.forum_of_group = $groupId AND
5180
                forum.c_id = $course_id AND
5181
                item_properties.c_id = $course_id AND                
5182
                item_properties.visibility = 1 AND
5183
                item_properties.tool = '".TOOL_FORUM."'
5184
            ORDER BY forum.forum_order ASC";
5185
5186
    // Select the number of threads of the forums (only the threads that are visible).
5187
    $sql2 = "SELECT 
5188
                count(thread_id) AS number_of_threads, 
5189
                threads.forum_id
5190
            FROM $table_threads threads 
5191
            INNER JOIN $table_item_property item_properties
5192
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5193
            WHERE                
5194
                threads.c_id = $course_id AND
5195
                item_properties.c_id = $course_id AND
5196
                item_properties.visibility = 1 AND
5197
                item_properties.tool='".TOOL_FORUM_THREAD."'
5198
            GROUP BY threads.forum_id";
5199
5200
    // Select the number of posts of the forum (post that are visible and that are in a thread that is visible).
5201
    $sql3 = "SELECT count(post_id) AS number_of_posts, posts.forum_id
5202
            FROM $table_posts posts 
5203
            INNER JOIN $table_threads threads 
5204
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
5205
            INNER JOIN $table_item_property item_properties
5206
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5207
            WHERE 
5208
                posts.visible=1 AND
5209
                posts.c_id = $course_id AND
5210
                item_properties.c_id = $course_id AND
5211
                threads.c_id = $course_id AND 
5212
                item_properties.visibility = 1 AND 
5213
                item_properties.tool='".TOOL_FORUM_THREAD."'
5214
            GROUP BY threads.forum_id";
5215
5216
    // Course Admin
5217
    if (api_is_allowed_to_edit()) {
5218
        // Select all the forum information of all forums (that are not deleted).
5219
        $sql = "SELECT *
5220
                FROM $table_forums forum 
5221
                INNER JOIN $table_item_property item_properties
5222
                ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5223
                WHERE
5224
                    forum.forum_of_group = $groupId AND
5225
                    forum.c_id = $course_id AND
5226
                    item_properties.c_id = $course_id AND                    
5227
                    item_properties.visibility <> 2 AND
5228
                    item_properties.tool = '".TOOL_FORUM."'
5229
                ORDER BY forum_order ASC";
5230
5231
        // Select the number of threads of the forums (only the threads that are not deleted).
5232
        $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id
5233
                 FROM $table_threads threads 
5234
                 INNER JOIN $table_item_property item_properties
5235
                 ON (threads.thread_id=item_properties.ref AND item_properties.c_id = threads.c_id)
5236
                 WHERE
5237
                    threads.c_id = $course_id AND
5238
                    item_properties.c_id = $course_id AND
5239
                    item_properties.visibility <> 2 AND
5240
                    item_properties.tool='".TOOL_FORUM_THREAD."'
5241
                GROUP BY threads.forum_id";
5242
        // Select the number of posts of the forum.
5243
        $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id
5244
                FROM $table_posts
5245
                WHERE c_id = $course_id 
5246
                GROUP BY forum_id";
5247
    }
5248
5249
    // Handling all the forum information.
5250
    $result = Database::query($sql);
5251
    $forum_list = [];
5252
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5253
        $forum_list[$row['forum_id']] = $row;
5254
    }
5255
5256
    // Handling the thread count information.
5257
    $result2 = Database::query($sql2);
5258
    while ($row2 = Database::fetch_array($result2, 'ASSOC')) {
5259
        if (is_array($forum_list)) {
5260
            if (array_key_exists($row2['forum_id'], $forum_list)) {
5261
                $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
5262
            }
5263
        }
5264
    }
5265
5266
    // Handling the post count information.
5267
    $result3 = Database::query($sql3);
5268
    while ($row3 = Database::fetch_array($result3, 'ASSOC')) {
5269
        if (is_array($forum_list)) {
5270
            if (array_key_exists($row3['forum_id'], $forum_list)) {
5271
                // This is needed because sql3 takes also the deleted forums into account.
5272
                $forum_list[$row3['forum_id']]['number_of_posts'] = $row3['number_of_posts'];
5273
            }
5274
        }
5275
    }
5276
5277
    // Finding the last post information
5278
    // (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname).
5279
    if (!empty($forum_list)) {
5280
        foreach ($forum_list as $key => $value) {
5281
            $last_post_info_of_forum = get_last_post_information($key, api_is_allowed_to_edit());
5282
            if ($last_post_info_of_forum) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $last_post_info_of_forum 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...
5283
                $forum_list[$key]['last_post_id'] = $last_post_info_of_forum['last_post_id'];
5284
                $forum_list[$key]['last_poster_id'] = $last_post_info_of_forum['last_poster_id'];
5285
                $forum_list[$key]['last_post_date'] = $last_post_info_of_forum['last_post_date'];
5286
                $forum_list[$key]['last_poster_name'] = $last_post_info_of_forum['last_poster_name'];
5287
                $forum_list[$key]['last_poster_lastname'] = $last_post_info_of_forum['last_poster_lastname'];
5288
                $forum_list[$key]['last_poster_firstname'] = $last_post_info_of_forum['last_poster_firstname'];
5289
            }
5290
        }
5291
    }
5292
5293
    return $forum_list;
5294
}
5295
5296
/**
5297
 * This function stores which users have to be notified of which forums or threads.
5298
 *
5299
 * @param string $content does the user want to be notified about a forum or about a thread
5300
 * @param int    $id      the id of the forum or thread
5301
 *
5302
 * @return string language variable
5303
 *
5304
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5305
 *
5306
 * @version May 2008, dokeos 1.8.5
5307
 *
5308
 * @since May 2008, dokeos 1.8.5
5309
 */
5310
function set_notification($content, $id, $add_only = false)
5311
{
5312
    $_user = api_get_user_info();
5313
    // Database table definition
5314
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5315
5316
    $course_id = api_get_course_int_id();
5317
5318
    // Which database field do we have to store the id in?
5319
    if ($content == 'forum') {
5320
        $database_field = 'forum_id';
5321
    } else {
5322
        $database_field = 'thread_id';
5323
    }
5324
5325
    // First we check if the notification is already set for this.
5326
    $sql = "SELECT * FROM $table_notification
5327
            WHERE
5328
                c_id = $course_id AND
5329
                $database_field = '".Database::escape_string($id)."' AND
5330
                user_id = '".intval($_user['user_id'])."'";
5331
    $result = Database::query($sql);
5332
    $total = Database::num_rows($result);
5333
5334
    // If the user did not indicate that (s)he wanted to be notified already
5335
    // then we store the notification request (to prevent double notification requests).
5336
    if ($total <= 0) {
5337
        $sql = "INSERT INTO $table_notification (c_id, $database_field, user_id)
5338
                VALUES (".$course_id.", '".Database::escape_string($id)."','".intval($_user['user_id'])."')";
5339
        Database::query($sql);
5340
        Session::erase('forum_notification');
5341
        get_notifications_of_user(0, true);
5342
5343
        return get_lang('YouWillBeNotifiedOfNewPosts');
5344
    } else {
5345
        if (!$add_only) {
5346
            $sql = "DELETE FROM $table_notification
5347
                    WHERE
5348
                        c_id = $course_id AND
5349
                        $database_field = '".Database::escape_string($id)."' AND
5350
                        user_id = '".intval($_user['user_id'])."'";
5351
            Database::query($sql);
5352
            Session::erase('forum_notification');
5353
            get_notifications_of_user(0, true);
5354
5355
            return get_lang('YouWillNoLongerBeNotifiedOfNewPosts');
5356
        }
5357
    }
5358
}
5359
5360
/**
5361
 * This function retrieves all the email adresses of the users who wanted to be notified
5362
 * about a new post in a certain forum or thread.
5363
 *
5364
 * @param string $content does the user want to be notified about a forum or about a thread
5365
 * @param int    $id      the id of the forum or thread
5366
 *
5367
 * @return array returns
5368
 *
5369
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5370
 *
5371
 * @version May 2008, dokeos 1.8.5
5372
 *
5373
 * @since May 2008, dokeos 1.8.5
5374
 */
5375
function get_notifications($content, $id)
5376
{
5377
    // Database table definition
5378
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5379
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5380
    $course_id = api_get_course_int_id();
5381
5382
    // Which database field contains the notification?
5383
    if ($content == 'forum') {
5384
        $database_field = 'forum_id';
5385
    } else {
5386
        $database_field = 'thread_id';
5387
    }
5388
5389
    $sql = "SELECT user.user_id, user.firstname, user.lastname, user.email, user.user_id user
5390
            FROM $table_users user, $table_notification notification
5391
            WHERE 
5392
                notification.c_id = $course_id AND user.active = 1 AND
5393
                user.user_id = notification.user_id AND
5394
                notification.$database_field= '".Database::escape_string($id)."'";
5395
5396
    $result = Database::query($sql);
5397
    $return = [];
5398
5399
    while ($row = Database::fetch_array($result)) {
5400
        $return['user'.$row['user_id']] = ['email' => $row['email'], 'user_id' => $row['user_id']];
5401
    }
5402
5403
    return $return;
5404
}
5405
5406
/**
5407
 * Get all the users who need to receive a notification of a new post (those subscribed to
5408
 * the forum or the thread).
5409
 *
5410
 * @param int $forum_id  the id of the forum
5411
 * @param int $thread_id the id of the thread
5412
 * @param int $post_id   the id of the post
5413
 *
5414
 * @return false|null
5415
 *
5416
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5417
 *
5418
 * @version May 2008, dokeos 1.8.5
5419
 *
5420
 * @since May 2008, dokeos 1.8.5
5421
 */
5422
function send_notifications($forum_id = 0, $thread_id = 0, $post_id = 0)
5423
{
5424
    $_course = api_get_course_info();
5425
    $forum_id = (int) $forum_id;
5426
5427
    // The content of the mail
5428
    $thread_link = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&forum='.$forum_id.'&thread='.$thread_id;
5429
5430
    // Users who subscribed to the forum
5431
    if ($forum_id != 0) {
5432
        $users_to_be_notified_by_forum = get_notifications('forum', $forum_id);
5433
    } else {
5434
        return false;
5435
    }
5436
5437
    $current_thread = get_thread_information($forum_id, $thread_id);
5438
    $current_forum = get_forum_information($current_thread['forum_id']);
0 ignored issues
show
Deprecated Code introduced by
The function get_forum_information() has been deprecated: this functionality is now moved to get_forums($forum_id) ( Ignorable by Annotation )

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

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

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

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

Loading history...
5439
    $subject = get_lang('NewForumPost').' - '.$_course['official_code'].' - '.$current_forum['forum_title'].' - '.$current_thread['thread_title'];
5440
5441
    // User who subscribed to the thread
5442
    if ($thread_id != 0) {
5443
        $users_to_be_notified_by_thread = get_notifications('thread', $thread_id);
5444
    }
5445
5446
    // Merging the two
5447
    $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...
5448
    $sender_id = api_get_user_id();
5449
5450
    if (is_array($users_to_be_notified)) {
5451
        foreach ($users_to_be_notified as $value) {
5452
            $user_info = api_get_user_info($value['user_id']);
5453
            $email_body = get_lang('Dear').' '.api_get_person_name($user_info['firstname'], $user_info['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
5454
            $email_body .= get_lang('NewForumPost').": ".$current_forum['forum_title'].' - '.$current_thread['thread_title']." <br />\n";
5455
            $email_body .= get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."]  <br />\n";
5456
            $email_body .= get_lang('YouWantedToStayInformed')."<br />\n";
5457
            $email_body .= get_lang('ThreadCanBeFoundHere').': <br /> <a href="'.$thread_link.'">'.$thread_link."</a>\n";
5458
5459
            MessageManager::send_message_simple(
5460
                $value['user_id'],
5461
                $subject,
5462
                $email_body,
5463
                $sender_id
5464
            );
5465
        }
5466
    }
5467
}
5468
5469
/**
5470
 * Get all the notification subscriptions of the user
5471
 * = which forums and which threads does the user wants to be informed of when a new
5472
 * post is added to this thread.
5473
 *
5474
 * @param int  $user_id the user_id of a user (default = 0 => the current user)
5475
 * @param bool $force   force get the notification subscriptions (even if the information is already in the session
5476
 *
5477
 * @return array returns
5478
 *
5479
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5480
 *
5481
 * @version May 2008, dokeos 1.8.5
5482
 *
5483
 * @since May 2008, dokeos 1.8.5
5484
 */
5485
function get_notifications_of_user($user_id = 0, $force = false)
5486
{
5487
    // Database table definition
5488
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5489
    $course_id = api_get_course_int_id();
5490
    if (empty($course_id) || $course_id == -1) {
5491
        return null;
5492
    }
5493
    if ($user_id == 0) {
5494
        $user_id = api_get_user_id();
5495
    }
5496
5497
    if (!isset($_SESSION['forum_notification']) ||
5498
        $_SESSION['forum_notification']['course'] != $course_id ||
5499
        $force = true
5500
    ) {
5501
        $_SESSION['forum_notification']['course'] = $course_id;
5502
5503
        $sql = "SELECT * FROM $table_notification
5504
                WHERE c_id = $course_id AND user_id='".intval($user_id)."'";
5505
        $result = Database::query($sql);
5506
        while ($row = Database::fetch_array($result)) {
5507
            if (!is_null($row['forum_id'])) {
5508
                $_SESSION['forum_notification']['forum'][] = $row['forum_id'];
5509
            }
5510
            if (!is_null($row['thread_id'])) {
5511
                $_SESSION['forum_notification']['thread'][] = $row['thread_id'];
5512
            }
5513
        }
5514
    }
5515
}
5516
5517
/**
5518
 * This function counts the number of post inside a thread.
5519
 *
5520
 * @param int $thread_id
5521
 *
5522
 * @return int the number of post inside a thread
5523
 *
5524
 * @author Jhon Hinojosa <[email protected]>,
5525
 *
5526
 * @version octubre 2008, dokeos 1.8
5527
 */
5528
function count_number_of_post_in_thread($thread_id)
5529
{
5530
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5531
    $course_id = api_get_course_int_id();
5532
    if (empty($course_id)) {
5533
        return 0;
5534
    }
5535
    $sql = "SELECT count(*) count FROM $table_posts
5536
            WHERE 
5537
                c_id = $course_id AND 
5538
                thread_id='".intval($thread_id)."' ";
5539
    $result = Database::query($sql);
5540
5541
    $count = 0;
5542
    if (Database::num_rows($result) > 0) {
5543
        $row = Database::fetch_array($result);
5544
        $count = $row['count'];
5545
    }
5546
5547
    return $count;
5548
}
5549
5550
/**
5551
 * This function counts the number of post inside a thread user.
5552
 *
5553
 * @param int $thread_id
5554
 * @param int $user_id
5555
 *
5556
 * @return int the number of post inside a thread user
5557
 */
5558
function count_number_of_post_for_user_thread($thread_id, $user_id)
5559
{
5560
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5561
    $course_id = api_get_course_int_id();
5562
    $sql = "SELECT count(iid) as count 
5563
            FROM $table_posts
5564
            WHERE c_id = $course_id AND
5565
                  thread_id=".intval($thread_id)." AND
5566
                  poster_id = ".intval($user_id)." AND visible = 1 ";
5567
    $result = Database::query($sql);
5568
    $count = 0;
5569
    if (Database::num_rows($result) > 0) {
5570
        $count = Database::fetch_array($result);
5571
        $count = $count['count'];
5572
    }
5573
5574
    return $count;
5575
}
5576
5577
/**
5578
 * This function retrieves information of statistical.
5579
 *
5580
 * @param int $thread_id
5581
 * @param int $user_id
5582
 * @param int $course_id
5583
 *
5584
 * @return array the information of statistical
5585
 *
5586
 * @author Jhon Hinojosa <[email protected]>,
5587
 *
5588
 * @version oct 2008, dokeos 1.8
5589
 */
5590
function get_statistical_information($thread_id, $user_id, $course_id)
5591
{
5592
    $result = [];
5593
    $courseInfo = api_get_course_info_by_id($course_id);
5594
    $result['user_course'] = CourseManager::get_users_count_in_course($courseInfo['code']);
5595
    $result['post'] = count_number_of_post_in_thread($thread_id);
5596
    $result['user_post'] = count_number_of_post_for_user_thread($thread_id, $user_id);
5597
5598
    return $result;
5599
}
5600
5601
/**
5602
 * This function return the posts inside a thread from a given user.
5603
 *
5604
 * @param string $course_code
5605
 * @param int    $thread_id
5606
 * @param int    $user_id
5607
 *
5608
 * @return array posts inside a thread
5609
 *
5610
 * @author Jhon Hinojosa <[email protected]>,
5611
 *
5612
 * @version oct 2008, dokeos 1.8
5613
 */
5614
function get_thread_user_post($course_code, $thread_id, $user_id)
5615
{
5616
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5617
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5618
    $thread_id = intval($thread_id);
5619
    $user_id = intval($user_id);
5620
    $course_info = api_get_user_info($course_code);
5621
    $course_id = $course_info['real_id'];
5622
5623
    if (empty($course_id)) {
5624
        $course_id = api_get_course_int_id();
5625
    }
5626
    $sql = "SELECT * FROM $table_posts posts
5627
            LEFT JOIN  $table_users users
5628
                ON posts.poster_id=users.user_id
5629
            WHERE
5630
                posts.c_id = $course_id AND
5631
                posts.thread_id='$thread_id'
5632
                AND posts.poster_id='$user_id'
5633
            ORDER BY posts.post_id ASC";
5634
5635
    $result = Database::query($sql);
5636
    $post_list = [];
5637
    while ($row = Database::fetch_array($result)) {
5638
        $row['status'] = '1';
5639
        $post_list[] = $row;
5640
        $sql = "SELECT * FROM $table_posts posts
5641
                LEFT JOIN $table_users users
5642
                ON (posts.poster_id=users.user_id)
5643
                WHERE
5644
                    posts.c_id = $course_id AND
5645
                    posts.thread_id='$thread_id'
5646
                    AND posts.post_parent_id='".$row['post_id']."'
5647
                ORDER BY posts.post_id ASC";
5648
        $result2 = Database::query($sql);
5649
        while ($row2 = Database::fetch_array($result2)) {
5650
            $row2['status'] = '0';
5651
            $post_list[] = $row2;
5652
        }
5653
    }
5654
5655
    return $post_list;
5656
}
5657
5658
/**
5659
 * This function get the name of an thread by id.
5660
 *
5661
 * @param int thread_id
5662
 *
5663
 * @return string
5664
 *
5665
 * @author Christian Fasanando
5666
 * @author Julio Montoya <[email protected]> Adding security
5667
 */
5668
function get_name_thread_by_id($thread_id)
5669
{
5670
    $t_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
5671
    $course_id = api_get_course_int_id();
5672
    $sql = "SELECT thread_title 
5673
            FROM $t_forum_thread
5674
            WHERE c_id = $course_id AND thread_id = '".intval($thread_id)."' ";
5675
    $result = Database::query($sql);
5676
    $row = Database::fetch_array($result);
5677
5678
    return $row[0];
5679
}
5680
5681
/**
5682
 * This function gets all the post written by an user.
5683
 *
5684
 * @param int    $user_id
5685
 * @param string $course_code
5686
 *
5687
 * @return string
5688
 */
5689
function get_all_post_from_user($user_id, $course_code)
5690
{
5691
    $j = 0;
5692
    $forums = get_forums('', $course_code);
5693
    krsort($forums);
5694
    $forum_results = '';
5695
5696
    foreach ($forums as $forum) {
5697
        if ($forum['visibility'] == 0) {
5698
            continue;
5699
        }
5700
        if ($j <= 4) {
5701
            $threads = get_threads($forum['forum_id']);
5702
5703
            if (is_array($threads)) {
5704
                $i = 0;
5705
                $hand_forums = '';
5706
                $post_counter = 0;
5707
                foreach ($threads as $thread) {
5708
                    if ($thread['visibility'] == 0) {
5709
                        continue;
5710
                    }
5711
                    if ($i <= 4) {
5712
                        $post_list = get_thread_user_post_limit(
5713
                            $course_code,
5714
                            $thread['thread_id'],
5715
                            $user_id,
5716
                            1
5717
                        );
5718
                        $post_counter = count($post_list);
5719
                        if (is_array($post_list) && count($post_list) > 0) {
5720
                            $hand_forums .= '<div id="social-thread">';
5721
                            $hand_forums .= Display::return_icon(
5722
                                'thread.png',
5723
                                get_lang('Thread'),
5724
                                '',
5725
                                ICON_SIZE_MEDIUM
5726
                            );
5727
                            $hand_forums .= '&nbsp;'.Security::remove_XSS($thread['thread_title'], STUDENT);
5728
                            $hand_forums .= '</div>';
5729
5730
                            foreach ($post_list as $posts) {
5731
                                $hand_forums .= '<div id="social-post">';
5732
                                $hand_forums .= '<strong>'.Security::remove_XSS($posts['post_title'], STUDENT).'</strong>';
5733
                                $hand_forums .= '<br / >';
5734
                                $hand_forums .= Security::remove_XSS($posts['post_text'], STUDENT);
5735
                                $hand_forums .= '</div>';
5736
                                $hand_forums .= '<br / >';
5737
                            }
5738
                        }
5739
                    }
5740
                    $i++;
5741
                }
5742
                $forum_results .= '<div id="social-forum">';
5743
                $forum_results .= '<div class="clear"></div><br />';
5744
                $forum_results .= '<div id="social-forum-title">'.
5745
                    Display::return_icon('forum.gif', get_lang('Forum')).'&nbsp;'.Security::remove_XSS($forum['forum_title'], STUDENT).
5746
                    '<div style="float:right;margin-top:-35px">
5747
                        <a href="../forum/viewforum.php?'.api_get_cidreq_params($course_code).'&forum='.$forum['forum_id'].' " >'.
5748
                            get_lang('SeeForum').'    
5749
                        </a>
5750
                     </div></div>';
5751
                $forum_results .= '<br / >';
5752
                if ($post_counter > 0) {
5753
                    $forum_results .= $hand_forums;
5754
                }
5755
                $forum_results .= '</div>';
5756
            }
5757
            $j++;
5758
        }
5759
    }
5760
5761
    return $forum_results;
5762
}
5763
5764
/**
5765
 * @param string $course_code
5766
 * @param int    $thread_id
5767
 * @param int    $user_id
5768
 * @param int    $limit
5769
 *
5770
 * @return array
5771
 */
5772
function get_thread_user_post_limit($course_code, $thread_id, $user_id, $limit = 10)
5773
{
5774
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5775
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5776
5777
    $course_info = api_get_course_info($course_code);
5778
    $course_id = $course_info['real_id'];
5779
5780
    $sql = "SELECT * FROM $table_posts posts
5781
            LEFT JOIN  $table_users users
5782
                ON posts.poster_id=users.user_id
5783
            WHERE
5784
                posts.c_id = $course_id AND
5785
                posts.thread_id='".Database::escape_string($thread_id)."' AND 
5786
                posts.poster_id='".Database::escape_string($user_id)."'
5787
            ORDER BY posts.post_id DESC LIMIT $limit ";
5788
    $result = Database::query($sql);
5789
    $post_list = [];
5790
    while ($row = Database::fetch_array($result)) {
5791
        $row['status'] = '1';
5792
        $post_list[] = $row;
5793
    }
5794
5795
    return $post_list;
5796
}
5797
5798
/**
5799
 * @param string $user_id
5800
 * @param int    $courseId
5801
 * @param int    $sessionId
5802
 *
5803
 * @return array
5804
 */
5805
function getForumCreatedByUser($user_id, $courseId, $sessionId)
5806
{
5807
    $items = api_get_item_property_list_by_tool_by_user(
5808
        $user_id,
5809
        'forum',
5810
        $courseId,
5811
        $sessionId
5812
    );
5813
5814
    $courseInfo = api_get_course_info_by_id($courseId);
5815
    $forumList = [];
5816
    if (!empty($items)) {
5817
        foreach ($items as $forum) {
5818
            $forumInfo = get_forums(
5819
                $forum['ref'],
5820
                $courseInfo['code'],
5821
                true,
5822
                $sessionId
5823
            );
5824
            if (!empty($forumInfo)) {
5825
                $forumList[] = [
5826
                    $forumInfo['forum_title'],
5827
                    api_get_local_time($forum['insert_date']),
5828
                    api_get_local_time($forum['lastedit_date']),
5829
                ];
5830
            }
5831
        }
5832
    }
5833
5834
    return $forumList;
5835
}
5836
5837
/**
5838
 * This function builds an array of all the posts in a given thread
5839
 * where the key of the array is the post_id
5840
 * It also adds an element children to the array which itself is an array
5841
 * that contains all the id's of the first-level children.
5842
 *
5843
 * @return array $rows containing all the information on the posts of a thread
5844
 *
5845
 * @author Patrick Cool <[email protected]>, Ghent University
5846
 */
5847
function calculate_children($rows)
5848
{
5849
    $sorted_rows = [0 => []];
5850
    if (!empty($rows)) {
5851
        foreach ($rows as $row) {
5852
            $rows_with_children[$row['post_id']] = $row;
5853
            $rows_with_children[$row['post_parent_id']]['children'][] = $row['post_id'];
5854
        }
5855
5856
        $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 5851. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
5857
        forumRecursiveSort($rows, $sorted_rows);
5858
        unset($sorted_rows[0]);
5859
    }
5860
5861
    return $sorted_rows;
5862
}
5863
5864
/**
5865
 * @param $rows
5866
 * @param $threads
5867
 * @param int $seed
5868
 * @param int $indent
5869
 */
5870
function forumRecursiveSort($rows, &$threads, $seed = 0, $indent = 0)
5871
{
5872
    if ($seed > 0) {
5873
        $threads[$rows[$seed]['post_id']] = $rows[$seed];
5874
        $threads[$rows[$seed]['post_id']]['indent_cnt'] = $indent;
5875
        $indent++;
5876
    }
5877
5878
    if (isset($rows[$seed]['children'])) {
5879
        foreach ($rows[$seed]['children'] as $child) {
5880
            forumRecursiveSort($rows, $threads, $child, $indent);
5881
        }
5882
    }
5883
}
5884
5885
/**
5886
 * Update forum attachment data, used to update comment and post ID.
5887
 *
5888
 * @param $array array (field => value) to update forum attachment row
5889
 * @param $id attach ID to find row to update
5890
 * @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...
5891
 *
5892
 * @return int number of affected rows
5893
 */
5894
function editAttachedFile($array, $id, $courseId = null)
5895
{
5896
    // Init variables
5897
    $setString = '';
5898
    $id = intval($id);
5899
    $courseId = intval($courseId);
5900
    if (empty($courseId)) {
5901
        // $courseId can be null, use api method
5902
        $courseId = api_get_course_int_id();
5903
    }
5904
    /*
5905
     * Check if Attachment ID and Course ID are greater than zero
5906
     * and array of field values is not empty
5907
     */
5908
    if ($id > 0 && $courseId > 0 && !empty($array) && is_array($array)) {
5909
        foreach ($array as $key => &$item) {
5910
            $item = Database::escape_string($item);
5911
            $setString .= $key.' = "'.$item.'", ';
5912
        }
5913
        // Delete last comma
5914
        $setString = substr($setString, 0, strlen($setString) - 2);
5915
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5916
        $sql = "UPDATE $forumAttachmentTable 
5917
                SET $setString WHERE c_id = $courseId AND id = $id";
5918
        $result = Database::query($sql);
5919
        if ($result !== false) {
5920
            $affectedRows = Database::affected_rows($result);
5921
            if ($affectedRows > 0) {
5922
                /*
5923
                 * If exist in $_SESSION variable, then delete them from it
5924
                 * because they would be deprecated
5925
                 */
5926
                if (!empty($_SESSION['forum']['upload_file'][$courseId][$id])) {
5927
                    unset($_SESSION['forum']['upload_file'][$courseId][$id]);
5928
                }
5929
            }
5930
5931
            return $affectedRows;
5932
        }
5933
    }
5934
5935
    return 0;
5936
}
5937
5938
/**
5939
 * Return a table where the attachments will be set.
5940
 *
5941
 * @param int $postId Forum Post ID
5942
 *
5943
 * @return string The Forum Attachments Ajax Table
5944
 */
5945
function getAttachmentsAjaxTable($postId = 0)
5946
{
5947
    // Init variables
5948
    $postId = intval($postId);
5949
    $courseId = api_get_course_int_id();
5950
    $attachIds = getAttachmentIdsByPostId($postId, $courseId);
5951
    $fileDataContent = '';
5952
    // Update comment to show if form did not pass validation
5953
    if (!empty($_REQUEST['file_ids']) && is_array($_REQUEST['file_ids'])) {
5954
        // 'file_ids is the name from forum attachment ajax form
5955
        foreach ($_REQUEST['file_ids'] as $key => $attachId) {
5956
            if (!empty($_SESSION['forum']['upload_file'][$courseId][$attachId]) &&
5957
                is_array($_SESSION['forum']['upload_file'][$courseId][$attachId])
5958
            ) {
5959
                // If exist forum attachment then update into $_SESSION data
5960
                $_SESSION['forum']['upload_file'][$courseId][$attachId]['comment'] = $_POST['file_comments'][$key];
5961
            }
5962
        }
5963
    }
5964
5965
    // Get data to fill into attachment files table
5966
    if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
5967
        is_array($_SESSION['forum']['upload_file'][$courseId])
5968
    ) {
5969
        $uploadedFiles = $_SESSION['forum']['upload_file'][$courseId];
5970
        foreach ($uploadedFiles as $k => $uploadedFile) {
5971
            if (!empty($uploadedFile) && in_array($uploadedFile['id'], $attachIds)) {
5972
                // Buil html table including an input with attachmentID
5973
                $fileDataContent .= '<tr id="'.$uploadedFile['id'].'" ><td>'.$uploadedFile['name'].'</td><td>'.$uploadedFile['size'].'</td><td>&nbsp;'.$uploadedFile['result'].
5974
                    ' </td><td> <input style="width:90%;" type="text" value="'.$uploadedFile['comment'].'" name="file_comments[]"> </td><td>'.
5975
                    $uploadedFile['delete'].'</td>'.
5976
                    '<input type="hidden" value="'.$uploadedFile['id'].'" name="file_ids[]">'.'</tr>';
5977
            } else {
5978
                /*
5979
                 * If attachment data is empty, then delete it from $_SESSION
5980
                 * because could generate and empty row into html table
5981
                 */
5982
                unset($_SESSION['forum']['upload_file'][$courseId][$k]);
5983
            }
5984
        }
5985
    }
5986
    $style = empty($fileDataContent) ? 'display: none;' : '';
5987
    // Forum attachment Ajax table
5988
    $fileData = '
5989
    <div class="control-group " style="'.$style.'">
5990
        <label class="control-label">'.get_lang('AttachmentList').'</label>
5991
        <div class="controls">
5992
            <table id="attachmentFileList" class="files data_table span10">
5993
                <tr>
5994
                    <th>'.get_lang('FileName').'</th>
5995
                    <th>'.get_lang('Size').'</th>
5996
                    <th>'.get_lang('Status').'</th>
5997
                    <th>'.get_lang('Comment').'</th>
5998
                    <th>'.get_lang('Delete').'</th>
5999
                </tr>
6000
                '.$fileDataContent.'
6001
            </table>
6002
        </div>
6003
    </div>';
6004
6005
    return $fileData;
6006
}
6007
6008
/**
6009
 * Return an array of prepared attachment data to build forum attachment table
6010
 * Also, save this array into $_SESSION to do available the attachment data.
6011
 *
6012
 * @param int $forumId
6013
 * @param int $threadId
6014
 * @param int $postId
6015
 * @param int $attachId
6016
 * @param int $courseId
6017
 *
6018
 * @return array
6019
 */
6020
function getAttachedFiles(
6021
    $forumId,
6022
    $threadId,
6023
    $postId = 0,
6024
    $attachId = 0,
6025
    $courseId = 0
6026
) {
6027
    $forumId = intval($forumId);
6028
    $courseId = intval($courseId);
6029
    $attachId = intval($attachId);
6030
    $postId = intval($postId);
6031
    $threadId = !empty($threadId) ? intval($threadId) : isset($_REQUEST['thread']) ? intval($_REQUEST['thread']) : '';
6032
    if (empty($courseId)) {
6033
        // $courseId can be null, use api method
6034
        $courseId = api_get_course_int_id();
6035
    }
6036
    if (empty($forumId)) {
6037
        if (!empty($_REQUEST['forum'])) {
6038
            $forumId = intval($_REQUEST['forum']);
6039
        } else {
6040
            // if forum ID is empty, cannot generate delete url
6041
6042
            return [];
6043
        }
6044
    }
6045
    // Check if exist at least one of them to filter forum attachment select query
6046
    if (empty($postId) && empty($attachId)) {
6047
        return [];
6048
    } elseif (empty($postId)) {
6049
        $filter = "AND iid = $attachId";
6050
    } elseif (empty($attachId)) {
6051
        $filter = "AND post_id = $postId";
6052
    } else {
6053
        $filter = "AND post_id = $postId AND iid = $attachId";
6054
    }
6055
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6056
    $sql = "SELECT iid, comment, filename, path, size
6057
            FROM $forumAttachmentTable
6058
            WHERE c_id = $courseId $filter";
6059
    $result = Database::query($sql);
6060
    $json = [];
6061
    if ($result !== false && Database::num_rows($result) > 0) {
6062
        while ($row = Database::fetch_array($result, 'ASSOC')) {
6063
            // name contains an URL to download attachment file and its filename
6064
            $json['name'] = Display::url(
6065
                api_htmlentities($row['filename']),
6066
                api_get_path(WEB_CODE_PATH).'forum/download.php?file='.$row['path'].'&'.api_get_cidreq(),
6067
                ['target' => '_blank', 'class' => 'attachFilename']
6068
            );
6069
            $json['id'] = $row['iid'];
6070
            $json['comment'] = $row['comment'];
6071
            // Format file size
6072
            $json['size'] = format_file_size($row['size']);
6073
            // Check if $row is consistent
6074
            if (!empty($row) && is_array($row)) {
6075
                // Set result as success and bring delete URL
6076
                $json['result'] = Display::return_icon('accept.png', get_lang('Uploaded'));
6077
                $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&action=delete_attach&forum='.$forumId.'&thread='.$threadId.'&id_attach='.$row['iid'];
6078
                $json['delete'] = Display::url(
6079
                    Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL),
6080
                    $url,
6081
                    ['class' => 'deleteLink']
6082
                );
6083
            } else {
6084
                // If not, set an exclamation result
6085
                $json['result'] = Display::return_icon('exclamation.png', get_lang('Error'));
6086
            }
6087
            // Store array data into $_SESSION
6088
            $_SESSION['forum']['upload_file'][$courseId][$json['id']] = $json;
6089
        }
6090
    }
6091
6092
    return $json;
6093
}
6094
6095
/**
6096
 * Clear forum attachment data stored in $_SESSION,
6097
 * If is not defined post, it will clear all forum attachment data from course.
6098
 *
6099
 * @param int $postId   -1 : Clear all attachments from course stored in $_SESSION
6100
 *                      0 : Clear attachments from course, except from temporal post "0"
6101
 *                      but without delete them from file system and database
6102
 *                      Other values : Clear attachments from course except specified post
6103
 *                      and delete them from file system and database
6104
 * @param int $courseId : Course ID, if it is null, will use api_get_course_int_id()
6105
 *
6106
 * @return array
6107
 */
6108
function clearAttachedFiles($postId = null, $courseId = null)
6109
{
6110
    // Init variables
6111
    $courseId = intval($courseId);
6112
    $postId = intval($postId);
6113
    $array = [];
6114
    if (empty($courseId)) {
6115
        // $courseId can be null, use api method
6116
        $courseId = api_get_course_int_id();
6117
    }
6118
    if ($postId === -1) {
6119
        // If post ID is -1 then delete course's attachment data from $_SESSION
6120
        if (!empty($_SESSION['forum']['upload_file'][$courseId])) {
6121
            $array = array_keys($_SESSION['forum']['upload_file'][$courseId]);
6122
            unset($_SESSION['forum']['upload_file'][$courseId]);
6123
        }
6124
    } else {
6125
        $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6126
        if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6127
            is_array($_SESSION['forum']['upload_file'][$courseId])) {
6128
            foreach ($_SESSION['forum']['upload_file'][$courseId] as $attachId => $attach) {
6129
                if (!in_array($attachId, $attachIds)) {
6130
                    // If attach ID is not into specified post, delete attachment
6131
                    // Save deleted attachment ID
6132
                    $array[] = $attachId;
6133
                    if ($postId !== 0) {
6134
                        // Post 0 is temporal, delete them from file system and DB
6135
                        delete_attachment(0, $attachId, false);
6136
                    }
6137
                    // Delete attachment data from $_SESSION
6138
                    unset($_SESSION['forum']['upload_file'][$courseId][$attachId]);
6139
                }
6140
            }
6141
        }
6142
    }
6143
6144
    return $array;
6145
}
6146
6147
/**
6148
 * Returns an array of forum attachment ids into a course and forum post.
6149
 *
6150
 * @param int $postId
6151
 * @param int $courseId
6152
 *
6153
 * @return array
6154
 */
6155
function getAttachmentIdsByPostId($postId, $courseId = 0)
6156
{
6157
    $array = [];
6158
    $courseId = intval($courseId);
6159
    $postId = intval($postId);
6160
    if (empty($courseId)) {
6161
        // $courseId can be null, use api method
6162
        $courseId = api_get_course_int_id();
6163
    }
6164
    if ($courseId > 0) {
6165
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6166
        $sql = "SELECT id FROM $forumAttachmentTable
6167
                WHERE c_id = $courseId AND post_id = $postId";
6168
        $result = Database::query($sql);
6169
        if ($result !== false && Database::num_rows($result) > 0) {
6170
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6171
                $array[] = $row['id'];
6172
            }
6173
        }
6174
    }
6175
6176
    return $array;
6177
}
6178
6179
/**
6180
 * Check if the forum category exists looking for its title.
6181
 *
6182
 * @param string $title     The forum category title
6183
 * @param int    $courseId  The course ID
6184
 * @param int    $sessionId Optional. The session ID
6185
 *
6186
 * @return bool
6187
 */
6188
function getForumCategoryByTitle($title, $courseId, $sessionId = 0)
6189
{
6190
    $sessionId = intval($sessionId);
6191
    $forumCategoryTable = Database::get_course_table(TABLE_FORUM_CATEGORY);
6192
    $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6193
6194
    $fakeFrom = "$forumCategoryTable fc
6195
        INNER JOIN $itemProperty ip ";
6196
6197
    if ($sessionId === 0) {
6198
        $fakeFrom .= "
6199
            ON (
6200
                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)
6201
            )
6202
        ";
6203
    } else {
6204
        $fakeFrom .= "
6205
            ON (
6206
                fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND fc.session_id = ip.session_id
6207
            )
6208
        ";
6209
    }
6210
6211
    $resultData = Database::select(
6212
        'fc.*',
6213
        $fakeFrom,
6214
        [
6215
            'where' => [
6216
                'ip.visibility != ? AND ' => 2,
6217
                'ip.tool = ? AND ' => TOOL_FORUM_CATEGORY,
6218
                'fc.session_id = ? AND ' => $sessionId,
6219
                'fc.cat_title = ? AND ' => $title,
6220
                'fc.c_id = ?' => intval($courseId),
6221
            ],
6222
        ],
6223
        'first'
6224
    );
6225
6226
    if (empty($resultData)) {
6227
        return false;
6228
    }
6229
6230
    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...
6231
}
6232
6233
/**
6234
 * @param array $current_forum
6235
 * @param array $row
6236
 * @param bool  $addWrapper
6237
 *
6238
 * @return string
6239
 */
6240
function getPostStatus($current_forum, $row, $addWrapper = true)
6241
{
6242
    $statusIcon = '';
6243
    if ($current_forum['moderated']) {
6244
        if ($addWrapper) {
6245
            $statusIcon = '<br /><br /><span id="status_post_'.$row['iid'].'">';
6246
        }
6247
        $row['status'] = empty($row['status']) ? 2 : $row['status'];
6248
6249
        $addUrl = false;
6250
        $showStatus = false;
6251
        if (api_is_allowed_to_edit(false, true)) {
6252
            $addUrl = true;
6253
        } else {
6254
            if ($row['user_id'] == api_get_user_id()) {
6255
                $showStatus = true;
6256
            }
6257
        }
6258
6259
        $label = '';
6260
        $icon = '';
6261
        $buttonType = '';
6262
        switch ($row['status']) {
6263
            case CForumPost::STATUS_VALIDATED:
6264
                $label = get_lang('Validated');
6265
                $icon = 'check-circle';
6266
                $buttonType = 'success';
6267
                break;
6268
            case CForumPost::STATUS_WAITING_MODERATION:
6269
                $label = get_lang('WaitingModeration');
6270
                $icon = 'warning';
6271
                $buttonType = 'warning';
6272
                break;
6273
            case CForumPost::STATUS_REJECTED:
6274
                $label = get_lang('Rejected');
6275
                $icon = 'minus-circle';
6276
                $buttonType = 'danger';
6277
                break;
6278
        }
6279
6280
        if ($addUrl) {
6281
            $statusIcon .= Display::toolbarButton(
6282
                $label.'&nbsp;',
6283
                'javascript:void(0)',
6284
                $icon,
6285
                $buttonType,
6286
                ['class' => 'change_post_status']
6287
            );
6288
        } else {
6289
            if ($showStatus) {
6290
                $statusIcon .= Display::label(
6291
                    Display::returnFontAwesomeIcon($icon).$label,
6292
                    $buttonType
6293
                );
6294
            }
6295
        }
6296
6297
        if ($addWrapper) {
6298
            $statusIcon .= '</span>';
6299
        }
6300
    }
6301
6302
    return $statusIcon;
6303
}
6304
6305
/**
6306
 * @param array $forumInfo
6307
 * @param int   $threadId
6308
 * @param int   $status
6309
 *
6310
 * @return mixed
6311
 */
6312
function getCountPostsWithStatus($status, $forumInfo, $threadId = null)
6313
{
6314
    $em = Database::getManager();
6315
    $criteria = Criteria::create();
6316
    $criteria
6317
        ->where(Criteria::expr()->eq('status', $status))
6318
        ->andWhere(Criteria::expr()->eq('cId', $forumInfo['c_id']))
6319
        ->andWhere(Criteria::expr()->eq('visible', 1))
6320
    ;
6321
6322
    if (!empty($threadId)) {
6323
        $criteria->andWhere(Criteria::expr()->eq('threadId', $threadId));
6324
    }
6325
6326
    $qb = $em->getRepository('ChamiloCourseBundle:CForumPost')->createQueryBuilder('p');
6327
    $qb->select('count(p.iid)')
6328
        ->addCriteria($criteria);
6329
6330
    return $qb->getQuery()->getSingleScalarResult();
6331
}
6332
6333
/**
6334
 * @param array $forum
6335
 * @param array $post
6336
 *
6337
 * @return bool
6338
 */
6339
function postIsEditableByStudent($forum, $post)
6340
{
6341
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
6342
        return true;
6343
    }
6344
6345
    if ($forum['moderated'] == 1) {
6346
        if (is_null($post['status'])) {
6347
            return true;
6348
        } else {
6349
            return in_array(
6350
                $post['status'],
6351
                [
6352
                    CForumPost::STATUS_WAITING_MODERATION,
6353
                    CForumPost::STATUS_REJECTED,
6354
                ]
6355
            );
6356
        }
6357
    } else {
6358
        return true;
6359
    }
6360
}
6361