Passed
Push — master ( 6a2455...6d3a7a )
by Julito
09:25
created

delete_post()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 62
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 35
nc 9
nop 1
dl 0
loc 62
rs 8.4266
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
6
use Chamilo\CoreBundle\Framework\Container;
7
use Chamilo\CourseBundle\Entity\CForumAttachment;
8
use Chamilo\CourseBundle\Entity\CForumCategory;
9
use Chamilo\CourseBundle\Entity\CForumForum;
10
use Chamilo\CourseBundle\Entity\CForumNotification;
11
use Chamilo\CourseBundle\Entity\CForumPost;
12
use Chamilo\CourseBundle\Entity\CForumThread;
13
use ChamiloSession as Session;
14
use Doctrine\Common\Collections\Criteria;
15
use Symfony\Component\HttpFoundation\File\UploadedFile;
16
17
/*
18
 * These files are a complete rework of the forum. The database structure is
19
 * based on phpBB but all the code is rewritten. A lot of new functionalities
20
 * are added:
21
 * - forum categories and forums can be sorted up or down, locked or made invisible
22
 * - consistent and integrated forum administration
23
 * - forum options:     are students allowed to edit their post?
24
 *                         moderation of posts (approval)
25
 *                         reply only forums (students cannot create new threads)
26
 *                         multiple forums per group
27
 * - sticky messages
28
 * - new view option: nested view
29
 * - quoting a message.
30
 *
31
 * @package chamilo.forum
32
 *
33
 * @todo convert into a class
34
 */
35
define('FORUM_NEW_POST', 0);
36
getNotificationsPerUser();
37
38
$htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
39
$htmlHeadXtra[] = '<script>
40
41
function check_unzip() {
42
    if (document.upload.unzip.checked){
43
        document.upload.if_exists[0].disabled=true;
44
        document.upload.if_exists[1].checked=true;
45
        document.upload.if_exists[2].disabled=true;
46
    } else {
47
        document.upload.if_exists[0].checked=true;
48
        document.upload.if_exists[0].disabled=false;
49
        document.upload.if_exists[2].disabled=false;
50
    }
51
}
52
function setFocus() {
53
    $("#title_file").focus();
54
}
55
</script>';
56
// The next javascript script is to manage ajax upload file
57
$htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
58
59
// Recover Thread ID, will be used to generate delete attachment URL to do ajax
60
$threadId = isset($_REQUEST['thread']) ? (int) ($_REQUEST['thread']) : 0;
61
$forumId = isset($_REQUEST['forum']) ? (int) ($_REQUEST['forum']) : 0;
62
63
$ajaxUrl = api_get_path(WEB_AJAX_PATH).'forum.ajax.php?'.api_get_cidreq();
64
// The next javascript script is to delete file by ajax
65
$htmlHeadXtra[] = '<script>
66
$(function () {
67
    $(document).on("click", ".deleteLink", function(e) {
68
        e.preventDefault();
69
        e.stopPropagation();
70
        var l = $(this);
71
        var id = l.closest("tr").attr("id");
72
        var filename = l.closest("tr").find(".attachFilename").html();
73
        if (confirm("'.get_lang('Are you sure to delete').'", filename)) {
74
            $.ajax({
75
                type: "POST",
76
                url: "'.$ajaxUrl.'&a=delete_file&attachId=" + id +"&thread='.$threadId.'&forum='.$forumId.'",
77
                dataType: "json",
78
                success: function(data) {
79
                    if (data.error == false) {
80
                        l.closest("tr").remove();
81
                        if ($(".files td").length < 1) {
82
                            $(".files").closest(".control-group").hide();
83
                        }
84
                    }
85
                }
86
            })
87
        }
88
    });
89
});
90
</script>';
91
92
function handleForum($url)
93
{
94
    $id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : null;
95
96
    if (api_is_allowed_to_edit(false, true)) {
97
        //if is called from a learning path lp_id
98
        $lp_id = isset($_REQUEST['lp_id']) ? (int) $_REQUEST['lp_id'] : null;
99
        $content = isset($_REQUEST['content']) ? $_REQUEST['content'] : '';
100
        $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null;
101
102
        $repo = null;
103
104
        switch ($content) {
105
            case 'forumcategory':
106
                $repo = Container::getForumCategoryRepository();
107
                break;
108
            case 'forum':
109
                $repo = Container::getForumRepository();
110
                break;
111
            case 'thread':
112
                $repo = Container::getForumThreadRepository();
113
                break;
114
        }
115
116
        if ($repo && $id) {
117
            $resource = $repo->find($id);
118
        }
119
120
        switch ($action) {
121
            case 'add_forum':
122
                $formContent = forumForm(null, $lp_id);
123
124
                return $formContent;
125
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
126
            case 'edit_forum':
127
                $repo = Container::getForumRepository();
128
                $resource = $repo->find($id);
129
                $formContent = forumForm($resource, $lp_id);
130
131
                return $formContent;
132
                break;
133
            case 'add_category':
134
                $formContent = show_add_forumcategory_form([], $lp_id);
135
136
                return $formContent;
137
                break;
138
            case 'edit_category':
139
                $repo = Container::getForumCategoryRepository();
140
                $category = $repo->find($id);
141
                $formContent = editForumCategoryForm($category);
142
143
                return $formContent;
144
                break;
145
            case 'notify':
146
                if (0 != api_get_session_id() &&
147
                    false == api_is_allowed_to_session_edit(false, true)
148
                ) {
149
                    api_not_allowed();
150
                }
151
                $message = set_notification($content, $id);
152
                Display::addFlash(Display::return_message($message, 'confirm', false));
153
154
                header('Location: '. $url);
155
                exit;
156
                break;
157
            case 'lock':
158
            case 'unlock':
159
                if ($resource) {
160
                    if ('lock' === $action) {
161
                        $locked = 1;
162
                        $message = get_lang('Locked: students can no longer post new messages in this forum category, forum or thread but they can still read the messages that were already posted');
163
                    } else  {
164
                        $locked = 0;
165
                        $message = get_lang('Unlocked: learners can post new messages in this forum category, forum or thread');
166
                    }
167
168
                    $resource->setLocked($locked);
169
                    $repo->getEntityManager()->persist($resource);
170
                    $repo->getEntityManager()->flush();
171
172
                    Display::addFlash(
173
                        Display::return_message($message, 'confirmation', false)
174
                    );
175
                }
176
177
                header('Location: '. $url);
178
                exit;
179
                break;
180
            case 'move':
181
                move_up_down($content, $_REQUEST['direction'] ?? '', $id);
182
                header('Location: '. $url);
183
                exit;
184
                break;
185
            case 'move_thread':
186
                $message = move_thread_form();
187
188
                return $message;
189
                break;
190
            case 'visible':
191
            case 'invisible':
192
                if ('visible' === $action) {
193
                    $repo->setVisibilityPublished($resource);
194
                } else {
195
                    $repo->setVisibilityPending($resource);
196
                }
197
198
                if ('visible' === $action) {
199
                    handle_mail_cue($content, $id);
200
                }
201
202
                Display::addFlash(
203
                    Display::return_message(get_lang('Updated'), 'confirmation', false)
204
                );
205
                header('Location: '. $url);
206
                exit;
207
                break;
208
            case 'delete':
209
                $locked = api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD);
210
                if ($resource && false === $locked) {
211
                    $repo->delete($resource);
212
213
                    if ('thread' === $content) {
214
                        $return_message = get_lang('Thread deleted');
215
                        Skill::deleteSkillsFromItem($id, ITEM_TYPE_FORUM_THREAD);
216
                    }
217
218
                    $link_info = GradebookUtils::isResourceInCourseGradebook(
219
                        api_get_course_id(),
220
                        5,
221
                        $id,
222
                        api_get_session_id()
223
                    );
224
225
                    $link_id = $link_info['id'];
226
                    if (false !== $link_info) {
227
                        GradebookUtils::remove_resource_from_course_gradebook($link_id);
228
                    }
229
                }
230
231
                Display::addFlash(Display::return_message(get_lang('Forum category deleted'), 'confirmation', false));
232
                header('Location: '. $url);
233
                exit;
234
                break;
235
        }
236
    }
237
}
238
239
/**
240
 * This function displays the form that is used to add a forum category.
241
 *
242
 * @param array $inputvalues (deprecated, set to null when calling)
243
 * @param int   $lp_id       Learning path ID
244
 *
245
 * @return string
246
 *
247
 * @author Patrick Cool <[email protected]>, Ghent University
248
 * @author Juan Carlos Raña Trabado (return to lp_id)
249
 *
250
 * @version may 2011, Chamilo 1.8.8
251
 */
252
function show_add_forumcategory_form($lp_id)
253
{
254
    $form = new FormValidator(
255
        'forumcategory',
256
        'post',
257
        'index.php?'.api_get_cidreq().'&action=add_category'
258
    );
259
    // hidden field if from learning path
260
    $form->addElement('hidden', 'lp_id', $lp_id);
261
    $form->addElement('hidden', 'action', 'add_category');
262
    // Setting the form elements.
263
    $form->addElement('header', get_lang('Add forum category'));
264
    $form->addElement('text', 'forum_category_title', get_lang('Title'), ['autofocus']);
265
    $form->addElement(
266
        'html_editor',
267
        'forum_category_comment',
268
        get_lang('Description'),
269
        null,
270
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
271
    );
272
273
    $extraField = new ExtraField('forum_category');
274
    $returnParams = $extraField->addElements(
275
        $form,
276
        null,
277
        [], //exclude
278
        false, // filter
279
        false, // tag as select
280
        [], //show only fields
281
        [], // order fields
282
        [] // extra data
283
    );
284
285
    $form->addButtonCreate(get_lang('Create category'), 'SubmitForumCategory');
286
287
    // Setting the rules.
288
    $form->addRule('forum_category_title', get_lang('Required field'), 'required');
289
290
    // The validation or display
291
    if ($form->validate()) {
292
        $check = Security::check_token('post');
293
        if ($check) {
294
            $values = $form->exportValues();
295
            store_forumcategory($values);
296
        }
297
        Security::clear_token();
298
    } else {
299
        $token = Security::get_token();
300
        $form->addElement('hidden', 'sec_token');
301
        $form->setConstants(['sec_token' => $token]);
302
303
        return $form->returnForm();
304
    }
305
}
306
307
function forumForm(CForumForum $forum = null, $lp_id)
308
{
309
    $_course = api_get_course_info();
310
    // The header for the form
311
    $form_title = get_lang('Add a forum');
312
    $action = 'add_forum';
313
    $id = 0;
314
    if ($forum) {
315
        $id = $forum->getIid();
316
        $action = 'edit_forum';
317
        $form_title = get_lang('Edit forum');
318
    }
319
320
    $form = new FormValidator('forumcategory', 'post', 'index.php?'.api_get_cidreq().'&action='.$action.'&id='.$id);
321
    $form->addHidden('action', $action);
322
    $form->addHeader($form_title);
323
324
    // We have a hidden field if we are editing.
325
    if ($forum) {
326
        $form->addElement('hidden', 'forum_id', $id);
327
    }
328
    $lp_id = (int) $lp_id;
329
330
    // hidden field if from learning path
331
    $form->addElement('hidden', 'lp_id', $lp_id);
332
333
    // The title of the forum
334
    $form->addElement('text', 'forum_title', get_lang('Title'), ['autofocus']);
335
336
    // The comment of the forum.
337
    $form->addElement(
338
        'html_editor',
339
        'forum_comment',
340
        get_lang('Description'),
341
        null,
342
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
343
    );
344
345
    // Dropdown list: Forum categories
346
    $forum_categories = get_forum_categories();
347
    $forum_categories_titles = [];
348
    foreach ($forum_categories as $value) {
349
        $forum_categories_titles[$value->getCatId()] = $value->getCatTitle();
350
    }
351
    $form->addElement(
352
        'select',
353
        'forum_category',
354
        get_lang('Create in category'),
355
        $forum_categories_titles
356
    );
357
    $form->applyFilter('forum_category', 'html_filter');
358
359
    if (COURSE_VISIBILITY_OPEN_WORLD == $_course['visibility']) {
360
        // This is for horizontal
361
        $group = [];
362
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('Yes'), 1);
363
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('No'), 0);
364
        $form->addGroup($group, 'allow_anonymous_group', get_lang('Allow anonymous posts?'));
365
    }
366
367
    $form->addButtonAdvancedSettings('advanced_params');
368
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
369
370
    $form->addDateTimePicker(
371
        'start_time',
372
        [get_lang('Public access (access authorized to any member of the course)ation date'), get_lang('Public access (access authorized to any member of the course)ation dateComment')],
373
        ['id' => 'start_time']
374
    );
375
376
    $form->addDateTimePicker(
377
        'end_time',
378
        [get_lang('Closing date'), get_lang('Closing dateComment')],
379
        ['id' => 'end_time']
380
    );
381
382
    $form->addRule(
383
        ['start_time', 'end_time'],
384
        get_lang('Start date must be before the end date'),
385
        'compare_datetime_text',
386
        '< allow_empty'
387
    );
388
389
    $group = [];
390
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('Yes'), 1);
391
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('No'), 0);
392
    $form->addGroup($group, 'moderated', get_lang('Moderated forum'));
393
394
    $group = [];
395
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('Yes'), 1);
396
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('No'), 0);
397
    $form->addGroup($group, 'students_can_edit_group', get_lang('Can learners edit their own posts?'));
398
399
    $group = [];
400
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Approval'), 1);
401
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Direct'), 0);
402
403
    $group = [];
404
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('Yes'), 1);
405
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('No'), 0);
406
407
    $group = [];
408
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('Yes'), 1);
409
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('No'), 0);
410
    $form->addGroup($group, 'allow_new_threads_group', get_lang('Allow users to start new threads'));
411
412
    $group = [];
413
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Flat'), 'flat');
414
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Threaded'), 'threaded');
415
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Nested'), 'nested');
416
    $form->addGroup($group, 'default_view_type_group', get_lang('Default view type'));
417
418
    // Drop down list: Groups
419
    $groups = GroupManager::get_group_list();
420
    $groups_titles[0] = get_lang('Not a group forum');
421
    foreach ($groups as $key => $value) {
422
        $groups_titles[$value['id']] = $value['name'];
423
    }
424
    $form->addElement('select', 'group_forum', get_lang('For Group'), $groups_titles);
425
426
    // Public or private group forum
427
    $group = [];
428
    $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Public access (access authorized to any member of the course)'), 'public');
429
    $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Private access (access authorized to group members only)'), 'private');
430
    $form->addGroup($group, 'public_private_group_forum_group', get_lang('Public access (access authorized to any member of the course)Private access (access authorized to group members only)GroupForum'));
431
432
    // Forum image
433
    $form->addProgress();
434
    /*
435
    if ($forum) {
436
        $baseImagePath = api_get_course_path().'/upload/forum/images/'.$inputvalues['forum_image'];
437
        $image_path = api_get_path(WEB_COURSE_PATH).$baseImagePath;
438
        $sysImagePath = api_get_path(SYS_COURSE_PATH).$baseImagePath;
439
440
        if (file_exists($sysImagePath)) {
441
            $show_preview_image = Display::img(
442
                $image_path,
443
                null,
444
                ['class' => 'img-responsive']
445
            );
446
            $form->addElement('label', get_lang('Preview image'), $show_preview_image);
447
            $form->addElement('checkbox', 'remove_picture', null, get_lang('Remove picture'));
448
        }
449
    }
450
    $forum_image = isset($inputvalues['forum_image']) ? $inputvalues['forum_image'] : '';
451
    $form->addElement('file', 'picture', ('' != $forum_image ? get_lang('Update Image') : get_lang('Add image')));
452
    $form->addRule(
453
        'picture',
454
        get_lang('Only PNG, JPG or GIF images allowed'),
455
        'filetype',
456
        ['jpg', 'jpeg', 'png', 'gif']
457
    );*/
458
459
    //$forumId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
460
    //$skillList = Skill::addSkillsToForm($form, ITEM_TYPE_FORUM, $forumId);
461
462
    $form->addElement('html', '</div>');
463
464
    // The OK button
465
    if ($forum) {
466
        $form->addButtonUpdate(get_lang('Edit forum'), 'SubmitForum');
467
    } else {
468
        $form->addButtonCreate(get_lang('Create forum'), 'SubmitForum');
469
    }
470
471
    // setting the rules
472
    $form->addRule('forum_title', get_lang('Required field'), 'required');
473
    $form->addRule('forum_category', get_lang('Required field'), 'required');
474
475
    $defaultSettingAllowNewThreads = api_get_default_tool_setting('forum', 'allow_new_threads', 0);
476
477
    // Settings the defaults
478
    if (null === $forum) {
479
        $defaults['moderated']['moderated'] = 0;
480
        $defaults['allow_anonymous_group']['allow_anonymous'] = 0;
481
        $defaults['students_can_edit_group']['students_can_edit'] = 0;
482
        $defaults['approval_direct_group']['approval_direct'] = 0;
483
        $defaults['allow_attachments_group']['allow_attachments'] = 1;
484
        $defaults['allow_new_threads_group']['allow_new_threads'] = $defaultSettingAllowNewThreads;
485
        $defaults['default_view_type_group']['default_view_type'] = api_get_setting('default_forum_view');
486
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = 'public';
487
        if (isset($_GET['forumcategory'])) {
488
            $defaults['forum_category'] = Security::remove_XSS($_GET['forumcategory']);
489
        }
490
    } else {
491
        // the default values when editing = the data in the table
492
        $defaults['forum_id'] = $forum->getIid();
493
        $defaults['forum_title'] = prepare4display($forum->getForumTitle());
494
        $defaults['forum_comment'] = prepare4display($forum->getForumComment());
495
        $defaults['start_time'] = api_get_local_time($forum->getStartTime());
496
        $defaults['end_time'] = api_get_local_time($forum->getEndTime());
497
        $defaults['moderated']['moderated'] = $forum->isModerated();
498
        $defaults['forum_category'] = $forum->getForumCategory()->getIid();
499
        $defaults['allow_anonymous_group']['allow_anonymous'] = $forum->getAllowAnonymous();
500
        $defaults['students_can_edit_group']['students_can_edit'] = $forum->getAllowEdit();
501
        $defaults['approval_direct_group']['approval_direct'] = $forum->getApprovalDirectPost();
502
        $defaults['allow_attachments_group']['allow_attachments'] = $forum->getAllowAttachments();
503
        $defaults['allow_new_threads_group']['allow_new_threads'] = $forum->getAllowNewThreads();
504
        $defaults['default_view_type_group']['default_view_type'] = $forum->getDefaultView();
505
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = $forum->getForumGroupPublicPrivate();
506
        $defaults['group_forum'] = $forum->getForumOfGroup();
507
    }
508
509
    $form->setDefaults($defaults);
510
    // Validation or display
511
    if ($form->validate()) {
512
        $check = Security::check_token('post');
513
        if ($check) {
514
            $values = $form->getSubmitValues();
515
            $forumId = store_forum($values, '', true);
516
            if ($forumId) {
517
                // Skill::saveSkills($form, ITEM_TYPE_FORUM, $forumId);
518
                if (isset($values['forum_id'])) {
519
                    Display::addFlash(Display::return_message(get_lang('The forum has been modified'), 'confirmation'));
520
                } else {
521
                    Display::addFlash(Display::return_message(get_lang('The forum has been added'), 'confirmation'));
522
                }
523
            }
524
            $url = api_get_path(WEB_CODE_PATH).'forum/index.php?'.api_get_cidreq();
525
            header('Location: '.$url);
526
            exit;
527
        }
528
        Security::clear_token();
529
    } else {
530
        $token = Security::get_token();
531
        $form->addElement('hidden', 'sec_token');
532
        $form->setConstants(['sec_token' => $token]);
533
534
        return $form->returnForm();
535
    }
536
}
537
538
/**
539
 * This function deletes the forum image if exists.
540
 *
541
 * @param int $forum_id forum id
542
 *
543
 * @return bool true if success
544
 *
545
 * @author Julio Montoya <[email protected]>
546
 *
547
 * @version february 2006, dokeos 1.8
548
 */
549
function delete_forum_image($forum_id)
550
{
551
    $table_forums = Database::get_course_table(TABLE_FORUM);
552
    $course_id = api_get_course_int_id();
553
    $forum_id = (int) $forum_id;
554
555
    $sql = "SELECT forum_image FROM $table_forums
556
            WHERE forum_id = $forum_id AND c_id = $course_id";
557
    $result = Database::query($sql);
558
    $row = Database::fetch_array($result);
559
    if ('' != $row['forum_image']) {
560
        $file = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/forum/images/'.$row['forum_image'];
561
        if (file_exists($file)) {
562
            unlink($file);
563
        }
564
565
        return true;
566
    } else {
567
        return false;
568
    }
569
}
570
571
function editForumCategoryForm(CForumCategory $category)
572
{
573
    $categoryId = $category->getIid();
574
    $form = new FormValidator('forumcategory', 'post', 'index.php?action=edit_category&'.api_get_cidreq().'&id='.$categoryId);
575
576
    // Setting the form elements.
577
    $form->addElement('header', '', get_lang('Edit forumCategory'));
578
579
    $form->addElement('hidden', 'action', 'edit_category');
580
    $form->addElement('hidden', 'forum_category_id');
581
    $form->addElement('text', 'forum_category_title', get_lang('Title'));
582
583
    $form->addElement(
584
        'html_editor',
585
        'forum_category_comment',
586
        get_lang('Comment'),
587
        null,
588
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
589
    );
590
591
    $extraField = new ExtraField('forum_category');
592
    $returnParams = $extraField->addElements(
593
        $form,
594
        $categoryId,
595
        [], //exclude
596
        false, // filter
597
        false, // tag as select
598
        [], //show only fields
599
        [], // order fields
600
        [] // extra data
601
    );
602
603
    $form->addButtonUpdate(get_lang('Edit category'), 'SubmitEdit forumCategory');
604
605
    // Setting the default values.
606
    $defaultvalues['forum_category_id'] = $categoryId;
607
    $defaultvalues['forum_category_title'] = $category->getCatTitle();
608
    $defaultvalues['forum_category_comment'] = $category->getCatComment();
609
    $form->setDefaults($defaultvalues);
610
611
    // Setting the rules.
612
    $form->addRule('forum_category_title', get_lang('Required field'), 'required');
613
614
    // Validation or display
615
    if ($form->validate()) {
616
        $check = Security::check_token('post');
617
        if ($check) {
618
            $values = $form->exportValues();
619
            store_forumcategory($values);
620
        }
621
        Security::clear_token();
622
    } else {
623
        $token = Security::get_token();
624
        $form->addElement('hidden', 'sec_token');
625
        $form->setConstants(['sec_token' => $token]);
626
627
        return $form->returnForm();
628
    }
629
}
630
631
/**
632
 * This function stores the forum category in the database.
633
 * The new category is added to the end.
634
 *
635
 * @param array $values
636
 * @param array $courseInfo
637
 * @param bool  $showMessage
638
 */
639
function store_forumcategory($values, $courseInfo = [], $showMessage = true)
640
{
641
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
642
    $course_id = $courseInfo['real_id'];
643
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
644
645
    // Find the max cat_order. The new forum category is added at the end => max cat_order + &
646
    $sql = "SELECT MAX(cat_order) as sort_max
647
            FROM $table_categories
648
            WHERE c_id = $course_id";
649
    $result = Database::query($sql);
650
    $row = Database::fetch_array($result);
651
    $new_max = $row['sort_max'] + 1;
652
    $session_id = api_get_session_id();
653
    $clean_cat_title = $values['forum_category_title'];
654
    $last_id = null;
655
656
    $repo = Container::getForumCategoryRepository();
657
658
    if (isset($values['forum_category_id'])) {
659
        /** @var CForumCategory $category */
660
        $category = $repo->find($values['forum_category_id']);
661
        $category
662
            ->setCatComment(isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '')
663
            ->setCatTitle($values['forum_category_title'])
664
        ;
665
666
        $repo->getEntityManager()->persist($category);
667
        $repo->getEntityManager()->flush();
668
669
        /*api_item_property_update(
670
            $courseInfo,
671
            TOOL_FORUM_CATEGORY,
672
            $values['forum_category_id'],
673
            'ForumCategoryUpdated',
674
            api_get_user_id()
675
        );*/
676
        $return_message = get_lang('The forum category has been modified');
677
678
        $logInfo = [
679
            'tool' => TOOL_FORUM,
680
            'action' => 'update-forumcategory',
681
            'action_details' => 'forumcategory',
682
            'info' => $clean_cat_title,
683
        ];
684
        Event::registerLog($logInfo);
685
686
        $values['item_id'] = $values['forum_category_id'];
687
    } else {
688
        $category = new CForumCategory();
689
        $category
690
            ->setCatTitle($clean_cat_title)
691
            ->setCatComment(isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '')
692
            ->setCatOrder($new_max)
693
            ->setCId($course_id)
694
            ->setSessionId($session_id)
695
        ;
696
        $user = api_get_user_entity(api_get_user_id());
697
        $course = api_get_course_entity($course_id);
698
        $session = api_get_session_entity($session_id);
699
700
        $repo->addResourceToCourse($category, ResourceLink::VISIBILITY_PUBLISHED, $user, $course, $session);
701
        $repo->getEntityManager()->persist($category);
702
        $repo->getEntityManager()->flush();
703
704
        $last_id = $category->getIid();
705
706
        if ($last_id > 0) {
707
            $sql = "UPDATE $table_categories SET cat_id = $last_id WHERE iid = $last_id";
708
            Database::query($sql);
709
710
            /*api_item_property_update(
711
                $courseInfo,
712
                TOOL_FORUM_CATEGORY,
713
                $last_id,
714
                'ForumCategoryAdded',
715
                api_get_user_id()
716
            );
717
            api_set_default_visibility(
718
                $last_id,
719
                TOOL_FORUM_CATEGORY,
720
                0,
721
                $courseInfo
722
            );*/
723
        }
724
        $return_message = get_lang('The forum category has been added');
725
726
        $logInfo = [
727
            'tool' => TOOL_FORUM,
728
            'tool_id' => 0,
729
            'tool_id_detail' => 0,
730
            'action' => 'new-forumcategory',
731
            'action_details' => 'forumcategory',
732
            'info' => $clean_cat_title,
733
        ];
734
        Event::registerLog($logInfo);
735
736
        $values['item_id'] = $last_id;
737
    }
738
739
    $extraFieldValue = new ExtraFieldValue('forum_category');
740
    $extraFieldValue->saveFieldValues($values);
741
742
    if ($showMessage) {
743
        Display::addFlash(Display::return_message($return_message, 'confirmation'));
744
    }
745
746
    return $last_id;
747
}
748
749
/**
750
 * This function stores the forum in the database. The new forum is added to the end.
751
 *
752
 * @param array $values
753
 * @param array $courseInfo
754
 * @param bool  $returnId
755
 *
756
 * @return string language variable
757
 */
758
function store_forum($values, $courseInfo = [], $returnId = false)
759
{
760
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
761
    $courseId = $courseInfo['real_id'];
762
    $session_id = api_get_session_id();
763
    $table_forums = Database::get_course_table(TABLE_FORUM);
764
765
    // Find the max forum_order for the given category. The new forum is added at the end => max cat_order + &
766
    if (null === $values['forum_category']) {
767
        $new_max = null;
768
    } else {
769
        $sql = "SELECT MAX(forum_order) as sort_max
770
                FROM $table_forums
771
                WHERE
772
                    c_id = $courseId AND
773
                    forum_category='".Database::escape_string($values['forum_category'])."'";
774
        $result = Database::query($sql);
775
        $row = Database::fetch_array($result);
776
        $new_max = $row['sort_max'] + 1;
777
    }
778
779
    // Forum images
780
    $has_attachment = false;
781
    $image_moved = true;
782
    if (!empty($_FILES['picture']['name'])) {
783
        $upload_ok = process_uploaded_file($_FILES['picture']);
784
        $has_attachment = true;
785
    }
786
787
    // Remove existing picture if it was requested.
788
    if (!empty($_POST['remove_picture'])) {
789
        delete_forum_image($values['forum_id']);
790
    }
791
792
    $new_file_name = '';
793
    if (isset($upload_ok)) {
794
        if ($has_attachment) {
795
            $course_dir = $courseInfo['path'].'/upload/forum/images';
796
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
797
            $updir = $sys_course_path.$course_dir;
798
            // Try to add an extension to the file if it hasn't one.
799
            $new_file_name = add_ext_on_mime(
800
                Database::escape_string($_FILES['picture']['name']),
801
                $_FILES['picture']['type']
802
            );
803
            if (!filter_extension($new_file_name)) {
804
                //Display::addFlash(Display::return_message(get_lang('File upload failed: this file extension or file type is prohibited'), 'error'));
805
                $image_moved = false;
806
            } else {
807
                $file_extension = explode('.', $_FILES['picture']['name']);
808
                $file_extension = strtolower($file_extension[count($file_extension) - 1]);
809
                $new_file_name = uniqid('').'.'.$file_extension;
810
                $new_path = $updir.'/'.$new_file_name;
811
                $result = @move_uploaded_file($_FILES['picture']['tmp_name'], $new_path);
812
                // Storing the attachments if any
813
                if ($result) {
814
                    $image_moved = true;
815
                }
816
            }
817
        }
818
    }
819
820
    $repo = Container::getForumRepository();
821
822
    if (!isset($values['forum_id'])) {
823
        $forum = new CForumForum();
824
        $forum
825
            ->setCId($courseId)
826
            ->setSessionId($session_id)
827
            ->setForumOrder(isset($new_max) ? $new_max : null)
828
        ;
829
    } else {
830
        $forum = $repo->find($values['forum_id']);
831
    }
832
833
    $forumCategory = null;
834
    if (!empty($values['forum_category'])) {
835
        $repoForumCategory = Container::getForumCategoryRepository();
836
        $forumCategory = $repoForumCategory->find($values['forum_category']);
837
    }
838
    //'forum_image' => $new_file_name,
839
    $forum
840
        ->setForumTitle($values['forum_title'])
841
        ->setForumComment($values['forum_comment'] ?? null)
842
        ->setForumCategory($forumCategory)
843
        ->setAllowAnonymous($values['allow_anonymous_group']['allow_anonymous'] ?? null)
844
        ->setAllowEdit($values['students_can_edit_group']['students_can_edit'] ?? null)
845
        ->setApprovalDirectPost($values['approval_direct_group']['approval_direct'] ?? null)
846
        ->setAllowAttachments($values['allow_attachments_group']['allow_attachments'] ?? null)
847
        ->setAllowNewThreads($values['allow_new_threads_group']['allow_new_threads'] ?? null)
848
        ->setDefaultView($values['default_view_type_group']['default_view_type'] ?? null)
849
        ->setForumOfGroup($values['group_forum'] ?? null)
850
        ->setForumGroupPublicPrivate($values['public_private_group_forum_group']['public_private_group_forum'] ?? '')
851
        ->setModerated($values['moderated']['moderated'] ?? null)
852
        ->setStartTime(!empty($values['start_time']) ? api_get_utc_datetime($values['start_time'], true, true) : null)
853
        ->setEndTime(!empty($values['end_time']) ? api_get_utc_datetime($values['end_time'], true, true) : null)
854
        ->setSessionId($session_id)
855
        ->setLpId($values['lp_id'] ?? 0)
856
    ;
857
858
    $user = api_get_user_entity(api_get_user_id());
859
    $course = api_get_course_entity($courseId);
860
    $session = api_get_session_entity($session_id);
861
862
    if (isset($values['forum_id'])) {
863
        // Edit
864
        $repo->getEntityManager()->persist($forum);
865
        $repo->getEntityManager()->flush();
866
867
        if (isset($upload_ok)) {
868
            if ($has_attachment) {
869
                //$params['forum_image'] = $new_file_name;
870
            }
871
        }
872
873
        if (isset($values['remove_picture']) && 1 == $values['remove_picture']) {
874
            /*$params['forum_image'] = '';
875
            delete_forum_image($values['forum_id']);*/
876
        }
877
878
        // Move groups from one group to another
879
        if (isset($values['group_forum']) && false) {
880
            $forumData = get_forums($values['forum_id']);
881
            $currentGroupId = $forumData['forum_of_group'];
882
            if ($currentGroupId != $values['group_forum']) {
883
                $threads = get_threads($values['forum_id']);
884
                $toGroupId = 'NULL';
885
                if (!empty($values['group_forum'])) {
886
                    $toGroupId = $values['group_forum'];
887
                }
888
                $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
889
                foreach ($threads as $thread) {
890
                    $sql = "UPDATE $tableItemProperty
891
                            SET to_group_id = $toGroupId
892
                            WHERE
893
                                tool = '".TOOL_FORUM_THREAD."' AND
894
                                ref = ".$thread['thread_id'].' AND
895
                                c_id = '.$courseId;
896
                    Database::query($sql);
897
898
                    $posts = getPosts(
899
                        $forumData,
900
                        $thread['thread_id']
901
                    );
902
903
                    /*foreach ($posts as $post) {
904
                        $postId = $post['post_id'];
905
                        $attachMentList = getAllAttachment($postId);
906
                        if (!empty($attachMentList)) {
907
                            foreach ($attachMentList as $attachMent) {
908
                                $sql = "UPDATE $tableItemProperty
909
                                        SET to_group_id = $toGroupId
910
                                        WHERE
911
                                            tool = '".TOOL_FORUM_ATTACH."' AND
912
                                            ref = ".$attachMent['iid'].' AND
913
                                            c_id = '.$courseId;
914
                                Database::query($sql);
915
                            }
916
                        }
917
918
                        $sql = "UPDATE $tableItemProperty
919
                                SET to_group_id = $toGroupId
920
                                WHERE
921
                                    tool = '".TOOL_FORUM_POST."' AND
922
                                    ref = $postId AND
923
                                    c_id = $courseId";
924
                        Database::query($sql);
925
                    }*/
926
                }
927
            }
928
        }
929
930
        /*
931
        api_item_property_update(
932
            $courseInfo,
933
            TOOL_FORUM,
934
            Database::escape_string($values['forum_id']),
935
            'ForumUpdated',
936
            api_get_user_id(),
937
            $groupInfo
938
        );*/
939
940
        $return_message = get_lang('The forum has been modified');
941
        $forumId = $forum->getIid();
942
943
        $logInfo = [
944
            'tool' => TOOL_FORUM,
945
            'tool_id' => $values['forum_id'],
946
            'action' => 'update-forum',
947
            'action_details' => 'forum',
948
            'info' => $values['forum_title'],
949
        ];
950
        Event::registerLog($logInfo);
951
    } else {
952
        if ($image_moved) {
953
            $new_file_name = isset($new_file_name) ? $new_file_name : '';
954
        }
955
956
        $repo->addResourceToCourse($forum, ResourceLink::VISIBILITY_PUBLISHED, $user, $course, $session);
957
        $repo->getEntityManager()->persist($forum);
958
        $repo->getEntityManager()->flush();
959
960
        $forumId = $forum->getIid();
961
        if ($forumId > 0) {
962
            $sql = "UPDATE $table_forums SET forum_id = iid WHERE iid = $forumId";
963
            Database::query($sql);
964
            $courseCode = $courseInfo['code'];
965
            $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications');
966
967
            $status = STUDENT;
968
            if (!empty($session_id)) {
969
                $status = 0;
970
            }
971
            if (1 === $subscribe) {
972
                $userList = CourseManager::get_user_list_from_course_code(
973
                    $courseCode,
974
                    $session_id,
975
                    null,
976
                    null,
977
                    $status
978
                );
979
                foreach ($userList as $userInfo) {
980
                    set_notification('forum', $forumId, false, $userInfo, $courseInfo);
981
                }
982
            }
983
984
            /*api_item_property_update(
985
                $courseInfo,
986
                TOOL_FORUM,
987
                $forumId,
988
                'ForumAdded',
989
                api_get_user_id(),
990
                $groupInfo
991
            );
992
993
            api_set_default_visibility(
994
                $forumId,
995
                TOOL_FORUM,
996
                $group_id,
997
                $courseInfo
998
            );*/
999
1000
            $logInfo = [
1001
                'tool' => TOOL_FORUM,
1002
                'tool_id' => $forumId,
1003
                'action' => 'new-forum',
1004
                'action_details' => 'forum',
1005
                'info' => $values['forum_title'],
1006
            ];
1007
            Event::registerLog($logInfo);
1008
        }
1009
        $return_message = get_lang('The forum has been added');
1010
    }
1011
1012
    if ($returnId) {
1013
        return $forumId;
1014
    }
1015
1016
    return $return_message;
1017
}
1018
1019
/**
1020
 * This function deletes a forum post. This separate function is needed because forum posts do not appear
1021
 * in the item_property table (yet)
1022
 * and because deleting a post also has consequence on the posts that have this post as parent_id
1023
 * (they are also deleted).
1024
 * an alternative would be to store the posts also in item_property and mark this post as deleted (visibility = 2).
1025
 * We also have to decrease the number of replies in the thread table.
1026
 *
1027
 * @param the $post_id id of the post that will be deleted
1028
 *
1029
 * @todo write recursive function that deletes all the posts that have this message as parent
1030
 *
1031
 * @return string language variable
1032
 *
1033
 * @author Patrick Cool <[email protected]>, Ghent University
1034
 * @author Hubert Borderiou Function cleanead and fixed
1035
 *
1036
 * @version february 2006
1037
 */
1038
function delete_post($post_id)
1039
{
1040
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1041
    $post_id = (int) $post_id;
1042
    $course_id = api_get_course_int_id();
1043
    $em = Database::getManager();
1044
    /** @var CForumPost $post */
1045
    $post = $em
1046
        ->getRepository('ChamiloCourseBundle:CForumPost')
1047
        ->findOneBy(['cId' => $course_id, 'postId' => $post_id]);
1048
1049
    if ($post) {
1050
        $em
1051
            ->createQuery('
1052
                UPDATE ChamiloCourseBundle:CForumPost p
1053
                SET p.postParentId = :parent_of_deleted_post
1054
                WHERE
1055
                    p.cId = :course AND
1056
                    p.postParentId = :post AND
1057
                    p.thread = :thread_of_deleted_post AND
1058
                    p.forum = :forum_of_deleted_post
1059
            ')
1060
            ->execute([
1061
                'parent_of_deleted_post' => $post->getPostParentId(),
1062
                'course' => $course_id,
1063
                'post' => $post->getPostId(),
1064
                'thread_of_deleted_post' => $post->getThread() ? $post->getThread()->getIid() : 0,
1065
                'forum_of_deleted_post' => $post->getForum(),
1066
            ]);
1067
1068
        $attachments = $post->getAttachments();
1069
        if (!empty($attachments)) {
1070
            foreach ($attachments as $attachment) {
1071
                $em->remove($attachment);
1072
            }
1073
        }
1074
1075
        $em->remove($post);
1076
        $em->flush();
1077
    }
1078
1079
    $last_post_of_thread = check_if_last_post_of_thread($_GET['thread']);
1080
1081
    if (is_array($last_post_of_thread)) {
1082
        // Decreasing the number of replies for this thread and also changing the last post information.
1083
        $sql = "UPDATE $table_threads
1084
                SET
1085
                    thread_replies = thread_replies - 1,
1086
                    thread_last_post = ".(int) ($last_post_of_thread['post_id']).",
1087
                    thread_date='".Database::escape_string($last_post_of_thread['post_date'])."'
1088
                WHERE c_id = $course_id AND thread_id = ".(int) ($_GET['thread']);
1089
        Database::query($sql);
1090
1091
        return 'PostDeleted';
1092
    }
1093
    if (!$last_post_of_thread) {
1094
        // We deleted the very single post of the thread so we need to delete the entry in the thread table also.
1095
        $sql = "DELETE FROM $table_threads
1096
                WHERE c_id = $course_id AND thread_id = ".(int) ($_GET['thread']);
1097
        Database::query($sql);
1098
1099
        return 'PostDeletedSpecial';
1100
    }
1101
}
1102
1103
/**
1104
 * This function gets the all information of the last (=most recent) post of the thread
1105
 * This can be done by sorting the posts that have the field thread_id=$thread_id and sort them by post_date.
1106
 *
1107
 * @param the $thread_id id of the thread we want to know the last post of
1108
 *
1109
 * @return an array or bool if there is a last post found, false if there is
1110
 *            no post entry linked to that thread => thread will be deleted
1111
 *
1112
 * @author Patrick Cool <[email protected]>, Ghent University
1113
 *
1114
 * @version february 2006, dokeos 1.8
1115
 */
1116
function check_if_last_post_of_thread($thread_id)
1117
{
1118
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1119
    $course_id = api_get_course_int_id();
1120
    $sql = "SELECT * FROM $table_posts
1121
            WHERE c_id = $course_id AND thread_id = ".(int) $thread_id.'
1122
            ORDER BY post_date DESC';
1123
    $result = Database::query($sql);
1124
    if (Database::num_rows($result) > 0) {
1125
        return Database::fetch_array($result);
1126
    } else {
1127
        return false;
1128
    }
1129
}
1130
1131
/**
1132
 * @param string $content                   Type of content forum category, forum, thread, post
1133
 * @param int    $id                        the id of the content we want to make invisible
1134
 * @param int    $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
1135
 * @param array  $additional_url_parameters
1136
 *
1137
 * @return string HTML
1138
 */
1139
function return_visible_invisible_icon(
1140
    $content,
1141
    $id,
1142
    $current_visibility_status,
1143
    $additional_url_parameters = ''
1144
) {
1145
    $html = '';
1146
    $id = (int) $id;
1147
1148
    if ($current_visibility_status) {
1149
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1150
        if (is_array($additional_url_parameters)) {
1151
            foreach ($additional_url_parameters as $key => $value) {
1152
                $html .= $key.'='.$value.'&';
1153
            }
1154
        }
1155
        $html .= 'action=invisible&content='.$content.'&id='.$id.'">'.
1156
            Display::return_icon('visible.png', get_lang('Make invisible'), [], ICON_SIZE_SMALL).'</a>';
1157
    } else {
1158
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1159
        if (is_array($additional_url_parameters)) {
1160
            foreach ($additional_url_parameters as $key => $value) {
1161
                $html .= $key.'='.$value.'&';
1162
            }
1163
        }
1164
        $html .= 'action=visible&content='.$content.'&id='.$id.'">'.
1165
            Display::return_icon('invisible.png', get_lang('Make Visible'), [], ICON_SIZE_SMALL).'</a>';
1166
    }
1167
1168
    return $html;
1169
}
1170
1171
/**
1172
 * @param $content
1173
 * @param $id
1174
 * @param $current_lock_status
1175
 * @param string $additional_url_parameters
1176
 *
1177
 * @return string
1178
 */
1179
function return_lock_unlock_icon($content, $id, $current_lock_status, $additional_url_parameters = '')
1180
{
1181
    $html = '';
1182
    $id = (int) $id;
1183
    //check if the forum is blocked due
1184
    if ('thread' == $content) {
1185
        if (api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD)) {
1186
            return $html.Display::return_icon(
1187
                'lock_na.png',
1188
                get_lang('This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'),
1189
                [],
1190
                ICON_SIZE_SMALL
1191
            );
1192
        }
1193
    }
1194
    if ('1' == $current_lock_status) {
1195
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1196
        if (is_array($additional_url_parameters)) {
1197
            foreach ($additional_url_parameters as $key => $value) {
1198
                $html .= $key.'='.$value.'&';
1199
            }
1200
        }
1201
        $html .= 'action=unlock&content='.$content.'&id='.$id.'">'.
1202
            Display::return_icon('lock.png', get_lang('Unlock'), [], ICON_SIZE_SMALL).'</a>';
1203
    }
1204
    if ('0' == $current_lock_status) {
1205
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1206
        if (is_array($additional_url_parameters)) {
1207
            foreach ($additional_url_parameters as $key => $value) {
1208
                $html .= $key.'='.$value.'&';
1209
            }
1210
        }
1211
        $html .= 'action=lock&content='.$content.'&id='.$id.'">'.
1212
            Display::return_icon('unlock.png', get_lang('Lock'), [], ICON_SIZE_SMALL).'</a>';
1213
    }
1214
1215
    return $html;
1216
}
1217
1218
/**
1219
 * This function takes care of the display of the up and down icon.
1220
 *
1221
 * @param string $content what is it that we want to make (in)visible: forum category, forum, thread, post
1222
 * @param int    $id      is the id of the item we want to display the icons for
1223
 * @param array  $list    is an array of all the items. All items in this list should have
1224
 *                        an up and down icon except for the first (no up icon) and the last (no down icon)
1225
 *                        The key of this $list array is the id of the item.
1226
 *
1227
 * @return string HTML
1228
 */
1229
function return_up_down_icon($content, $id, $list)
1230
{
1231
    $id = (int) $id;
1232
    $total_items = count($list);
1233
    $position = 0;
1234
    $internal_counter = 0;
1235
    $forumCategory = isset($_GET['forumcategory']) ? Security::remove_XSS($_GET['forumcategory']) : null;
1236
1237
    if (is_array($list)) {
1238
        foreach ($list as $item) {
1239
            $internal_counter++;
1240
            if ($id == $item->getIid()) {
1241
                $position = $internal_counter;
1242
            }
1243
        }
1244
    }
1245
1246
    if ($position > 1) {
1247
        $return_value = '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=up&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('Move up').'">'.
1248
            Display::return_icon('up.png', get_lang('Move up'), [], ICON_SIZE_SMALL).'</a>';
1249
    } else {
1250
        $return_value = Display::return_icon('up_na.png', '-', [], ICON_SIZE_SMALL);
1251
    }
1252
1253
    if ($position < $total_items) {
1254
        $return_value .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=down&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('Move down').'" >'.
1255
            Display::return_icon('down.png', get_lang('Move down'), [], ICON_SIZE_SMALL).'</a>';
1256
    } else {
1257
        $return_value .= Display::return_icon('down_na.png', '-', [], ICON_SIZE_SMALL);
1258
    }
1259
1260
    return $return_value;
1261
}
1262
1263
1264
/**
1265
 * This function moves a forum or a forum category up or down.
1266
 *
1267
 * @param what $content   is it that we want to make (in)visible: forum category, forum, thread, post
1268
 * @param do   $direction we want to move it up or down
1269
 * @param the  $id        id of the content we want to make invisible
1270
 *
1271
 * @todo consider removing the table_item_property calls here but this can
1272
 * prevent unwanted side effects when a forum does not have an entry in
1273
 * the item_property table but does have one in the forum table.
1274
 *
1275
 * @return string language variable
1276
 *
1277
 * @author Patrick Cool <[email protected]>, Ghent University
1278
 *
1279
 * @version february 2006, dokeos 1.8
1280
 */
1281
function move_up_down($content, $direction, $id)
1282
{
1283
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1284
    $table_forums = Database::get_course_table(TABLE_FORUM);
1285
    $course_id = api_get_course_int_id();
1286
    $id = (int) $id;
1287
1288
    // Determine which field holds the sort order.
1289
    if ('forumcategory' == $content) {
1290
        $table = $table_categories;
1291
        $sort_column = 'cat_order';
1292
        $id_column = 'cat_id';
1293
        $sort_column = 'cat_order';
1294
    } elseif ('forum' == $content) {
1295
        $table = $table_forums;
1296
        $sort_column = 'forum_order';
1297
        $id_column = 'forum_id';
1298
        $sort_column = 'forum_order';
1299
        // We also need the forum_category of this forum.
1300
        $sql = "SELECT forum_category FROM $table_forums
1301
                WHERE c_id = $course_id AND forum_id = ".(int) $id;
1302
        $result = Database::query($sql);
1303
        $row = Database::fetch_array($result);
1304
        $forum_category = $row['forum_category'];
1305
    } else {
1306
        return false;
1307
    }
1308
1309
    // Determine the need for sorting ascending or descending order.
1310
    if ('down' == $direction) {
1311
        $sort_direction = 'ASC';
1312
    } elseif ('up' == $direction) {
1313
        $sort_direction = 'DESC';
1314
    } else {
1315
        return false;
1316
    }
1317
1318
    // The SQL statement
1319
    if ('forumcategory' == $content) {
1320
        $sql = "SELECT *
1321
                FROM $table_categories forum_categories
1322
                WHERE
1323
                    forum_categories.c_id = $course_id
1324
                ORDER BY forum_categories.cat_order $sort_direction";
1325
    }
1326
    if ('forum' == $content) {
1327
        $sql = "SELECT *
1328
            FROM $table
1329
            WHERE
1330
                c_id = $course_id AND
1331
                forum_category='".Database::escape_string($forum_category)."'
1332
            ORDER BY forum_order $sort_direction";
1333
    }
1334
    // Finding the items that need to be switched.
1335
    $result = Database::query($sql);
1336
    $found = false;
1337
    $next_sort = '';
1338
    $this_sort = '';
1339
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1340
        //var_dump($content, $row, $id_column, $sort_column);
1341
        if ($found) {
1342
            $next_id = $row[$id_column];
1343
            $next_sort = $row[$sort_column];
1344
            $found = false;
1345
        }
1346
        if ($id == $row[$id_column]) {
1347
            $this_id = $id;
1348
            $this_sort = $row[$sort_column];
1349
            $found = true;
1350
        }
1351
    }
1352
1353
    if ('forum' == $content && $next_sort) {
1354
        $repo = Container::getForumRepository();
1355
        /** @var CForumForum $forum */
1356
        $forum = $repo->find($id);
1357
        $forum->setForumOrder($next_sort);
1358
        $repo->getEntityManager()->persist($forum);
1359
        $repo->getEntityManager()->flush();
1360
1361
        Display::addFlash(Display::return_message(get_lang('Updated')));
1362
    } else {
1363
        if ($next_sort) {
1364
            $repo = Container::getForumCategoryRepository();
1365
            /** @var CForumCategory $forum */
1366
            $category = $repo->find($id);
1367
            if ($category) {
1368
1369
                $category->setCatOrder($next_sort);
1370
                $repo->getEntityManager()->persist($category);
1371
                $repo->getEntityManager()->flush();
1372
1373
                Display::addFlash(Display::return_message(get_lang('Updated')));
1374
            }
1375
        }
1376
    }
1377
}
1378
1379
/**
1380
 * Retrieve all the information off the forum categories (or one specific) for the current course.
1381
 * The categories are sorted according to their sorting order (cat_order.
1382
 *
1383
 * @param int        $courseId  Optional. The course ID
1384
 * @param int        $sessionId Optional. The session ID
1385
 *
1386
 * @return CForumCategory[]
1387
 */
1388
function get_forum_categories($courseId = 0, $sessionId = 0)
1389
{
1390
    $repo = Container::getForumCategoryRepository();
1391
1392
    $course = api_get_course_entity($courseId);
1393
    $session = api_get_session_entity($sessionId);
1394
1395
    $qb = $repo->getResources(api_get_user_entity(api_get_user_id()), $course->getResourceNode(), $course, $session);
1396
1397
    return $qb->getQuery()->getResult();
1398
}
1399
1400
/**
1401
 * This function retrieves all the fora in a given forum category.
1402
 *
1403
 * @param int $categoryId   the id of the forum category
1404
 * @param int $courseId Optional. The course ID
1405
 *
1406
 * @return CForumForum[] containing all the information about the forums (regardless of their category)
1407
 *
1408
 * @author Patrick Cool <[email protected]>, Ghent University
1409
 *
1410
 * @version february 2006, dokeos 1.8
1411
 */
1412
function get_forums_in_category($categoryId, $courseId = 0)
1413
{
1414
    $repo = Container::getForumRepository();
1415
    $course = api_get_course_entity($courseId);
1416
1417
    $qb = $repo->getResourcesByCourse($course, null);
1418
    $qb
1419
        ->andWhere('resource.forumCategory = :catId')
1420
        ->setParameter('catId', $categoryId)
1421
        ->orderBy('resource.forumOrder')
1422
    ;
1423
1424
    return $qb->getQuery()->getResult();
1425
}
1426
1427
/**
1428
 * Retrieve all the forums (regardless of their category) or of only one.
1429
 * The forums are sorted according to the forum_order.
1430
 * Since it does not take the forum category into account there probably
1431
 * will be two or more forums that have forum_order=1, ...
1432
 *
1433
 * @param int  $id                 forum id
1434
 * @param bool $includeGroupsForum
1435
 * @param int  $sessionId
1436
 *
1437
 * @return CForumForum[]
1438
 */
1439
function get_forums(
1440
    $courseId = '',
1441
    $includeGroupsForum = true,
1442
    $sessionId = 0
1443
) {
1444
    $repo = Container::getForumRepository();
1445
    $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
1446
    $course = api_get_course_entity($courseId);
1447
    $session = api_get_session_entity($sessionId);
1448
1449
    $qb = $repo->getResourcesByCourse($course, $session);
1450
1451
    /*$qb->andWhere('resource.forumCategory = :catId')
1452
        ->setParameter('catId', $cat_id);
1453
    */
1454
    return $qb->getQuery()->getResult();
1455
1456
    $id = (int) $id;
0 ignored issues
show
Unused Code introduced by
$id = (int)$id is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1457
    $course_info = api_get_course_info($course_code);
1458
1459
    $table_forums = Database::get_course_table(TABLE_FORUM);
1460
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1461
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1462
1463
    // Condition for the session
1464
    $session_id = (int) $sessionId ?: api_get_session_id();
1465
    $sessionIdLink = 0 === $session_id ? '' : ' AND threads.session_id = item_properties.session_id';
1466
1467
    $condition_session = api_get_session_condition(
1468
        $session_id,
1469
        true,
1470
        false,
1471
        'item_properties.session_id'
1472
    );
1473
1474
    $course_id = $course_info['real_id'];
1475
1476
    $forum_list = [];
1477
    $includeGroupsForumSelect = '';
1478
    if (!$includeGroupsForum) {
1479
        $includeGroupsForumSelect = ' AND (forum_of_group = 0 OR forum_of_group IS NULL) ';
1480
    }
1481
1482
    $allowToEdit = api_is_allowed_to_edit();
1483
1484
    if (empty($id)) {
1485
        // Student
1486
        // Select all the forum information of all forums (that are visible to students).
1487
        $sql = "SELECT item_properties.*, forum.*
1488
                FROM $table_forums forum
1489
                INNER JOIN $table_item_property item_properties
1490
                ON (
1491
                    forum.forum_id = item_properties.ref AND
1492
                    forum.c_id = item_properties.c_id
1493
                )
1494
                WHERE
1495
                    item_properties.visibility = 1 AND
1496
                    item_properties.tool = '".TOOL_FORUM."'
1497
                    $condition_session AND
1498
                    forum.c_id = $course_id AND
1499
                    item_properties.c_id = $course_id
1500
                    $includeGroupsForumSelect
1501
                ORDER BY forum.forum_order ASC";
1502
1503
        // Select the number of threads of the forums (only the threads that are visible).
1504
        $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1505
                FROM $table_threads threads
1506
                INNER JOIN $table_item_property item_properties
1507
                ON (
1508
                    threads.thread_id = item_properties.ref AND
1509
                    threads.c_id = item_properties.c_id
1510
                    $sessionIdLink
1511
                )
1512
                WHERE
1513
                    item_properties.visibility=1 AND
1514
                    item_properties.tool='".TOOL_FORUM_THREAD."' AND
1515
                    threads.c_id = $course_id AND
1516
                    item_properties.c_id = $course_id
1517
                GROUP BY threads.forum_id";
1518
1519
        // Course Admin
1520
        if ($allowToEdit) {
1521
            // Select all the forum information of all forums (that are not deleted).
1522
            $sql = "SELECT item_properties.*, forum.*
1523
                    FROM $table_forums forum
1524
                    INNER JOIN $table_item_property item_properties
1525
                    ON (
1526
                        forum.forum_id = item_properties.ref AND
1527
                        forum.c_id = item_properties.c_id
1528
                    )
1529
                    WHERE
1530
                        item_properties.visibility <> 2 AND
1531
                        item_properties.tool = '".TOOL_FORUM."'
1532
                        $condition_session AND
1533
                        forum.c_id = $course_id AND
1534
                        item_properties.c_id = $course_id
1535
                        $includeGroupsForumSelect
1536
                    ORDER BY forum_order ASC";
1537
1538
            // Select the number of threads of the forums (only the threads that are not deleted).
1539
            $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1540
                    FROM $table_threads threads
1541
                    INNER JOIN $table_item_property item_properties
1542
                    ON (
1543
                        threads.thread_id = item_properties.ref AND
1544
                        threads.c_id = item_properties.c_id
1545
                        $sessionIdLink
1546
                    )
1547
                    WHERE
1548
                        item_properties.visibility<>2 AND
1549
                        item_properties.tool='".TOOL_FORUM_THREAD."' AND
1550
                        threads.c_id = $course_id AND
1551
                        item_properties.c_id = $course_id
1552
                    GROUP BY threads.forum_id";
1553
        }
1554
    } else {
1555
        // GETTING ONE SPECIFIC FORUM
1556
        /* We could do the splitup into student and course admin also but we want
1557
        to have as much as information about a certain forum as possible
1558
        so we do not take too much information into account. This function
1559
         (or this section of the function) is namely used to fill the forms
1560
        when editing a forum (and for the moment it is the only place where
1561
        we use this part of the function) */
1562
1563
        // Select all the forum information of the given forum (that is not deleted).
1564
        $sql = "SELECT * FROM $table_item_property item_properties
1565
                INNER JOIN $table_forums forum
1566
                ON (forum.forum_id = item_properties.ref AND forum.c_id = item_properties.c_id)
1567
                WHERE
1568
                    forum.forum_id = $id AND
1569
                    forum.c_id = $course_id AND
1570
                    item_properties.visibility != 2 AND
1571
                    item_properties.tool = '".TOOL_FORUM."'
1572
                ORDER BY forum_order ASC";
1573
1574
        // Select the number of threads of the forum.
1575
        $sql2 = "SELECT count(*) AS number_of_threads, forum_id
1576
                FROM $table_threads
1577
                WHERE
1578
                    forum_id = $id
1579
                GROUP BY forum_id";
1580
    }
1581
1582
    // Handling all the forum information.
1583
    $result = Database::query($sql);
1584
    while ($row = Database::fetch_assoc($result)) {
1585
        if (empty($id)) {
1586
            $forum_list[$row['forum_id']] = $row;
1587
        } else {
1588
            $forum_list = $row;
1589
        }
1590
    }
1591
1592
    // Handling the thread count information.
1593
    $result2 = Database::query($sql2);
1594
    while ($row2 = Database::fetch_array($result2)) {
1595
        if (empty($id)) {
1596
            $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
1597
        } else {
1598
            $forum_list['number_of_threads'] = $row2['number_of_threads'];
1599
        }
1600
    }
1601
1602
    /* Finding the last post information
1603
    (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)*/
1604
    if (empty($id)) {
1605
        if (is_array($forum_list)) {
1606
            foreach ($forum_list as $key => $value) {
1607
                $lastPost = get_last_post_information(
1608
                    $key,
1609
                    $allowToEdit,
1610
                    $course_id
1611
                );
1612
1613
                if ($lastPost) {
1614
                    $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
1615
                    $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
1616
                    $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
1617
                    $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
1618
                    $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
1619
                    $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
1620
                    $forum_list[$key]['last_post_title'] = $lastPost['last_post_title'];
1621
                    $forum_list[$key]['last_post_text'] = $lastPost['last_post_text'];
1622
                }
1623
            }
1624
        } else {
1625
            $forum_list = [];
1626
        }
1627
    } else {
1628
        $lastPost = get_last_post_information(
1629
            $id,
1630
            $allowToEdit,
1631
            $course_id
1632
        );
1633
        if ($lastPost) {
1634
            $forum_list['last_post_id'] = $lastPost['last_post_id'];
1635
            $forum_list['last_poster_id'] = $lastPost['last_poster_id'];
1636
            $forum_list['last_post_date'] = $lastPost['last_post_date'];
1637
            $forum_list['last_poster_name'] = $lastPost['last_poster_name'];
1638
            $forum_list['last_poster_lastname'] = $lastPost['last_poster_lastname'];
1639
            $forum_list['last_poster_firstname'] = $lastPost['last_poster_firstname'];
1640
            $forum_list['last_post_title'] = $lastPost['last_post_title'];
1641
            $forum_list['last_post_text'] = $lastPost['last_post_text'];
1642
        }
1643
    }
1644
1645
    return $forum_list;
1646
}
1647
1648
/**
1649
 * @param int  $course_id
1650
 * @param int  $thread_id
1651
 * @param int  $forum_id
1652
 * @param bool $show_visible
1653
 *
1654
 * @return array|bool
1655
 */
1656
function get_last_post_by_thread($course_id, $thread_id, $forum_id, $show_visible = true)
1657
{
1658
    if (empty($thread_id) || empty($forum_id) || empty($course_id)) {
1659
        return false;
1660
    }
1661
1662
    $thread_id = (int) $thread_id;
1663
    $forum_id = (int) $forum_id;
1664
    $course_id = (int) $course_id;
1665
1666
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1667
    $sql = "SELECT * FROM $table_posts
1668
            WHERE
1669
                c_id = $course_id AND
1670
                thread_id = $thread_id AND
1671
                forum_id = $forum_id";
1672
1673
    if (false == $show_visible) {
1674
        $sql .= ' AND visible = 1 ';
1675
    }
1676
1677
    $sql .= ' ORDER BY post_id DESC LIMIT 1';
1678
    $result = Database::query($sql);
1679
    if (Database::num_rows($result)) {
1680
        return Database::fetch_array($result, 'ASSOC');
1681
    } else {
1682
        return false;
1683
    }
1684
}
1685
1686
/**
1687
 * This function gets all the last post information of a certain forum.
1688
 *
1689
 * @param int    $forum_id        the id of the forum we want to know the last post information of
1690
 * @param bool   $show_invisibles
1691
 * @param string $course_id       course db name
1692
 * @param int    $sessionId       Optional. The session id
1693
 *
1694
 * @return array containing all the information about the last post
1695
 *               (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname,
1696
 *               last_poster_firstname)
1697
 *
1698
 * @author Patrick Cool <[email protected]>, Ghent University
1699
 *
1700
 * @version february 2006, dokeos 1.8
1701
 */
1702
function get_last_post_information($forum_id, $show_invisibles = false, $course_id = null, $sessionId = 0)
1703
{
1704
    if (!isset($course_id)) {
1705
        $course_id = api_get_course_int_id();
1706
    } else {
1707
        $course_id = (int) $course_id;
1708
    }
1709
    $sessionId = $sessionId ? (int) $sessionId : api_get_session_id();
1710
1711
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1712
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1713
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
1714
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1715
1716
    $forum_id = (int) $forum_id;
1717
    $return_array = [];
1718
1719
    // First get the threads to make sure there is no inconsistency in the
1720
    // database between forum and thread
1721
    $sql = "SELECT thread_id FROM $table_threads
1722
            WHERE
1723
                forum_id = $forum_id AND
1724
                c_id = $course_id AND
1725
                session_id = $sessionId";
1726
    $result = Database::query($sql);
1727
    if (0 == Database::num_rows($result)) {
1728
        // If there are no threads in this forum, then there are no posts
1729
        return [];
1730
    }
1731
    $threads = [];
1732
    while ($row = Database::fetch_row($result)) {
1733
        $threads[] = $row[0];
1734
    }
1735
    $threadsList = implode(',', $threads);
1736
    // Now get the posts that are linked to these threads
1737
    $sql = "SELECT
1738
                post.post_id,
1739
                post.forum_id,
1740
                post.poster_id,
1741
                post.poster_name,
1742
                post.post_date,
1743
                users.lastname,
1744
                users.firstname,
1745
                post.visible,
1746
                thread_properties.visibility AS thread_visibility,
1747
                forum_properties.visibility AS forum_visibility,
1748
                post.post_title,
1749
                post.post_text
1750
            FROM
1751
                $table_posts post,
1752
                $table_users users,
1753
                $table_item_property thread_properties,
1754
                $table_item_property forum_properties
1755
            WHERE
1756
                post.forum_id = $forum_id
1757
                AND post.thread_id IN ($threadsList)
1758
                AND post.poster_id = users.user_id
1759
                AND post.thread_id = thread_properties.ref
1760
                AND thread_properties.tool='".TOOL_FORUM_THREAD."'
1761
                AND post.forum_id=forum_properties.ref
1762
                AND forum_properties.tool='".TOOL_FORUM."'
1763
                AND post.c_id = $course_id AND
1764
                thread_properties.c_id = $course_id AND
1765
                forum_properties.c_id = $course_id
1766
            ORDER BY post.post_id DESC";
1767
    $result = Database::query($sql);
1768
1769
    if ($show_invisibles) {
1770
        $row = Database::fetch_array($result);
1771
        $return_array['last_post_id'] = $row['post_id'];
1772
        $return_array['last_poster_id'] = $row['poster_id'];
1773
        $return_array['last_post_date'] = $row['post_date'];
1774
        $return_array['last_poster_name'] = $row['poster_name'];
1775
        $return_array['last_poster_lastname'] = $row['lastname'];
1776
        $return_array['last_poster_firstname'] = $row['firstname'];
1777
        $return_array['last_post_title'] = $row['post_title'];
1778
        $return_array['last_post_text'] = $row['post_text'];
1779
1780
        return $return_array;
1781
    } else {
1782
        // We have to loop through the results to find the first one that is
1783
        // actually visible to students (forum_category, forum, thread AND post are visible).
1784
        while ($row = Database::fetch_array($result)) {
1785
            if ('1' == $row['visible'] && '1' == $row['thread_visibility'] && '1' == $row['forum_visibility']) {
1786
                $return_array['last_post_id'] = $row['post_id'];
1787
                $return_array['last_poster_id'] = $row['poster_id'];
1788
                $return_array['last_post_date'] = $row['post_date'];
1789
                $return_array['last_poster_name'] = $row['poster_name'];
1790
                $return_array['last_poster_lastname'] = $row['lastname'];
1791
                $return_array['last_poster_firstname'] = $row['firstname'];
1792
                $return_array['last_post_title'] = $row['post_title'];
1793
                $return_array['last_post_text'] = $row['post_text'];
1794
1795
                return $return_array;
1796
            }
1797
        }
1798
    }
1799
}
1800
1801
/**
1802
 * Retrieve all the threads of a given forum.
1803
 *
1804
 * @param int      $forum_id
1805
 * @param int|null $courseId  Optional If is null then it is considered the current course
1806
 * @param int|null $sessionId Optional. If is null then it is considered the current session
1807
 *
1808
 * @return CForumThread[]
1809
 */
1810
function get_threads($forumId, $courseId = null, $sessionId = null)
1811
{
1812
    $repo = Container::getForumThreadRepository();
1813
    $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
1814
    $course = api_get_course_entity($courseId);
1815
    $session = api_get_session_entity($sessionId);
1816
1817
    $qb = $repo->getResourcesByCourse($course, $session);
1818
1819
    $qb->andWhere('resource.forum = :forum')->setParameter('forum', $forumId);
1820
1821
    return $qb->getQuery()->getResult();
1822
1823
    $groupId = api_get_group_id();
0 ignored issues
show
Unused Code introduced by
$groupId = api_get_group_id() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1824
    $sessionId = null !== $sessionId ? (int) $sessionId : api_get_session_id();
1825
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1826
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1827
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
1828
1829
    $courseId = null !== $courseId ? (int) $courseId : api_get_course_int_id();
1830
    $groupInfo = GroupManager::get_group_properties($groupId);
1831
    $groupCondition = '';
1832
1833
    if (!empty($groupInfo)) {
1834
        $groupIid = $groupInfo['iid'];
1835
        $groupCondition = " AND item_properties.to_group_id = '$groupIid' ";
1836
    }
1837
1838
    $sessionCondition = api_get_session_condition(
1839
        $sessionId,
1840
        true,
1841
        false,
1842
        'item_properties.session_id'
1843
    );
1844
1845
    // important note:  it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
1846
    // because we also have thread.* in it. This is because thread has a field locked and post also has the same field
1847
    // since we are merging these we would have the post.locked value but in fact we want the thread.locked value
1848
    // This is why it is added to the end of the field selection
1849
    $sql = "SELECT DISTINCT
1850
                item_properties.*,
1851
                users.firstname,
1852
                users.lastname,
1853
                users.user_id,
1854
                thread.locked as locked,
1855
                thread.*
1856
            FROM $table_threads thread
1857
            INNER JOIN $table_item_property item_properties
1858
            ON
1859
                thread.thread_id = item_properties.ref AND
1860
                item_properties.c_id = thread.c_id AND
1861
                item_properties.tool = '".TABLE_FORUM_THREAD."'
1862
                $groupCondition
1863
                $sessionCondition
1864
            LEFT JOIN $table_users users
1865
                ON thread.thread_poster_id = users.user_id
1866
            WHERE
1867
                item_properties.visibility='1' AND
1868
                thread.forum_id = ".(int) $forum_id." AND
1869
                thread.c_id = $courseId
1870
            ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1871
1872
    if (api_is_allowed_to_edit()) {
1873
        $sql = "SELECT DISTINCT
1874
                    item_properties.*,
1875
                    users.firstname,
1876
                    users.lastname,
1877
                    users.user_id,
1878
                    thread.locked as locked,
1879
                    thread.*
1880
                FROM $table_threads thread
1881
                INNER JOIN $table_item_property item_properties
1882
                ON
1883
                    thread.thread_id = item_properties.ref AND
1884
                    item_properties.c_id = thread.c_id AND
1885
                    item_properties.tool = '".TABLE_FORUM_THREAD."'
1886
                    $groupCondition
1887
                    $sessionCondition
1888
                LEFT JOIN $table_users users
1889
                    ON thread.thread_poster_id=users.user_id
1890
                WHERE
1891
                    item_properties.visibility<>2 AND
1892
                    thread.forum_id = ".(int) $forum_id." AND
1893
                    thread.c_id = $courseId
1894
                ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1895
    }
1896
    $result = Database::query($sql);
1897
    $list = [];
1898
    $alreadyAdded = [];
1899
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1900
        if (in_array($row['thread_id'], $alreadyAdded)) {
1901
            continue;
1902
        }
1903
        $list[] = $row;
1904
        $alreadyAdded[] = $row['thread_id'];
1905
    }
1906
1907
    return $list;
1908
}
1909
1910
/**
1911
 * Get a thread by Id and course id.
1912
 *
1913
 * @param int $threadId the thread Id
1914
 * @param int $cId      the course id
1915
 *
1916
 * @return array containing all the information about the thread
1917
 */
1918
function getThreadInfo($threadId, $cId)
1919
{
1920
    $repo = Database::getManager()->getRepository('ChamiloCourseBundle:CForumThread');
1921
    /** @var CForumThread $forumThread */
1922
    $forumThread = $repo->findOneBy(['threadId' => $threadId, 'cId' => $cId]);
1923
1924
    $thread = [];
1925
    if ($forumThread) {
1926
        $thread['threadId'] = $forumThread->getThreadId();
1927
        $thread['threadTitle'] = $forumThread->getThreadTitle();
1928
        $thread['forumId'] = $forumThread->getForum() ? $forumThread->getForum()->getIid() : 0;
1929
        $thread['sessionId'] = $forumThread->getSessionId();
1930
        $thread['threadSticky'] = $forumThread->getThreadSticky();
1931
        $thread['locked'] = $forumThread->getLocked();
1932
        $thread['threadTitleQualify'] = $forumThread->getThreadTitleQualify();
1933
        $thread['threadQualifyMax'] = $forumThread->getThreadQualifyMax();
1934
        $thread['threadCloseDate'] = $forumThread->getThreadCloseDate();
1935
        $thread['threadWeight'] = $forumThread->getThreadWeight();
1936
        $thread['threadPeerQualify'] = $forumThread->isThreadPeerQualify();
1937
    }
1938
1939
    return $thread;
1940
}
1941
1942
/**
1943
 * Retrieve all posts of a given thread.
1944
 *
1945
 * @param int    $threadId       The thread ID
1946
 * @param string $orderDirection Optional. The direction for sort the posts
1947
 * @param bool   $recursive      Optional. If the list is recursive
1948
 * @param int    $postId         Optional. The post ID for recursive list
1949
 * @param int    $depth          Optional. The depth to indicate the indent
1950
 *
1951
 * @todo move to a repository
1952
 *
1953
 * @return array containing all the information about the posts of a given thread
1954
 */
1955
function getPosts(
1956
    CForumForum $forum,
1957
    $threadId,
1958
    $orderDirection = 'ASC',
1959
    $recursive = false,
1960
    $postId = null,
1961
    $depth = -1
1962
) {
1963
    $em = Database::getManager();
1964
1965
    if (api_is_allowed_to_edit(false, true)) {
1966
        $visibleCriteria = Criteria::expr()->neq('visible', 2);
1967
    } else {
1968
        $visibleCriteria = Criteria::expr()->eq('visible', 1);
1969
    }
1970
1971
    $criteria = Criteria::create();
1972
    $criteria
1973
        ->where(Criteria::expr()->eq('thread', $threadId))
1974
        ->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
1975
        ->andWhere($visibleCriteria)
1976
    ;
1977
1978
    $groupId = api_get_group_id();
1979
    $groupInfo = GroupManager::get_group_properties($groupId);
1980
    $filterModerated = true;
1981
1982
    if (empty($groupId)) {
1983
        if (api_is_allowed_to_edit()) {
1984
            $filterModerated = false;
1985
        }
1986
    } else {
1987
        if (GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo) ||
1988
            api_is_allowed_to_edit(false, true)
1989
        ) {
1990
            $filterModerated = false;
1991
        }
1992
    }
1993
1994
    if ($recursive) {
1995
        $criteria->andWhere(Criteria::expr()->eq('postParentId', $postId));
1996
    }
1997
1998
    $qb = $em->getRepository('ChamiloCourseBundle:CForumPost')->createQueryBuilder('p');
1999
    $qb->select('p')
2000
        ->addCriteria($criteria)
2001
        ->addOrderBy('p.postId', $orderDirection);
2002
2003
    if ($filterModerated && 1 == $forum->isModerated()) {
2004
        if (!api_is_allowed_to_edit(false, true)) {
2005
            $userId = api_get_user_id();
2006
            $qb->andWhere(
2007
                'p.status = 1 OR
2008
                    (p.status = '.CForumPost::STATUS_WAITING_MODERATION." AND p.posterId = $userId) OR
2009
                    (p.status = ".CForumPost::STATUS_REJECTED." AND p.posterId = $userId) OR
2010
                    (p.status IS NULL AND p.posterId = $userId)
2011
                    "
2012
            );
2013
        }
2014
    }
2015
2016
    $posts = $qb->getQuery()->getResult();
2017
    $depth++;
2018
2019
    $list = [];
2020
    /** @var CForumPost $post */
2021
    foreach ($posts as $post) {
2022
        $postInfo = [
2023
            'iid' => $post->getIid(),
2024
            'c_id' => $post->getCId(),
2025
            'post_id' => $post->getPostId(),
2026
            'post_title' => $post->getPostTitle(),
2027
            'post_text' => $post->getPostText(),
2028
            'thread_id' => $post->getThread() ? $post->getThread()->getIid() : 0,
2029
            'forum_id' => $post->getForum()->getIid(),
2030
            'poster_id' => $post->getPosterId(),
2031
            'poster_name' => $post->getPosterName(),
2032
            'post_date' => $post->getPostDate(),
2033
            'post_notification' => $post->getPostNotification(),
2034
            'post_parent_id' => $post->getPostParentId(),
2035
            'visible' => $post->getVisible(),
2036
            'status' => $post->getStatus(),
2037
            'indent_cnt' => $depth,
2038
            'entity' => $post
2039
        ];
2040
2041
        $posterId = $post->getPosterId();
2042
        if (!empty($posterId)) {
2043
            $user = api_get_user_entity($posterId);
2044
            if ($user) {
2045
                $postInfo['user_id'] = $user->getUserId();
2046
                $postInfo['username'] = $user->getUsername();
2047
                $postInfo['username_canonical'] = $user->getUsernameCanonical();
2048
                $postInfo['lastname'] = $user->getLastname();
2049
                $postInfo['firstname'] = $user->getFirstname();
2050
                $postInfo['complete_name'] = UserManager::formatUserFullName($user);
2051
            }
2052
        }
2053
2054
        $list[] = $postInfo;
2055
2056
        if (!$recursive) {
2057
            continue;
2058
        }
2059
        $list = array_merge(
2060
            $list,
2061
            getPosts(
2062
                $forum,
2063
                $threadId,
2064
                $orderDirection,
2065
                $recursive,
2066
                $post->getPostId(),
2067
                $depth
2068
            )
2069
        );
2070
    }
2071
2072
    return $list;
2073
}
2074
2075
/**
2076
 * This function retrieves forum thread users details.
2077
 *
2078
 * @param int $thread_id Thread ID
2079
 * @param   string  Course DB name (optional)
2080
 *
2081
 * @return Doctrine\DBAL\Driver\Statement|null array Array of type
2082
 *                                             ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2083
 *
2084
 * @author Christian Fasanando <[email protected]>,
2085
 *
2086
 * @todo     this function need to be improved
2087
 *
2088
 * @version octubre 2008, dokeos 1.8
2089
 */
2090
function get_thread_users_details($thread_id)
2091
{
2092
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2093
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2094
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2095
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2096
2097
    $course_id = api_get_course_int_id();
2098
2099
    $is_western_name_order = api_is_western_name_order();
2100
    if ($is_western_name_order) {
2101
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2102
    } else {
2103
        $orderby = 'ORDER BY user.lastname, user.firstname';
2104
    }
2105
2106
    if (api_get_session_id()) {
2107
        $session_info = api_get_session_info(api_get_session_id());
2108
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2109
        //not showing coaches
2110
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2111
                FROM $t_posts p, $t_users user, $t_session_rel_user session_rel_user_rel_course
2112
                WHERE
2113
                    p.poster_id = user.id AND
2114
                    user.id = session_rel_user_rel_course.user_id AND
2115
                    session_rel_user_rel_course.status<>'2' AND
2116
                    session_rel_user_rel_course.user_id NOT IN ($user_to_avoid) AND
2117
                    p.thread_id = ".(int) $thread_id.' AND
2118
                    session_id = '.api_get_session_id()." AND
2119
                    p.c_id = $course_id AND
2120
                    session_rel_user_rel_course.c_id = ".$course_id." $orderby ";
2121
    } else {
2122
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2123
                FROM $t_posts p, $t_users user, $t_course_user course_user
2124
                WHERE
2125
                    p.poster_id = user.id
2126
                    AND user.id = course_user.user_id
2127
                    AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
2128
                    AND p.thread_id = '.(int) $thread_id."
2129
                    AND course_user.status NOT IN('1') AND
2130
                    p.c_id = $course_id AND
2131
                    course_user.c_id = ".$course_id." $orderby";
2132
    }
2133
2134
    return Database::query($sql);
2135
}
2136
2137
/**
2138
 * This function retrieves forum thread users qualify.
2139
 *
2140
 * @param int $thread_id Thread ID
2141
 * @param   string  Course DB name (optional)
2142
 *
2143
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2144
 *
2145
 * @author Jhon Hinojosa
2146
 *
2147
 * @todo     this function need to be improved
2148
 */
2149
function get_thread_users_qualify($thread_id)
2150
{
2151
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2152
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2153
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2154
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2155
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2156
2157
    $course_id = api_get_course_int_id();
2158
    $sessionId = api_get_session_id();
2159
2160
    $is_western_name_order = api_is_western_name_order();
2161
    if ($is_western_name_order) {
2162
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2163
    } else {
2164
        $orderby = 'ORDER BY user.lastname, user.firstname';
2165
    }
2166
2167
    if ($sessionId) {
2168
        $session_info = api_get_session_info($sessionId);
2169
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2170
        //not showing coaches
2171
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2172
                FROM $t_posts post , $t_users user, $t_session_rel_user scu, $t_qualify qualify
2173
                WHERE poster_id = user.id
2174
                    AND post.poster_id = qualify.user_id
2175
                    AND user.id = scu.user_id
2176
                    AND scu.status<>'2'
2177
                    AND scu.user_id NOT IN ($user_to_avoid)
2178
                    AND qualify.thread_id = ".(int) $thread_id.'
2179
                    AND post.thread_id = '.(int) $thread_id."
2180
                    AND scu.session_id = $sessionId
2181
                    AND scu.c_id = ".$course_id." AND
2182
                    qualify.c_id = $course_id AND
2183
                    post.c_id = $course_id
2184
                $orderby ";
2185
    } else {
2186
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2187
                FROM $t_posts post,
2188
                     $t_qualify qualify,
2189
                     $t_users user,
2190
                     $t_course_user course_user
2191
                WHERE
2192
                     post.poster_id = user.id
2193
                     AND post.poster_id = qualify.user_id
2194
                     AND user.id = course_user.user_id
2195
                     AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
2196
                     AND qualify.thread_id = '.(int) $thread_id.'
2197
                     AND post.thread_id = '.(int) $thread_id."
2198
                     AND course_user.status not in('1')
2199
                     AND course_user.c_id = $course_id
2200
                     AND qualify.c_id = $course_id
2201
                     AND post.c_id = $course_id
2202
                 $orderby ";
2203
    }
2204
2205
    return Database::query($sql);
2206
}
2207
2208
/**
2209
 * This function retrieves forum thread users not qualify.
2210
 *
2211
 * @param int $thread_id Thread ID
2212
 * @param   string  Course DB name (optional)
2213
 *
2214
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2215
 *
2216
 * @author   Jhon Hinojosa<[email protected]>,
2217
 *
2218
 * @version oct 2008, dokeos 1.8
2219
 */
2220
function get_thread_users_not_qualify($thread_id)
2221
{
2222
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2223
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2224
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2225
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2226
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2227
2228
    $is_western_name_order = api_is_western_name_order();
2229
    if ($is_western_name_order) {
2230
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2231
    } else {
2232
        $orderby = 'ORDER BY user.lastname, user.firstname';
2233
    }
2234
2235
    $course_id = api_get_course_int_id();
2236
2237
    $sql1 = "SELECT user_id FROM  $t_qualify
2238
             WHERE c_id = $course_id AND thread_id = '".$thread_id."'";
2239
    $result1 = Database::query($sql1);
2240
    $cad = '';
2241
    while ($row = Database::fetch_array($result1)) {
2242
        $cad .= $row['user_id'].',';
2243
    }
2244
    if ('' == $cad) {
2245
        $cad = '0';
2246
    } else {
2247
        $cad = substr($cad, 0, strlen($cad) - 1);
2248
    }
2249
2250
    if (api_get_session_id()) {
2251
        $session_info = api_get_session_info(api_get_session_id());
2252
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2253
        //not showing coaches
2254
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2255
                FROM $t_posts post , $t_users user, $t_session_rel_user session_rel_user_rel_course
2256
                WHERE poster_id = user.id
2257
                    AND user.id NOT IN (".$cad.")
2258
                    AND user.id = session_rel_user_rel_course.user_id
2259
                    AND session_rel_user_rel_course.status<>'2'
2260
                    AND session_rel_user_rel_course.user_id NOT IN ($user_to_avoid)
2261
                    AND post.thread_id = ".(int) $thread_id.'
2262
                    AND session_id = '.api_get_session_id()."
2263
                    AND session_rel_user_rel_course.c_id = $course_id AND post.c_id = $course_id $orderby ";
2264
    } else {
2265
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2266
                FROM $t_posts post, $t_users user,$t_course_user course_user
2267
                WHERE post.poster_id = user.id
2268
                AND user.id NOT IN (".$cad.')
2269
                AND user.id = course_user.user_id
2270
                AND course_user.relation_type<>'.COURSE_RELATION_TYPE_RRHH.'
2271
                AND post.thread_id = '.(int) $thread_id."
2272
                AND course_user.status not in('1')
2273
                AND course_user.c_id = $course_id AND post.c_id = $course_id  $orderby";
2274
    }
2275
2276
    return Database::query($sql);
2277
}
2278
2279
/**
2280
 * This function retrieves all the information of a given forumcategory id.
2281
 *
2282
 * @param int $cat_id that indicates the forum
2283
 *
2284
 * @return array returns if there are category or bool returns if there aren't category
2285
 *
2286
 * @author Patrick Cool <[email protected]>, Ghent University
2287
 *
2288
 * @version february 2006, dokeos 1.8
2289
 */
2290
function get_forumcategory_information($cat_id)
2291
{
2292
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
2293
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2294
2295
    $course_id = api_get_course_int_id();
2296
    $sql = "SELECT *
2297
            FROM $table_categories forumcategories
2298
            INNER JOIN $table_item_property item_properties
2299
            ON (forumcategories.c_id = item_properties.c_id)
2300
            WHERE
2301
                forumcategories.c_id = $course_id AND
2302
                item_properties.c_id = $course_id AND
2303
                item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
2304
                item_properties.ref='".Database::escape_string($cat_id)."' AND
2305
                forumcategories.cat_id='".Database::escape_string($cat_id)."'";
2306
    $result = Database::query($sql);
2307
2308
    return Database::fetch_array($result);
2309
}
2310
2311
/**
2312
 * This function counts the number of forums inside a given category.
2313
 *
2314
 * @param int $cat_id the id of the forum category
2315
 *
2316
 * @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return
2317
 *       the number of visible forums, $countinvisible=1 would return the number of visible and invisible forums
2318
 *
2319
 * @return int the number of forums inside the given category
2320
 *
2321
 * @author Patrick Cool <[email protected]>, Ghent University
2322
 *
2323
 * @version february 2006, dokeos 1.8
2324
 */
2325
function count_number_of_forums_in_category($cat_id)
2326
{
2327
    $table_forums = Database::get_course_table(TABLE_FORUM);
2328
    $course_id = api_get_course_int_id();
2329
    $cat_id = (int) $cat_id;
2330
    $sql = "SELECT count(*) AS number_of_forums
2331
            FROM $table_forums
2332
            WHERE c_id = $course_id AND forum_category = $cat_id";
2333
    $result = Database::query($sql);
2334
    $row = Database::fetch_array($result);
2335
2336
    return $row['number_of_forums'];
2337
}
2338
2339
/**
2340
 * This function update a thread.
2341
 *
2342
 * @param array $values - The form Values
2343
 */
2344
function updateThread($values)
2345
{
2346
    if (!api_is_allowed_to_edit()) {
2347
        return '';
2348
    }
2349
2350
    $logInfo = [
2351
        'tool' => TOOL_FORUM,
2352
        'tool_id' => $values['forum_id'],
2353
        'tool_id_detail' => $values['thread_id'],
2354
        'action' => 'edit-thread',
2355
        'action_details' => 'thread',
2356
        'info' => $values['thread_title'],
2357
    ];
2358
    Event::registerLog($logInfo);
2359
2360
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
2361
    $courseId = api_get_course_int_id();
2362
    $courseCode = api_get_course_id();
2363
    $sessionId = api_get_session_id();
2364
2365
    // Simple update + set gradebook values to null
2366
    $params = [
2367
        'thread_title' => $values['thread_title'],
2368
        'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
2369
    ];
2370
    $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2371
    Database::update($threadTable, $params, $where);
2372
2373
    $id = $values['thread_id'];
2374
    $linkInfo = GradebookUtils::isResourceInCourseGradebook(
2375
        $courseCode,
2376
        LINK_FORUM_THREAD,
2377
        $id,
2378
        $sessionId
2379
    );
2380
2381
    $gradebookLink = null;
2382
    $em = Database::getManager();
2383
    if (!empty($linkInfo) && isset($linkInfo['id'])) {
2384
        $linkId = $linkInfo['id'];
2385
        $gradebookLink = $em->getRepository('ChamiloCoreBundle:GradebookLink')->find($linkId);
2386
    }
2387
2388
    // values 1 or 0
2389
    $check = isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : false;
2390
    if ($check) {
2391
        $title = Security::remove_XSS(stripslashes($values['calification_notebook_title']));
2392
        $value = isset($values['numeric_calification']) ? (int) ($values['numeric_calification']) : 0;
2393
        $weight = isset($values['weight_calification']) ? (float) ($values['weight_calification']) : 0;
2394
        $description = '';
2395
        // Update title
2396
        $params = [
2397
            'thread_title_qualify' => $values['calification_notebook_title'],
2398
            'thread_qualify_max' => api_float_val($values['numeric_calification']),
2399
            'thread_weight' => api_float_val($values['weight_calification']),
2400
            'thread_peer_qualify' => $values['thread_peer_qualify'],
2401
        ];
2402
        $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2403
        Database::update($threadTable, $params, $where);
2404
2405
        if (!$linkInfo) {
2406
            GradebookUtils::add_resource_to_course_gradebook(
2407
                $values['category_id'],
2408
                $courseCode,
2409
                LINK_FORUM_THREAD,
2410
                $id,
2411
                $title,
2412
                $weight,
2413
                $value,
2414
                $description,
2415
                1,
2416
                $sessionId
2417
            );
2418
        } else {
2419
            if ($gradebookLink) {
2420
                $gradebookLink->setWeight($weight);
2421
                $em->persist($gradebookLink);
2422
                $em->flush();
2423
            }
2424
        }
2425
    } else {
2426
        $params = [
2427
            'thread_title_qualify' => '',
2428
            'thread_qualify_max' => 0,
2429
            'thread_weight' => 0,
2430
            'thread_peer_qualify' => 0,
2431
        ];
2432
        $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2433
        Database::update($threadTable, $params, $where);
2434
2435
        if (!empty($linkInfo)) {
2436
            if ($gradebookLink) {
2437
                $em->remove($gradebookLink);
2438
                $em->flush();
2439
            }
2440
        }
2441
    }
2442
2443
    $message = get_lang('The post has been modified').'<br />';
2444
    Display::addFlash(Display::return_message($message, 'confirmation', false));
2445
}
2446
2447
/**
2448
 * This function stores a new thread. This is done through an entry in the forum_thread table AND
2449
 * in the forum_post table because. The threads are also stored in the item_property table. (forum posts are not (yet)).
2450
 *
2451
 * @param bool $showMessage
2452
 * @param int  $userId      Optional. The user ID
2453
 * @param int  $sessionId
2454
 *
2455
 * @return CForumThread
2456
 *
2457
 * @author Patrick Cool <[email protected]>, Ghent University
2458
 *
2459
 * @version february 2006, dokeos 1.8
2460
 */
2461
function store_thread(
2462
    CForumForum $forum,
2463
    array $values,
2464
    array $courseInfo = [],
2465
    $showMessage = true,
2466
    $userId = 0,
2467
    $sessionId = 0
2468
) {
2469
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
2470
    $userId = $userId ?: api_get_user_id();
2471
    $course_id = $courseInfo['real_id'];
2472
    $courseCode = $courseInfo['code'];
2473
    $sessionId = $sessionId ?: api_get_session_id();
2474
2475
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2476
2477
    $post_date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
2478
    $visible = 1;
2479
    if ('1' == $forum->getApprovalDirectPost() && !api_is_allowed_to_edit(null, true)) {
2480
        $visible = 0; // The post has not been approved yet.
2481
    }
2482
    $clean_post_title = $values['post_title'];
2483
2484
    // We first store an entry in the forum_thread table because the thread_id is used in the forum_post table.
2485
    $thread = new CForumThread();
2486
    $thread
2487
        ->setCId($course_id)
2488
        ->setThreadTitle($clean_post_title)
2489
        ->setForum($forum)
2490
        ->setThreadPosterId($userId)
2491
        ->setThreadPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2492
        ->setThreadDate($post_date)
2493
        ->setThreadSticky(isset($values['thread_sticky']) ? $values['thread_sticky'] : 0)
2494
        ->setThreadTitleQualify(
2495
            isset($values['calification_notebook_title']) ? $values['calification_notebook_title'] : null
2496
        )
2497
        ->setThreadQualifyMax(isset($values['numeric_calification']) ? (int) $values['numeric_calification'] : 0)
2498
        ->setThreadWeight(isset($values['weight_calification']) ? (int) $values['weight_calification'] : 0)
2499
        ->setThreadPeerQualify(isset($values['thread_peer_qualify']) ? (bool) $values['thread_peer_qualify'] : false)
2500
        ->setSessionId($sessionId)
2501
        ->setLpItemId(isset($values['lp_item_id']) ? (int) $values['lp_item_id'] : 0)
2502
    ;
2503
    $user = api_get_user_entity(api_get_user_id());
2504
    $course = api_get_course_entity($course_id);
2505
    $session = api_get_session_entity($sessionId);
2506
2507
    $repo = Container::getForumThreadRepository();
2508
    $em = $repo->getEntityManager();
2509
    $repo->addResourceToCourseWithParent(
2510
        $thread,
2511
        $forum->getResourceNode(),
2512
        ResourceLink::VISIBILITY_PUBLISHED,
2513
        $user,
2514
        $course,
2515
        $session,
2516
        null
2517
    );
2518
    $em->flush();
2519
2520
    if (!$thread->getIid()) {
2521
        return null;
2522
    }
2523
2524
    // Add option gradebook qualify.
2525
    if (isset($values['thread_qualify_gradebook']) &&
2526
        1 == $values['thread_qualify_gradebook']
2527
    ) {
2528
        // Add function gradebook.
2529
        $resourcename = stripslashes($values['calification_notebook_title']);
2530
        GradebookUtils::add_resource_to_course_gradebook(
2531
            $values['category_id'],
2532
            $courseCode,
2533
            5,
2534
            $thread->getIid(),
2535
            $resourcename,
2536
            $values['weight_calification'],
2537
            $values['numeric_calification'],
2538
            '',
2539
            0,
2540
            $sessionId
2541
        );
2542
    }
2543
2544
    $thread->setThreadId($thread->getIid());
2545
    $em->persist($thread);
2546
    $em->flush();
2547
2548
    /*api_item_property_update(
2549
        $courseInfo,
2550
        TOOL_FORUM_THREAD,
2551
        $thread->getIid(),
2552
        'ForumThreadAdded',
2553
        $userId,
2554
        $groupInfo,
2555
        null,
2556
        null,
2557
        null,
2558
        $sessionId
2559
    );*/
2560
2561
    // If the forum properties tell that the posts have to be approved
2562
    // we have to put the whole thread invisible,
2563
    // because otherwise the students will see the thread and not the post
2564
    // in the thread.
2565
    // We also have to change $visible because the post itself has to be
2566
    // visible in this case (otherwise the teacher would have
2567
    // to make the thread visible AND the post.
2568
    // Default behaviour
2569
    /*api_set_default_visibility(
2570
        $thread->getIid(),
2571
        TOOL_FORUM_THREAD,
2572
        $groupId,
2573
        $courseInfo,
2574
        $sessionId,
2575
        $userId
2576
    );*/
2577
2578
    if (0 == $visible) {
2579
        /*api_item_property_update(
2580
            $courseInfo,
2581
            TOOL_FORUM_THREAD,
2582
            $thread->getIid(),
2583
            'invisible',
2584
            $userId,
2585
            $groupInfo
2586
        );*/
2587
        $visible = 1;
2588
    }
2589
2590
    $logInfo = [
2591
        'tool' => TOOL_FORUM,
2592
        'tool_id' => $values['forum_id'],
2593
        'tool_id_detail' => $thread->getIid(),
2594
        'action' => 'new-thread',
2595
        'info' => $clean_post_title,
2596
    ];
2597
    Event::registerLog($logInfo);
2598
2599
    // We now store the content in the table_post table.
2600
    $post = new CForumPost();
2601
    $post
2602
        ->setCId($course_id)
2603
        ->setPostTitle($clean_post_title)
2604
        ->setPostText($values['post_text'])
2605
        ->setThread($thread)
2606
        ->setForum($forum)
2607
        ->setPosterId($userId)
2608
        ->setPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2609
        ->setPostDate($post_date)
2610
        ->setPostNotification(isset($values['post_notification']) ? (int) $values['post_notification'] : null)
2611
        ->setVisible($visible)
2612
        ->setStatus(CForumPost::STATUS_VALIDATED);
2613
2614
    if ($forum->isModerated()) {
2615
        $post->setStatus(
2616
            api_is_course_admin() ? CForumPost::STATUS_VALIDATED : CForumPost::STATUS_WAITING_MODERATION
2617
        );
2618
    }
2619
2620
    $repo = Container::getForumPostRepository();
2621
    $em = $repo->getEntityManager();
2622
    $repo->addResourceToCourseWithParent(
2623
        $post,
2624
        $thread->getResourceNode(),
2625
        ResourceLink::VISIBILITY_PUBLISHED,
2626
        $user,
2627
        $course,
2628
        $session,
2629
        null
2630
    );
2631
    $em->flush();
2632
2633
    $postId = $post->getIid();
2634
    $thread->setThreadLastPost($postId);
2635
    $em->persist($thread);
2636
    $em->flush();
2637
2638
    $logInfo = [
2639
        'tool' => TOOL_FORUM,
2640
        'tool_id' => $values['forum_id'],
2641
        'tool_id_detail' => $thread->getIid(),
2642
        'action' => 'new-post',
2643
        'info' => $clean_post_title,
2644
    ];
2645
    Event::registerLog($logInfo);
2646
2647
    if ($postId) {
2648
        $post->setPostId($postId);
2649
        $em->persist($post);
2650
        $em->flush();
2651
    }
2652
2653
    // Now we have to update the thread table to fill the thread_last_post
2654
    // field (so that we know when the thread has been updated for the last time).
2655
    $sql = "UPDATE $table_threads
2656
            SET thread_last_post = '".$postId."'
2657
            WHERE
2658
                c_id = $course_id AND
2659
                thread_id='".$thread->getIid()."'";
2660
    Database::query($sql);
2661
    $message = get_lang('The new thread has been added');
2662
2663
    // Overwrite default message.
2664
    if ($forum->isModerated() &&
2665
        !api_is_allowed_to_edit(null, true)
2666
    ) {
2667
        $message = get_lang('Your message has to be approved before people can view it.');
2668
    }
2669
2670
    add_forum_attachment_file(
2671
        null,
2672
        $post
2673
    );
2674
2675
    if ('1' == $forum->getApprovalDirectPost() &&
2676
        !api_is_allowed_to_edit(null, true)
2677
    ) {
2678
        $message .= get_lang('Your message has to be approved before people can view it.').'<br />';
2679
        $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2680
            get_lang('Forum').'</a><br />';
2681
    } else {
2682
        $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2683
            get_lang('Forum').'</a><br />';
2684
        $message .= get_lang('You can now return to the').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&thread='.$thread->getIid().'">'.
2685
            get_lang('Message').'</a>';
2686
    }
2687
    $reply_info['new_post_id'] = $postId;
2688
    $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
2689
2690
    if (1 == $my_post_notification) {
2691
        set_notification('thread', $thread->getIid(), true);
2692
    }
2693
2694
    send_notification_mails(
2695
        $forum,
2696
        $thread,
2697
        $reply_info,
2698
        $courseInfo['code']
2699
    );
2700
2701
    Session::erase('formelements');
2702
    Session::erase('origin');
2703
    Session::erase('breadcrumbs');
2704
    Session::erase('addedresource');
2705
    Session::erase('addedresourceid');
2706
2707
    if ($showMessage) {
2708
        Display::addFlash(Display::return_message($message, 'success', false));
2709
    }
2710
2711
    return $thread;
2712
}
2713
2714
/**
2715
 * This function displays the form that is used to add a post. This can be a new thread or a reply.
2716
 *
2717
 * @param CForumForum  $forum
2718
 * @param CForumThread $thread
2719
 * @param string       $action
2720
 *  is the parameter that determines if we are
2721
 *  2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete thread (if enabled)
2722
 *  3. replymessage: Replying to a message ($action =replymessage) => I-frame with the complete thread (if enabled)
2723
 *  (I first thought to put and I-frame with the message only)
2724
 *  4. quote: Quoting a message ($action= quotemessage) => I-frame with the complete thread (if enabled).
2725
 *  The message will be in the reply. (I first thought not to put an I-frame here)
2726
 * @param array        $form_values
2727
 * @param bool         $showPreview
2728
 *
2729
 * @return FormValidator
2730
 */
2731
function show_add_post_form(CForumForum $forum, CForumThread $thread, CForumPost $post = null, $action, $form_values = '', $showPreview = true)
2732
{
2733
    $_user = api_get_user_info();
2734
    $action = isset($action) ? Security::remove_XSS($action) : '';
2735
    $threadId = $thread->getIid();
2736
    $forumId = $forum->getIid();
2737
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
2738
    $postId = $post ? $post->getIid() : 0;
2739
2740
    $url = api_get_self().'?'.http_build_query(
2741
        [
2742
            'action' => $action,
2743
            'forum' => $forumId,
2744
            'thread' => $threadId,
2745
            'post' => $postId,
2746
        ]
2747
    ).'&'.api_get_cidreq();
2748
2749
    $form = new FormValidator(
2750
        'thread',
2751
        'post',
2752
        $url
2753
    );
2754
    $form->setConstants(['forum' => '5']);
2755
2756
    // Setting the form elements.
2757
    $form->addElement('hidden', 'forum_id', $forumId);
2758
    $form->addElement('hidden', 'thread_id', $threadId);
2759
    $form->addElement('hidden', 'action', $action);
2760
2761
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2762
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2763
        $form->addElement('text', 'poster_name', get_lang('Name'));
2764
        $form->applyFilter('poster_name', 'html_filter');
2765
    }
2766
2767
    $form->addElement('text', 'post_title', get_lang('Title'));
2768
    $form->addHtmlEditor(
2769
        'post_text',
2770
        get_lang('Text'),
2771
        true,
2772
        false,
2773
        api_is_allowed_to_edit(null, true) ? [
2774
            'ToolbarSet' => 'Forum',
2775
            'Width' => '100%',
2776
            'Height' => '300',
2777
        ] : [
2778
            'ToolbarSet' => 'ForumStudent',
2779
            'Width' => '100%',
2780
            'Height' => '300',
2781
            'UserStatus' => 'student',
2782
        ]
2783
    );
2784
    $form->addRule('post_text', get_lang('Required field'), 'required');
2785
2786
    if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2787
        $extraFields = new ExtraField('forum_post');
2788
        $extraFields->addElements(
2789
            $form,
2790
            null,
2791
            [], //exclude
2792
            false, // filter
2793
            false, // tag as select
2794
            ['ask_for_revision'], //show only fields
2795
            [], // order fields
2796
            [] // extra data);
2797
        );
2798
    }
2799
2800
    $iframe = null;
2801
    if ($showPreview) {
2802
        if ('newthread' !== $action && !empty($threadId)) {
2803
            $iframe = '<iframe style="border: 1px solid black"
2804
            src="iframe_thread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId.'#'.$postId.'" width="100%"></iframe>';
2805
        }
2806
        if (!empty($iframe)) {
2807
            $form->addElement('label', get_lang('Thread'), $iframe);
2808
        }
2809
    }
2810
2811
    if (in_array($action, ['quote', 'replymessage'])) {
2812
        $form->addFile('user_upload[]', get_lang('Attachment'));
2813
        $form->addButton(
2814
            'add_attachment',
2815
            get_lang('Add attachment'),
2816
            'paperclip',
2817
            'default',
2818
            'default',
2819
            null,
2820
            ['id' => 'reply-add-attachment']
2821
        );
2822
    } else {
2823
        $form->addFile('user_upload', get_lang('Attachment'));
2824
    }
2825
2826
    if ($giveRevision) {
2827
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
2828
        $form->addHidden('give_revision', 1);
2829
        if (false === $hide) {
2830
            $extraField = new ExtraField('forum_post');
2831
            $extraField->addElements(
2832
                $form,
2833
                null,
2834
                [], //exclude
2835
                false, // filter
2836
                false, // tag as select
2837
                ['revision_language'], //show only fields
2838
                [], // order fields
2839
                [] // extra data
2840
            );
2841
        } else {
2842
            $form->addHidden('extra_revision_language', 1);
2843
        }
2844
    }
2845
2846
    // Setting the class and text of the form title and submit button.
2847
    if ('quote' === $action) {
2848
        $form->addButtonCreate(get_lang('Quote this message'), 'SubmitPost');
2849
    } elseif ('replythread' === $action) {
2850
        $form->addButtonCreate(get_lang('Reply to this thread'), 'SubmitPost');
2851
    } elseif ('replymessage' === $action) {
2852
        $form->addButtonCreate(get_lang('Reply to this message'), 'SubmitPost');
2853
    }
2854
2855
    $defaults['thread_peer_qualify'] = 0;
2856
    if (!empty($form_values)) {
2857
        $defaults['post_title'] = prepare4display($form_values['post_title']);
2858
        $defaults['post_text'] = prepare4display($form_values['post_text']);
2859
        $defaults['post_notification'] = (int) $form_values['post_notification'];
2860
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
2861
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
2862
    }
2863
2864
    // If we are quoting a message we have to retrieve the information of the post we are quoting so that
2865
    // we can add this as default to the textarea.
2866
    // We also need to put the parent_id of the post in a hidden form when
2867
    if (('quote' === $action || 'replymessage' === $action || $giveRevision) && !empty($postId)) {
2868
        // we are quoting or replying to a message (<> reply to a thread !!!)
2869
        $form->addHidden('post_parent_id', $post->getIid());
2870
        // If we are replying or are quoting then we display a default title.
2871
        $posterInfo = api_get_user_info($post->getPosterId());
2872
        $posterName = '';
2873
        if ($posterInfo) {
2874
            $posterName = $posterInfo['complete_name'];
2875
        }
2876
        $defaults['post_title'] = get_lang('Re:').api_html_entity_decode($post->getPostTitle(), ENT_QUOTES);
2877
        // When we are quoting a message then we have to put that message into the wysiwyg editor.
2878
        // Note: The style has to be hardcoded here because using class="quote" didn't work.
2879
        if ('quote' === $action) {
2880
            $defaults['post_text'] = '<div>&nbsp;</div>
2881
                <div style="margin: 5px;">
2882
                    <div style="font-size: 90%; font-style: italic;">'.
2883
                get_lang('Quoting').' '.$posterName.':</div>
2884
                        <div style="color: #006600; font-size: 90%;  font-style: italic; background-color: #FAFAFA; border: #D1D7DC 1px solid; padding: 3px;">'.
2885
                prepare4display($post->getPostText()).'
2886
                        </div>
2887
                    </div>
2888
                <div>&nbsp;</div>
2889
                <div>&nbsp;</div>
2890
            ';
2891
        }
2892
        if ($giveRevision) {
2893
            $defaults['post_text'] = prepare4display($post->getPostText());
2894
        }
2895
    }
2896
2897
    $form->setDefaults(isset($defaults) ? $defaults : []);
2898
2899
    // The course admin can make a thread sticky (=appears with special icon and always on top).
2900
    $form->addRule('post_title', get_lang('Required field'), 'required');
2901
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2902
        $form->addRule(
2903
            'poster_name',
2904
            get_lang('Required field'),
2905
            'required'
2906
        );
2907
    }
2908
2909
    // Validation or display
2910
    if ($form->validate()) {
2911
        $check = Security::check_token('post');
2912
        if ($check) {
2913
            $values = $form->getSubmitValues();
2914
            if (isset($values['thread_qualify_gradebook']) &&
2915
                '1' == $values['thread_qualify_gradebook'] &&
2916
                empty($values['weight_calification'])
2917
            ) {
2918
                Display::addFlash(
2919
                    Display::return_message(
2920
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
2921
                        'error',
2922
                        false
2923
                    )
2924
                );
2925
2926
                return false;
2927
            }
2928
2929
            $postId = 0;
2930
            $threadId = 0;
2931
2932
            switch ($action) {
2933
                case 'quote':
2934
                case 'replythread':
2935
                case 'replymessage':
2936
                    $postId = store_reply($forum, $thread, $values);
2937
2938
                    break;
2939
            }
2940
2941
            if ($postId) {
2942
                if (isset($values['give_revision']) && 1 == $values['give_revision']) {
2943
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2944
                    $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
2945
                    $params = [
2946
                        'item_id' => $postId,
2947
                        'extra_revision_language' => $revisionLanguage,
2948
                    ];
2949
2950
                    $extraFieldValues->saveFieldValues(
2951
                        $params,
2952
                        false,
2953
                        false,
2954
                        ['revision_language']
2955
                    );
2956
                }
2957
2958
                if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2959
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2960
                    $params = [
2961
                        'item_id' => $postId,
2962
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
2963
                    ];
2964
                    $extraFieldValues->saveFieldValues(
2965
                        $params,
2966
                        false,
2967
                        false,
2968
                        ['ask_for_revision']
2969
                    );
2970
                }
2971
            }
2972
2973
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
2974
                [
2975
                    'forum' => $forumId,
2976
                    'thread' => $thread->getIid(),
2977
                ]
2978
            );
2979
2980
            Security::clear_token();
2981
            header('Location: '.$url);
2982
            exit;
2983
        }
2984
    } else {
2985
        $token = Security::get_token();
2986
        $form->addElement('hidden', 'sec_token');
2987
        $form->setConstants(['sec_token' => $token]);
2988
2989
        // Delete from $_SESSION forum attachment from other posts
2990
        // and keep only attachments for new post
2991
        clearAttachedFiles(FORUM_NEW_POST);
2992
        // Get forum attachment ajax table to add it to form
2993
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
2994
        $ajaxHtml = $attachmentAjaxTable;
2995
        $form->addElement('html', $ajaxHtml);
2996
2997
        return $form;
2998
    }
2999
}
3000
3001
function newThread(CForumForum $forum, $form_values = '', $showPreview = true)
3002
{
3003
    $_user = api_get_user_info();
3004
    $forumId = $forum->getIid();
3005
    $my_post = isset($_GET['post']) ? (int) $_GET['post'] : '';
3006
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
3007
    $action = 'new_thread';
3008
3009
    $url = api_get_self().'?'.http_build_query(
3010
            [
3011
                'action' => $action,
3012
                'forum' => $forumId,
3013
                'post' => $my_post,
3014
            ]
3015
        ).'&'.api_get_cidreq();
3016
3017
    $form = new FormValidator(
3018
        'thread',
3019
        'post',
3020
        $url
3021
    );
3022
3023
    // Setting the form elements.
3024
    $form->addElement('hidden', 'forum_id', $forumId);
3025
    $form->addElement('hidden', 'thread_id', 0);
3026
    $form->addElement('hidden', 'action', $action);
3027
3028
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
3029
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
3030
        $form->addElement('text', 'poster_name', get_lang('Name'));
3031
        $form->applyFilter('poster_name', 'html_filter');
3032
    }
3033
3034
    $form->addElement('text', 'post_title', get_lang('Title'));
3035
    $form->addHtmlEditor(
3036
        'post_text',
3037
        get_lang('Text'),
3038
        true,
3039
        false,
3040
        api_is_allowed_to_edit(null, true) ? [
3041
            'ToolbarSet' => 'Forum',
3042
            'Width' => '100%',
3043
            'Height' => '300',
3044
        ] : [
3045
            'ToolbarSet' => 'ForumStudent',
3046
            'Width' => '100%',
3047
            'Height' => '300',
3048
            'UserStatus' => 'student',
3049
        ]
3050
    );
3051
    $form->addRule('post_text', get_lang('Required field'), 'required');
3052
3053
    $extraFields = new ExtraField('forum_post');
3054
    $extraFields->addElements(
3055
        $form,
3056
        null,
3057
        [], //exclude
3058
        false, // filter
3059
        false, // tag as select
3060
        ['ask_for_revision'], //show only fields
3061
        [], // order fields
3062
        [] // extra data);
3063
    );
3064
3065
    if (Gradebook::is_active() &&
3066
        (api_is_course_admin() || api_is_session_general_coach() || api_is_course_tutor())
3067
    ) {
3068
        $form->addElement('advanced_settings', 'advanced_params', get_lang('Advanced settings'));
3069
        $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3070
3071
        // Thread qualify
3072
        if (Gradebook::is_active()) {
3073
            //Loading gradebook select
3074
            GradebookUtils::load_gradebook_select_in_tool($form);
3075
            $form->addElement(
3076
                'checkbox',
3077
                'thread_qualify_gradebook',
3078
                '',
3079
                get_lang('Grade this thread'),
3080
                'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"'
3081
            );
3082
        } else {
3083
            $form->addElement('hidden', 'thread_qualify_gradebook', false);
3084
        }
3085
3086
        $form->addElement('html', '<div id="options_field" style="display:none">');
3087
        $form->addElement('text', 'numeric_calification', get_lang('Maximum score'));
3088
        $form->applyFilter('numeric_calification', 'html_filter');
3089
        $form->addElement('text', 'calification_notebook_title', get_lang('Column header in Competences Report'));
3090
        $form->applyFilter('calification_notebook_title', 'html_filter');
3091
3092
        $form->addElement(
3093
            'text',
3094
            'weight_calification',
3095
            get_lang('Weight in Report'),
3096
            ['value' => '0.00', 'onfocus' => 'javascript: this.select();']
3097
        );
3098
        $form->applyFilter('weight_calification', 'html_filter');
3099
3100
        $group = [];
3101
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('Yes'), 1);
3102
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('No'), 0);
3103
        $form->addGroup(
3104
            $group,
3105
            '',
3106
            [
3107
                get_lang('Thread scored by peers'),
3108
                get_lang('Thread scored by peersComment'),
3109
            ]
3110
        );
3111
        $form->addElement('html', '</div>');
3112
        $form->addElement('html', '</div>');
3113
    }
3114
3115
    Skill::addSkillsToForm($form, ITEM_TYPE_FORUM_THREAD, 0);
3116
    $form->addElement('checkbox', 'thread_sticky', '', get_lang('This is a sticky message (appears always on top and has a special sticky icon)'));
3117
3118
    $form->addFile('user_upload', get_lang('Attachment'));
3119
3120
    if ($giveRevision) {
3121
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
3122
        $form->addHidden('give_revision', 1);
3123
        if (false === $hide) {
3124
            $extraField = new ExtraField('forum_post');
3125
            $extraField->addElements(
3126
                $form,
3127
                null,
3128
                [], //exclude
3129
                false, // filter
3130
                false, // tag as select
3131
                ['revision_language'], //show only fields
3132
                [], // order fields
3133
                [] // extra data
3134
            );
3135
        } else {
3136
            $form->addHidden('extra_revision_language', 1);
3137
        }
3138
    }
3139
    $form->addButtonCreate(get_lang('Create thread'), 'SubmitPost');
3140
3141
    $defaults['thread_peer_qualify'] = 0;
3142
    if (!empty($form_values)) {
3143
        $defaults['post_title'] = prepare4display($form_values['post_title']);
3144
        $defaults['post_text'] = prepare4display($form_values['post_text']);
3145
        $defaults['post_notification'] = (int) $form_values['post_notification'];
3146
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
3147
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
3148
    }
3149
3150
    $form->setDefaults(isset($defaults) ? $defaults : []);
3151
3152
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3153
    $form->addRule('post_title', get_lang('Required field'), 'required');
3154
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
3155
        $form->addRule(
3156
            'poster_name',
3157
            get_lang('Required field'),
3158
            'required'
3159
        );
3160
    }
3161
3162
    // Validation or display
3163
    if ($form->validate()) {
3164
        $check = Security::check_token('post');
3165
        if ($check) {
3166
            $values = $form->getSubmitValues();
3167
            if (isset($values['thread_qualify_gradebook']) &&
3168
                '1' == $values['thread_qualify_gradebook'] &&
3169
                empty($values['weight_calification'])
3170
            ) {
3171
                Display::addFlash(
3172
                    Display::return_message(
3173
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
3174
                        'error',
3175
                        false
3176
                    )
3177
                );
3178
3179
                return false;
3180
            }
3181
3182
            $newThread = store_thread($forum, $values);
3183
            if ($newThread) {
3184
                Skill::saveSkills($form, ITEM_TYPE_FORUM_THREAD, $newThread->getIid());
3185
                $postId = $newThread->getThreadLastPost();
3186
3187
                if ($postId) {
3188
                    if (isset($values['give_revision']) && 1 == $values['give_revision']) {
3189
                        $extraFieldValues = new ExtraFieldValue('forum_post');
3190
                        $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
3191
3192
                        $params = [
3193
                            'item_id' => $postId,
3194
                            'extra_revision_language' => $revisionLanguage,
3195
                        ];
3196
3197
                        $extraFieldValues->saveFieldValues(
3198
                            $params,
3199
                            false,
3200
                            false,
3201
                            ['revision_language']
3202
                        );
3203
                    }
3204
                    $extraFieldValues = new ExtraFieldValue('forum_post');
3205
                    $params = [
3206
                        'item_id' => $postId,
3207
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
3208
                    ];
3209
                    $extraFieldValues->saveFieldValues(
3210
                        $params,
3211
                        false,
3212
                        false,
3213
                        ['ask_for_revision']
3214
                    );
3215
                }
3216
            }
3217
3218
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
3219
                [
3220
                    'forum' => $forumId,
3221
                    'thread' => $newThread->getIid(),
3222
                ]
3223
            );
3224
3225
            Security::clear_token();
3226
            header('Location: '.$url);
3227
            exit;
3228
        }
3229
    } else {
3230
        $token = Security::get_token();
3231
        $form->addElement('hidden', 'sec_token');
3232
        $form->setConstants(['sec_token' => $token]);
3233
3234
        // Delete from $_SESSION forum attachment from other posts
3235
        // and keep only attachments for new post
3236
        clearAttachedFiles(FORUM_NEW_POST);
3237
        // Get forum attachment ajax table to add it to form
3238
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
3239
        $ajaxHtml = $attachmentAjaxTable;
3240
        $form->addElement('html', $ajaxHtml);
3241
3242
        return $form;
3243
    }
3244
}
3245
3246
/**
3247
 * @param array $threadInfo
3248
 * @param int   $user_id
3249
 * @param int   $thread_id
3250
 * @param int   $thread_qualify
3251
 * @param int   $qualify_time
3252
 * @param int   $session_id
3253
 *
3254
 * @return array optional
3255
 *
3256
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3257
 *
3258
 * @version October 2008, dokeos  1.8.6
3259
 */
3260
function saveThreadScore(
3261
    $threadInfo,
3262
    $user_id,
3263
    $thread_id,
3264
    $thread_qualify = 0,
3265
    $qualify_time,
3266
    $session_id = 0
3267
) {
3268
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3269
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3270
3271
    $course_id = api_get_course_int_id();
3272
    $session_id = (int) $session_id;
3273
    $currentUserId = api_get_user_id();
3274
3275
    if ($user_id == (string) ((int) $user_id) &&
3276
        $thread_id == (string) ((int) $thread_id) &&
3277
        $thread_qualify == (string) ((float) $thread_qualify)
3278
    ) {
3279
        // Testing
3280
        $sql = "SELECT thread_qualify_max FROM $table_threads
3281
                WHERE c_id = $course_id AND thread_id=".$thread_id;
3282
        $res_string = Database::query($sql);
3283
        $row_string = Database::fetch_array($res_string);
3284
        if ($thread_qualify <= $row_string[0]) {
3285
            if (0 == $threadInfo['thread_peer_qualify']) {
3286
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3287
                        WHERE
3288
                            c_id = $course_id AND
3289
                            user_id = $user_id AND
3290
                            thread_id = ".$thread_id;
3291
            } else {
3292
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3293
                        WHERE
3294
                            c_id = $course_id AND
3295
                            user_id = $user_id AND
3296
                            qualify_user_id = $currentUserId AND
3297
                            thread_id = ".$thread_id;
3298
            }
3299
3300
            $result = Database::query($sql);
3301
            $row = Database::fetch_array($result);
3302
3303
            if (0 == $row[0]) {
3304
                $sql = "INSERT INTO $table_threads_qualify (c_id, user_id, thread_id,qualify,qualify_user_id,qualify_time,session_id)
3305
                        VALUES (".$course_id.", '".$user_id."','".$thread_id."',".(float) $thread_qualify.", '".$currentUserId."','".$qualify_time."','".$session_id."')";
3306
                Database::query($sql);
3307
                $insertId = Database::insert_id();
3308
                if ($insertId) {
3309
                    $sql = "UPDATE $table_threads_qualify SET id = iid
3310
                            WHERE iid = $insertId";
3311
                    Database::query($sql);
3312
                }
3313
3314
                return 'insert';
3315
            } else {
3316
                saveThreadScoreHistory(
3317
                    '1',
3318
                    $course_id,
3319
                    $user_id,
3320
                    $thread_id
3321
                );
3322
3323
                // Update
3324
                $sql = "UPDATE $table_threads_qualify
3325
                        SET
3326
                            qualify = '".$thread_qualify."',
3327
                            qualify_time = '".$qualify_time."'
3328
                        WHERE
3329
                            c_id = $course_id AND
3330
                            user_id=".$user_id.' AND
3331
                            thread_id='.$thread_id." AND
3332
                            qualify_user_id = $currentUserId
3333
                        ";
3334
                Database::query($sql);
3335
3336
                return 'update';
3337
            }
3338
        } else {
3339
            return null;
3340
        }
3341
    }
3342
}
3343
3344
/**
3345
 * This function shows qualify.
3346
 *
3347
 * @param string $option    contains the information of option to run
3348
 * @param int    $user_id   contains the information the current user id
3349
 * @param int    $thread_id contains the information the current thread id
3350
 *
3351
 * @return int qualify
3352
 *             <code> $option=1 obtained the qualification of the current thread</code>
3353
 *
3354
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3355
 *
3356
 * @version October 2008, dokeos  1.8.6
3357
 */
3358
function showQualify($option, $user_id, $thread_id)
3359
{
3360
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3361
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3362
3363
    $course_id = api_get_course_int_id();
3364
    $user_id = (int) $user_id;
3365
    $thread_id = (int) $thread_id;
3366
3367
    if (empty($user_id) || empty($thread_id)) {
3368
        return false;
3369
    }
3370
3371
    $sql = '';
3372
    switch ($option) {
3373
        case 1:
3374
            $sql = "SELECT qualify FROM $table_threads_qualify
3375
                    WHERE
3376
                        c_id = $course_id AND
3377
                        user_id=".$user_id.' AND
3378
                        thread_id='.$thread_id;
3379
3380
            break;
3381
        case 2:
3382
            $sql = "SELECT thread_qualify_max FROM $table_threads
3383
                    WHERE c_id = $course_id AND thread_id=".$thread_id;
3384
3385
            break;
3386
    }
3387
3388
    if (!empty($sql)) {
3389
        $rs = Database::query($sql);
3390
        $row = Database::fetch_array($rs);
3391
3392
        return $row[0];
3393
    }
3394
3395
    return [];
3396
}
3397
3398
/**
3399
 * This function gets qualify historical.
3400
 *
3401
 * @param int  $user_id   contains the information the current user id
3402
 * @param int  $thread_id contains the information the current thread id
3403
 * @param bool $opt       contains the information of option to run
3404
 *
3405
 * @return array
3406
 *
3407
 * @author Christian Fasanando <[email protected]>,
3408
 * @author Isaac Flores <[email protected]>,
3409
 *
3410
 * @version October 2008, dokeos  1.8.6
3411
 */
3412
function getThreadScoreHistory($user_id, $thread_id, $opt)
3413
{
3414
    $user_id = (int) $user_id;
3415
    $thread_id = (int) $thread_id;
3416
3417
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3418
    $course_id = api_get_course_int_id();
3419
3420
    if ('false' == $opt) {
3421
        $sql = "SELECT * FROM $table_threads_qualify_log
3422
                WHERE
3423
                    c_id = $course_id AND
3424
                    thread_id='".$thread_id."' AND
3425
                    user_id='".$user_id."'
3426
                ORDER BY qualify_time";
3427
    } else {
3428
        $sql = "SELECT * FROM $table_threads_qualify_log
3429
                WHERE
3430
                    c_id = $course_id AND
3431
                    thread_id='".$thread_id."' AND
3432
                    user_id='".$user_id."'
3433
                ORDER BY qualify_time DESC";
3434
    }
3435
    $rs = Database::query($sql);
3436
    $log = [];
3437
    while ($row = Database::fetch_array($rs, 'ASSOC')) {
3438
        $log[] = $row;
3439
    }
3440
3441
    return $log;
3442
}
3443
3444
/**
3445
 * This function stores qualify historical.
3446
 *
3447
 * @param bool contains the information of option to run
3448
 * @param string contains the information the current course id
3449
 * @param int contains the information the current forum id
3450
 * @param int contains the information the current user id
3451
 * @param int contains the information the current thread id
3452
 * @param int contains the information the current qualify
3453
 * @param string $option
3454
 * @param int    $course_id
3455
 * @param int    $user_id
3456
 * @param int    $thread_id
3457
 *
3458
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3459
 *
3460
 * @version October 2008, dokeos  1.8.6
3461
 */
3462
function saveThreadScoreHistory(
3463
    $option,
3464
    $course_id,
3465
    $user_id,
3466
    $thread_id
3467
) {
3468
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3469
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3470
3471
    $course_id = (int) $course_id;
3472
    $qualify_user_id = api_get_user_id();
3473
3474
    if ($user_id == (string) ((int) $user_id) &&
3475
        $thread_id == (string) ((int) $thread_id) && 1 == $option
3476
    ) {
3477
        // Extract information of thread_qualify.
3478
        $sql = "SELECT qualify, qualify_time
3479
                FROM $table_threads_qualify
3480
                WHERE
3481
                    c_id = $course_id AND
3482
                    user_id = ".$user_id.' AND
3483
                    thread_id = '.$thread_id." AND
3484
                    qualify_user_id = $qualify_user_id
3485
                ";
3486
        $rs = Database::query($sql);
3487
        $row = Database::fetch_array($rs);
3488
3489
        // Insert thread_historical.
3490
        $sql = "INSERT INTO $table_threads_qualify_log (c_id, user_id, thread_id, qualify, qualify_user_id,qualify_time,session_id)
3491
                VALUES(".$course_id.", '".$user_id."','".$thread_id."',".(float) $row[0].", '".$qualify_user_id."','".$row[1]."','')";
3492
        Database::query($sql);
3493
3494
        $insertId = Database::insert_id();
3495
        if ($insertId) {
3496
            $sql = "UPDATE $table_threads_qualify_log SET id = iid
3497
                    WHERE iid = $insertId";
3498
            Database::query($sql);
3499
        }
3500
    }
3501
}
3502
3503
/**
3504
 * This function shows current thread qualify .
3505
 *
3506
 * @param int $threadId
3507
 * @param int $sessionId
3508
 * @param int $userId
3509
 *
3510
 * @return array or null if is empty
3511
 *
3512
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3513
 *
3514
 * @version December 2008, dokeos  1.8.6
3515
 */
3516
function current_qualify_of_thread($threadId, $sessionId, $userId)
3517
{
3518
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3519
3520
    $course_id = api_get_course_int_id();
3521
    $currentUserId = api_get_user_id();
3522
    $sessionId = (int) $sessionId;
3523
    $threadId = (int) $threadId;
3524
3525
    $sql = "SELECT qualify FROM $table_threads_qualify
3526
            WHERE
3527
                c_id = $course_id AND
3528
                thread_id = $threadId AND
3529
                session_id = $sessionId AND
3530
                qualify_user_id = $currentUserId AND
3531
                user_id = $userId
3532
            ";
3533
    $res = Database::query($sql);
3534
    $row = Database::fetch_array($res, 'ASSOC');
3535
3536
    return $row['qualify'];
3537
}
3538
3539
/**
3540
 * This function stores a reply in the forum_post table.
3541
 * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date).
3542
 *
3543
 * @param array $values
3544
 * @param int   $courseId Optional
3545
 * @param int   $userId   Optional
3546
 *
3547
 * @return int post id
3548
 */
3549
function store_reply(CForumForum $forum, CForumThread $thread, $values, $courseId = 0, $userId = 0)
3550
{
3551
    $courseId = !empty($courseId) ? $courseId : api_get_course_int_id();
3552
    $_course = api_get_course_info_by_id($courseId);
3553
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3554
    $post_date = api_get_utc_datetime();
3555
    $userId = $userId ?: api_get_user_id();
3556
3557
    if (1 == $forum->getAllowAnonymous()) {
3558
        if (api_is_anonymous() && empty($userId)) {
3559
            $userId = api_get_anonymous_id();
3560
        }
3561
    }
3562
3563
    if (empty($userId)) {
3564
        return false;
3565
    }
3566
3567
    $visible = 1;
3568
    if ('1' == $forum->getApprovalDirectPost() &&
3569
        !api_is_allowed_to_edit(null, true)
3570
    ) {
3571
        $visible = 0;
3572
    }
3573
3574
    $upload_ok = 1;
3575
    $new_post_id = 0;
3576
3577
    if ($upload_ok) {
3578
        $post = new CForumPost();
3579
        $post
3580
            ->setCId($courseId)
3581
            ->setPostTitle($values['post_title'])
3582
            ->setPostText(isset($values['post_text']) ?: null)
3583
            ->setThread($thread)
3584
            ->setForum($forum)
3585
            ->setPosterId($userId)
3586
            ->setPostNotification(isset($values['post_notification']) ? $values['post_notification'] : null)
3587
            ->setPostParentId(isset($values['post_parent_id']) ? $values['post_parent_id'] : null)
3588
            ->setVisible($visible)
3589
            ->setPostDate(api_get_utc_datetime(null, false, true))
3590
        ;
3591
3592
        $repo = Container::getForumPostRepository();
3593
3594
        $user = api_get_user_entity(api_get_user_id());
3595
        $course = api_get_course_entity($courseId);
3596
        $session = api_get_session_entity();
3597
3598
        $em = $repo->getEntityManager();
3599
3600
        $repo->addResourceToCourseWithParent(
3601
            $post,
3602
            $thread->getResourceNode(),
3603
            ResourceLink::VISIBILITY_PUBLISHED,
3604
            $user,
3605
            $course,
3606
            $session,
3607
            null
3608
        );
3609
        $em->flush();
3610
3611
        $new_post_id = $post->getIid();
3612
3613
        if ($new_post_id) {
3614
            $sql = "UPDATE $table_posts SET post_id = iid WHERE iid = $new_post_id";
3615
            Database::query($sql);
3616
3617
            $values['new_post_id'] = $new_post_id;
3618
            $message = get_lang('The reply has been added');
3619
3620
            if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3621
                foreach ($_POST['file_ids'] as $key => $id) {
3622
                    editAttachedFile(
3623
                        [
3624
                            'comment' => $_POST['file_comments'][$key],
3625
                            'post_id' => $new_post_id,
3626
                        ],
3627
                        $id
3628
                    );
3629
                }
3630
            }
3631
3632
            // Update the thread.
3633
            updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
3634
3635
            // Update the forum.
3636
            /*api_item_property_update(
3637
                $_course,
3638
                TOOL_FORUM,
3639
                $values['forum_id'],
3640
                'NewMessageInForum',
3641
                $userId
3642
            );
3643
3644
            // Insert post
3645
            api_item_property_update(
3646
                $_course,
3647
                TOOL_FORUM_POST,
3648
                $new_post_id,
3649
                'NewPost',
3650
                $userId
3651
            );*/
3652
3653
            if ('1' == $forum->getApprovalDirectPost() &&
3654
                !api_is_allowed_to_edit(null, true)
3655
            ) {
3656
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
3657
            }
3658
3659
            if ($forum->isModerated() &&
3660
                !api_is_allowed_to_edit(null, true)
3661
            ) {
3662
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
3663
            }
3664
3665
            // Setting the notification correctly.
3666
            $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
3667
            if (1 == $my_post_notification) {
3668
                set_notification('thread', $values['thread_id'], true);
3669
            }
3670
3671
            send_notification_mails(
3672
                $forum,
3673
                $thread,
3674
                $values
3675
            );
3676
            add_forum_attachment_file('', $post);
3677
3678
            $logInfo = [
3679
                'tool' => TOOL_FORUM,
3680
                'tool_id' => $values['forum_id'],
3681
                'tool_id_detail' => $values['thread_id'],
3682
                'action' => 'new-post',
3683
                'action_details' => $values['action'],
3684
                'info' => $values['post_title'],
3685
            ];
3686
            Event::registerLog($logInfo);
3687
        }
3688
3689
        Session::erase('formelements');
3690
        Session::erase('origin');
3691
        Session::erase('breadcrumbs');
3692
        Session::erase('addedresource');
3693
        Session::erase('addedresourceid');
3694
3695
        Display::addFlash(Display::return_message($message, 'confirmation', false));
3696
    } else {
3697
        Display::addFlash(
3698
            Display::return_message(
3699
                get_lang('No file was uploaded.').' '.get_lang('Please select a file before pressing the upload button.'),
3700
                'error'
3701
            )
3702
        );
3703
    }
3704
3705
    return $new_post_id;
3706
}
3707
3708
/**
3709
 * This function displays the form that is used to edit a post. This can be a new thread or a reply.
3710
 *
3711
 * @param CForumPost   $post        contains all the information about the current post
3712
 * @param CForumThread $thread      contains all the information about the current thread
3713
 * @param CForumForum  $forum       contains all info about the current forum (to check if attachments are allowed)
3714
 * @param array        $form_values contains the default values to fill the form
3715
 *
3716
 * @author Patrick Cool <[email protected]>, Ghent University
3717
 *
3718
 * @version february 2006, dokeos 1.8
3719
 */
3720
function show_edit_post_form(
3721
    $post,
3722
    $thread,
3723
    $forum,
3724
    $form_values = '',
3725
    $id_attach = 0
3726
) {
3727
    // Initialize the object.
3728
    $form = new FormValidator(
3729
        'edit_post',
3730
        'post',
3731
        api_get_self().'?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&post='.(int) ($_GET['post'])
3732
    );
3733
    $form->addElement('header', get_lang('Edit a post'));
3734
    // Setting the form elements.
3735
    $form->addElement('hidden', 'post_id', $post->getIid());
3736
    $form->addElement('hidden', 'thread_id', $thread->getIid());
3737
    $form->addElement('hidden', 'id_attach', $id_attach);
3738
3739
    if (empty($post->getPostParentId())) {
3740
        $form->addElement('hidden', 'is_first_post_of_thread', '1');
3741
    }
3742
3743
    $form->addElement('text', 'post_title', get_lang('Title'));
3744
    $form->applyFilter('post_title', 'html_filter');
3745
    $form->addElement(
3746
        'html_editor',
3747
        'post_text',
3748
        get_lang('Text'),
3749
        null,
3750
        api_is_allowed_to_edit(null, true) ? [
3751
            'ToolbarSet' => 'Forum',
3752
            'Width' => '100%',
3753
            'Height' => '400',
3754
        ] : [
3755
            'ToolbarSet' => 'ForumStudent',
3756
            'Width' => '100%',
3757
            'Height' => '400',
3758
            'UserStatus' => 'student',
3759
        ]
3760
    );
3761
    $form->addRule('post_text', get_lang('Required field'), 'required');
3762
3763
    $extraFields = new ExtraField('forum_post');
3764
    $extraFields->addElements($form, $post->getIid());
3765
3766
    $form->addButtonAdvancedSettings('advanced_params');
3767
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3768
3769
    if ($forum->isModerated() && api_is_allowed_to_edit(null, true)) {
3770
        $group = [];
3771
        $group[] = $form->createElement(
3772
            'radio',
3773
            'status',
3774
            null,
3775
            get_lang('Validated'),
3776
            1
3777
        );
3778
        $group[] = $form->createElement(
3779
            'radio',
3780
            'status',
3781
            null,
3782
            get_lang('Waiting for moderation'),
3783
            2
3784
        );
3785
        $group[] = $form->createElement(
3786
            'radio',
3787
            'status',
3788
            null,
3789
            get_lang('Rejected'),
3790
            3
3791
        );
3792
        $form->addGroup($group, 'status', get_lang('Status'));
3793
    }
3794
3795
    $defaults['status']['status'] = $post->getStatus();
3796
3797
    $form->addElement(
3798
        'checkbox',
3799
        'post_notification',
3800
        '',
3801
        get_lang('Notify me by e-mail when somebody replies')
3802
    );
3803
3804
    if (api_is_allowed_to_edit(null, true) &&
3805
        empty($post->getPostParentId())
3806
    ) {
3807
        // The sticky checkbox only appears when it is the first post of a thread.
3808
        $form->addElement(
3809
            'checkbox',
3810
            'thread_sticky',
3811
            '',
3812
            get_lang('This is a sticky message (appears always on top and has a special sticky icon)')
3813
        );
3814
        if (1 == $thread->getThreadSticky()) {
3815
            $defaults['thread_sticky'] = true;
3816
        }
3817
    }
3818
3819
    $form->addElement('html', '</div>');
3820
3821
    $form->addFile('user_upload[]', get_lang('Attachment'));
3822
    $form->addButton(
3823
        'add_attachment',
3824
        get_lang('Add attachment'),
3825
        'paperclip',
3826
        'default',
3827
        'default',
3828
        null,
3829
        ['id' => 'reply-add-attachment']
3830
    );
3831
3832
    $form->addButtonUpdate(get_lang('Edit'), 'SubmitPost');
3833
3834
    // Setting the default values for the form elements.
3835
    $defaults['post_title'] = $post->getPostTitle();
3836
    $defaults['post_text'] = $post->getPostText();
3837
3838
    if (1 == $post->getPostNotification()) {
3839
        $defaults['post_notification'] = true;
3840
    }
3841
3842
    if (!empty($form_values)) {
3843
        $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
3844
        $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
3845
    }
3846
3847
    $form->setDefaults($defaults);
3848
3849
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3850
    $form->addRule('post_title', get_lang('Required field'), 'required');
3851
3852
    // Validation or display
3853
    if ($form->validate()) {
3854
        $values = $form->exportValues();
3855
        $values['item_id'] = $post->getIid();
3856
        $extraFieldValues = new ExtraFieldValue('forum_post');
3857
        $extraFieldValues->saveFieldValues($values);
3858
3859
        store_edit_post($forum, $values);
3860
    } else {
3861
        // Delete from $_SESSION forum attachment from other posts
3862
        clearAttachedFiles($post->getIid());
3863
        // Get forum attachment ajax table to add it to form
3864
        $fileData = getAttachmentsAjaxTable($post->getIid(), $forum->getIid());
3865
        $form->addElement('html', $fileData);
3866
        $form->display();
3867
    }
3868
}
3869
3870
/**
3871
 * This function stores the edit of a post in the forum_post table.
3872
 *
3873
 * @author Patrick Cool <[email protected]>, Ghent University
3874
 *
3875
 * @version february 2006, dokeos 1.8
3876
 */
3877
function store_edit_post(CForumForum $forum, $values)
3878
{
3879
    $logInfo = [
3880
        'tool' => TOOL_FORUM,
3881
        'tool_id' => $_GET['forum'],
3882
        'tool_id_detail' => $values['thread_id'],
3883
        'action' => 'edit-post',
3884
        'action_details' => 'post',
3885
        'info' => $values['post_title'],
3886
    ];
3887
    Event::registerLog($logInfo);
3888
3889
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
3890
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3891
    $course_id = api_get_course_int_id();
3892
3893
    //check if this post is the first of the thread
3894
    // First we check if the change affects the thread and if so we commit
3895
    // the changes (sticky and post_title=thread_title are relevant).
3896
3897
    $posts = getPosts($forum, $values['thread_id']);
3898
    $first_post = null;
3899
    if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
3900
        $first_post = $posts[0];
3901
    }
3902
3903
    if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
3904
        // Simple edit
3905
        $params = [
3906
            'thread_title' => $values['post_title'],
3907
            'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
3908
        ];
3909
        $where = ['c_id = ? AND thread_id = ?' => [$course_id, $values['thread_id']]];
3910
        Database::update($threadTable, $params, $where);
3911
    }
3912
3913
    $status = '';
3914
    $updateStatus = false;
3915
    if ($forum->isModerated()) {
3916
        if (api_is_allowed_to_edit(null, true)) {
3917
            $status = $values['status']['status'];
3918
            $updateStatus = true;
3919
        } else {
3920
            $status = CForumPost::STATUS_WAITING_MODERATION;
3921
            $updateStatus = true;
3922
        }
3923
    }
3924
3925
    $postId = $values['post_id'];
3926
    $repo = Container::getForumPostRepository();
3927
    /** @var CForumPost $post */
3928
    $post = $repo->find($postId);
3929
    if ($post) {
3930
        $post
3931
            ->setPostTitle($values['post_title'])
3932
            ->setPostText($values['post_text'])
3933
            ->setPostNotification(isset($values['post_notification']) ? 1 : 0)
3934
        ;
3935
3936
        if ($updateStatus) {
3937
            $post->setStatus($status);
3938
        }
3939
        $repo->getEntityManager()->persist($post);
3940
        $repo->getEntityManager()->flush();
3941
    }
3942
3943
    // Update attached files
3944
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3945
        foreach ($_POST['file_ids'] as $key => $id) {
3946
            editAttachedFile(
3947
                [
3948
                    'comment' => $_POST['file_comments'][$key],
3949
                    'post_id' => $values['post_id'],
3950
                ],
3951
                $id
3952
            );
3953
        }
3954
    }
3955
3956
    if (!empty($values['remove_attach'])) {
3957
        delete_attachment($values['post_id']);
3958
    }
3959
3960
    if (empty($values['id_attach'])) {
3961
        add_forum_attachment_file(
3962
            isset($values['file_comment']) ? $values['file_comment'] : null,
3963
            $post
3964
        );
3965
    } else {
3966
        /*edit_forum_attachment_file(
3967
            isset($values['file_comment']) ? $values['file_comment'] : null,
3968
            $values['post_id'],
3969
            $values['id_attach']
3970
        );*/
3971
    }
3972
3973
    $message = get_lang('The post has been modified').'<br />';
3974
    $message .= get_lang('You can now return to the').
3975
        ' <a href="viewforum.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&">'.get_lang('Forum').'</a><br />';
3976
    $message .= get_lang('You can now return to the').
3977
        ' <a href="viewthread.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.$values['thread_id'].'&post='.Security::remove_XSS($_GET['post']).'">'.get_lang('Message').'</a>';
3978
3979
    Session::erase('formelements');
3980
    Session::erase('origin');
3981
    Session::erase('breadcrumbs');
3982
    Session::erase('addedresource');
3983
    Session::erase('addedresourceid');
3984
3985
    echo Display::return_message($message, 'confirmation', false);
3986
}
3987
3988
/**
3989
 * This function displays the firstname and lastname of the user as a link to the user tool.
3990
 *
3991
 * @param string $user_id names
3992
 * @ in_title : title tootip
3993
 *
3994
 * @return string HTML
3995
 *
3996
 * @author Patrick Cool <[email protected]>, Ghent University
3997
 *
3998
 * @version february 2006, dokeos 1.8
3999
 */
4000
function display_user_link($user_id, $name, $origin = '', $in_title = '')
4001
{
4002
    if (0 != $user_id) {
4003
        $userInfo = api_get_user_info($user_id);
4004
4005
        return '<a href="'.$userInfo['profile_url'].'">'.Security::remove_XSS($userInfo['complete_name']).'</a>';
4006
    } else {
4007
        return $name.' ('.get_lang('Anonymous').')';
4008
    }
4009
}
4010
4011
/**
4012
 * This function displays the user image from the profile, with a link to the user's details.
4013
 *
4014
 * @param int    $user_id User's database ID
4015
 * @param string $name    User's name
4016
 * @param string $origin  the origin where the forum is called (example : learnpath)
4017
 *
4018
 * @return string An HTML with the anchor and the image of the user
4019
 *
4020
 * @author Julio Montoya <[email protected]>
4021
 */
4022
function display_user_image($user_id, $name, $origin = '')
4023
{
4024
    $userInfo = api_get_user_info($user_id);
4025
    $link = '<a href="'.(!empty($origin) ? '#' : $userInfo['profile_url']).'" '.(!empty($origin) ? 'target="_self"' : '').'>';
4026
4027
    if (0 != $user_id) {
4028
        return $link.'<img src="'.$userInfo['avatar'].'"  alt="'.$name.'"  title="'.$name.'" /></a>';
4029
    } else {
4030
        return $link.Display::return_icon('unknown.jpg', $name).'</a>';
4031
    }
4032
}
4033
4034
/**
4035
 * The thread view counter gets increased every time someone looks at the thread.
4036
 *
4037
 * @param int $thread_id
4038
 *
4039
 * @author Patrick Cool <[email protected]>, Ghent University
4040
 *
4041
 * @version february 2006, dokeos 1.8
4042
 */
4043
function increase_thread_view($thread_id)
4044
{
4045
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4046
    $course_id = api_get_course_int_id();
4047
4048
    $sql = "UPDATE $table_threads
4049
            SET thread_views = thread_views + 1
4050
            WHERE
4051
                c_id = $course_id AND
4052
                thread_id = '".(int) $thread_id."'";
4053
    Database::query($sql);
4054
}
4055
4056
/**
4057
 * The relies counter gets increased every time somebody replies to the thread.
4058
 *
4059
 * @author Patrick Cool <[email protected]>, Ghent University
4060
 *
4061
 * @version february 2006, dokeos 1.8
4062
 *
4063
 * @param int    $threadId
4064
 * @param string $lastPostId
4065
 * @param string $post_date
4066
 */
4067
function updateThreadInfo($threadId, $lastPostId, $post_date)
4068
{
4069
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4070
    $course_id = api_get_course_int_id();
4071
    $sql = "UPDATE $table_threads SET
4072
            thread_replies = thread_replies+1,
4073
            thread_last_post = '".Database::escape_string($lastPostId)."',
4074
            thread_date = '".Database::escape_string($post_date)."'
4075
            WHERE
4076
                c_id = $course_id AND
4077
                thread_id='".Database::escape_string($threadId)."'"; // this needs to be cleaned first
4078
    Database::query($sql);
4079
}
4080
4081
/**
4082
 * This function is used to find all the information about what's new in the forum tool.
4083
 *
4084
 * @author Patrick Cool <[email protected]>, Ghent University
4085
 *
4086
 * @version february 2006, dokeos 1.8
4087
 */
4088
function get_whats_new()
4089
{
4090
    $userId = api_get_user_id();
4091
    $course_id = api_get_course_int_id();
4092
4093
    if (empty($course_id) || empty($userId)) {
4094
        return false;
4095
    }
4096
4097
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4098
    $tracking_last_tool_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4099
4100
    $tool = TOOL_FORUM;
4101
    $lastForumAccess = Session::read('last_forum_access');
4102
4103
    if (!$lastForumAccess) {
4104
        $sql = "SELECT * FROM $tracking_last_tool_access
4105
                WHERE
4106
                    access_user_id = $userId AND
4107
                    c_id = $course_id AND
4108
                    access_tool = '".Database::escape_string($tool)."'";
4109
        $result = Database::query($sql);
4110
        $row = Database::fetch_array($result);
4111
        if ($row) {
4112
            Session::write('last_forum_access', $row['access_date']);
4113
            $lastForumAccess = $row['access_date'];
4114
        }
4115
    }
4116
4117
    $whatsNew = Session::read('whatsnew_post_info');
4118
4119
    if (!$whatsNew) {
4120
        if ('' != $lastForumAccess) {
4121
            $postInfo = [];
4122
            $sql = "SELECT * FROM $table_posts
4123
                    WHERE
4124
                        c_id = $course_id AND
4125
                        visible = 1 AND
4126
                        post_date > '".Database::escape_string($lastForumAccess)."'";
4127
            $result = Database::query($sql);
4128
            while ($row = Database::fetch_array($result)) {
4129
                $postInfo[$row['forum_id']][$row['thread_id']][$row['post_id']] = $row['post_date'];
4130
            }
4131
            Session::write('whatsnew_post_info', $postInfo);
4132
        }
4133
    }
4134
}
4135
4136
/**
4137
 * This function approves a post = change.
4138
 *
4139
 * @param int    $post_id the id of the post that will be deleted
4140
 * @param string $action  make the post visible or invisible
4141
 *
4142
 * @return string language variable
4143
 *
4144
 * @author Patrick Cool <[email protected]>, Ghent University
4145
 *
4146
 * @version february 2006, dokeos 1.8
4147
 */
4148
function approve_post($post_id, $action)
4149
{
4150
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4151
    $course_id = api_get_course_int_id();
4152
4153
    if ('invisible' == $action) {
4154
        $visibility_value = 0;
4155
    }
4156
4157
    if ('visible' == $action) {
4158
        $visibility_value = 1;
4159
        handle_mail_cue('post', $post_id);
4160
    }
4161
4162
    $sql = "UPDATE $table_posts SET
4163
            visible='".Database::escape_string($visibility_value)."'
4164
            WHERE c_id = $course_id AND post_id='".Database::escape_string($post_id)."'";
4165
    $return = Database::query($sql);
4166
4167
    if ($return) {
4168
        return 'PostThe visibility has been changed.';
4169
    }
4170
}
4171
4172
/**
4173
 * This function retrieves all the unapproved messages for a given forum
4174
 * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see
4175
 * this).
4176
 *
4177
 * @param the $forum_id forum where we want to know the unapproved messages of
4178
 *
4179
 * @return array returns
4180
 *
4181
 * @author Patrick Cool <[email protected]>, Ghent University
4182
 *
4183
 * @version february 2006, dokeos 1.8
4184
 */
4185
function get_unaproved_messages($forum_id)
4186
{
4187
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4188
    $course_id = api_get_course_int_id();
4189
4190
    $return_array = [];
4191
    $sql = "SELECT DISTINCT thread_id FROM $table_posts
4192
            WHERE
4193
                c_id = $course_id AND
4194
                forum_id='".Database::escape_string($forum_id)."' AND
4195
                visible='0' ";
4196
    $result = Database::query($sql);
4197
    while ($row = Database::fetch_array($result)) {
4198
        $return_array[] = $row['thread_id'];
4199
    }
4200
4201
    return $return_array;
4202
}
4203
4204
/**
4205
 * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
4206
 * was added to a given thread.
4207
 *
4208
 * @param array $forum reply information
4209
 */
4210
function send_notification_mails(CForumForum $forum, CForumThread $thread, $reply_info)
4211
{
4212
    $courseEntity = api_get_course_entity($forum->getCId());
4213
    $courseId = $courseEntity->getId();
4214
4215
    $sessionId = api_get_session_id();
4216
    $sessionEntity = api_get_session_entity($sessionId);
4217
4218
    $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4219
4220
    // First we need to check if
4221
    // 1. the forum category is visible
4222
    // 2. the forum is visible
4223
    // 3. the thread is visible
4224
    // 4. the reply is visible (=when there is)
4225
4226
    $current_forum_category = null;
4227
    if ($forum->getForumCategory()) {
4228
        $current_forum_category = $forum->getForumCategory();
4229
    }
4230
4231
    $send_mails = false;
4232
    if ($thread->isVisible($courseEntity, $sessionEntity) &&
4233
        $forum->isVisible($courseEntity, $sessionEntity) &&
4234
        ($current_forum_category && $forum->getForumCategory()->isVisible($courseEntity, $sessionEntity)) &&
4235
        '1' != $forum->getApprovalDirectPost()
4236
    ) {
4237
        $send_mails = true;
4238
    }
4239
4240
    // The forum category, the forum, the thread and the reply are visible to the user
4241
    if ($send_mails && !empty($forum)) {
4242
        $postId = isset($reply_info['new_post_id']) ? $reply_info['new_post_id'] : 0;
4243
        send_notifications($forum, $thread, $postId);
4244
    } else {
4245
        $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4246
        if ($forum) {
4247
            $sql = "SELECT * FROM $table_notification
4248
                    WHERE
4249
                        c_id = ".$courseId." AND
4250
                        (
4251
                            forum_id = '".$forum->getIid()."' OR
4252
                            thread_id = '".$thread->getIid()."'
4253
                        ) ";
4254
            $result = Database::query($sql);
4255
            $user_id = api_get_user_id();
4256
            while ($row = Database::fetch_array($result)) {
4257
                $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
4258
                        VALUES (".$courseId.", '".$thread->getIid()."', '".(int) ($reply_info['new_post_id'])."', '$user_id' )";
4259
                Database::query($sql);
4260
            }
4261
        }
4262
    }
4263
}
4264
4265
/**
4266
 * This function is called whenever something is made visible because there might
4267
 * be new posts and the user might have indicated that (s)he wanted to be
4268
 * informed about the new posts by mail.
4269
 *
4270
 * @param string $content Content type (post, thread, forum, forum_category)
4271
 * @param int    $id      Item DB ID of the corresponding content type
4272
 *
4273
 * @return string language variable
4274
 *
4275
 * @author Patrick Cool <[email protected]>, Ghent University
4276
 *
4277
 * @version february 2006, dokeos 1.8
4278
 */
4279
function handle_mail_cue($content, $id)
4280
{
4281
    $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4282
    $table_forums = Database::get_course_table(TABLE_FORUM);
4283
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4284
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4285
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4286
4287
    $course_id = api_get_course_int_id();
4288
    $id = (int) $id;
4289
4290
    /* If the post is made visible we only have to send mails to the people
4291
     who indicated that they wanted to be informed for that thread.*/
4292
    if ('post' == $content) {
4293
        // Getting the information about the post (need the thread_id).
4294
        $post_info = get_post_information($id);
4295
        $thread_id = (int) $post_info['thread_id'];
4296
4297
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4298
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email
4299
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4300
                WHERE
4301
                    posts.c_id = $course_id AND
4302
                    mailcue.c_id = $course_id AND
4303
                    posts.thread_id = $thread_id AND
4304
                    posts.post_notification = '1' AND
4305
                    mailcue.thread_id = $thread_id AND
4306
                    users.user_id = posts.poster_id AND
4307
                    users.active = 1
4308
                GROUP BY users.email";
4309
4310
        $result = Database::query($sql);
4311
        while ($row = Database::fetch_array($result)) {
4312
            $forumInfo = get_forum_information($post_info['forum_id']);
4313
            send_mail($row, $forumInfo, get_thread_information($post_info['forum_id'], $post_info['thread_id']), $post_info);
4314
        }
4315
    } elseif ('thread' == $content) {
4316
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4317
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
4318
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4319
                WHERE
4320
                    posts.c_id = $course_id AND
4321
                    mailcue.c_id = $course_id AND
4322
                    posts.thread_id = $id AND
4323
                    posts.post_notification = '1' AND
4324
                    mailcue.thread_id = $id AND
4325
                    users.user_id = posts.poster_id AND
4326
                    users.active = 1
4327
                GROUP BY users.email";
4328
        $result = Database::query($sql);
4329
        while ($row = Database::fetch_array($result)) {
4330
            $forumInfo = get_forum_information($row['forum_id']);
4331
            send_mail($row, $forumInfo, get_thread_information($row['forum_id'], $id));
4332
        }
4333
4334
        // Deleting the relevant entries from the mailcue.
4335
        $sql = "DELETE FROM $table_mailcue
4336
                WHERE c_id = $course_id AND thread_id = $id";
4337
        Database::query($sql);
4338
    } elseif ('forum' == $content) {
4339
        $sql = "SELECT thread_id FROM $table_threads
4340
                WHERE c_id = $course_id AND forum_id = $id";
4341
        $result = Database::query($sql);
4342
        while ($row = Database::fetch_array($result)) {
4343
            handle_mail_cue('thread', $row['thread_id']);
4344
        }
4345
    } elseif ('forum_category' == $content) {
4346
        $sql = "SELECT forum_id FROM $table_forums
4347
                WHERE c_id = $course_id AND forum_category = $id";
4348
        $result = Database::query($sql);
4349
        while ($row = Database::fetch_array($result)) {
4350
            handle_mail_cue('forum', $row['forum_id']);
4351
        }
4352
    } else {
4353
        return get_lang('Error');
4354
    }
4355
}
4356
4357
/**
4358
 * This function sends the mails for the mail notification.
4359
 */
4360
function send_mail($userInfo, CForumForum $forum, CForumThread $thread, CForumPost $postInfo = null)
4361
{
4362
    if (empty($userInfo) || empty($forum) || empty($thread)) {
4363
        return false;
4364
    }
4365
4366
    $_course = api_get_course_info();
4367
    $user_id = api_get_user_id();
4368
    $forumId = $forum->getIid();
4369
    $threadId = $thread->getIid();
4370
4371
    $thread_link = api_get_path(WEB_CODE_PATH).
4372
        'forum/viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId;
4373
4374
    $email_body = get_lang('Dear').' '.api_get_person_name($userInfo['firstname'], $userInfo['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
4375
    $email_body .= get_lang('New Post in the forum').': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4376
4377
    $courseId = api_get_configuration_value('global_forums_course_id');
4378
    $subject = get_lang('New Post in the forum').' - '.$_course['official_code'].': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4379
4380
    $courseInfoTitle = get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
4381
    if (!empty($courseId) && $_course['real_id'] == $courseId) {
4382
        $subject = get_lang('New Post in the forum').': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4383
        $courseInfoTitle = " <br />\n";
4384
    }
4385
    $email_body .= $courseInfoTitle;
4386
4387
    if (!empty($postInfo)) {
4388
        $text = cut(strip_tags($postInfo->getPostText()), 100);
4389
        if (!empty($text)) {
4390
            $email_body .= get_lang('Message').": <br />\n ";
4391
            $email_body .= $text;
4392
            $email_body .= "<br /><br />\n";
4393
        }
4394
    }
4395
4396
    $email_body .= get_lang('You stated that you wanted to be informed by e-mail whenever somebody replies on the thread')."<br />\n";
4397
4398
    if (!empty($thread_link)) {
4399
        $email_body .= get_lang('The thread can be found here').' : <br /><a href="'.$thread_link.'">'.$thread_link."</a>\n";
4400
    }
4401
4402
    if ($userInfo['user_id'] != $user_id) {
4403
        MessageManager::send_message(
4404
            $userInfo['user_id'],
4405
            $subject,
4406
            $email_body,
4407
            [],
4408
            [],
4409
            null,
4410
            null,
4411
            null,
4412
            null,
4413
            $user_id
4414
        );
4415
    }
4416
}
4417
4418
/**
4419
 * This function displays the form for moving a thread to a different (already existing) forum.
4420
 *
4421
 * @author Patrick Cool <[email protected]>, Ghent University
4422
 *
4423
 * @version february 2006, dokeos 1.8
4424
 */
4425
function move_thread_form()
4426
{
4427
    $form = new FormValidator(
4428
        'movepost',
4429
        'post',
4430
        api_get_self().'?forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
4431
    );
4432
    $form->addHeader(get_lang('Move Thread'));
4433
    // Invisible form: the thread_id
4434
    $form->addHidden('thread_id', (int) ($_GET['thread']));
4435
    $forum_categories = get_forum_categories();
4436
4437
    $htmlcontent = '<div class="row">
4438
        <div class="label">
4439
            <span class="form_required">*</span>'.get_lang('Move to').'
4440
        </div>
4441
        <div class="formw">';
4442
    $htmlcontent .= '<select name="forum">';
4443
    foreach ($forum_categories as $category) {
4444
        $htmlcontent .= '<optgroup label="'.$category->getCatTitle().'">';
4445
        $forums = $category->getForums();
4446
        foreach ($forums as $forum) {
4447
            $htmlcontent .= '<option value="'.$forum->getIid().'">'.$forum->getForumTitle().'</option>';
4448
        }
4449
        $htmlcontent .= '</optgroup>';
4450
    }
4451
    $htmlcontent .= '</select>';
4452
    $htmlcontent .= '   </div>
4453
                    </div>';
4454
4455
    $form->addElement('html', $htmlcontent);
4456
4457
    // The OK button
4458
    $form->addButtonSave(get_lang('Move Thread'), 'SubmitForum');
4459
4460
    // Validation or display
4461
    if ($form->validate()) {
4462
        $values = $form->exportValues();
4463
        if (isset($_POST['forum'])) {
4464
            store_move_thread($values);
4465
            Display::addFlash(Display::return_message(get_lang('Moved')));
4466
        }
4467
    } else {
4468
        return $form->returnForm();
4469
    }
4470
}
4471
4472
/**
4473
 * This function displays the form for moving a post message to a different (already existing) or a new thread.
4474
 *
4475
 * @author Patrick Cool <[email protected]>, Ghent University
4476
 *
4477
 * @version february 2006, dokeos 1.8
4478
 */
4479
function move_post_form()
4480
{
4481
    $form = new FormValidator(
4482
        'movepost',
4483
        'post',
4484
        api_get_self().'?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&post='.Security::remove_XSS($_GET['post']).'&action='.Security::remove_XSS($_GET['action']).'&post='.Security::remove_XSS($_GET['post'])
4485
    );
4486
    // The header for the form
4487
    $form->addElement('header', '', get_lang('Move post'));
4488
4489
    // Invisible form: the post_id
4490
    $form->addElement('hidden', 'post_id', (int) ($_GET['post']));
4491
4492
    // Dropdown list: Threads of this forum
4493
    $threads = get_threads($_GET['forum']);
4494
    $threads_list[0] = get_lang('A new thread');
4495
    foreach ($threads as $thread) {
4496
        $threads_list[$thread->getIid()] = $thread->getThreadTitle();
4497
    }
4498
    $form->addElement('select', 'thread', get_lang('Move toThread'), $threads_list);
4499
    $form->applyFilter('thread', 'html_filter');
4500
4501
    // The OK button
4502
    $form->addButtonSave(get_lang('Move post'), 'submit');
4503
4504
    // Setting the rules
4505
    $form->addRule('thread', get_lang('Required field'), 'required');
4506
4507
4508
    return $form;
4509
}
4510
4511
/**
4512
 * @param array $values
4513
 *
4514
 * @return string HTML language variable
4515
 *
4516
 * @author Patrick Cool <[email protected]>, Ghent University
4517
 *
4518
 * @version february 2006, dokeos 1.8
4519
 */
4520
function store_move_post($values)
4521
{
4522
    $_course = api_get_course_info();
4523
    $course_id = api_get_course_int_id();
4524
4525
    $table_forums = Database::get_course_table(TABLE_FORUM);
4526
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4527
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4528
4529
    $user = api_get_user_entity(api_get_user_id());
4530
    $course = api_get_course_entity($course_id);
4531
    $session = api_get_session_entity();
4532
4533
    if ('0' == $values['thread']) {
4534
        $repoPost = Container::getForumPostRepository();
4535
        $repoThread = Container::getForumThreadRepository();
4536
        $repoForum = Container::getForumRepository();
4537
4538
        $em = $repoPost->getEntityManager();
4539
4540
        /** @var CForumPost $post */
4541
        $post = $repoPost->find($values['post_id']);
4542
        $forumId = $post->getForum()->getIid();
4543
        $threadId = $post->getThread()->getIid();
4544
4545
        $thread = new CForumThread();
4546
        $thread
4547
            ->setCId($course_id)
4548
            ->setThreadTitle($post->getPostTitle())
4549
            ->setForum($post->getForum())
4550
            ->setThreadPosterId($post->getPosterId())
4551
            ->setThreadPosterName($post->getPosterName())
4552
            ->setThreadLastPost($post->getIid())
4553
            ->setThreadDate($post->getPostDate())
4554
        ;
4555
4556
        $repo = Container::getForumThreadRepository();
4557
        $em = $repo->getEntityManager();
4558
        $repo->addResourceToCourseWithParent(
4559
            $thread,
4560
            $post->getForum()->getResourceNode(),
4561
            ResourceLink::VISIBILITY_PUBLISHED,
4562
            $user,
4563
            $course,
4564
            $session,
4565
            null
4566
        );
4567
        $em->flush();
4568
4569
        $new_thread_id = $thread->getIid();
4570
4571
4572
        // Storing a new thread.
4573
        /*$params = [
4574
            'c_id' => $course_id,
4575
            'thread_title' => $current_post['post_title'],
4576
            'forum_id' => $current_post['forum_id'],
4577
            'thread_poster_id' => $current_post['poster_id'],
4578
            'thread_poster_name' => $current_post['poster_name'],
4579
            'thread_last_post' => $values['post_id'],
4580
            'thread_date' => $current_post['post_date'],
4581
        ];
4582
4583
        $new_thread_id = Database::insert($table_threads, $params);
4584
4585
        api_item_property_update(
4586
            $_course,
4587
            TOOL_FORUM_THREAD,
4588
            $new_thread_id,
4589
            'visible',
4590
            $current_post['poster_id']
4591
        );*/;
4592
4593
        // Moving the post to the newly created thread.
4594
        $sql = "UPDATE $table_posts SET thread_id='".(int) $new_thread_id."', post_parent_id = NULL
4595
                WHERE c_id = $course_id AND post_id='".(int) ($values['post_id'])."'";
4596
        Database::query($sql);
4597
4598
        // Resetting the parent_id of the thread to 0 for all those who had this moved post as parent.
4599
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4600
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
4601
        Database::query($sql);
4602
4603
        // Updating updating the number of threads in the forum.
4604
        $sql = "UPDATE $table_forums SET forum_threads=forum_threads+1
4605
                WHERE c_id = $course_id AND forum_id='".$forumId."'";
4606
        Database::query($sql);
4607
4608
        // Resetting the last post of the old thread and decreasing the number of replies and the thread.
4609
        $sql = "SELECT * FROM $table_posts
4610
                WHERE c_id = $course_id AND thread_id='".$threadId."'
4611
                ORDER BY post_id DESC";
4612
        $result = Database::query($sql);
4613
        $row = Database::fetch_array($result);
4614
        $sql = "UPDATE $table_threads SET
4615
                    thread_last_post='".$row['post_id']."',
4616
                    thread_replies=thread_replies-1
4617
                WHERE
4618
                    c_id = $course_id AND
4619
                    thread_id='".$threadId."'";
4620
        Database::query($sql);
4621
    } else {
4622
        // Moving to the chosen thread.
4623
        $sql = 'SELECT thread_id FROM '.$table_posts."
4624
                WHERE c_id = $course_id AND post_id = '".$values['post_id']."' ";
4625
        $result = Database::query($sql);
4626
        $row = Database::fetch_array($result);
4627
4628
        $original_thread_id = $row['thread_id'];
4629
4630
        $sql = 'SELECT thread_last_post FROM '.$table_threads."
4631
                WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
4632
4633
        $result = Database::query($sql);
4634
        $row = Database::fetch_array($result);
4635
        $thread_is_last_post = $row['thread_last_post'];
4636
        // If is this thread, update the thread_last_post with the last one.
4637
4638
        if ($thread_is_last_post == $values['post_id']) {
4639
            $sql = 'SELECT post_id FROM '.$table_posts."
4640
                    WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' AND post_id <> '".$values['post_id']."'
4641
                    ORDER BY post_date DESC LIMIT 1";
4642
            $result = Database::query($sql);
4643
4644
            $row = Database::fetch_array($result);
4645
            $thread_new_last_post = $row['post_id'];
4646
4647
            $sql = 'UPDATE '.$table_threads." SET thread_last_post = '".$thread_new_last_post."'
4648
                    WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
4649
            Database::query($sql);
4650
        }
4651
4652
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies-1
4653
                WHERE c_id = $course_id AND thread_id='".$original_thread_id."'";
4654
        Database::query($sql);
4655
4656
        // moving to the chosen thread
4657
        $sql = "UPDATE $table_posts SET thread_id='".(int) ($_POST['thread'])."', post_parent_id = NULL
4658
                WHERE c_id = $course_id AND post_id='".(int) ($values['post_id'])."'";
4659
        Database::query($sql);
4660
4661
        // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
4662
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4663
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
4664
        Database::query($sql);
4665
4666
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies+1
4667
                WHERE c_id = $course_id AND thread_id='".(int) ($_POST['thread'])."'";
4668
        Database::query($sql);
4669
    }
4670
4671
    return get_lang('Thread moved');
4672
}
4673
4674
/**
4675
 * @param array $values
4676
 *
4677
 * @return string HTML language variable
4678
 *
4679
 * @author Patrick Cool <[email protected]>, Ghent University
4680
 *
4681
 * @version february 2006, dokeos 1.8
4682
 */
4683
function store_move_thread($values)
4684
{
4685
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4686
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4687
4688
    $courseId = api_get_course_int_id();
4689
    $sessionId = api_get_session_id();
4690
4691
    $forumId = (int) ($_POST['forum']);
4692
    $threadId = (int) ($_POST['thread_id']);
4693
    //$forumInfo = get_forums($forumId);
4694
4695
    // Change the thread table: Setting the forum_id to the new forum.
4696
    $sql = "UPDATE $table_threads SET forum_id = $forumId
4697
            WHERE c_id = $courseId AND thread_id = $threadId";
4698
    Database::query($sql);
4699
4700
    // Changing all the posts of the thread: setting the forum_id to the new forum.
4701
    $sql = "UPDATE $table_posts SET forum_id = $forumId
4702
            WHERE c_id = $courseId AND thread_id= $threadId";
4703
    Database::query($sql);
4704
4705
    // Fix group id, if forum is moved to a different group
4706
    if (!empty($forumInfo['to_group_id'])) {
4707
        /*$groupId = $forumInfo['to_group_id'];
4708
        $item = api_get_item_property_info(
4709
            $courseId,
4710
            TABLE_FORUM_THREAD,
4711
            $threadId,
4712
            $sessionId,
4713
            $groupId
4714
        );
4715
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4716
        $sessionCondition = api_get_session_condition($sessionId);
4717
4718
        if (!empty($item)) {
4719
            if ($item['to_group_id'] != $groupId) {
4720
                $sql = "UPDATE $table
4721
                    SET to_group_id = $groupId
4722
                    WHERE
4723
                      tool = '".TABLE_FORUM_THREAD."' AND
4724
                      c_id = $courseId AND
4725
                      ref = ".$item['ref']."
4726
                      $sessionCondition
4727
                ";
4728
                Database::query($sql);
4729
            }
4730
        } else {
4731
            $sql = "UPDATE $table
4732
                    SET to_group_id = $groupId
4733
                    WHERE
4734
                      tool = '".TABLE_FORUM_THREAD."' AND
4735
                      c_id = $courseId AND
4736
                      ref = ".$threadId."
4737
                      $sessionCondition
4738
            ";
4739
            Database::query($sql);
4740
        }*/
4741
    }
4742
4743
    return get_lang('Thread moved');
4744
}
4745
4746
/**
4747
 * Prepares a string for displaying by highlighting the search results inside, if any.
4748
 *
4749
 * @param string $input the input string
4750
 *
4751
 * @return string the same string with highlighted hits inside
4752
 *
4753
 * @author Patrick Cool <[email protected]>, Ghent University, February 2006 - the initial version.
4754
 * @author Ivan Tcholakov, March 2011 - adaptation for Chamilo LMS.
4755
 */
4756
function prepare4display($input)
4757
{
4758
    static $highlightcolors = ['yellow', '#33CC33', '#3399CC', '#9999FF', '#33CC33'];
4759
    static $search;
4760
4761
    if (!isset($search)) {
4762
        if (isset($_POST['search_term'])) {
4763
            $search = $_POST['search_term']; // No html at all.
4764
        } elseif (isset($_GET['search'])) {
4765
            $search = $_GET['search'];
4766
        } else {
4767
            $search = '';
4768
        }
4769
    }
4770
4771
    if (!empty($search)) {
4772
        if (strstr($search, '+')) {
4773
            $search_terms = explode('+', $search);
4774
        } else {
4775
            $search_terms[] = trim($search);
4776
        }
4777
        $counter = 0;
4778
        foreach ($search_terms as $key => $search_term) {
4779
            $input = api_preg_replace(
4780
                '/'.preg_quote(trim($search_term), '/').'/i',
4781
                '<span style="background-color: '.$highlightcolors[$counter].'">$0</span>',
4782
                $input
4783
            );
4784
            $counter++;
4785
        }
4786
    }
4787
4788
    // TODO: Security should be implemented outside this function.
4789
    // Change this to COURSEMANAGERLOWSECURITY or COURSEMANAGER to lower filtering and allow more styles
4790
    // (see comments of Security::remove_XSS() method to learn about other levels).
4791
4792
    return Security::remove_XSS($input, STUDENT, true);
4793
}
4794
4795
/**
4796
 * Display the search form for the forum and display the search results.
4797
 *
4798
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4799
 *
4800
 * @version march 2008, dokeos 1.8.5
4801
 */
4802
function forum_search()
4803
{
4804
    $form = new FormValidator(
4805
        'forumsearch',
4806
        'post',
4807
        'forumsearch.php?'.api_get_cidreq()
4808
    );
4809
4810
    // Setting the form elements.
4811
    $form->addElement('header', '', get_lang('Search in the Forum'));
4812
    $form->addElement('text', 'search_term', get_lang('Search term'), ['autofocus']);
4813
    $form->applyFilter('search_term', 'html_filter');
4814
    $form->addElement('static', 'search_information', '', get_lang('Search in the ForumInformation'));
4815
    $form->addButtonSearch(get_lang('Search'));
4816
4817
    // Setting the rules.
4818
    $form->addRule('search_term', get_lang('Required field'), 'required');
4819
    $form->addRule('search_term', get_lang('Too short'), 'minlength', 3);
4820
4821
    // Validation or display.
4822
    if ($form->validate()) {
4823
        $values = $form->exportValues();
4824
        $form->setDefaults($values);
4825
        $form->display();
4826
        // Display the search results.
4827
        display_forum_search_results(stripslashes($values['search_term']));
4828
    } else {
4829
        $form->display();
4830
    }
4831
}
4832
4833
/**
4834
 * Display the search results.
4835
 *
4836
 * @param string $search_term
4837
 *
4838
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4839
 *
4840
 * @version march 2008, dokeos 1.8.5
4841
 */
4842
function display_forum_search_results($search_term)
4843
{
4844
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4845
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4846
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
4847
    $session_id = api_get_session_id();
4848
    $course_id = api_get_course_int_id();
4849
4850
    // Defining the search strings as an array.
4851
    if (strstr($search_term, '+')) {
4852
        $search_terms = explode('+', $search_term);
4853
    } else {
4854
        $search_terms[] = $search_term;
4855
    }
4856
4857
    // Search restriction.
4858
    foreach ($search_terms as $value) {
4859
        $search_restriction[] = "
4860
        (
4861
            posts.post_title LIKE '%".Database::escape_string(trim($value))."%' OR
4862
            posts.post_text LIKE '%".Database::escape_string(trim($value))."%'
4863
        )";
4864
    }
4865
4866
    $sessionCondition = api_get_session_condition(
4867
        $session_id,
4868
        true,
4869
        false,
4870
        'item_property.session_id'
4871
    );
4872
4873
    $sql = "SELECT posts.*
4874
            FROM $table_posts posts
4875
            INNER JOIN $table_threads threads
4876
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
4877
            INNER JOIN $table_item_property item_property
4878
            ON (item_property.ref = threads.thread_id AND item_property.c_id = threads.c_id)
4879
            WHERE
4880
                posts.c_id = $course_id AND
4881
                item_property.c_id = $course_id AND
4882
                item_property.visibility = 1
4883
                $sessionCondition AND
4884
                posts.visible = 1 AND
4885
                item_property.tool = '".TOOL_FORUM_THREAD."' AND
4886
                ".implode(' AND ', $search_restriction).'
4887
            GROUP BY posts.post_id';
4888
4889
    // Getting all the information of the forum categories.
4890
    $forum_categories_list = get_forum_categories();
4891
4892
    // Getting all the information of the forums.
4893
    $forum_list = get_forums();
4894
4895
    $result = Database::query($sql);
4896
    $search_results = [];
4897
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4898
        $forumId = $row['forum_id'];
4899
        $forumData = get_forums($forumId);
4900
        $category = isset($forum_categories_list[$forumData['forum_category']]) ? $forum_categories_list[$forumData['forum_category']] : null;
4901
        $display_result = false;
4902
        /*
4903
          We only show it when
4904
          1. forum category is visible
4905
          2. forum is visible
4906
          3. thread is visible (to do)
4907
          4. post is visible
4908
         */
4909
        if (!api_is_allowed_to_edit(null, true)) {
4910
            if (!empty($category)) {
4911
                if ('1' == $category['visibility'] && '1' == $forumData['visibility']) {
4912
                    $display_result = true;
4913
                }
4914
            } else {
4915
                if ('1' == $forumData['visible']) {
4916
                    $display_result = true;
4917
                }
4918
            }
4919
        } else {
4920
            $display_result = true;
4921
        }
4922
4923
        if ($display_result) {
4924
            $categoryName = !empty($category) ? $category['cat_title'] : '';
4925
            $search_results_item = '<li><a href="viewforumcategory.php?'.api_get_cidreq().'&forumcategory='.$forumData['forum_category'].'&search='.urlencode($search_term).'">'.
4926
                prepare4display($categoryName).'</a> &gt; ';
4927
            $search_results_item .= '<a href="viewforum.php?'.api_get_cidreq().'&forum='.$forumId.'&search='.urlencode($search_term).'">'.
4928
                prepare4display($forum_list[$row['forum_id']]['forum_title']).'</a> &gt; ';
4929
            $search_results_item .= '<a href="viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$row['thread_id'].'&search='.urlencode($search_term).'">'.
4930
                prepare4display($row['post_title']).'</a>';
4931
            $search_results_item .= '<br />';
4932
            if (api_strlen($row['post_title']) > 200) {
4933
                $search_results_item .= prepare4display(api_substr(strip_tags($row['post_title']), 0, 200)).'...';
4934
            } else {
4935
                $search_results_item .= prepare4display($row['post_title']);
4936
            }
4937
            $search_results_item .= '</li>';
4938
            $search_results[] = $search_results_item;
4939
        }
4940
    }
4941
    echo '<legend>'.count($search_results).' '.get_lang('Search in the ForumResults').'</legend>';
4942
    echo '<ol>';
4943
    if ($search_results) {
4944
        echo implode($search_results);
4945
    }
4946
    echo '</ol>';
4947
}
4948
4949
/**
4950
 * Return the link to the forum search page.
4951
 *
4952
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4953
 *
4954
 * @version April 2008, dokeos 1.8.5
4955
 */
4956
function search_link()
4957
{
4958
    // @todo implement search
4959
4960
    return '';
4961
4962
    $return = '';
0 ignored issues
show
Unused Code introduced by
$return = '' is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
4963
    $origin = api_get_origin();
4964
    if ('learnpath' != $origin) {
4965
        $return = '<a href="forumsearch.php?'.api_get_cidreq().'&action=search"> ';
4966
        $return .= Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
4967
4968
        if (!empty($_GET['search'])) {
4969
            $return .= ': '.Security::remove_XSS($_GET['search']).' ';
4970
            $url = api_get_self().'?';
4971
            $url_parameter = [];
4972
            foreach ($_GET as $key => $value) {
4973
                if ('search' != $key) {
4974
                    $url_parameter[] = Security::remove_XSS($key).'='.Security::remove_XSS($value);
4975
                }
4976
            }
4977
            $url .= implode('&', $url_parameter);
4978
            $return .= '<a href="'.$url.'">'.Display::return_icon('delete.gif', get_lang('Clean search results')).'</a>';
4979
        }
4980
    }
4981
4982
    return $return;
4983
}
4984
4985
/**
4986
 * This function adds an attachment file into a forum.
4987
 *
4988
 * @param string $file_comment a comment about file
4989
 * @param CForumPost    $post      from forum_post table
4990
 *
4991
 * @return false|null
4992
 */
4993
function add_forum_attachment_file($file_comment, CForumPost $post)
4994
{
4995
    $request = Container::getRequest();
4996
    if (false === $request->files->has('user_upload')) {
4997
        return false;
4998
    }
4999
5000
    $file = $request->files->get('user_upload');
5001
    if (empty($file)) {
5002
        return false;
5003
    }
5004
5005
    $files = [];
5006
    if ($file instanceof UploadedFile) {
5007
        $files[] = $file;
5008
    } else {
5009
        $files = $file;
5010
    }
5011
5012
    /** @var UploadedFile $attachment */
5013
    foreach ($files as $file) {
5014
        $valid = process_uploaded_file($file);
5015
5016
        if (!$valid) {
5017
            continue;
5018
        }
5019
5020
        // Try to add an extension to the file if it hasn't one.
5021
        $new_file_name = add_ext_on_mime(
5022
            stripslashes($file->getPathname()),
5023
            $file->getType()
5024
        );
5025
5026
        // User's file name
5027
        $file_name = $file->getClientOriginalName();
5028
5029
        if (!filter_extension($new_file_name)) {
5030
            Display::addFlash(
5031
                Display::return_message(
5032
                    get_lang('File upload failed: this file extension or file type is prohibited'),
5033
                    'error'
5034
                )
5035
            );
5036
5037
            return;
5038
        }
5039
5040
        $new_file_name = uniqid('');
5041
        $safe_file_comment = Database::escape_string($file_comment);
5042
        $attachment = new CForumAttachment();
5043
        $attachment
5044
            ->setCId(api_get_course_int_id())
5045
            ->setComment($safe_file_comment)
5046
            ->setFilename($file_name)
5047
            ->setPath($file_name)
5048
            ->setPost($post)
5049
            ->setSize($file->getSize())
5050
        ;
5051
5052
        $user = api_get_user_entity(api_get_user_id());
5053
        $course = api_get_course_entity(api_get_course_int_id());
5054
        $session = api_get_session_entity(api_get_session_id());
5055
5056
        $repo = Container::getForumAttachmentRepository();
5057
        $em = $repo->getEntityManager();
5058
        $repo->addResourceToCourseWithParent(
5059
            $attachment,
5060
            $post->getResourceNode(),
5061
            ResourceLink::VISIBILITY_PUBLISHED,
5062
            $user,
5063
            $course,
5064
            $session,
5065
            null,
5066
            $file
5067
        );
5068
        $em->flush();
5069
5070
        /*$last_id_file = Database::insert(
5071
            $agenda_forum_attachment,
5072
            [
5073
                'path' => $safe_new_file_name,
5074
            ]
5075
        );*/
5076
5077
        /*api_item_property_update(
5078
            $_course,
5079
            TOOL_FORUM_ATTACH,
5080
            $last_id_file,
5081
            'ForumAttachmentAdded',
5082
            api_get_user_id()
5083
        );*/
5084
    }
5085
}
5086
5087
/**
5088
 * This function edits an attachment file into a forum.
5089
 *
5090
 * @param string $file_comment a comment about file
5091
 * @param int    $post_id
5092
 * @param int    $id_attach    attachment file Id
5093
 */
5094
function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
5095
{
5096
    $_course = api_get_course_info();
5097
    $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5098
    $course_id = api_get_course_int_id();
5099
5100
    $filesData = [];
5101
5102
    if (!is_array($_FILES['user_upload']['name'])) {
5103
        $filesData[] = $_FILES['user_upload'];
5104
    } else {
5105
        $fileCount = count($_FILES['user_upload']['name']);
5106
        $fileKeys = array_keys($_FILES['user_upload']);
5107
5108
        for ($i = 0; $i < $fileCount; $i++) {
5109
            foreach ($fileKeys as $key) {
5110
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
5111
            }
5112
        }
5113
    }
5114
5115
    foreach ($filesData as $attachment) {
5116
        if (empty($attachment['name'])) {
5117
            continue;
5118
        }
5119
5120
        $upload_ok = process_uploaded_file($attachment);
5121
5122
        if (!$upload_ok) {
5123
            continue;
5124
        }
5125
5126
        $course_dir = $_course['path'].'/upload/forum';
5127
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
5128
        $updir = $sys_course_path.$course_dir;
5129
5130
        // Try to add an extension to the file if it hasn't one.
5131
        $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
5132
        // User's file name
5133
        $file_name = $attachment['name'];
5134
5135
        if (!filter_extension($new_file_name)) {
5136
            Display::addFlash(
5137
                Display::return_message(
5138
                    get_lang('File upload failed: this file extension or file type is prohibited'),
5139
                    'error'
5140
                )
5141
            );
5142
        } else {
5143
            $new_file_name = uniqid('');
5144
            $new_path = $updir.'/'.$new_file_name;
5145
            $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5146
            $safe_file_comment = Database::escape_string($file_comment);
5147
            $safe_file_name = Database::escape_string($file_name);
5148
            $safe_new_file_name = Database::escape_string($new_file_name);
5149
            $safe_post_id = (int) $post_id;
5150
            $safe_id_attach = (int) $id_attach;
5151
            // Storing the attachments if any.
5152
            if ($result) {
5153
                $sql = "UPDATE $table_forum_attachment
5154
                        SET
5155
                            filename = '$safe_file_name',
5156
                            comment = '$safe_file_comment',
5157
                            path = '$safe_new_file_name',
5158
                            post_id = '$safe_post_id',
5159
                            size ='".$attachment['size']."'
5160
                        WHERE c_id = $course_id AND id = '$safe_id_attach'";
5161
                Database::query($sql);
5162
                api_item_property_update(
5163
                    $_course,
5164
                    TOOL_FORUM_ATTACH,
5165
                    $safe_id_attach,
5166
                    'ForumAttachmentUpdated',
5167
                    api_get_user_id()
5168
                );
5169
            }
5170
        }
5171
    }
5172
}
5173
5174
/**
5175
 * Show a list with all the attachments according to the post's id.
5176
 *
5177
 * @param int $postId
5178
 *
5179
 * @return array with the post info
5180
 *
5181
 * @author Julio Montoya
5182
 *
5183
 * @version avril 2008, dokeos 1.8.5
5184
 */
5185
function get_attachment($postId)
5186
{
5187
    $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5188
    $course_id = api_get_course_int_id();
5189
    $row = [];
5190
    $postId = (int) $postId;
5191
5192
    if (empty($postId)) {
5193
        return [];
5194
    }
5195
5196
    $sql = "SELECT iid, path, filename, comment
5197
            FROM $table
5198
            WHERE c_id = $course_id AND post_id = $postId";
5199
    $result = Database::query($sql);
5200
    if (0 != Database::num_rows($result)) {
5201
        $row = Database::fetch_array($result);
5202
    }
5203
5204
    return $row;
5205
}
5206
5207
/**
5208
 * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
5209
 *
5210
 * @param int $postId
5211
 * @param int $attachmentId
5212
 *
5213
 * @return bool
5214
 */
5215
function delete_attachment($postId, $attachmentId)
5216
{
5217
    $repo = Container::getForumPostRepository();
5218
    /** @var CForumPost $post */
5219
    $post = $repo->find($postId);
5220
    if ($post) {
5221
        $repoAttachment = Container::getForumAttachmentRepository();
5222
        $attachment = $repoAttachment->find($attachmentId);
5223
        if ($attachment) {
5224
            $post->removeAttachment($attachment);
5225
            $repo->getEntityManager()->remove($attachment);
5226
        }
5227
        $repo->getEntityManager()->persist($post);
5228
        $repo->getEntityManager()->flush();
5229
5230
        Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
5231
    }
5232
5233
    return true;
5234
5235
    $forum_table_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
0 ignored issues
show
Unused Code introduced by
$forum_table_attachment ...TABLE_FORUM_ATTACHMENT) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5236
    $course_id = api_get_course_int_id();
5237
5238
    $cond = !empty($id_attach) ? ' iid = '.(int) $id_attach.'' : ' post_id = '.(int) $post_id.'';
5239
    $sql = "SELECT path FROM $forum_table_attachment WHERE c_id = $course_id AND $cond";
5240
    $res = Database::query($sql);
5241
    $row = Database::fetch_array($res);
5242
5243
    $course_dir = $_course['path'].'/upload/forum';
5244
    $sys_course_path = api_get_path(SYS_COURSE_PATH);
5245
    $updir = $sys_course_path.$course_dir;
5246
    $my_path = isset($row['path']) ? $row['path'] : null;
5247
    $file = $updir.'/'.$my_path;
5248
    if (Security::check_abs_path($file, $updir)) {
5249
        @unlink($file);
5250
    }
5251
5252
    // Delete from forum_attachment table.
5253
    $sql = "DELETE FROM $forum_table_attachment
5254
            WHERE c_id = $course_id AND $cond ";
5255
    $result = Database::query($sql);
5256
    if (false !== $result) {
5257
        $affectedRows = Database::affected_rows($result);
5258
    } else {
5259
        $affectedRows = 0;
5260
    }
5261
5262
    // Update item_property.
5263
    api_item_property_update(
5264
        $_course,
5265
        TOOL_FORUM_ATTACH,
5266
        $id_attach,
5267
        'ForumAttachmentDelete',
5268
        api_get_user_id()
5269
    );
5270
5271
    if (!empty($result) && !empty($id_attach)) {
5272
        Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
5273
    }
5274
5275
    return $affectedRows;
5276
}
5277
5278
/**
5279
 * This function gets all the forum information of the all the forum of the group.
5280
 *
5281
 * @param array $groupInfo the id of the group we need the fora of (see forum.forum_of_group)
5282
 *
5283
 * @return CForumForum[]
5284
 *
5285
 * @todo this is basically the same code as the get_forums function. Consider merging the two.
5286
 */
5287
function get_forums_of_group($groupInfo)
5288
{
5289
    $groupId = (int) $groupInfo['id'];
5290
5291
    $group = api_get_group_entity($groupId);
5292
    $course = api_get_course_entity();
5293
    $session = api_get_session_entity();
5294
5295
    $repo = Container::getForumRepository();
5296
5297
    $qb = $repo->getResourcesByCourse($course, $session, $group);
5298
5299
    return $qb->getQuery()->getResult();
5300
5301
    $table_forums = Database::get_course_table(TABLE_FORUM);
0 ignored issues
show
Unused Code introduced by
$table_forums = Database...urse_table(TABLE_FORUM) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5302
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
5303
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5304
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
5305
    $course_id = api_get_course_int_id();
5306
    $groupId = (int) $groupInfo['id'];
5307
5308
    // Student
5309
    // Select all the forum information of all forums (that are visible to students).
5310
    $sql = "SELECT * FROM $table_forums forum
5311
            INNER JOIN $table_item_property item_properties
5312
            ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5313
            WHERE
5314
                forum.forum_of_group = $groupId AND
5315
                forum.c_id = $course_id AND
5316
                item_properties.c_id = $course_id AND
5317
                item_properties.visibility = 1 AND
5318
                item_properties.tool = '".TOOL_FORUM."'
5319
            ORDER BY forum.forum_order ASC";
5320
5321
    // Select the number of threads of the forums (only the threads that are visible).
5322
    $sql2 = "SELECT
5323
                count(thread_id) AS number_of_threads,
5324
                threads.forum_id
5325
            FROM $table_threads threads
5326
            INNER JOIN $table_item_property item_properties
5327
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5328
            WHERE
5329
                threads.c_id = $course_id AND
5330
                item_properties.c_id = $course_id AND
5331
                item_properties.visibility = 1 AND
5332
                item_properties.tool='".TOOL_FORUM_THREAD."'
5333
            GROUP BY threads.forum_id";
5334
5335
    // Select the number of posts of the forum (post that are visible and that are in a thread that is visible).
5336
    $sql3 = "SELECT count(post_id) AS number_of_posts, posts.forum_id
5337
            FROM $table_posts posts
5338
            INNER JOIN $table_threads threads
5339
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
5340
            INNER JOIN $table_item_property item_properties
5341
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5342
            WHERE
5343
                posts.visible=1 AND
5344
                posts.c_id = $course_id AND
5345
                item_properties.c_id = $course_id AND
5346
                threads.c_id = $course_id AND
5347
                item_properties.visibility = 1 AND
5348
                item_properties.tool='".TOOL_FORUM_THREAD."'
5349
            GROUP BY threads.forum_id";
5350
5351
    // Course Admin
5352
    if (api_is_allowed_to_edit()) {
5353
        // Select all the forum information of all forums (that are not deleted).
5354
        $sql = "SELECT *
5355
                FROM $table_forums forum
5356
                INNER JOIN $table_item_property item_properties
5357
                ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5358
                WHERE
5359
                    forum.forum_of_group = $groupId AND
5360
                    forum.c_id = $course_id AND
5361
                    item_properties.c_id = $course_id AND
5362
                    item_properties.visibility <> 2 AND
5363
                    item_properties.tool = '".TOOL_FORUM."'
5364
                ORDER BY forum_order ASC";
5365
5366
        // Select the number of threads of the forums (only the threads that are not deleted).
5367
        $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id
5368
                 FROM $table_threads threads
5369
                 INNER JOIN $table_item_property item_properties
5370
                 ON (threads.thread_id=item_properties.ref AND item_properties.c_id = threads.c_id)
5371
                 WHERE
5372
                    threads.c_id = $course_id AND
5373
                    item_properties.c_id = $course_id AND
5374
                    item_properties.visibility <> 2 AND
5375
                    item_properties.tool='".TOOL_FORUM_THREAD."'
5376
                GROUP BY threads.forum_id";
5377
        // Select the number of posts of the forum.
5378
        $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id
5379
                FROM $table_posts
5380
                WHERE c_id = $course_id
5381
                GROUP BY forum_id";
5382
    }
5383
5384
    // Handling all the forum information.
5385
    $result = Database::query($sql);
5386
    $forum_list = [];
5387
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5388
        $forum_list[$row['forum_id']] = $row;
5389
    }
5390
5391
    // Handling the thread count information.
5392
    $result2 = Database::query($sql2);
5393
    while ($row2 = Database::fetch_array($result2, 'ASSOC')) {
5394
        if (is_array($forum_list)) {
5395
            if (array_key_exists($row2['forum_id'], $forum_list)) {
5396
                $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
5397
            }
5398
        }
5399
    }
5400
5401
    // Handling the post count information.
5402
    $result3 = Database::query($sql3);
5403
    while ($row3 = Database::fetch_array($result3, 'ASSOC')) {
5404
        if (is_array($forum_list)) {
5405
            if (array_key_exists($row3['forum_id'], $forum_list)) {
5406
                // This is needed because sql3 takes also the deleted forums into account.
5407
                $forum_list[$row3['forum_id']]['number_of_posts'] = $row3['number_of_posts'];
5408
            }
5409
        }
5410
    }
5411
5412
    // Finding the last post information
5413
    // (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname).
5414
    if (!empty($forum_list)) {
5415
        foreach ($forum_list as $key => $value) {
5416
            $lastPost = get_last_post_information($key, api_is_allowed_to_edit());
5417
            if ($lastPost) {
5418
                $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
5419
                $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
5420
                $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
5421
                $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
5422
                $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
5423
                $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
5424
            }
5425
        }
5426
    }
5427
5428
    return $forum_list;
5429
}
5430
5431
/**
5432
 * This function stores which users have to be notified of which forums or threads.
5433
 *
5434
 * @param string $content    does the user want to be notified about a forum or about a thread
5435
 * @param int    $id         the id of the forum or thread
5436
 * @param bool   $addOnly
5437
 * @param array  $userInfo
5438
 * @param array  $courseInfo
5439
 *
5440
 * @return string language variable
5441
 *
5442
 * @author  Patrick Cool <[email protected]>, Ghent University, Belgium
5443
 * @author  Julio Montoya
5444
 *
5445
 * @since   May 2008 v1.8.5
5446
 */
5447
function set_notification($content, $id, $addOnly = false, $userInfo = [], $courseInfo = [])
5448
{
5449
    $userInfo = empty($userInfo) ? api_get_user_info() : $userInfo;
5450
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
5451
    $id = (int) $id;
5452
5453
    if (empty($userInfo) || empty($courseInfo) || empty($id) || empty($content)) {
5454
        return false;
5455
    }
5456
5457
    // Database table definition
5458
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5459
    $course_id = $courseInfo['real_id'];
5460
5461
    // Which database field do we have to store the id in?
5462
    $field = 'thread_id';
5463
    if ('forum' === $content) {
5464
        $field = 'forum_id';
5465
    }
5466
5467
    $userId = $userInfo['user_id'];
5468
5469
    // First we check if the notification is already set for this.
5470
    $sql = "SELECT * FROM $table_notification
5471
            WHERE
5472
                c_id = $course_id AND
5473
                $field = $id AND
5474
                user_id = $userId ";
5475
    $result = Database::query($sql);
5476
    $total = Database::num_rows($result);
5477
5478
    // If the user did not indicate that (s)he wanted to be notified already
5479
    // then we store the notification request (to prevent double notification requests).
5480
    if ($total <= 0) {
5481
        $notification = new CForumNotification();
5482
        $notification
5483
            ->setCId($course_id)
5484
            ->setUserId($userId)
5485
        ;
5486
5487
        if ('forum' === $content) {
5488
            $notification->setForumId($id);
5489
        } else {
5490
            $notification->setThreadId($id);
5491
        }
5492
5493
        $em = Database::getManager();
5494
        $em->persist($notification);
5495
        $em->flush();
5496
5497
        Session::erase('forum_notification');
5498
        getNotificationsPerUser(0, true);
5499
5500
        return get_lang('You will be notified of new posts by e-mail.');
5501
    } else {
5502
        if (!$addOnly) {
5503
            $sql = "DELETE FROM $table_notification
5504
                    WHERE
5505
                        c_id = $course_id AND
5506
                        $field = $id AND
5507
                        user_id = $userId ";
5508
            Database::query($sql);
5509
            Session::erase('forum_notification');
5510
            getNotificationsPerUser(0, true);
5511
5512
            return get_lang('You will no longer be notified of new posts by email');
5513
        }
5514
    }
5515
}
5516
5517
/**
5518
 * This function retrieves all the email adresses of the users who wanted to be notified
5519
 * about a new post in a certain forum or thread.
5520
 *
5521
 * @param string $content does the user want to be notified about a forum or about a thread
5522
 * @param int    $id      the id of the forum or thread
5523
 *
5524
 * @return array returns
5525
 *
5526
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5527
 * @author Julio Montoya
5528
 *
5529
 * @version May 2008, dokeos 1.8.5
5530
 *
5531
 * @since May 2008, dokeos 1.8.5
5532
 */
5533
function get_notifications($content, $id)
5534
{
5535
    // Database table definition
5536
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5537
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5538
    $course_id = api_get_course_int_id();
5539
5540
    // Which database field contains the notification?
5541
    $field = 'thread_id';
5542
    if ('forum' === $content) {
5543
        $field = 'forum_id';
5544
    }
5545
5546
    $id = (int) $id;
5547
5548
    $sql = "SELECT user.user_id, user.firstname, user.lastname, user.email, user.user_id user
5549
            FROM $table_users user, $table_notification notification
5550
            WHERE
5551
                notification.c_id = $course_id AND user.active = 1 AND
5552
                user.user_id = notification.user_id AND
5553
                notification.$field = $id ";
5554
5555
    $result = Database::query($sql);
5556
    $return = [];
5557
5558
    while ($row = Database::fetch_array($result)) {
5559
        $return['user'.$row['user_id']] = ['email' => $row['email'], 'user_id' => $row['user_id']];
5560
    }
5561
5562
    return $return;
5563
}
5564
5565
/**
5566
 * Get all the users who need to receive a notification of a new post (those subscribed to
5567
 * the forum or the thread).
5568
 *
5569
 * @param int $post_id the id of the post
5570
 *
5571
 * @return false|null
5572
 *
5573
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5574
 *
5575
 * @version May 2008, dokeos 1.8.5
5576
 *
5577
 * @since May 2008, dokeos 1.8.5
5578
 */
5579
function send_notifications(CForumForum $forum, CForumThread $thread, $post_id = 0)
5580
{
5581
    if (!$forum) {
5582
        return false;
5583
    }
5584
5585
    // Users who subscribed to the forum
5586
    $users_to_be_notified_by_forum = get_notifications('forum', $forum->getIid());
5587
5588
    // User who subscribed to the thread
5589
    $users_to_be_notified_by_thread = [];
5590
    if (!$thread) {
5591
        $users_to_be_notified_by_thread = get_notifications('thread', $thread->getIid());
5592
    }
5593
5594
    $postInfo = null;
5595
    if (!empty($post_id)) {
5596
        $postInfo = Container::getForumPostRepository()->find($post_id);
5597
    }
5598
5599
    // Merging the two
5600
    $users_to_be_notified = array_merge($users_to_be_notified_by_forum, $users_to_be_notified_by_thread);
5601
5602
    if (is_array($users_to_be_notified)) {
5603
        foreach ($users_to_be_notified as $value) {
5604
            $userInfo = api_get_user_info($value['user_id']);
5605
            send_mail($userInfo, $forum, $thread, $postInfo);
5606
        }
5607
    }
5608
}
5609
5610
/**
5611
 * Get all the notification subscriptions of the user
5612
 * = which forums and which threads does the user wants to be informed of when a new
5613
 * post is added to this thread.
5614
 *
5615
 * @param int  $user_id the user_id of a user (default = 0 => the current user)
5616
 * @param bool $force   force get the notification subscriptions (even if the information is already in the session
5617
 *
5618
 * @return array
5619
 *
5620
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5621
 *
5622
 * @version May 2008, dokeos 1.8.5
5623
 *
5624
 * @since May 2008, dokeos 1.8.5
5625
 */
5626
function getNotificationsPerUser($user_id = 0, $force = false, $course_id = 0)
5627
{
5628
    // Database table definition
5629
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5630
    $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
5631
    if (empty($course_id) || -1 == $course_id) {
5632
        return null;
5633
    }
5634
5635
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
5636
5637
    if (!isset($_SESSION['forum_notification']) ||
5638
        $_SESSION['forum_notification']['course'] != $course_id ||
5639
        true == $force
5640
    ) {
5641
        $_SESSION['forum_notification']['course'] = $course_id;
5642
        $sql = "SELECT * FROM $table_notification
5643
                WHERE c_id = $course_id AND user_id='".$user_id."'";
5644
5645
        $result = Database::query($sql);
5646
        while ($row = Database::fetch_array($result)) {
5647
            if (null !== $row['forum_id']) {
5648
                $_SESSION['forum_notification']['forum'][] = $row['forum_id'];
5649
            }
5650
            if (null !== $row['thread_id']) {
5651
                $_SESSION['forum_notification']['thread'][] = $row['thread_id'];
5652
            }
5653
        }
5654
    }
5655
}
5656
5657
/**
5658
 * This function counts the number of post inside a thread.
5659
 *
5660
 * @param int $thread_id
5661
 *
5662
 * @return int the number of post inside a thread
5663
 *
5664
 * @author Jhon Hinojosa <[email protected]>,
5665
 *
5666
 * @version octubre 2008, dokeos 1.8
5667
 */
5668
function count_number_of_post_in_thread($thread_id)
5669
{
5670
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5671
    $course_id = api_get_course_int_id();
5672
    if (empty($course_id)) {
5673
        return 0;
5674
    }
5675
    $sql = "SELECT count(*) count FROM $table_posts
5676
            WHERE
5677
                c_id = $course_id AND
5678
                thread_id='".(int) $thread_id."' ";
5679
    $result = Database::query($sql);
5680
5681
    $count = 0;
5682
    if (Database::num_rows($result) > 0) {
5683
        $row = Database::fetch_array($result);
5684
        $count = $row['count'];
5685
    }
5686
5687
    return $count;
5688
}
5689
5690
/**
5691
 * This function counts the number of post inside a thread user.
5692
 *
5693
 * @param int $thread_id
5694
 * @param int $user_id
5695
 *
5696
 * @return int the number of post inside a thread user
5697
 */
5698
function count_number_of_post_for_user_thread($thread_id, $user_id)
5699
{
5700
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5701
    $course_id = api_get_course_int_id();
5702
    $sql = "SELECT count(iid) as count
5703
            FROM $table_posts
5704
            WHERE c_id = $course_id AND
5705
                  thread_id=".(int) $thread_id.' AND
5706
                  poster_id = '.(int) $user_id.' AND visible = 1 ';
5707
    $result = Database::query($sql);
5708
    $count = 0;
5709
    if (Database::num_rows($result) > 0) {
5710
        $count = Database::fetch_array($result);
5711
        $count = $count['count'];
5712
    }
5713
5714
    return $count;
5715
}
5716
5717
/**
5718
 * This function retrieves information of statistical.
5719
 *
5720
 * @param int $thread_id
5721
 * @param int $user_id
5722
 * @param int $course_id
5723
 *
5724
 * @return array the information of statistical
5725
 *
5726
 * @author Jhon Hinojosa <[email protected]>,
5727
 *
5728
 * @version oct 2008, dokeos 1.8
5729
 */
5730
function get_statistical_information($thread_id, $user_id, $course_id)
5731
{
5732
    $result = [];
5733
    $courseInfo = api_get_course_info_by_id($course_id);
5734
    $result['user_course'] = CourseManager::get_users_count_in_course($courseInfo['code']);
5735
    $result['post'] = count_number_of_post_in_thread($thread_id);
5736
    $result['user_post'] = count_number_of_post_for_user_thread($thread_id, $user_id);
5737
5738
    return $result;
5739
}
5740
5741
/**
5742
 * This function return the posts inside a thread from a given user.
5743
 *
5744
 * @param string $course_code
5745
 * @param int    $thread_id
5746
 * @param int    $user_id
5747
 *
5748
 * @return array posts inside a thread
5749
 *
5750
 * @author Jhon Hinojosa <[email protected]>,
5751
 *
5752
 * @version oct 2008, dokeos 1.8
5753
 */
5754
function get_thread_user_post($course_code, $thread_id, $user_id)
5755
{
5756
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5757
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5758
    $thread_id = (int) $thread_id;
5759
    $user_id = (int) $user_id;
5760
    $course_info = api_get_user_info($course_code);
5761
    $course_id = $course_info['real_id'];
5762
5763
    if (empty($course_id)) {
5764
        $course_id = api_get_course_int_id();
5765
    }
5766
    $sql = "SELECT * FROM $table_posts posts
5767
            LEFT JOIN  $table_users users
5768
                ON posts.poster_id=users.user_id
5769
            WHERE
5770
                posts.c_id = $course_id AND
5771
                posts.thread_id='$thread_id'
5772
                AND posts.poster_id='$user_id'
5773
            ORDER BY posts.post_id ASC";
5774
5775
    $result = Database::query($sql);
5776
    $post_list = [];
5777
    while ($row = Database::fetch_array($result)) {
5778
        $row['status'] = '1';
5779
        $post_list[] = $row;
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='$thread_id'
5786
                    AND posts.post_parent_id='".$row['post_id']."'
5787
                ORDER BY posts.post_id ASC";
5788
        $result2 = Database::query($sql);
5789
        while ($row2 = Database::fetch_array($result2)) {
5790
            $row2['status'] = '0';
5791
            $post_list[] = $row2;
5792
        }
5793
    }
5794
5795
    return $post_list;
5796
}
5797
5798
/**
5799
 * This function get the name of an thread by id.
5800
 *
5801
 * @param int $thread_id
5802
 *
5803
 * @return string
5804
 *
5805
 * @author Christian Fasanando
5806
 * @author Julio Montoya <[email protected]> Adding security
5807
 */
5808
function get_name_thread_by_id($thread_id)
5809
{
5810
    $t_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
5811
    $course_id = api_get_course_int_id();
5812
    $sql = "SELECT thread_title
5813
            FROM $t_forum_thread
5814
            WHERE c_id = $course_id AND thread_id = '".(int) $thread_id."' ";
5815
    $result = Database::query($sql);
5816
    $row = Database::fetch_array($result);
5817
5818
    return $row[0];
5819
}
5820
5821
/**
5822
 * This function gets all the post written by an user.
5823
 *
5824
 * @param int    $user_id
5825
 * @param string $course_code
5826
 *
5827
 * @return string
5828
 */
5829
function get_all_post_from_user($user_id, $course_code)
5830
{
5831
    $j = 0;
5832
    $forums = get_forums('', $course_code);
5833
    krsort($forums);
5834
    $forum_results = '';
5835
5836
    foreach ($forums as $forum) {
5837
        if (0 == $forum['visibility']) {
5838
            continue;
5839
        }
5840
        if ($j <= 4) {
5841
            $threads = get_threads($forum['forum_id']);
5842
5843
            if (is_array($threads)) {
5844
                $i = 0;
5845
                $hand_forums = '';
5846
                $post_counter = 0;
5847
                foreach ($threads as $thread) {
5848
                    if (0 == $thread['visibility']) {
5849
                        continue;
5850
                    }
5851
                    if ($i <= 4) {
5852
                        $post_list = get_thread_user_post_limit(
5853
                            $course_code,
5854
                            $thread['thread_id'],
5855
                            $user_id,
5856
                            1
5857
                        );
5858
                        $post_counter = count($post_list);
5859
                        if (is_array($post_list) && count($post_list) > 0) {
5860
                            $hand_forums .= '<div id="social-thread">';
5861
                            $hand_forums .= Display::return_icon(
5862
                                'thread.png',
5863
                                get_lang('Thread'),
5864
                                '',
5865
                                ICON_SIZE_MEDIUM
5866
                            );
5867
                            $hand_forums .= '&nbsp;'.Security::remove_XSS($thread['thread_title'], STUDENT);
5868
                            $hand_forums .= '</div>';
5869
5870
                            foreach ($post_list as $posts) {
5871
                                $hand_forums .= '<div id="social-post">';
5872
                                $hand_forums .= '<strong>'.Security::remove_XSS($posts['post_title'], STUDENT).'</strong>';
5873
                                $hand_forums .= '<br / >';
5874
                                $hand_forums .= Security::remove_XSS($posts['post_text'], STUDENT);
5875
                                $hand_forums .= '</div>';
5876
                                $hand_forums .= '<br / >';
5877
                            }
5878
                        }
5879
                    }
5880
                    $i++;
5881
                }
5882
                $forum_results .= '<div id="social-forum">';
5883
                $forum_results .= '<div class="clear"></div><br />';
5884
                $forum_results .= '<div id="social-forum-title">'.
5885
                    Display::return_icon('forum.gif', get_lang('Forum')).'&nbsp;'.Security::remove_XSS($forum['forum_title'], STUDENT).
5886
                    '<div style="float:right;margin-top:-35px">
5887
                        <a href="../forum/viewforum.php?'.api_get_cidreq_params($course_code).'&forum='.$forum['forum_id'].' " >'.
5888
                    get_lang('See forum').'
5889
                        </a>
5890
                     </div></div>';
5891
                $forum_results .= '<br / >';
5892
                if ($post_counter > 0) {
5893
                    $forum_results .= $hand_forums;
5894
                }
5895
                $forum_results .= '</div>';
5896
            }
5897
            $j++;
5898
        }
5899
    }
5900
5901
    return $forum_results;
5902
}
5903
5904
/**
5905
 * @param string $course_code
5906
 * @param int    $thread_id
5907
 * @param int    $user_id
5908
 * @param int    $limit
5909
 *
5910
 * @return array
5911
 */
5912
function get_thread_user_post_limit($course_code, $thread_id, $user_id, $limit = 10)
5913
{
5914
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5915
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5916
5917
    $course_info = api_get_course_info($course_code);
5918
    $course_id = $course_info['real_id'];
5919
5920
    $sql = "SELECT * FROM $table_posts posts
5921
            LEFT JOIN  $table_users users
5922
                ON posts.poster_id=users.user_id
5923
            WHERE
5924
                posts.c_id = $course_id AND
5925
                posts.thread_id='".Database::escape_string($thread_id)."' AND
5926
                posts.poster_id='".Database::escape_string($user_id)."'
5927
            ORDER BY posts.post_id DESC LIMIT $limit ";
5928
    $result = Database::query($sql);
5929
    $post_list = [];
5930
    while ($row = Database::fetch_array($result)) {
5931
        $row['status'] = '1';
5932
        $post_list[] = $row;
5933
    }
5934
5935
    return $post_list;
5936
}
5937
5938
/**
5939
 * @param string $userId
5940
 * @param array  $courseInfo
5941
 * @param int    $sessionId
5942
 *
5943
 * @return array
5944
 */
5945
function getForumCreatedByUser($userId, $courseInfo, $sessionId)
5946
{
5947
    if (empty($userId) || empty($courseInfo)) {
5948
        return [];
5949
    }
5950
5951
    $courseId = $courseInfo['real_id'];
5952
    $items = api_get_item_property_list_by_tool_by_user(
5953
        $userId,
5954
        'forum',
5955
        $courseId,
5956
        $sessionId
5957
    );
5958
5959
    $forumList = [];
5960
    if (!empty($items)) {
5961
        foreach ($items as $forum) {
5962
            $forumInfo = get_forums(
5963
                $forum['ref'],
5964
                $courseInfo['code'],
5965
                true,
5966
                $sessionId
5967
            );
5968
            if (!empty($forumInfo) && isset($forumInfo['forum_title'])) {
5969
                $forumList[] = [
5970
                    $forumInfo['forum_title'],
5971
                    api_get_local_time($forum['insert_date']),
5972
                    api_get_local_time($forum['lastedit_date']),
5973
                ];
5974
            }
5975
        }
5976
    }
5977
5978
    return $forumList;
5979
}
5980
5981
/**
5982
 * This function builds an array of all the posts in a given thread
5983
 * where the key of the array is the post_id
5984
 * It also adds an element children to the array which itself is an array
5985
 * that contains all the id's of the first-level children.
5986
 *
5987
 * @return array containing all the information on the posts of a thread
5988
 *
5989
 * @author Patrick Cool <[email protected]>, Ghent University
5990
 */
5991
function calculate_children($rows)
5992
{
5993
    $sorted_rows = [0 => []];
5994
    if (!empty($rows)) {
5995
        foreach ($rows as $row) {
5996
            $rows_with_children[$row['post_id']] = $row;
5997
            $rows_with_children[$row['post_parent_id']]['children'][] = $row['post_id'];
5998
        }
5999
6000
        $rows = $rows_with_children;
6001
        forumRecursiveSort($rows, $sorted_rows);
6002
        unset($sorted_rows[0]);
6003
    }
6004
6005
    return $sorted_rows;
6006
}
6007
6008
/**
6009
 * @param $rows
6010
 * @param $threads
6011
 * @param int $seed
6012
 * @param int $indent
6013
 */
6014
function forumRecursiveSort($rows, &$threads, $seed = 0, $indent = 0)
6015
{
6016
    if ($seed > 0) {
6017
        $threads[$rows[$seed]['post_id']] = $rows[$seed];
6018
        $threads[$rows[$seed]['post_id']]['indent_cnt'] = $indent;
6019
        $indent++;
6020
    }
6021
6022
    if (isset($rows[$seed]['children'])) {
6023
        foreach ($rows[$seed]['children'] as $child) {
6024
            forumRecursiveSort($rows, $threads, $child, $indent);
6025
        }
6026
    }
6027
}
6028
6029
/**
6030
 * Update forum attachment data, used to update comment and post ID.
6031
 *
6032
 * @param array  $array    (field => value) to update forum attachment row
6033
 * @param attach $id       ID to find row to update
6034
 * @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...
6035
 *
6036
 * @return int number of affected rows
6037
 */
6038
function editAttachedFile($array, $id, $courseId = null)
6039
{
6040
    // Init variables
6041
    $setString = '';
6042
    $id = (int) $id;
6043
    $courseId = (int) $courseId;
6044
    if (empty($courseId)) {
6045
        // $courseId can be null, use api method
6046
        $courseId = api_get_course_int_id();
6047
    }
6048
    /*
6049
     * Check if Attachment ID and Course ID are greater than zero
6050
     * and array of field values is not empty
6051
     */
6052
    if ($id > 0 && $courseId > 0 && !empty($array) && is_array($array)) {
6053
        foreach ($array as $key => &$item) {
6054
            $item = Database::escape_string($item);
6055
            $setString .= $key.' = "'.$item.'", ';
6056
        }
6057
        // Delete last comma
6058
        $setString = substr($setString, 0, strlen($setString) - 2);
6059
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6060
        $sql = "UPDATE $forumAttachmentTable
6061
                SET $setString WHERE c_id = $courseId AND id = $id";
6062
        $result = Database::query($sql);
6063
        if (false !== $result) {
6064
            $affectedRows = Database::affected_rows($result);
6065
            if ($affectedRows > 0) {
6066
                /*
6067
                 * If exist in $_SESSION variable, then delete them from it
6068
                 * because they would be deprecated
6069
                 */
6070
                if (!empty($_SESSION['forum']['upload_file'][$courseId][$id])) {
6071
                    unset($_SESSION['forum']['upload_file'][$courseId][$id]);
6072
                }
6073
            }
6074
6075
            return $affectedRows;
6076
        }
6077
    }
6078
6079
    return 0;
6080
}
6081
6082
/**
6083
 * Return a table where the attachments will be set.
6084
 *
6085
 * @param int $postId Forum Post ID
6086
 *
6087
 * @return string The Forum Attachments Ajax Table
6088
 */
6089
function getAttachmentsAjaxTable($postId = 0)
6090
{
6091
    $postId = (int) $postId;
6092
    $courseId = api_get_course_int_id();
6093
    $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6094
    $fileDataContent = '';
6095
    // Update comment to show if form did not pass validation
6096
    if (!empty($_REQUEST['file_ids']) && is_array($_REQUEST['file_ids'])) {
6097
        // 'file_ids is the name from forum attachment ajax form
6098
        foreach ($_REQUEST['file_ids'] as $key => $attachId) {
6099
            if (!empty($_SESSION['forum']['upload_file'][$courseId][$attachId]) &&
6100
                is_array($_SESSION['forum']['upload_file'][$courseId][$attachId])
6101
            ) {
6102
                // If exist forum attachment then update into $_SESSION data
6103
                $_SESSION['forum']['upload_file'][$courseId][$attachId]['comment'] = $_POST['file_comments'][$key];
6104
            }
6105
        }
6106
    }
6107
6108
    // Get data to fill into attachment files table
6109
    if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6110
        is_array($_SESSION['forum']['upload_file'][$courseId])
6111
    ) {
6112
        $uploadedFiles = $_SESSION['forum']['upload_file'][$courseId];
6113
        foreach ($uploadedFiles as $k => $uploadedFile) {
6114
            if (!empty($uploadedFile) && in_array($uploadedFile['id'], $attachIds)) {
6115
                // Buil html table including an input with attachmentID
6116
                $fileDataContent .= '<tr id="'.$uploadedFile['id'].'" ><td>'.$uploadedFile['name'].'</td><td>'.$uploadedFile['size'].'</td><td>&nbsp;'.$uploadedFile['result'].
6117
                    ' </td><td> <input style="width:90%;" type="text" value="'.$uploadedFile['comment'].'" name="file_comments[]"> </td><td>'.
6118
                    $uploadedFile['delete'].'</td>'.
6119
                    '<input type="hidden" value="'.$uploadedFile['id'].'" name="file_ids[]">'.'</tr>';
6120
            } else {
6121
                /*
6122
                 * If attachment data is empty, then delete it from $_SESSION
6123
                 * because could generate and empty row into html table
6124
                 */
6125
                unset($_SESSION['forum']['upload_file'][$courseId][$k]);
6126
            }
6127
        }
6128
    }
6129
    $style = empty($fileDataContent) ? 'display: none;' : '';
6130
    // Forum attachment Ajax table
6131
    return '
6132
    <div class="control-group " style="'.$style.'">
6133
        <label class="control-label">'.get_lang('Attachments list').'</label>
6134
        <div class="controls">
6135
            <table id="attachmentFileList" class="files data_table span10">
6136
                <tr>
6137
                    <th>'.get_lang('Filename').'</th>
6138
                    <th>'.get_lang('Size').'</th>
6139
                    <th>'.get_lang('Status').'</th>
6140
                    <th>'.get_lang('Comment').'</th>
6141
                    <th>'.get_lang('Delete').'</th>
6142
                </tr>
6143
                '.$fileDataContent.'
6144
            </table>
6145
        </div>
6146
    </div>';
6147
}
6148
6149
/**
6150
 * Return an array of prepared attachment data to build forum attachment table
6151
 * Also, save this array into $_SESSION to do available the attachment data.
6152
 *
6153
 * @param int $forumId
6154
 * @param int $threadId
6155
 * @param int $postId
6156
 * @param int $attachId
6157
 * @param int $courseId
6158
 *
6159
 * @return array
6160
 */
6161
function getAttachedFiles(
6162
    $forumId,
6163
    $threadId,
6164
    $postId = 0,
6165
    $attachId = 0,
6166
    $courseId = 0
6167
) {
6168
    $forumId = (int) $forumId;
6169
    $courseId = (int) $courseId;
6170
    $attachId = (int) $attachId;
6171
    $postId = (int) $postId;
6172
    $threadId = !empty($threadId) ? (int) $threadId : isset($_REQUEST['thread']) ? (int) ($_REQUEST['thread']) : '';
6173
    if (empty($courseId)) {
6174
        // $courseId can be null, use api method
6175
        $courseId = api_get_course_int_id();
6176
    }
6177
    if (empty($forumId)) {
6178
        if (!empty($_REQUEST['forum'])) {
6179
            $forumId = (int) $_REQUEST['forum'];
6180
        } else {
6181
            // if forum ID is empty, cannot generate delete url
6182
6183
            return [];
6184
        }
6185
    }
6186
    // Check if exist at least one of them to filter forum attachment select query
6187
    if (empty($postId) && empty($attachId)) {
6188
        return [];
6189
    }
6190
6191
    if (empty($postId)) {
6192
        $filter = "AND iid = $attachId";
6193
    } elseif (empty($attachId)) {
6194
        $filter = "AND post_id = $postId";
6195
    } else {
6196
        $filter = "AND post_id = $postId AND iid = $attachId";
6197
    }
6198
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6199
    $sql = "SELECT iid
6200
            FROM $forumAttachmentTable
6201
            WHERE c_id = $courseId $filter";
6202
    $result = Database::query($sql);
6203
    $json = [];
6204
    if (Database::num_rows($result) > 0) {
6205
        $repo = Container::getForumAttachmentRepository();
6206
        while ($row = Database::fetch_array($result, 'ASSOC')) {
6207
            /** @var CForumAttachment $attachment */
6208
            $attachment = $repo->find($row['iid']);
6209
            $downloadUrl = $repo->getResourceFileUrl($attachment);
6210
6211
            // name contains an URL to download attachment file and its filename
6212
            $json['name'] = Display::url(
6213
                api_htmlentities($attachment->getFilename()),
6214
                $downloadUrl,
6215
                ['target' => '_blank', 'class' => 'attachFilename']
6216
            );
6217
            $json['id'] = $row['iid'];
6218
            $json['comment'] = $attachment->getComment();
6219
            // Format file size
6220
            $json['size'] = format_file_size($attachment->getSize());
6221
            // Check if $row is consistent
6222
            if ($attachment) {
6223
                // Set result as success and bring delete URL
6224
                $json['result'] = Display::return_icon('accept.png', get_lang('Uploaded.'));
6225
                $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&action=delete_attach&forum='.$forumId.'&thread='.$threadId.'&id_attach='.$row['iid'];
6226
                $json['delete'] = Display::url(
6227
                    Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL),
6228
                    $url,
6229
                    ['class' => 'deleteLink']
6230
                );
6231
            } else {
6232
                // If not, set an exclamation result
6233
                $json['result'] = Display::return_icon('exclamation.png', get_lang('Error'));
6234
            }
6235
            // Store array data into $_SESSION
6236
            $_SESSION['forum']['upload_file'][$courseId][$json['id']] = $json;
6237
        }
6238
    }
6239
6240
    return $json;
6241
}
6242
6243
/**
6244
 * Clear forum attachment data stored in $_SESSION,
6245
 * If is not defined post, it will clear all forum attachment data from course.
6246
 *
6247
 * @param int $postId   -1 : Clear all attachments from course stored in $_SESSION
6248
 *                      0 : Clear attachments from course, except from temporal post "0"
6249
 *                      but without delete them from file system and database
6250
 *                      Other values : Clear attachments from course except specified post
6251
 *                      and delete them from file system and database
6252
 * @param int $courseId : Course ID, if it is null, will use api_get_course_int_id()
6253
 *
6254
 * @return array
6255
 */
6256
function clearAttachedFiles($postId = 0, $courseId = 0)
6257
{
6258
    // Init variables
6259
    $courseId = (int) $courseId;
6260
    $postId = (int) $postId;
6261
    $array = [];
6262
    if (empty($courseId)) {
6263
        // $courseId can be null, use api method
6264
        $courseId = api_get_course_int_id();
6265
    }
6266
    if (-1 === $postId) {
6267
        // If post ID is -1 then delete course's attachment data from $_SESSION
6268
        if (!empty($_SESSION['forum']['upload_file'][$courseId])) {
6269
            $array = array_keys($_SESSION['forum']['upload_file'][$courseId]);
6270
            unset($_SESSION['forum']['upload_file'][$courseId]);
6271
        }
6272
    } else {
6273
        $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6274
        if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6275
            is_array($_SESSION['forum']['upload_file'][$courseId])) {
6276
            foreach ($_SESSION['forum']['upload_file'][$courseId] as $attachId => $attach) {
6277
                if (!in_array($attachId, $attachIds)) {
6278
                    // If attach ID is not into specified post, delete attachment
6279
                    // Save deleted attachment ID
6280
                    $array[] = $attachId;
6281
                    if (0 !== $postId) {
6282
                        // Post 0 is temporal, delete them from file system and DB
6283
                        delete_attachment(0, $attachId);
6284
                    }
6285
                    // Delete attachment data from $_SESSION
6286
                    unset($_SESSION['forum']['upload_file'][$courseId][$attachId]);
6287
                }
6288
            }
6289
        }
6290
    }
6291
6292
    return $array;
6293
}
6294
6295
/**
6296
 * Returns an array of forum attachment ids into a course and forum post.
6297
 *
6298
 * @param int $postId
6299
 * @param int $courseId
6300
 *
6301
 * @return array
6302
 */
6303
function getAttachmentIdsByPostId($postId, $courseId = 0)
6304
{
6305
    $array = [];
6306
    $courseId = (int) $courseId;
6307
    $postId = (int) $postId;
6308
    if (empty($courseId)) {
6309
        // $courseId can be null, use api method
6310
        $courseId = api_get_course_int_id();
6311
    }
6312
    if ($courseId > 0) {
6313
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6314
        $sql = "SELECT id FROM $forumAttachmentTable
6315
                WHERE c_id = $courseId AND post_id = $postId";
6316
        $result = Database::query($sql);
6317
        if (false !== $result && Database::num_rows($result) > 0) {
6318
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6319
                $array[] = $row['id'];
6320
            }
6321
        }
6322
    }
6323
6324
    return $array;
6325
}
6326
6327
/**
6328
 * Check if the forum category exists looking for its title.
6329
 *
6330
 * @param string $title     The forum category title
6331
 * @param int    $courseId  The course ID
6332
 * @param int    $sessionId Optional. The session ID
6333
 *
6334
 * @return bool
6335
 */
6336
function getForumCategoryByTitle($title, $courseId, $sessionId = 0)
6337
{
6338
    $sessionId = (int) $sessionId;
6339
    $courseId = (int) $courseId;
6340
    $forumCategoryTable = Database::get_course_table(TABLE_FORUM_CATEGORY);
6341
    $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6342
6343
    $fakeFrom = "$forumCategoryTable fc
6344
        INNER JOIN $itemProperty ip ";
6345
6346
    if (0 === $sessionId) {
6347
        $fakeFrom .= '
6348
            ON (
6349
                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)
6350
            )
6351
        ';
6352
    } else {
6353
        $fakeFrom .= '
6354
            ON (
6355
                fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND fc.session_id = ip.session_id
6356
            )
6357
        ';
6358
    }
6359
6360
    $resultData = Database::select(
6361
        'fc.*',
6362
        $fakeFrom,
6363
        [
6364
            'where' => [
6365
                'ip.visibility != ? AND ' => 2,
6366
                'ip.tool = ? AND ' => TOOL_FORUM_CATEGORY,
6367
                'fc.session_id = ? AND ' => $sessionId,
6368
                'fc.cat_title = ? AND ' => $title,
6369
                'fc.c_id = ?' => $courseId,
6370
            ],
6371
        ],
6372
        'first'
6373
    );
6374
6375
    if (empty($resultData)) {
6376
        return false;
6377
    }
6378
6379
    return $resultData;
6380
}
6381
6382
/**
6383
 * @param array $row
6384
 * @param bool  $addWrapper
6385
 *
6386
 * @return string
6387
 */
6388
function getPostStatus(CForumForum $forum, $row, $addWrapper = true)
6389
{
6390
    $statusIcon = '';
6391
    if ($forum->isModerated()) {
6392
        if ($addWrapper) {
6393
            $statusIcon = '<br /><br /><span id="status_post_'.$row['iid'].'">';
6394
        }
6395
        $row['status'] = empty($row['status']) ? 2 : $row['status'];
6396
6397
        $addUrl = false;
6398
        $showStatus = false;
6399
        if (api_is_allowed_to_edit(false, true)) {
6400
            $addUrl = true;
6401
        } else {
6402
            if ($row['user_id'] == api_get_user_id()) {
6403
                $showStatus = true;
6404
            }
6405
        }
6406
6407
        $label = '';
6408
        $icon = '';
6409
        $buttonType = '';
6410
        switch ($row['status']) {
6411
            case CForumPost::STATUS_VALIDATED:
6412
                $label = get_lang('Validated');
6413
                $icon = 'check-circle';
6414
                $buttonType = 'success';
6415
6416
                break;
6417
            case CForumPost::STATUS_WAITING_MODERATION:
6418
                $label = get_lang('Waiting for moderation');
6419
                $icon = 'warning';
6420
                $buttonType = 'warning';
6421
6422
                break;
6423
            case CForumPost::STATUS_REJECTED:
6424
                $label = get_lang('Rejected');
6425
                $icon = 'minus-circle';
6426
                $buttonType = 'danger';
6427
6428
                break;
6429
        }
6430
6431
        if ($addUrl) {
6432
            $statusIcon .= Display::toolbarButton(
6433
                $label.'&nbsp;',
6434
                'javascript:void(0)',
6435
                $icon,
6436
                $buttonType,
6437
                ['class' => 'change_post_status']
6438
            );
6439
        } else {
6440
            if ($showStatus) {
6441
                $statusIcon .= Display::label(
6442
                    Display::returnFontAwesomeIcon($icon).$label,
6443
                    $buttonType
6444
                );
6445
            }
6446
        }
6447
6448
        if ($addWrapper) {
6449
            $statusIcon .= '</span>';
6450
        }
6451
    }
6452
6453
    return $statusIcon;
6454
}
6455
6456
/**
6457
 * @param CForumForum $forum
6458
 * @param int         $threadId
6459
 * @param int         $status
6460
 */
6461
function getCountPostsWithStatus($status, $forum, $threadId = null)
6462
{
6463
    $em = Database::getManager();
6464
    $criteria = Criteria::create();
6465
    $criteria
6466
        ->where(Criteria::expr()->eq('status', $status))
6467
        ->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
6468
        ->andWhere(Criteria::expr()->eq('visible', 1))
6469
    ;
6470
6471
    if (!empty($threadId)) {
6472
        $criteria->andWhere(Criteria::expr()->eq('thread', $threadId));
6473
    }
6474
6475
    $qb = $em->getRepository('ChamiloCourseBundle:CForumPost')->createQueryBuilder('p');
6476
    $qb->select('count(p.iid)')
6477
        ->addCriteria($criteria);
6478
6479
    return $qb->getQuery()->getSingleScalarResult();
6480
}
6481
6482
/**
6483
 * @param CForumForum $forum
6484
 * @param CForumPost  $post
6485
 *
6486
 * @return bool
6487
 */
6488
function postIsEditableByStudent($forum, $post)
6489
{
6490
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
6491
        return true;
6492
    }
6493
6494
    if (1 == $forum->isModerated()) {
6495
        if (null === $post->getStatus()) {
6496
            return true;
6497
        } else {
6498
            return in_array(
6499
                $post->getStatus(),
6500
                [
6501
                    CForumPost::STATUS_WAITING_MODERATION,
6502
                    CForumPost::STATUS_REJECTED,
6503
                ]
6504
            );
6505
        }
6506
    }
6507
6508
    return true;
6509
}
6510
6511
/**
6512
 * @param int $postId
6513
 *
6514
 * @return bool
6515
 */
6516
function savePostRevision($postId)
6517
{
6518
    $postData = get_post_information($postId);
6519
6520
    if (empty($postData)) {
6521
        return false;
6522
    }
6523
6524
    $userId = api_get_user_id();
6525
6526
    if ($postData['poster_id'] != $userId) {
6527
        return false;
6528
    }
6529
6530
    $status = (int) !postNeedsRevision($postId);
6531
    $extraFieldValue = new ExtraFieldValue('forum_post');
6532
    $params = [
6533
        'item_id' => $postId,
6534
        'extra_ask_for_revision' => ['extra_ask_for_revision' => $status],
6535
    ];
6536
    if (empty($status)) {
6537
        unset($params['extra_ask_for_revision']);
6538
    }
6539
    $extraFieldValue->saveFieldValues(
6540
        $params,
6541
        true,
6542
        false,
6543
        ['ask_for_revision']
6544
    );
6545
}
6546
6547
/**
6548
 * @param int $postId
6549
 *
6550
 * @return string
6551
 */
6552
function getPostRevision($postId)
6553
{
6554
    $extraFieldValue = new ExtraFieldValue('forum_post');
6555
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6556
        $postId,
6557
        'revision_language'
6558
    );
6559
    $revision = '';
6560
    if ($value && isset($value['value'])) {
6561
        $revision = $value['value'];
6562
    }
6563
6564
    return $revision;
6565
}
6566
6567
/**
6568
 * @param int $postId
6569
 *
6570
 * @return bool
6571
 */
6572
function postNeedsRevision($postId)
6573
{
6574
    $extraFieldValue = new ExtraFieldValue('forum_post');
6575
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6576
        $postId,
6577
        'ask_for_revision'
6578
    );
6579
    $hasRevision = false;
6580
    if ($value && isset($value['value'])) {
6581
        return 1 == $value['value'];
6582
    }
6583
6584
    return $hasRevision;
6585
}
6586
6587
/**
6588
 * @param int   $postId
6589
 * @param array $threadInfo
6590
 *
6591
 * @return string
6592
 */
6593
function getAskRevisionButton($postId, $threadInfo)
6594
{
6595
    if (false === api_get_configuration_value('allow_forum_post_revisions')) {
6596
        return '';
6597
    }
6598
6599
    $postId = (int) $postId;
6600
6601
    $status = 'btn-default';
6602
    if (postNeedsRevision($postId)) {
6603
        $status = 'btn-success';
6604
    }
6605
6606
    return Display::url(
6607
        get_lang('Ask for a revision'),
6608
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6609
        api_get_cidreq().'&action=ask_revision&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6610
        ['class' => "btn $status", 'title' => get_lang('Ask for a revision')]
6611
    );
6612
}
6613
6614
/**
6615
 * @param int   $postId
6616
 * @param array $threadInfo
6617
 *
6618
 * @return string
6619
 */
6620
function giveRevisionButton($postId, $threadInfo)
6621
{
6622
    $postId = (int) $postId;
6623
6624
    return Display::toolbarButton(
6625
        get_lang('Give revision'),
6626
        api_get_path(WEB_CODE_PATH).'forum/reply.php?'.api_get_cidreq().'&'.http_build_query(
6627
            [
6628
                'forum' => $threadInfo['forum_id'],
6629
                'thread' => $threadInfo['thread_id'],
6630
                'post' => $postId = (int) $postId,
6631
                'action' => 'replymessage',
6632
                'give_revision' => 1,
6633
            ]
6634
        ),
6635
        'reply',
6636
        'primary',
6637
        ['id' => "reply-to-post-{$postId}"]
6638
    );
6639
}
6640
6641
/**
6642
 * @param int   $postId
6643
 * @param array $threadInfo
6644
 *
6645
 * @return string
6646
 */
6647
function getReportButton($postId, $threadInfo)
6648
{
6649
    $postId = (int) $postId;
6650
6651
    return Display::url(
6652
        Display::returnFontAwesomeIcon('flag'),
6653
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6654
        api_get_cidreq().'&action=report&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6655
        ['class' => 'btn btn-danger', 'title' => get_lang('Report')]
6656
    );
6657
}
6658
6659
/**
6660
 * @return bool
6661
 */
6662
function reportAvailable()
6663
{
6664
    $extraFieldValue = new ExtraFieldValue('course');
6665
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6666
        api_get_course_int_id(),
6667
        'allow_forum_report_button'
6668
    );
6669
    $allowReport = false;
6670
    if ($value && isset($value['value']) && 1 == $value['value']) {
6671
        $allowReport = true;
6672
    }
6673
6674
    return $allowReport;
6675
}
6676
6677
/**
6678
 * @return array
6679
 */
6680
function getReportRecipients()
6681
{
6682
    $extraFieldValue = new ExtraFieldValue('course');
6683
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6684
        api_get_course_int_id(),
6685
        'forum_report_recipients'
6686
    );
6687
    $users = [];
6688
    if ($value && isset($value['value'])) {
6689
        $usersType = explode(';', $value['value']);
6690
6691
        foreach ($usersType as $type) {
6692
            switch ($type) {
6693
                case 'teachers':
6694
                    $teachers = CourseManager::get_teacher_list_from_course_code(api_get_course_id());
6695
                    if (!empty($teachers)) {
6696
                        $users = array_merge($users, array_column($teachers, 'user_id'));
6697
                    }
6698
6699
                break;
6700
                case 'admins':
6701
                    $admins = UserManager::get_all_administrators();
6702
                    if (!empty($admins)) {
6703
                        $users = array_merge($users, array_column($admins, 'user_id'));
6704
                    }
6705
6706
                    break;
6707
                case 'community_managers':
6708
                    $managers = api_get_configuration_value('community_managers_user_list');
6709
                    if (!empty($managers) && isset($managers['users'])) {
6710
                        $users = array_merge($users, $managers['users']);
6711
                    }
6712
6713
                    break;
6714
            }
6715
        }
6716
6717
        $users = array_unique(array_filter($users));
6718
    }
6719
6720
    return $users;
6721
}
6722
6723
/**
6724
 * @param int   $postId
6725
 * @param array $forumInfo
6726
 * @param array $threadInfo
6727
 *
6728
 * @return bool
6729
 */
6730
function reportPost($postId, $forumInfo, $threadInfo)
6731
{
6732
    if (!reportAvailable()) {
6733
        return false;
6734
    }
6735
6736
    if (empty($forumInfo) || empty($threadInfo)) {
6737
        return false;
6738
    }
6739
6740
    $postId = (int) $postId;
6741
6742
    $postData = get_post_information($postId);
6743
    $currentUser = api_get_user_info();
6744
6745
    if (!empty($postData)) {
6746
        $users = getReportRecipients();
6747
        if (!empty($users)) {
6748
            $url = api_get_path(WEB_CODE_PATH).
6749
                'forum/viewthread.php?forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'].'&'.api_get_cidreq().'&post_id='.$postId.'#post_id_'.$postId;
6750
            $postLink = Display::url(
6751
                $postData['post_title'],
6752
                $url
6753
            );
6754
            $subject = get_lang('Post reported');
6755
            $content = sprintf(
6756
                get_lang('User %s has reported the message %s in the forum %s'),
6757
                $currentUser['complete_name'],
6758
                $postLink,
6759
                $forumInfo['forum_title']
6760
            );
6761
            foreach ($users as $userId) {
6762
                MessageManager::send_message_simple($userId, $subject, $content);
6763
            }
6764
        }
6765
    }
6766
}
6767