Passed
Push — master ( 241b61...cc68cc )
by Julito
09:18
created

getForumCreatedByUser()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 32
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 3
nop 3
dl 0
loc 32
rs 9.3554
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\GradebookLink;
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
                    if (false !== $link_info) {
226
                        $link_id = $link_info['id'];
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 int $lp_id Learning path ID
243
 *
244
 * @return string
245
 *
246
 * @author Patrick Cool <[email protected]>, Ghent University
247
 * @author Juan Carlos Raña Trabado (return to lp_id)
248
 *
249
 * @version may 2011, Chamilo 1.8.8
250
 */
251
function show_add_forumcategory_form($lp_id)
252
{
253
    $form = new FormValidator(
254
        'forumcategory',
255
        'post',
256
        'index.php?'.api_get_cidreq().'&action=add_category'
257
    );
258
    // hidden field if from learning path
259
    $form->addElement('hidden', 'lp_id', $lp_id);
260
    $form->addElement('hidden', 'action', 'add_category');
261
    // Setting the form elements.
262
    $form->addElement('header', get_lang('Add forum category'));
263
    $form->addElement('text', 'forum_category_title', get_lang('Title'), ['autofocus']);
264
    $form->addElement(
265
        'html_editor',
266
        'forum_category_comment',
267
        get_lang('Description'),
268
        null,
269
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
270
    );
271
272
    $extraField = new ExtraField('forum_category');
273
    $extraField->addElements(
274
        $form,
275
        null,
276
        [], //exclude
277
        false, // filter
278
        false, // tag as select
279
        [], //show only fields
280
        [], // order fields
281
        [] // extra data
282
    );
283
284
    $form->addButtonCreate(get_lang('Create category'), 'SubmitForumCategory');
285
286
    // Setting the rules.
287
    $form->addRule('forum_category_title', get_lang('Required field'), 'required');
288
289
    // The validation or display
290
    if ($form->validate()) {
291
        $check = Security::check_token('post');
292
        if ($check) {
293
            $values = $form->exportValues();
294
            store_forumcategory($values);
295
        }
296
        Security::clear_token();
297
    } else {
298
        $token = Security::get_token();
299
        $form->addElement('hidden', 'sec_token');
300
        $form->setConstants(['sec_token' => $token]);
301
302
        return $form->returnForm();
303
    }
304
}
305
306
function forumForm(CForumForum $forum = null, $lp_id)
307
{
308
    $_course = api_get_course_info();
309
    // The header for the form
310
    $form_title = get_lang('Add a forum');
311
    $action = 'add_forum';
312
    $id = 0;
313
    if ($forum) {
314
        $id = $forum->getIid();
315
        $action = 'edit_forum';
316
        $form_title = get_lang('Edit forum');
317
    }
318
319
    $form = new FormValidator('forumcategory', 'post', 'index.php?'.api_get_cidreq().'&action='.$action.'&id='.$id);
320
    $form->addHidden('action', $action);
321
    $form->addHeader($form_title);
322
323
    // We have a hidden field if we are editing.
324
    if ($forum) {
325
        $form->addElement('hidden', 'forum_id', $id);
326
    }
327
    $lp_id = (int) $lp_id;
328
329
    // hidden field if from learning path
330
    $form->addElement('hidden', 'lp_id', $lp_id);
331
332
    // The title of the forum
333
    $form->addElement('text', 'forum_title', get_lang('Title'), ['autofocus']);
334
335
    // The comment of the forum.
336
    $form->addElement(
337
        'html_editor',
338
        'forum_comment',
339
        get_lang('Description'),
340
        null,
341
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
342
    );
343
344
    // Dropdown list: Forum categories
345
    $forum_categories = get_forum_categories();
346
    $forum_categories_titles = [];
347
    foreach ($forum_categories as $value) {
348
        $forum_categories_titles[$value->getCatId()] = $value->getCatTitle();
349
    }
350
    $form->addElement(
351
        'select',
352
        'forum_category',
353
        get_lang('Create in category'),
354
        $forum_categories_titles
355
    );
356
    $form->applyFilter('forum_category', 'html_filter');
357
358
    if (COURSE_VISIBILITY_OPEN_WORLD == $_course['visibility']) {
359
        // This is for horizontal
360
        $group = [];
361
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('Yes'), 1);
362
        $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('No'), 0);
363
        $form->addGroup($group, 'allow_anonymous_group', get_lang('Allow anonymous posts?'));
364
    }
365
366
    $form->addButtonAdvancedSettings('advanced_params');
367
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
368
369
    $form->addDateTimePicker(
370
        'start_time',
371
        [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')],
372
        ['id' => 'start_time']
373
    );
374
375
    $form->addDateTimePicker(
376
        'end_time',
377
        [get_lang('Closing date'), get_lang('Closing dateComment')],
378
        ['id' => 'end_time']
379
    );
380
381
    $form->addRule(
382
        ['start_time', 'end_time'],
383
        get_lang('Start date must be before the end date'),
384
        'compare_datetime_text',
385
        '< allow_empty'
386
    );
387
388
    $group = [];
389
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('Yes'), 1);
390
    $group[] = $form->createElement('radio', 'moderated', null, get_lang('No'), 0);
391
    $form->addGroup($group, 'moderated', get_lang('Moderated forum'));
392
393
    $group = [];
394
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('Yes'), 1);
395
    $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('No'), 0);
396
    $form->addGroup($group, 'students_can_edit_group', get_lang('Can learners edit their own posts?'));
397
398
    $group = [];
399
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Approval'), 1);
400
    $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Direct'), 0);
401
402
    $group = [];
403
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('Yes'), 1);
404
    $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('No'), 0);
405
406
    $group = [];
407
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('Yes'), 1);
408
    $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('No'), 0);
409
    $form->addGroup($group, 'allow_new_threads_group', get_lang('Allow users to start new threads'));
410
411
    $group = [];
412
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Flat'), 'flat');
413
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Threaded'), 'threaded');
414
    $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Nested'), 'nested');
415
    $form->addGroup($group, 'default_view_type_group', get_lang('Default view type'));
416
417
    // Drop down list: Groups
418
    $groups = GroupManager::get_group_list();
419
    $groups_titles[0] = get_lang('Not a group forum');
420
    foreach ($groups as $key => $value) {
421
        $groups_titles[$value['id']] = $value['name'];
422
    }
423
    $form->addElement('select', 'group_forum', get_lang('For Group'), $groups_titles);
424
425
    // Public or private group forum
426
    $group = [];
427
    $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Public access (access authorized to any member of the course)'), 'public');
428
    $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Private access (access authorized to group members only)'), 'private');
429
    $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'));
430
431
    // Forum image
432
    $form->addProgress();
433
    /*
434
    if ($forum) {
435
        $baseImagePath = api_get_course_path().'/upload/forum/images/'.$inputvalues['forum_image'];
436
        $image_path = api_get_path(WEB_COURSE_PATH).$baseImagePath;
437
        $sysImagePath = api_get_path(SYS_COURSE_PATH).$baseImagePath;
438
439
        if (file_exists($sysImagePath)) {
440
            $show_preview_image = Display::img(
441
                $image_path,
442
                null,
443
                ['class' => 'img-responsive']
444
            );
445
            $form->addElement('label', get_lang('Preview image'), $show_preview_image);
446
            $form->addElement('checkbox', 'remove_picture', null, get_lang('Remove picture'));
447
        }
448
    }
449
    $forum_image = isset($inputvalues['forum_image']) ? $inputvalues['forum_image'] : '';
450
    $form->addElement('file', 'picture', ('' != $forum_image ? get_lang('Update Image') : get_lang('Add image')));
451
    $form->addRule(
452
        'picture',
453
        get_lang('Only PNG, JPG or GIF images allowed'),
454
        'filetype',
455
        ['jpg', 'jpeg', 'png', 'gif']
456
    );*/
457
458
    //$forumId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
459
    //$skillList = Skill::addSkillsToForm($form, ITEM_TYPE_FORUM, $forumId);
460
461
    $form->addElement('html', '</div>');
462
463
    // The OK button
464
    if ($forum) {
465
        $form->addButtonUpdate(get_lang('Edit forum'), 'SubmitForum');
466
    } else {
467
        $form->addButtonCreate(get_lang('Create forum'), 'SubmitForum');
468
    }
469
470
    // setting the rules
471
    $form->addRule('forum_title', get_lang('Required field'), 'required');
472
    $form->addRule('forum_category', get_lang('Required field'), 'required');
473
474
    $defaultSettingAllowNewThreads = api_get_default_tool_setting('forum', 'allow_new_threads', 0);
475
476
    // Settings the defaults
477
    if (null === $forum) {
478
        $defaults['moderated']['moderated'] = 0;
479
        $defaults['allow_anonymous_group']['allow_anonymous'] = 0;
480
        $defaults['students_can_edit_group']['students_can_edit'] = 0;
481
        $defaults['approval_direct_group']['approval_direct'] = 0;
482
        $defaults['allow_attachments_group']['allow_attachments'] = 1;
483
        $defaults['allow_new_threads_group']['allow_new_threads'] = $defaultSettingAllowNewThreads;
484
        $defaults['default_view_type_group']['default_view_type'] = api_get_setting('default_forum_view');
485
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = 'public';
486
        if (isset($_GET['forumcategory'])) {
487
            $defaults['forum_category'] = Security::remove_XSS($_GET['forumcategory']);
488
        }
489
    } else {
490
        // the default values when editing = the data in the table
491
        $defaults['forum_id'] = $forum->getIid();
492
        $defaults['forum_title'] = prepare4display($forum->getForumTitle());
493
        $defaults['forum_comment'] = prepare4display($forum->getForumComment());
494
        $defaults['start_time'] = api_get_local_time($forum->getStartTime());
495
        $defaults['end_time'] = api_get_local_time($forum->getEndTime());
496
        $defaults['moderated']['moderated'] = $forum->isModerated();
497
        $defaults['forum_category'] = $forum->getForumCategory()->getIid();
498
        $defaults['allow_anonymous_group']['allow_anonymous'] = $forum->getAllowAnonymous();
499
        $defaults['students_can_edit_group']['students_can_edit'] = $forum->getAllowEdit();
500
        $defaults['approval_direct_group']['approval_direct'] = $forum->getApprovalDirectPost();
501
        $defaults['allow_attachments_group']['allow_attachments'] = $forum->getAllowAttachments();
502
        $defaults['allow_new_threads_group']['allow_new_threads'] = $forum->getAllowNewThreads();
503
        $defaults['default_view_type_group']['default_view_type'] = $forum->getDefaultView();
504
        $defaults['public_private_group_forum_group']['public_private_group_forum'] = $forum->getForumGroupPublicPrivate();
505
        $defaults['group_forum'] = $forum->getForumOfGroup();
506
    }
507
508
    $form->setDefaults($defaults);
509
    // Validation or display
510
    if ($form->validate()) {
511
        $check = Security::check_token('post');
512
        if ($check) {
513
            $values = $form->getSubmitValues();
514
            $forumId = store_forum($values, '', true);
515
            if ($forumId) {
516
                // Skill::saveSkills($form, ITEM_TYPE_FORUM, $forumId);
517
                if (isset($values['forum_id'])) {
518
                    Display::addFlash(Display::return_message(get_lang('The forum has been modified'), 'confirmation'));
519
                } else {
520
                    Display::addFlash(Display::return_message(get_lang('The forum has been added'), 'confirmation'));
521
                }
522
            }
523
            $url = api_get_path(WEB_CODE_PATH).'forum/index.php?'.api_get_cidreq();
524
            header('Location: '.$url);
525
            exit;
526
        }
527
        Security::clear_token();
528
    } else {
529
        $token = Security::get_token();
530
        $form->addElement('hidden', 'sec_token');
531
        $form->setConstants(['sec_token' => $token]);
532
533
        return $form->returnForm();
534
    }
535
}
536
537
/**
538
 * This function deletes the forum image if exists.
539
 *
540
 * @param int $forum_id forum id
541
 *
542
 * @return bool true if success
543
 *
544
 * @author Julio Montoya <[email protected]>
545
 *
546
 * @version february 2006, dokeos 1.8
547
 */
548
function delete_forum_image($forum_id)
549
{
550
    throw new Exception('delete_forum_image');
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(
575
        'forumcategory',
576
        'post',
577
        'index.php?action=edit_category&'.api_get_cidreq().'&id='.$categoryId
578
    );
579
    // Setting the form elements.
580
    $form->addElement('header', '', get_lang('Edit forumCategory'));
581
582
    $form->addElement('hidden', 'action', 'edit_category');
583
    $form->addElement('hidden', 'forum_category_id');
584
    $form->addElement('text', 'forum_category_title', get_lang('Title'));
585
586
    $form->addElement(
587
        'html_editor',
588
        'forum_category_comment',
589
        get_lang('Comment'),
590
        null,
591
        ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
592
    );
593
594
    $extraField = new ExtraField('forum_category');
595
    $returnParams = $extraField->addElements(
596
        $form,
597
        $categoryId,
598
        [], //exclude
599
        false, // filter
600
        false, // tag as select
601
        [], //show only fields
602
        [], // order fields
603
        [] // extra data
604
    );
605
606
    $form->addButtonUpdate(get_lang('Edit category'), 'SubmitEdit forumCategory');
607
608
    // Setting the default values.
609
    $defaultvalues['forum_category_id'] = $categoryId;
610
    $defaultvalues['forum_category_title'] = $category->getCatTitle();
611
    $defaultvalues['forum_category_comment'] = $category->getCatComment();
612
    $form->setDefaults($defaultvalues);
613
614
    // Setting the rules.
615
    $form->addRule('forum_category_title', get_lang('Required field'), 'required');
616
617
    // Validation or display
618
    if ($form->validate()) {
619
        $check = Security::check_token('post');
620
        if ($check) {
621
            $values = $form->exportValues();
622
            store_forumcategory($values);
623
        }
624
        Security::clear_token();
625
    } else {
626
        $token = Security::get_token();
627
        $form->addElement('hidden', 'sec_token');
628
        $form->setConstants(['sec_token' => $token]);
629
630
        return $form->returnForm();
631
    }
632
}
633
634
/**
635
 * This function stores the forum category in the database.
636
 * The new category is added to the end.
637
 *
638
 * @param array $values
639
 * @param array $courseInfo
640
 * @param bool  $showMessage
641
 */
642
function store_forumcategory($values, $courseInfo = [], $showMessage = true)
643
{
644
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
645
    $course_id = $courseInfo['real_id'];
646
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
647
648
    // Find the max cat_order. The new forum category is added at the end => max cat_order + &
649
    $sql = "SELECT MAX(cat_order) as sort_max
650
            FROM $table_categories
651
            WHERE c_id = $course_id";
652
    $result = Database::query($sql);
653
    $row = Database::fetch_array($result);
654
    $new_max = $row['sort_max'] + 1;
655
    $session_id = api_get_session_id();
656
    $clean_cat_title = $values['forum_category_title'];
657
    $last_id = null;
658
    $repo = Container::getForumCategoryRepository();
659
660
    if (isset($values['forum_category_id'])) {
661
        /** @var CForumCategory $category */
662
        $category = $repo->find($values['forum_category_id']);
663
        $category
664
            ->setCatComment(isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '')
665
            ->setCatTitle($values['forum_category_title'])
666
        ;
667
668
        $repo->getEntityManager()->persist($category);
669
        $repo->getEntityManager()->flush();
670
        $message = get_lang('The forum category has been modified');
671
672
        $logInfo = [
673
            'tool' => TOOL_FORUM,
674
            'action' => 'update-forumcategory',
675
            'action_details' => 'forumcategory',
676
            'info' => $clean_cat_title,
677
        ];
678
        Event::registerLog($logInfo);
679
680
        $values['item_id'] = $values['forum_category_id'];
681
    } else {
682
        $course = api_get_course_entity($course_id);
683
        $session = api_get_session_entity($session_id);
684
685
        $category = new CForumCategory();
686
        $category
687
            ->setCatTitle($clean_cat_title)
688
            ->setCatComment(isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '')
689
            ->setCatOrder($new_max)
690
            ->setCId($course_id)
691
            ->setSessionId($session_id)
692
            ->setParent($course)
693
            ->addCourseLink($course, $session)
694
        ;
695
        $repo->getEntityManager()->persist($category);
696
        $repo->getEntityManager()->flush();
697
698
        $last_id = $category->getIid();
699
        if ($last_id > 0) {
700
            $sql = "UPDATE $table_categories SET cat_id = $last_id WHERE iid = $last_id";
701
            Database::query($sql);
702
            $message = get_lang('The forum category has been added');
703
        }
704
705
        $logInfo = [
706
            'tool' => TOOL_FORUM,
707
            'action' => 'new-forumcategory',
708
            'action_details' => 'forumcategory',
709
            'info' => $clean_cat_title,
710
        ];
711
        Event::registerLog($logInfo);
712
713
        $values['item_id'] = $last_id;
714
    }
715
716
    $extraFieldValue = new ExtraFieldValue('forum_category');
717
    $extraFieldValue->saveFieldValues($values);
718
719
    if ($showMessage) {
720
        Display::addFlash(Display::return_message($message, 'confirmation'));
721
    }
722
723
    return $last_id;
724
}
725
726
/**
727
 * This function stores the forum in the database. The new forum is added to the end.
728
 *
729
 * @param array $values
730
 * @param array $courseInfo
731
 * @param bool  $returnId
732
 *
733
 * @return string language variable
734
 */
735
function store_forum($values, $courseInfo = [], $returnId = false)
736
{
737
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
738
    $courseId = $courseInfo['real_id'];
739
    $session_id = api_get_session_id();
740
    $table_forums = Database::get_course_table(TABLE_FORUM);
741
742
    // Find the max forum_order for the given category. The new forum is added at the end => max cat_order + &
743
    if (null === $values['forum_category']) {
744
        $new_max = null;
745
    } else {
746
        $sql = "SELECT MAX(forum_order) as sort_max
747
                FROM $table_forums
748
                WHERE
749
                    c_id = $courseId AND
750
                    forum_category='".Database::escape_string($values['forum_category'])."'";
751
        $result = Database::query($sql);
752
        $row = Database::fetch_array($result);
753
        $new_max = $row['sort_max'] + 1;
754
    }
755
756
    // Forum images
757
    $has_attachment = false;
758
    $image_moved = true;
759
    if (!empty($_FILES['picture']['name'])) {
760
        $upload_ok = process_uploaded_file($_FILES['picture']);
761
        $has_attachment = true;
762
    }
763
764
    // Remove existing picture if it was requested.
765
    if (!empty($_POST['remove_picture'])) {
766
        delete_forum_image($values['forum_id']);
767
    }
768
769
    $new_file_name = '';
770
    if (isset($upload_ok)) {
771
        if ($has_attachment) {
772
            throw new Exception('$has_attachment');
773
            /*$course_dir = $courseInfo['path'].'/upload/forum/images';
774
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
775
            $updir = $sys_course_path.$course_dir;
776
            // Try to add an extension to the file if it hasn't one.
777
            $new_file_name = add_ext_on_mime(
778
                Database::escape_string($_FILES['picture']['name']),
779
                $_FILES['picture']['type']
780
            );
781
            if (!filter_extension($new_file_name)) {
782
                //Display::addFlash(Display::return_message(get_lang('File upload failed: this file extension or file type is prohibited'), 'error'));
783
                $image_moved = false;
784
            } else {
785
                $file_extension = explode('.', $_FILES['picture']['name']);
786
                $file_extension = strtolower($file_extension[count($file_extension) - 1]);
787
                $new_file_name = uniqid('').'.'.$file_extension;
788
                $new_path = $updir.'/'.$new_file_name;
789
                $result = @move_uploaded_file($_FILES['picture']['tmp_name'], $new_path);
790
                // Storing the attachments if any
791
                if ($result) {
792
                    $image_moved = true;
793
                }
794
            }*/
795
        }
796
    }
797
798
    $repo = Container::getForumRepository();
799
800
    if (!isset($values['forum_id'])) {
801
        $forum = new CForumForum();
802
        $forum
803
            ->setCId($courseId)
804
            ->setSessionId($session_id)
805
            ->setForumOrder(isset($new_max) ? $new_max : null)
806
        ;
807
    } else {
808
        $forum = $repo->find($values['forum_id']);
809
    }
810
811
    $forumCategory = null;
812
    if (!empty($values['forum_category'])) {
813
        $repoForumCategory = Container::getForumCategoryRepository();
814
        $forumCategory = $repoForumCategory->find($values['forum_category']);
815
    }
816
    //'forum_image' => $new_file_name,
817
    $forum
818
        ->setForumTitle($values['forum_title'])
819
        ->setForumComment($values['forum_comment'] ?? null)
820
        ->setForumCategory($forumCategory)
821
        ->setAllowAnonymous($values['allow_anonymous_group']['allow_anonymous'] ?? null)
822
        ->setAllowEdit($values['students_can_edit_group']['students_can_edit'] ?? null)
823
        ->setApprovalDirectPost($values['approval_direct_group']['approval_direct'] ?? null)
824
        ->setAllowAttachments($values['allow_attachments_group']['allow_attachments'] ?? null)
825
        ->setAllowNewThreads($values['allow_new_threads_group']['allow_new_threads'] ?? null)
826
        ->setDefaultView($values['default_view_type_group']['default_view_type'] ?? null)
827
        ->setForumOfGroup($values['group_forum'] ?? null)
828
        ->setForumGroupPublicPrivate($values['public_private_group_forum_group']['public_private_group_forum'] ?? '')
829
        ->setModerated($values['moderated']['moderated'] ?? null)
830
        ->setStartTime(!empty($values['start_time']) ? api_get_utc_datetime($values['start_time'], true, true) : null)
831
        ->setEndTime(!empty($values['end_time']) ? api_get_utc_datetime($values['end_time'], true, true) : null)
832
        ->setSessionId($session_id)
833
        ->setLpId($values['lp_id'] ?? 0)
834
    ;
835
836
    $course = api_get_course_entity($courseId);
837
    $session = api_get_session_entity($session_id);
838
839
    if (isset($values['forum_id'])) {
840
        // Edit
841
        $repo->getEntityManager()->persist($forum);
842
        $repo->getEntityManager()->flush();
843
844
        if (isset($upload_ok)) {
845
            if ($has_attachment) {
846
                //$params['forum_image'] = $new_file_name;
847
            }
848
        }
849
850
        if (isset($values['remove_picture']) && 1 == $values['remove_picture']) {
851
            /*$params['forum_image'] = '';
852
            delete_forum_image($values['forum_id']);*/
853
        }
854
855
        // Move groups from one group to another
856
        if (isset($values['group_forum']) && false) {
857
            $forumData = get_forums($values['forum_id']);
858
            $currentGroupId = $forumData['forum_of_group'];
859
            if ($currentGroupId != $values['group_forum']) {
860
                $threads = get_threads($values['forum_id']);
861
                $toGroupId = 'NULL';
862
                if (!empty($values['group_forum'])) {
863
                    $toGroupId = $values['group_forum'];
864
                }
865
                $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
866
                foreach ($threads as $thread) {
867
                    /*$sql = "UPDATE $tableItemProperty
868
                            SET to_group_id = $toGroupId
869
                            WHERE
870
                                tool = '".TOOL_FORUM_THREAD."' AND
871
                                ref = ".$thread['thread_id'].' AND
872
                                c_id = '.$courseId;
873
                    Database::query($sql);
874
875
                    $posts = getPosts(
876
                        $forumData,
877
                        $thread['thread_id']
878
                    );*/
879
880
                    /*foreach ($posts as $post) {
881
                        $postId = $post['post_id'];
882
                        $attachMentList = getAllAttachment($postId);
883
                        if (!empty($attachMentList)) {
884
                            foreach ($attachMentList as $attachMent) {
885
                                $sql = "UPDATE $tableItemProperty
886
                                        SET to_group_id = $toGroupId
887
                                        WHERE
888
                                            tool = '".TOOL_FORUM_ATTACH."' AND
889
                                            ref = ".$attachMent['iid'].' AND
890
                                            c_id = '.$courseId;
891
                                Database::query($sql);
892
                            }
893
                        }
894
895
                        $sql = "UPDATE $tableItemProperty
896
                                SET to_group_id = $toGroupId
897
                                WHERE
898
                                    tool = '".TOOL_FORUM_POST."' AND
899
                                    ref = $postId AND
900
                                    c_id = $courseId";
901
                        Database::query($sql);
902
                    }*/
903
                }
904
            }
905
        }
906
907
        /*
908
        api_item_property_update(
909
            $courseInfo,
910
            TOOL_FORUM,
911
            Database::escape_string($values['forum_id']),
912
            'ForumUpdated',
913
            api_get_user_id(),
914
            $groupInfo
915
        );*/
916
917
        $return_message = get_lang('The forum has been modified');
918
        $forumId = $forum->getIid();
919
920
        $logInfo = [
921
            'tool' => TOOL_FORUM,
922
            'tool_id' => $values['forum_id'],
923
            'action' => 'update-forum',
924
            'action_details' => 'forum',
925
            'info' => $values['forum_title'],
926
        ];
927
        Event::registerLog($logInfo);
928
    } else {
929
        if ($image_moved) {
930
            $new_file_name = isset($new_file_name) ? $new_file_name : '';
931
        }
932
        $forum
933
            ->setParent($course)
934
            ->addCourseLink($course, $session);
935
        $repo->getEntityManager()->persist($forum);
936
        $repo->getEntityManager()->flush();
937
938
        $forumId = $forum->getIid();
939
        if ($forumId > 0) {
940
            $courseCode = $courseInfo['code'];
941
            $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications');
942
943
            $status = STUDENT;
944
            if (!empty($session_id)) {
945
                $status = 0;
946
            }
947
            if (1 === $subscribe) {
948
                $userList = CourseManager::get_user_list_from_course_code(
949
                    $courseCode,
950
                    $session_id,
951
                    null,
952
                    null,
953
                    $status
954
                );
955
                foreach ($userList as $userInfo) {
956
                    set_notification('forum', $forumId, false, $userInfo, $courseInfo);
957
                }
958
            }
959
960
            /*api_item_property_update(
961
                $courseInfo,
962
                TOOL_FORUM,
963
                $forumId,
964
                'ForumAdded',
965
                api_get_user_id(),
966
                $groupInfo
967
            );
968
969
            api_set_default_visibility(
970
                $forumId,
971
                TOOL_FORUM,
972
                $group_id,
973
                $courseInfo
974
            );*/
975
976
            $logInfo = [
977
                'tool' => TOOL_FORUM,
978
                'tool_id' => $forumId,
979
                'action' => 'new-forum',
980
                'action_details' => 'forum',
981
                'info' => $values['forum_title'],
982
            ];
983
            Event::registerLog($logInfo);
984
        }
985
        $return_message = get_lang('The forum has been added');
986
    }
987
988
    if ($returnId) {
989
        return $forumId;
990
    }
991
992
    return $return_message;
993
}
994
995
function deletePost(CForumPost $post)
996
{
997
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
998
    $course_id = api_get_course_int_id();
999
    $em = Database::getManager();
1000
    if ($post) {
1001
        $em
1002
            ->createQuery('
1003
                UPDATE ChamiloCourseBundle:CForumPost p
1004
                SET p.postParentId = :parent_of_deleted_post
1005
                WHERE
1006
                    p.cId = :course AND
1007
                    p.postParentId = :post AND
1008
                    p.thread = :thread_of_deleted_post AND
1009
                    p.forum = :forum_of_deleted_post
1010
            ')
1011
            ->execute([
1012
                'parent_of_deleted_post' => $post->getPostParentId(),
1013
                'course' => $course_id,
1014
                'post' => $post->getIid(),
1015
                'thread_of_deleted_post' => $post->getThread() ? $post->getThread()->getIid() : 0,
1016
                'forum_of_deleted_post' => $post->getForum(),
1017
            ]);
1018
1019
        $attachments = $post->getAttachments();
1020
        if (!empty($attachments)) {
1021
            foreach ($attachments as $attachment) {
1022
                $em->remove($attachment);
1023
            }
1024
        }
1025
1026
        $em->remove($post);
1027
        $em->flush();
1028
    }
1029
1030
    $last_post_of_thread = check_if_last_post_of_thread($_GET['thread']);
1031
1032
    if (is_array($last_post_of_thread)) {
1033
        // Decreasing the number of replies for this thread and also changing the last post information.
1034
        $sql = "UPDATE $table_threads
1035
                SET
1036
                    thread_replies = thread_replies - 1,
1037
                    thread_last_post = ".(int) ($last_post_of_thread['iid']).",
1038
                    thread_date='".Database::escape_string($last_post_of_thread['post_date'])."'
1039
                WHERE c_id = $course_id AND iid = ".(int) ($_GET['thread']);
1040
        Database::query($sql);
1041
        Display::addFlash(Display::return_message(get_lang('Post has been deleted')));
1042
    }
1043
    if (!$last_post_of_thread) {
1044
        // We deleted the very single post of the thread so we need to delete the entry in the thread table also.
1045
        $sql = "DELETE FROM $table_threads
1046
                WHERE c_id = $course_id AND iid = ".(int) ($_GET['thread']);
1047
        Database::query($sql);
1048
1049
        Display::addFlash(Display::return_message(get_lang('Special Post Deleted')));
1050
    }
1051
}
1052
1053
/**
1054
 * This function gets the all information of the last (=most recent) post of the thread
1055
 * This can be done by sorting the posts that have the field thread_id=$thread_id and sort them by post_date.
1056
 *
1057
 * @param int $thread_id id of the thread we want to know the last post of
1058
 *
1059
 * @return array an array or bool if there is a last post found, false if there is
1060
 *               no post entry linked to that thread => thread will be deleted
1061
 *
1062
 * @author Patrick Cool <[email protected]>, Ghent University
1063
 *
1064
 * @version february 2006, dokeos 1.8
1065
 */
1066
function check_if_last_post_of_thread($thread_id)
1067
{
1068
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1069
    $course_id = api_get_course_int_id();
1070
    $sql = "SELECT * FROM $table_posts
1071
            WHERE thread_id = ".(int) $thread_id.'
1072
            ORDER BY post_date DESC';
1073
    $result = Database::query($sql);
1074
    if (Database::num_rows($result) > 0) {
1075
        return Database::fetch_array($result);
1076
    }
1077
1078
    return false;
1079
}
1080
1081
/**
1082
 * @param string $content                   Type of content forum category, forum, thread, post
1083
 * @param int    $id                        the id of the content we want to make invisible
1084
 * @param int    $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
1085
 * @param array  $additional_url_parameters
1086
 *
1087
 * @return string HTML
1088
 */
1089
function return_visible_invisible_icon(
1090
    $content,
1091
    $id,
1092
    $current_visibility_status,
1093
    $additional_url_parameters = []
1094
) {
1095
    $html = '';
1096
    $id = (int) $id;
1097
    $current_visibility_status = (int) $current_visibility_status;
1098
1099
    if (1 == $current_visibility_status) {
1100
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1101
        if (is_array($additional_url_parameters)) {
1102
            foreach ($additional_url_parameters as $key => $value) {
1103
                $html .= $key.'='.$value.'&';
1104
            }
1105
        }
1106
        $html .= 'action=invisible&content='.$content.'&id='.$id.'">'.
1107
            Display::return_icon('visible.png', get_lang('MakeInvisible'), [], ICON_SIZE_SMALL).'</a>';
1108
    }
1109
    if (0 == $current_visibility_status) {
1110
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1111
        if (is_array($additional_url_parameters)) {
1112
            foreach ($additional_url_parameters as $key => $value) {
1113
                $html .= $key.'='.$value.'&';
1114
            }
1115
        }
1116
        $html .= 'action=visible&content='.$content.'&id='.$id.'">'.
1117
            Display::return_icon('invisible.png', get_lang('Make Visible'), [], ICON_SIZE_SMALL).'</a>';
1118
    }
1119
1120
    return $html;
1121
}
1122
1123
/**
1124
 * @param $content
1125
 * @param $id
1126
 * @param $current_lock_status
1127
 * @param string $additional_url_parameters
1128
 *
1129
 * @return string
1130
 */
1131
function return_lock_unlock_icon($content, $id, $current_lock_status, $additional_url_parameters = '')
1132
{
1133
    $html = '';
1134
    $id = (int) $id;
1135
    //check if the forum is blocked due
1136
    if ('thread' == $content) {
1137
        if (api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD)) {
1138
            return $html.Display::return_icon(
1139
                'lock_na.png',
1140
                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.'),
1141
                [],
1142
                ICON_SIZE_SMALL
1143
            );
1144
        }
1145
    }
1146
    if ('1' == $current_lock_status) {
1147
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1148
        if (is_array($additional_url_parameters)) {
1149
            foreach ($additional_url_parameters as $key => $value) {
1150
                $html .= $key.'='.$value.'&';
1151
            }
1152
        }
1153
        $html .= 'action=unlock&content='.$content.'&id='.$id.'">'.
1154
            Display::return_icon('lock.png', get_lang('Unlock'), [], ICON_SIZE_SMALL).'</a>';
1155
    }
1156
    if ('0' == $current_lock_status) {
1157
        $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
1158
        if (is_array($additional_url_parameters)) {
1159
            foreach ($additional_url_parameters as $key => $value) {
1160
                $html .= $key.'='.$value.'&';
1161
            }
1162
        }
1163
        $html .= 'action=lock&content='.$content.'&id='.$id.'">'.
1164
            Display::return_icon('unlock.png', get_lang('Lock'), [], ICON_SIZE_SMALL).'</a>';
1165
    }
1166
1167
    return $html;
1168
}
1169
1170
/**
1171
 * This function takes care of the display of the up and down icon.
1172
 *
1173
 * @param string $content what is it that we want to make (in)visible: forum category, forum, thread, post
1174
 * @param int    $id      is the id of the item we want to display the icons for
1175
 * @param array  $list    is an array of all the items. All items in this list should have
1176
 *                        an up and down icon except for the first (no up icon) and the last (no down icon)
1177
 *                        The key of this $list array is the id of the item.
1178
 *
1179
 * @return string HTML
1180
 */
1181
function return_up_down_icon($content, $id, $list)
1182
{
1183
    $id = (int) $id;
1184
    $total_items = count($list);
1185
    $position = 0;
1186
    $internal_counter = 0;
1187
    $forumCategory = isset($_GET['forumcategory']) ? Security::remove_XSS($_GET['forumcategory']) : null;
1188
1189
    if (is_array($list)) {
1190
        foreach ($list as $item) {
1191
            $internal_counter++;
1192
            if ($id == $item->getIid()) {
1193
                $position = $internal_counter;
1194
            }
1195
        }
1196
    }
1197
1198
    if ($position > 1) {
1199
        $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').'">'.
1200
            Display::return_icon('up.png', get_lang('Move up'), [], ICON_SIZE_SMALL).'</a>';
1201
    } else {
1202
        $return_value = Display::return_icon('up_na.png', '-', [], ICON_SIZE_SMALL);
1203
    }
1204
1205
    if ($position < $total_items) {
1206
        $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').'" >'.
1207
            Display::return_icon('down.png', get_lang('Move down'), [], ICON_SIZE_SMALL).'</a>';
1208
    } else {
1209
        $return_value .= Display::return_icon('down_na.png', '-', [], ICON_SIZE_SMALL);
1210
    }
1211
1212
    return $return_value;
1213
}
1214
1215
/**
1216
 * This function moves a forum or a forum category up or down.
1217
 *
1218
 * @param string $content   is it that we want to make (in)visible: forum category, forum, thread, post
1219
 * @param string $direction we want to move it up or down
1220
 * @param int    $id        id of the content we want to make invisible
1221
 *
1222
 * @return string language variable
1223
 *
1224
 * @todo consider removing the table_item_property calls here but this can
1225
 * prevent unwanted side effects when a forum does not have an entry in
1226
 * the item_property table but does have one in the forum table.
1227
 *
1228
 * @author Patrick Cool <[email protected]>, Ghent University
1229
 *
1230
 * @version february 2006, dokeos 1.8
1231
 */
1232
function move_up_down($content, $direction, $id)
1233
{
1234
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
1235
    $table_forums = Database::get_course_table(TABLE_FORUM);
1236
    $course_id = api_get_course_int_id();
1237
    $id = (int) $id;
1238
1239
    // Determine which field holds the sort order.
1240
    if ('forumcategory' === $content) {
1241
        $table = $table_categories;
1242
        $sort_column = 'cat_order';
1243
        $id_column = 'cat_id';
1244
        $sort_column = 'cat_order';
1245
    } elseif ('forum' === $content) {
1246
        $table = $table_forums;
1247
        $sort_column = 'forum_order';
1248
        $id_column = 'forum_id';
1249
        $sort_column = 'forum_order';
1250
        // We also need the forum_category of this forum.
1251
        $sql = "SELECT forum_category FROM $table_forums
1252
                WHERE c_id = $course_id AND forum_id = ".$id;
1253
        $result = Database::query($sql);
1254
        $row = Database::fetch_array($result);
1255
        $forum_category = $row['forum_category'];
1256
    } else {
1257
        return false;
1258
    }
1259
1260
    // Determine the need for sorting ascending or descending order.
1261
    if ('down' === $direction) {
1262
        $sort_direction = 'ASC';
1263
    } elseif ('up' === $direction) {
1264
        $sort_direction = 'DESC';
1265
    } else {
1266
        return false;
1267
    }
1268
1269
    // The SQL statement
1270
    if ('forumcategory' === $content) {
1271
        $sql = "SELECT *
1272
                FROM $table_categories forum_categories
1273
                WHERE
1274
                    forum_categories.c_id = $course_id
1275
                ORDER BY forum_categories.cat_order $sort_direction";
1276
    }
1277
    if ('forum' === $content) {
1278
        $sql = "SELECT *
1279
            FROM $table
1280
            WHERE
1281
                c_id = $course_id AND
1282
                forum_category='".Database::escape_string($forum_category)."'
1283
            ORDER BY forum_order $sort_direction";
1284
    }
1285
    // Finding the items that need to be switched.
1286
    $result = Database::query($sql);
1287
    $found = false;
1288
    $next_sort = '';
1289
    $this_sort = '';
1290
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1291
        //var_dump($content, $row, $id_column, $sort_column);
1292
        if ($found) {
1293
            $next_id = $row[$id_column];
1294
            $next_sort = $row[$sort_column];
1295
            $found = false;
1296
        }
1297
        if ($id == $row[$id_column]) {
1298
            $this_id = $id;
1299
            $this_sort = $row[$sort_column];
1300
            $found = true;
1301
        }
1302
    }
1303
1304
    if ('forum' === $content && $next_sort) {
1305
        $repo = Container::getForumRepository();
1306
        /** @var CForumForum $forum */
1307
        $forum = $repo->find($id);
1308
        $forum->setForumOrder($next_sort);
1309
        $repo->getEntityManager()->persist($forum);
1310
        $repo->getEntityManager()->flush();
1311
1312
        Display::addFlash(Display::return_message(get_lang('Updated')));
1313
    } else {
1314
        if ($next_sort) {
1315
            $repo = Container::getForumCategoryRepository();
1316
            /** @var CForumCategory $forum */
1317
            $category = $repo->find($id);
1318
            if ($category) {
1319
                $category->setCatOrder($next_sort);
1320
                $repo->getEntityManager()->persist($category);
1321
                $repo->getEntityManager()->flush();
1322
1323
                Display::addFlash(Display::return_message(get_lang('Updated')));
1324
            }
1325
        }
1326
    }
1327
}
1328
1329
/**
1330
 * Retrieve all the information off the forum categories (or one specific) for the current course.
1331
 * The categories are sorted according to their sorting order (cat_order.
1332
 *
1333
 * @param int $courseId  Optional. The course ID
1334
 * @param int $sessionId Optional. The session ID
1335
 *
1336
 * @return CForumCategory[]
1337
 */
1338
function get_forum_categories($courseId = 0, $sessionId = 0)
1339
{
1340
    $repo = Container::getForumCategoryRepository();
1341
1342
    $course = api_get_course_entity($courseId);
1343
    $session = api_get_session_entity($sessionId);
1344
1345
    $qb = $repo->getResources(api_get_user_entity(api_get_user_id()), $course->getResourceNode(), $course, $session);
1346
1347
    return $qb->getQuery()->getResult();
1348
}
1349
1350
/**
1351
 * This function retrieves all the fora in a given forum category.
1352
 *
1353
 * @param int $categoryId the id of the forum category
1354
 * @param int $courseId   Optional. The course ID
1355
 *
1356
 * @return CForumForum[] containing all the information about the forums (regardless of their category)
1357
 *
1358
 * @author Patrick Cool <[email protected]>, Ghent University
1359
 *
1360
 * @version february 2006, dokeos 1.8
1361
 */
1362
function get_forums_in_category($categoryId, $courseId = 0)
1363
{
1364
    $repo = Container::getForumRepository();
1365
    $course = api_get_course_entity($courseId);
1366
1367
    $qb = $repo->getResourcesByCourse($course, null);
1368
    $qb
1369
        ->andWhere('resource.forumCategory = :catId')
1370
        ->setParameter('catId', $categoryId)
1371
        ->orderBy('resource.forumOrder')
1372
    ;
1373
1374
    return $qb->getQuery()->getResult();
1375
}
1376
1377
/**
1378
 * Retrieve all the forums (regardless of their category) or of only one.
1379
 * The forums are sorted according to the forum_order.
1380
 * Since it does not take the forum category into account there probably
1381
 * will be two or more forums that have forum_order=1, ...
1382
 *
1383
 * @param bool $includeGroupsForum
1384
 * @param int  $sessionId
1385
 *
1386
 * @return CForumForum[]
1387
 */
1388
function get_forums(
1389
    $courseId = '',
1390
    $includeGroupsForum = true,
1391
    $sessionId = 0
1392
) {
1393
    $repo = Container::getForumRepository();
1394
    $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
1395
    $course = api_get_course_entity($courseId);
1396
    $session = api_get_session_entity($sessionId);
1397
1398
    $qb = $repo->getResourcesByCourse($course, $session);
1399
1400
    /*$qb->andWhere('resource.forumCategory = :catId')
1401
        ->setParameter('catId', $cat_id);
1402
    */
1403
    return $qb->getQuery()->getResult();
1404
1405
    $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...
1406
    $course_info = api_get_course_info($course_code);
1407
1408
    $table_forums = Database::get_course_table(TABLE_FORUM);
1409
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1410
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1411
1412
    // Condition for the session
1413
    $session_id = (int) $sessionId ?: api_get_session_id();
1414
    $sessionIdLink = 0 === $session_id ? '' : ' AND threads.session_id = item_properties.session_id';
1415
1416
    $condition_session = api_get_session_condition(
1417
        $session_id,
1418
        true,
1419
        false,
1420
        'item_properties.session_id'
1421
    );
1422
1423
    $course_id = $course_info['real_id'];
1424
1425
    $forum_list = [];
1426
    $includeGroupsForumSelect = '';
1427
    if (!$includeGroupsForum) {
1428
        $includeGroupsForumSelect = ' AND (forum_of_group = 0 OR forum_of_group IS NULL) ';
1429
    }
1430
1431
    $allowToEdit = api_is_allowed_to_edit();
1432
1433
    if (empty($id)) {
1434
        // Student
1435
        // Select all the forum information of all forums (that are visible to students).
1436
        $sql = "SELECT item_properties.*, forum.*
1437
                FROM $table_forums forum
1438
                INNER JOIN $table_item_property item_properties
1439
                ON (
1440
                    forum.forum_id = item_properties.ref AND
1441
                    forum.c_id = item_properties.c_id
1442
                )
1443
                WHERE
1444
                    item_properties.visibility = 1 AND
1445
                    item_properties.tool = '".TOOL_FORUM."'
1446
                    $condition_session AND
1447
                    forum.c_id = $course_id AND
1448
                    item_properties.c_id = $course_id
1449
                    $includeGroupsForumSelect
1450
                ORDER BY forum.forum_order ASC";
1451
1452
        // Select the number of threads of the forums (only the threads that are visible).
1453
        $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1454
                FROM $table_threads threads
1455
                INNER JOIN $table_item_property item_properties
1456
                ON (
1457
                    threads.thread_id = item_properties.ref AND
1458
                    threads.c_id = item_properties.c_id
1459
                    $sessionIdLink
1460
                )
1461
                WHERE
1462
                    item_properties.visibility=1 AND
1463
                    item_properties.tool='".TOOL_FORUM_THREAD."' AND
1464
                    threads.c_id = $course_id AND
1465
                    item_properties.c_id = $course_id
1466
                GROUP BY threads.forum_id";
1467
1468
        // Course Admin
1469
        if ($allowToEdit) {
1470
            // Select all the forum information of all forums (that are not deleted).
1471
            $sql = "SELECT item_properties.*, forum.*
1472
                    FROM $table_forums forum
1473
                    INNER JOIN $table_item_property item_properties
1474
                    ON (
1475
                        forum.forum_id = item_properties.ref AND
1476
                        forum.c_id = item_properties.c_id
1477
                    )
1478
                    WHERE
1479
                        item_properties.visibility <> 2 AND
1480
                        item_properties.tool = '".TOOL_FORUM."'
1481
                        $condition_session AND
1482
                        forum.c_id = $course_id AND
1483
                        item_properties.c_id = $course_id
1484
                        $includeGroupsForumSelect
1485
                    ORDER BY forum_order ASC";
1486
1487
            // Select the number of threads of the forums (only the threads that are not deleted).
1488
            $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
1489
                    FROM $table_threads threads
1490
                    INNER JOIN $table_item_property item_properties
1491
                    ON (
1492
                        threads.thread_id = item_properties.ref AND
1493
                        threads.c_id = item_properties.c_id
1494
                        $sessionIdLink
1495
                    )
1496
                    WHERE
1497
                        item_properties.visibility<>2 AND
1498
                        item_properties.tool='".TOOL_FORUM_THREAD."' AND
1499
                        threads.c_id = $course_id AND
1500
                        item_properties.c_id = $course_id
1501
                    GROUP BY threads.forum_id";
1502
        }
1503
    } else {
1504
        // GETTING ONE SPECIFIC FORUM
1505
        /* We could do the splitup into student and course admin also but we want
1506
        to have as much as information about a certain forum as possible
1507
        so we do not take too much information into account. This function
1508
         (or this section of the function) is namely used to fill the forms
1509
        when editing a forum (and for the moment it is the only place where
1510
        we use this part of the function) */
1511
1512
        // Select all the forum information of the given forum (that is not deleted).
1513
        $sql = "SELECT * FROM $table_item_property item_properties
1514
                INNER JOIN $table_forums forum
1515
                ON (forum.forum_id = item_properties.ref AND forum.c_id = item_properties.c_id)
1516
                WHERE
1517
                    forum.forum_id = $id AND
1518
                    forum.c_id = $course_id AND
1519
                    item_properties.visibility != 2 AND
1520
                    item_properties.tool = '".TOOL_FORUM."'
1521
                ORDER BY forum_order ASC";
1522
1523
        // Select the number of threads of the forum.
1524
        $sql2 = "SELECT count(*) AS number_of_threads, forum_id
1525
                FROM $table_threads
1526
                WHERE
1527
                    forum_id = $id
1528
                GROUP BY forum_id";
1529
    }
1530
1531
    // Handling all the forum information.
1532
    $result = Database::query($sql);
1533
    while ($row = Database::fetch_assoc($result)) {
1534
        if (empty($id)) {
1535
            $forum_list[$row['forum_id']] = $row;
1536
        } else {
1537
            $forum_list = $row;
1538
        }
1539
    }
1540
1541
    // Handling the thread count information.
1542
    $result2 = Database::query($sql2);
1543
    while ($row2 = Database::fetch_array($result2)) {
1544
        if (empty($id)) {
1545
            $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
1546
        } else {
1547
            $forum_list['number_of_threads'] = $row2['number_of_threads'];
1548
        }
1549
    }
1550
1551
    /* Finding the last post information
1552
    (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)*/
1553
    if (empty($id)) {
1554
        if (is_array($forum_list)) {
1555
            foreach ($forum_list as $key => $value) {
1556
                $lastPost = get_last_post_information(
1557
                    $key,
1558
                    $allowToEdit,
1559
                    $course_id
1560
                );
1561
1562
                if ($lastPost) {
1563
                    $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
1564
                    $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
1565
                    $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
1566
                    $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
1567
                    $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
1568
                    $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
1569
                    $forum_list[$key]['last_post_title'] = $lastPost['last_post_title'];
1570
                    $forum_list[$key]['last_post_text'] = $lastPost['last_post_text'];
1571
                }
1572
            }
1573
        } else {
1574
            $forum_list = [];
1575
        }
1576
    } else {
1577
        $lastPost = get_last_post_information(
1578
            $id,
1579
            $allowToEdit,
1580
            $course_id
1581
        );
1582
        if ($lastPost) {
1583
            $forum_list['last_post_id'] = $lastPost['last_post_id'];
1584
            $forum_list['last_poster_id'] = $lastPost['last_poster_id'];
1585
            $forum_list['last_post_date'] = $lastPost['last_post_date'];
1586
            $forum_list['last_poster_name'] = $lastPost['last_poster_name'];
1587
            $forum_list['last_poster_lastname'] = $lastPost['last_poster_lastname'];
1588
            $forum_list['last_poster_firstname'] = $lastPost['last_poster_firstname'];
1589
            $forum_list['last_post_title'] = $lastPost['last_post_title'];
1590
            $forum_list['last_post_text'] = $lastPost['last_post_text'];
1591
        }
1592
    }
1593
1594
    return $forum_list;
1595
}
1596
1597
/**
1598
 * @param int  $course_id
1599
 * @param int  $thread_id
1600
 * @param int  $forum_id
1601
 * @param bool $show_visible
1602
 *
1603
 * @return array|bool
1604
 */
1605
function get_last_post_by_thread($course_id, $thread_id, $forum_id, $show_visible = true)
1606
{
1607
    if (empty($thread_id) || empty($forum_id) || empty($course_id)) {
1608
        return false;
1609
    }
1610
1611
    $thread_id = (int) $thread_id;
1612
    $forum_id = (int) $forum_id;
1613
    $course_id = (int) $course_id;
1614
1615
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1616
    $sql = "SELECT * FROM $table_posts
1617
            WHERE
1618
                c_id = $course_id AND
1619
                thread_id = $thread_id AND
1620
                forum_id = $forum_id";
1621
1622
    if (false == $show_visible) {
1623
        $sql .= ' AND visible = 1 ';
1624
    }
1625
1626
    $sql .= ' ORDER BY iid DESC LIMIT 1';
1627
    $result = Database::query($sql);
1628
    if (Database::num_rows($result)) {
1629
        return Database::fetch_array($result, 'ASSOC');
1630
    } else {
1631
        return false;
1632
    }
1633
}
1634
1635
/**
1636
 * This function gets all the last post information of a certain forum.
1637
 *
1638
 * @param int    $forum_id        the id of the forum we want to know the last post information of
1639
 * @param bool   $show_invisibles
1640
 * @param string $course_id       course db name
1641
 * @param int    $sessionId       Optional. The session id
1642
 *
1643
 * @return array containing all the information about the last post
1644
 *               (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname,
1645
 *               last_poster_firstname)
1646
 *
1647
 * @author Patrick Cool <[email protected]>, Ghent University
1648
 *
1649
 * @version february 2006, dokeos 1.8
1650
 */
1651
function get_last_post_information($forum_id, $show_invisibles = false, $course_id = null, $sessionId = 0)
1652
{
1653
    if (!isset($course_id)) {
1654
        $course_id = api_get_course_int_id();
1655
    } else {
1656
        $course_id = (int) $course_id;
1657
    }
1658
    $sessionId = $sessionId ? (int) $sessionId : api_get_session_id();
1659
1660
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
1661
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1662
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
1663
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1664
1665
    $forum_id = (int) $forum_id;
1666
    $return_array = [];
1667
1668
    // First get the threads to make sure there is no inconsistency in the
1669
    // database between forum and thread
1670
    $sql = "SELECT iid as thread_id FROM $table_threads
1671
            WHERE
1672
                forum_id = $forum_id AND
1673
                c_id = $course_id AND
1674
                session_id = $sessionId";
1675
    $result = Database::query($sql);
1676
    if (0 == Database::num_rows($result)) {
1677
        // If there are no threads in this forum, then there are no posts
1678
        return [];
1679
    }
1680
    $threads = [];
1681
    while ($row = Database::fetch_row($result)) {
1682
        $threads[] = $row[0];
1683
    }
1684
    $threadsList = implode(',', $threads);
1685
    // Now get the posts that are linked to these threads
1686
    $sql = "SELECT
1687
                post.iid as post_id,
1688
                post.forum_id,
1689
                post.poster_id,
1690
                post.poster_name,
1691
                post.post_date,
1692
                users.lastname,
1693
                users.firstname,
1694
                post.visible,
1695
                thread_properties.visibility AS thread_visibility,
1696
                forum_properties.visibility AS forum_visibility,
1697
                post.post_title,
1698
                post.post_text
1699
            FROM
1700
                $table_posts post,
1701
                $table_users users,
1702
                $table_item_property thread_properties,
1703
                $table_item_property forum_properties
1704
            WHERE
1705
                post.forum_id = $forum_id AND
1706
                post.thread_id IN ($threadsList) AND
1707
                post.poster_id = users.id AND
1708
                 post.thread_id = thread_properties.ref AND thread_properties.tool='".TOOL_FORUM_THREAD."'
1709
                AND post.forum_id=forum_properties.ref
1710
                AND forum_properties.tool='".TOOL_FORUM."'
1711
                AND post.c_id = $course_id AND
1712
                thread_properties.c_id = $course_id AND
1713
                forum_properties.c_id = $course_id
1714
            ORDER BY post.post_id DESC";
1715
    $result = Database::query($sql);
1716
1717
    if ($show_invisibles) {
1718
        $row = Database::fetch_array($result);
1719
        $return_array['last_post_id'] = $row['post_id'];
1720
        $return_array['last_poster_id'] = $row['poster_id'];
1721
        $return_array['last_post_date'] = $row['post_date'];
1722
        $return_array['last_poster_name'] = $row['poster_name'];
1723
        $return_array['last_poster_lastname'] = $row['lastname'];
1724
        $return_array['last_poster_firstname'] = $row['firstname'];
1725
        $return_array['last_post_title'] = $row['post_title'];
1726
        $return_array['last_post_text'] = $row['post_text'];
1727
1728
        return $return_array;
1729
    } else {
1730
        // We have to loop through the results to find the first one that is
1731
        // actually visible to students (forum_category, forum, thread AND post are visible).
1732
        while ($row = Database::fetch_array($result)) {
1733
            if ('1' == $row['visible'] && '1' == $row['thread_visibility'] && '1' == $row['forum_visibility']) {
1734
                $return_array['last_post_id'] = $row['post_id'];
1735
                $return_array['last_poster_id'] = $row['poster_id'];
1736
                $return_array['last_post_date'] = $row['post_date'];
1737
                $return_array['last_poster_name'] = $row['poster_name'];
1738
                $return_array['last_poster_lastname'] = $row['lastname'];
1739
                $return_array['last_poster_firstname'] = $row['firstname'];
1740
                $return_array['last_post_title'] = $row['post_title'];
1741
                $return_array['last_post_text'] = $row['post_text'];
1742
1743
                return $return_array;
1744
            }
1745
        }
1746
    }
1747
}
1748
1749
/**
1750
 * Retrieve all the threads of a given forum.
1751
 *
1752
 * @param int|null $courseId  Optional If is null then it is considered the current course
1753
 * @param int|null $sessionId Optional. If is null then it is considered the current session
1754
 *
1755
 * @return CForumThread[]
1756
 */
1757
function get_threads($forumId, $courseId = null, $sessionId = null)
1758
{
1759
    $repo = Container::getForumThreadRepository();
1760
    $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
1761
    $course = api_get_course_entity($courseId);
1762
    $session = api_get_session_entity($sessionId);
1763
1764
    $qb = $repo->getResourcesByCourse($course, $session);
1765
1766
    $qb->andWhere('resource.forum = :forum')->setParameter('forum', $forumId);
1767
1768
    return $qb->getQuery()->getResult();
1769
1770
    $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...
1771
    $sessionId = null !== $sessionId ? (int) $sessionId : api_get_session_id();
1772
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1773
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1774
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
1775
1776
    $courseId = null !== $courseId ? (int) $courseId : api_get_course_int_id();
1777
    $groupInfo = GroupManager::get_group_properties($groupId);
1778
    $groupCondition = '';
1779
1780
    if (!empty($groupInfo)) {
1781
        $groupIid = $groupInfo['iid'];
1782
        $groupCondition = " AND item_properties.to_group_id = '$groupIid' ";
1783
    }
1784
1785
    $sessionCondition = api_get_session_condition(
1786
        $sessionId,
1787
        true,
1788
        false,
1789
        'item_properties.session_id'
1790
    );
1791
1792
    // important note:  it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
1793
    // because we also have thread.* in it. This is because thread has a field locked and post also has the same field
1794
    // since we are merging these we would have the post.locked value but in fact we want the thread.locked value
1795
    // This is why it is added to the end of the field selection
1796
    $sql = "SELECT DISTINCT
1797
                item_properties.*,
1798
                users.firstname,
1799
                users.lastname,
1800
                users.user_id,
1801
                thread.locked as locked,
1802
                thread.*
1803
            FROM $table_threads thread
1804
            INNER JOIN $table_item_property item_properties
1805
            ON
1806
                thread.thread_id = item_properties.ref AND
1807
                item_properties.c_id = thread.c_id AND
1808
                item_properties.tool = '".TABLE_FORUM_THREAD."'
1809
                $groupCondition
1810
                $sessionCondition
1811
            LEFT JOIN $table_users users
1812
                ON thread.thread_poster_id = users.user_id
1813
            WHERE
1814
                item_properties.visibility='1' AND
1815
                thread.forum_id = ".(int) $forum_id." AND
1816
                thread.c_id = $courseId
1817
            ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1818
1819
    if (api_is_allowed_to_edit()) {
1820
        $sql = "SELECT DISTINCT
1821
                    item_properties.*,
1822
                    users.firstname,
1823
                    users.lastname,
1824
                    users.user_id,
1825
                    thread.locked as locked,
1826
                    thread.*
1827
                FROM $table_threads thread
1828
                INNER JOIN $table_item_property item_properties
1829
                ON
1830
                    thread.thread_id = item_properties.ref AND
1831
                    item_properties.c_id = thread.c_id AND
1832
                    item_properties.tool = '".TABLE_FORUM_THREAD."'
1833
                    $groupCondition
1834
                    $sessionCondition
1835
                LEFT JOIN $table_users users
1836
                    ON thread.thread_poster_id=users.user_id
1837
                WHERE
1838
                    item_properties.visibility<>2 AND
1839
                    thread.forum_id = ".(int) $forum_id." AND
1840
                    thread.c_id = $courseId
1841
                ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1842
    }
1843
    $result = Database::query($sql);
1844
    $list = [];
1845
    $alreadyAdded = [];
1846
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1847
        if (in_array($row['thread_id'], $alreadyAdded)) {
1848
            continue;
1849
        }
1850
        $list[] = $row;
1851
        $alreadyAdded[] = $row['thread_id'];
1852
    }
1853
1854
    return $list;
1855
}
1856
1857
/**
1858
 * Get a thread by Id and course id.
1859
 *
1860
 * @param int $threadId the thread Id
1861
 * @param int $cId      the course id
1862
 *
1863
 * @return array containing all the information about the thread
1864
 */
1865
function getThreadInfo($threadId, $cId)
1866
{
1867
    $repo = Database::getManager()->getRepository(CForumThread::class);
1868
    /** @var CForumThread $forumThread */
1869
    $forumThread = $repo->findOneBy(['iid' => $threadId, 'cId' => $cId]);
1870
1871
    $thread = [];
1872
    if ($forumThread) {
1873
        $thread['iid'] = $forumThread->getIid();
1874
        $thread['threadId'] = $forumThread->getIid();
1875
        $thread['threadTitle'] = $forumThread->getThreadTitle();
1876
        $thread['forumId'] = $forumThread->getForum() ? $forumThread->getForum()->getIid() : 0;
1877
        $thread['sessionId'] = $forumThread->getSessionId();
1878
        $thread['threadSticky'] = $forumThread->getThreadSticky();
1879
        $thread['locked'] = $forumThread->getLocked();
1880
        $thread['threadTitleQualify'] = $forumThread->getThreadTitleQualify();
1881
        $thread['threadQualifyMax'] = $forumThread->getThreadQualifyMax();
1882
        $thread['threadCloseDate'] = $forumThread->getThreadCloseDate();
1883
        $thread['threadWeight'] = $forumThread->getThreadWeight();
1884
        $thread['threadPeerQualify'] = $forumThread->isThreadPeerQualify();
1885
    }
1886
1887
    return $thread;
1888
}
1889
1890
/**
1891
 * Retrieve all posts of a given thread.
1892
 *
1893
 * @param int    $threadId       The thread ID
1894
 * @param string $orderDirection Optional. The direction for sort the posts
1895
 * @param bool   $recursive      Optional. If the list is recursive
1896
 * @param int    $postId         Optional. The post ID for recursive list
1897
 * @param int    $depth          Optional. The depth to indicate the indent
1898
 *
1899
 * @todo move to a repository
1900
 *
1901
 * @return array containing all the information about the posts of a given thread
1902
 */
1903
function getPosts(
1904
    CForumForum $forum,
1905
    $threadId,
1906
    $orderDirection = 'ASC',
1907
    $recursive = false,
1908
    $postId = null,
1909
    $depth = -1
1910
) {
1911
    $em = Database::getManager();
1912
1913
    if (api_is_allowed_to_edit(false, true)) {
1914
        $visibleCriteria = Criteria::expr()->neq('visible', 2);
1915
    } else {
1916
        $visibleCriteria = Criteria::expr()->eq('visible', 1);
1917
    }
1918
1919
    $criteria = Criteria::create();
1920
    $criteria
1921
        ->where(Criteria::expr()->eq('thread', $threadId))
1922
        ->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
1923
        ->andWhere($visibleCriteria)
1924
    ;
1925
1926
    $groupId = api_get_group_id();
1927
    $groupInfo = GroupManager::get_group_properties($groupId);
1928
    $filterModerated = true;
1929
1930
    if (empty($groupId)) {
1931
        if (api_is_allowed_to_edit()) {
1932
            $filterModerated = false;
1933
        }
1934
    } else {
1935
        if (GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo) ||
1936
            api_is_allowed_to_edit(false, true)
1937
        ) {
1938
            $filterModerated = false;
1939
        }
1940
    }
1941
1942
    if ($recursive) {
1943
        $criteria->andWhere(Criteria::expr()->eq('postParentId', $postId));
1944
    }
1945
1946
    $qb = $em->getRepository(CForumPost::class)->createQueryBuilder('p');
1947
    $qb->select('p')
1948
        ->addCriteria($criteria)
1949
        ->addOrderBy('p.iid', $orderDirection);
1950
1951
    if ($filterModerated && 1 == $forum->isModerated()) {
1952
        if (!api_is_allowed_to_edit(false, true)) {
1953
            $userId = api_get_user_id();
1954
            $qb->andWhere(
1955
                'p.status = 1 OR
1956
                    (p.status = '.CForumPost::STATUS_WAITING_MODERATION." AND p.posterId = $userId) OR
1957
                    (p.status = ".CForumPost::STATUS_REJECTED." AND p.posterId = $userId) OR
1958
                    (p.status IS NULL AND p.posterId = $userId)
1959
                    "
1960
            );
1961
        }
1962
    }
1963
1964
    $posts = $qb->getQuery()->getResult();
1965
    $depth++;
1966
1967
    $list = [];
1968
    /** @var CForumPost $post */
1969
    foreach ($posts as $post) {
1970
        $postInfo = [
1971
            'iid' => $post->getIid(),
1972
            'c_id' => $post->getCId(),
1973
            'post_id' => $post->getIid(),
1974
            'post_title' => $post->getPostTitle(),
1975
            'post_text' => $post->getPostText(),
1976
            'thread_id' => $post->getThread() ? $post->getThread()->getIid() : 0,
1977
            'forum_id' => $post->getForum()->getIid(),
1978
            'poster_id' => $post->getPosterId(),
1979
            'poster_name' => $post->getPosterName(),
1980
            'post_date' => $post->getPostDate(),
1981
            'post_notification' => $post->getPostNotification(),
1982
            'post_parent_id' => $post->getPostParentId(),
1983
            'visible' => $post->getVisible(),
1984
            'status' => $post->getStatus(),
1985
            'indent_cnt' => $depth,
1986
            'entity' => $post,
1987
        ];
1988
1989
        $posterId = $post->getPosterId();
1990
        if (!empty($posterId)) {
1991
            $user = api_get_user_entity($posterId);
1992
            if ($user) {
1993
                $postInfo['user_id'] = $user->getId();
1994
                $postInfo['username'] = $user->getUsername();
1995
                $postInfo['username_canonical'] = $user->getUsernameCanonical();
1996
                $postInfo['lastname'] = $user->getLastname();
1997
                $postInfo['firstname'] = $user->getFirstname();
1998
                $postInfo['complete_name'] = UserManager::formatUserFullName($user);
1999
            }
2000
        }
2001
2002
        $list[] = $postInfo;
2003
2004
        if (!$recursive) {
2005
            continue;
2006
        }
2007
        $list = array_merge(
2008
            $list,
2009
            getPosts(
2010
                $forum,
2011
                $threadId,
2012
                $orderDirection,
2013
                $recursive,
2014
                $post->getIid(),
2015
                $depth
2016
            )
2017
        );
2018
    }
2019
2020
    return $list;
2021
}
2022
2023
/**
2024
 * This function retrieves forum thread users details.
2025
 *
2026
 * @param int $thread_id Thread ID
2027
 * @param   string  Course DB name (optional)
2028
 *
2029
 * @return Doctrine\DBAL\Driver\Statement|null array Array of type
2030
 *                                             ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2031
 *
2032
 * @author Christian Fasanando <[email protected]>,
2033
 *
2034
 * @todo     this function need to be improved
2035
 *
2036
 * @version octubre 2008, dokeos 1.8
2037
 */
2038
function get_thread_users_details($thread_id)
2039
{
2040
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2041
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2042
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2043
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2044
2045
    $course_id = api_get_course_int_id();
2046
2047
    $is_western_name_order = api_is_western_name_order();
2048
    if ($is_western_name_order) {
2049
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2050
    } else {
2051
        $orderby = 'ORDER BY user.lastname, user.firstname';
2052
    }
2053
2054
    if (api_get_session_id()) {
2055
        $session_info = api_get_session_info(api_get_session_id());
2056
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2057
        //not showing coaches
2058
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2059
                FROM $t_posts p, $t_users user, $t_session_rel_user session_rel_user_rel_course
2060
                WHERE
2061
                    p.poster_id = user.id AND
2062
                    user.id = session_rel_user_rel_course.user_id AND
2063
                    session_rel_user_rel_course.status<>'2' AND
2064
                    session_rel_user_rel_course.user_id NOT IN ($user_to_avoid) AND
2065
                    p.thread_id = ".(int) $thread_id.' AND
2066
                    session_id = '.api_get_session_id()." AND
2067
                    p.c_id = $course_id AND
2068
                    session_rel_user_rel_course.c_id = ".$course_id." $orderby ";
2069
    } else {
2070
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2071
                FROM $t_posts p, $t_users user, $t_course_user course_user
2072
                WHERE
2073
                    p.poster_id = user.id
2074
                    AND user.id = course_user.user_id
2075
                    AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
2076
                    AND p.thread_id = '.(int) $thread_id."
2077
                    AND course_user.status NOT IN('1') AND
2078
                    p.c_id = $course_id AND
2079
                    course_user.c_id = ".$course_id." $orderby";
2080
    }
2081
2082
    return Database::query($sql);
2083
}
2084
2085
/**
2086
 * This function retrieves forum thread users qualify.
2087
 *
2088
 * @param int $thread_id Thread ID
2089
 * @param   string  Course DB name (optional)
2090
 *
2091
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2092
 *
2093
 * @author Jhon Hinojosa
2094
 *
2095
 * @todo     this function need to be improved
2096
 */
2097
function get_thread_users_qualify($thread_id)
2098
{
2099
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2100
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2101
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2102
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2103
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2104
2105
    $course_id = api_get_course_int_id();
2106
    $sessionId = api_get_session_id();
2107
2108
    $is_western_name_order = api_is_western_name_order();
2109
    if ($is_western_name_order) {
2110
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2111
    } else {
2112
        $orderby = 'ORDER BY user.lastname, user.firstname';
2113
    }
2114
2115
    if ($sessionId) {
2116
        $session_info = api_get_session_info($sessionId);
2117
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2118
        //not showing coaches
2119
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2120
                FROM $t_posts post , $t_users user, $t_session_rel_user scu, $t_qualify qualify
2121
                WHERE poster_id = user.id
2122
                    AND post.poster_id = qualify.user_id
2123
                    AND user.id = scu.user_id
2124
                    AND scu.status<>'2'
2125
                    AND scu.user_id NOT IN ($user_to_avoid)
2126
                    AND qualify.thread_id = ".(int) $thread_id.'
2127
                    AND post.thread_id = '.(int) $thread_id."
2128
                    AND scu.session_id = $sessionId
2129
                    AND scu.c_id = ".$course_id." AND
2130
                    qualify.c_id = $course_id AND
2131
                    post.c_id = $course_id
2132
                $orderby ";
2133
    } else {
2134
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2135
                FROM $t_posts post,
2136
                     $t_qualify qualify,
2137
                     $t_users user,
2138
                     $t_course_user course_user
2139
                WHERE
2140
                     post.poster_id = user.id
2141
                     AND post.poster_id = qualify.user_id
2142
                     AND user.id = course_user.user_id
2143
                     AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
2144
                     AND qualify.thread_id = '.(int) $thread_id.'
2145
                     AND post.thread_id = '.(int) $thread_id."
2146
                     AND course_user.status not in('1')
2147
                     AND course_user.c_id = $course_id
2148
                     AND qualify.c_id = $course_id
2149
                     AND post.c_id = $course_id
2150
                 $orderby ";
2151
    }
2152
2153
    return Database::query($sql);
2154
}
2155
2156
/**
2157
 * This function retrieves forum thread users not qualify.
2158
 *
2159
 * @param int $thread_id Thread ID
2160
 * @param   string  Course DB name (optional)
2161
 *
2162
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2163
 *
2164
 * @author   Jhon Hinojosa<[email protected]>,
2165
 *
2166
 * @version oct 2008, dokeos 1.8
2167
 */
2168
function get_thread_users_not_qualify($thread_id)
2169
{
2170
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2171
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2172
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2173
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2174
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2175
2176
    $is_western_name_order = api_is_western_name_order();
2177
    if ($is_western_name_order) {
2178
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2179
    } else {
2180
        $orderby = 'ORDER BY user.lastname, user.firstname';
2181
    }
2182
2183
    $course_id = api_get_course_int_id();
2184
2185
    $sql1 = "SELECT user_id FROM  $t_qualify
2186
             WHERE c_id = $course_id AND thread_id = '".$thread_id."'";
2187
    $result1 = Database::query($sql1);
2188
    $cad = '';
2189
    while ($row = Database::fetch_array($result1)) {
2190
        $cad .= $row['user_id'].',';
2191
    }
2192
    if ('' == $cad) {
2193
        $cad = '0';
2194
    } else {
2195
        $cad = substr($cad, 0, strlen($cad) - 1);
2196
    }
2197
2198
    if (api_get_session_id()) {
2199
        $session_info = api_get_session_info(api_get_session_id());
2200
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2201
        //not showing coaches
2202
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2203
                FROM $t_posts post , $t_users user, $t_session_rel_user session_rel_user_rel_course
2204
                WHERE poster_id = user.id
2205
                    AND user.id NOT IN (".$cad.")
2206
                    AND user.id = session_rel_user_rel_course.user_id
2207
                    AND session_rel_user_rel_course.status<>'2'
2208
                    AND session_rel_user_rel_course.user_id NOT IN ($user_to_avoid)
2209
                    AND post.thread_id = ".(int) $thread_id.'
2210
                    AND session_id = '.api_get_session_id()."
2211
                    AND session_rel_user_rel_course.c_id = $course_id AND post.c_id = $course_id $orderby ";
2212
    } else {
2213
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2214
                FROM $t_posts post, $t_users user,$t_course_user course_user
2215
                WHERE post.poster_id = user.id
2216
                AND user.id NOT IN (".$cad.')
2217
                AND user.id = course_user.user_id
2218
                AND course_user.relation_type<>'.COURSE_RELATION_TYPE_RRHH.'
2219
                AND post.thread_id = '.(int) $thread_id."
2220
                AND course_user.status not in('1')
2221
                AND course_user.c_id = $course_id AND post.c_id = $course_id  $orderby";
2222
    }
2223
2224
    return Database::query($sql);
2225
}
2226
2227
/**
2228
 * This function retrieves all the information of a given forumcategory id.
2229
 *
2230
 * @param int $cat_id that indicates the forum
2231
 *
2232
 * @return array returns if there are category or bool returns if there aren't category
2233
 *
2234
 * @author Patrick Cool <[email protected]>, Ghent University
2235
 *
2236
 * @version february 2006, dokeos 1.8
2237
 */
2238
function get_forumcategory_information($cat_id)
2239
{
2240
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
2241
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2242
2243
    $course_id = api_get_course_int_id();
2244
    $sql = "SELECT *
2245
            FROM $table_categories forumcategories
2246
            INNER JOIN $table_item_property item_properties
2247
            ON (forumcategories.c_id = item_properties.c_id)
2248
            WHERE
2249
                forumcategories.c_id = $course_id AND
2250
                item_properties.c_id = $course_id AND
2251
                item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
2252
                item_properties.ref='".Database::escape_string($cat_id)."' AND
2253
                forumcategories.cat_id='".Database::escape_string($cat_id)."'";
2254
    $result = Database::query($sql);
2255
2256
    return Database::fetch_array($result);
2257
}
2258
2259
/**
2260
 * This function counts the number of forums inside a given category.
2261
 *
2262
 * @param int $cat_id the id of the forum category
2263
 *
2264
 * @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return
2265
 *       the number of visible forums, $countinvisible=1 would return the number of visible and invisible forums
2266
 *
2267
 * @return int the number of forums inside the given category
2268
 *
2269
 * @author Patrick Cool <[email protected]>, Ghent University
2270
 *
2271
 * @version february 2006, dokeos 1.8
2272
 */
2273
function count_number_of_forums_in_category($cat_id)
2274
{
2275
    $table_forums = Database::get_course_table(TABLE_FORUM);
2276
    $course_id = api_get_course_int_id();
2277
    $cat_id = (int) $cat_id;
2278
    $sql = "SELECT count(*) AS number_of_forums
2279
            FROM $table_forums
2280
            WHERE c_id = $course_id AND forum_category = $cat_id";
2281
    $result = Database::query($sql);
2282
    $row = Database::fetch_array($result);
2283
2284
    return $row['number_of_forums'];
2285
}
2286
2287
/**
2288
 * This function update a thread.
2289
 *
2290
 * @param array $values - The form Values
2291
 */
2292
function updateThread($values)
2293
{
2294
    if (!api_is_allowed_to_edit()) {
2295
        return '';
2296
    }
2297
2298
    $logInfo = [
2299
        'tool' => TOOL_FORUM,
2300
        'tool_id' => $values['forum_id'],
2301
        'tool_id_detail' => $values['thread_id'],
2302
        'action' => 'edit-thread',
2303
        'action_details' => 'thread',
2304
        'info' => $values['thread_title'],
2305
    ];
2306
    Event::registerLog($logInfo);
2307
2308
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
2309
    $courseId = api_get_course_int_id();
2310
    $courseCode = api_get_course_id();
2311
    $sessionId = api_get_session_id();
2312
2313
    // Simple update + set gradebook values to null
2314
    $params = [
2315
        'thread_title' => $values['thread_title'],
2316
        'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
2317
    ];
2318
    $where = ['c_id = ? AND iid = ?' => [$courseId, $values['thread_id']]];
2319
    Database::update($threadTable, $params, $where);
2320
2321
    $id = $values['thread_id'];
2322
    $linkInfo = GradebookUtils::isResourceInCourseGradebook(
2323
        $courseCode,
2324
        LINK_FORUM_THREAD,
2325
        $id,
2326
        $sessionId
2327
    );
2328
2329
    $gradebookLink = null;
2330
    $em = Database::getManager();
2331
    if (!empty($linkInfo) && isset($linkInfo['id'])) {
2332
        $gradebookLink = $em->getRepository(GradebookLink::class)->find($linkInfo['id']);
2333
    }
2334
2335
    // values 1 or 0
2336
    $check = isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : false;
2337
    if ($check) {
2338
        $title = Security::remove_XSS(stripslashes($values['calification_notebook_title']));
2339
        $value = isset($values['numeric_calification']) ? (int) ($values['numeric_calification']) : 0;
2340
        $weight = isset($values['weight_calification']) ? (float) ($values['weight_calification']) : 0;
2341
        $description = '';
2342
        // Update title
2343
        $params = [
2344
            'thread_title_qualify' => $values['calification_notebook_title'],
2345
            'thread_qualify_max' => api_float_val($values['numeric_calification']),
2346
            'thread_weight' => api_float_val($values['weight_calification']),
2347
            'thread_peer_qualify' => $values['thread_peer_qualify'],
2348
        ];
2349
        $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2350
        Database::update($threadTable, $params, $where);
2351
2352
        if (!$linkInfo) {
2353
            GradebookUtils::add_resource_to_course_gradebook(
2354
                $values['category_id'],
2355
                $courseCode,
2356
                LINK_FORUM_THREAD,
2357
                $id,
2358
                $title,
2359
                $weight,
2360
                $value,
2361
                $description,
2362
                1,
2363
                $sessionId
2364
            );
2365
        } else {
2366
            if ($gradebookLink) {
2367
                $gradebookLink->setWeight($weight);
2368
                $em->persist($gradebookLink);
2369
                $em->flush();
2370
            }
2371
        }
2372
    } else {
2373
        $params = [
2374
            'thread_title_qualify' => '',
2375
            'thread_qualify_max' => 0,
2376
            'thread_weight' => 0,
2377
            'thread_peer_qualify' => 0,
2378
        ];
2379
        $where = ['c_id = ? AND iid = ?' => [$courseId, $values['thread_id']]];
2380
        Database::update($threadTable, $params, $where);
2381
2382
        if (!empty($linkInfo)) {
2383
            if ($gradebookLink) {
2384
                $em->remove($gradebookLink);
2385
                $em->flush();
2386
            }
2387
        }
2388
    }
2389
2390
    $message = get_lang('The post has been modified').'<br />';
2391
    Display::addFlash(Display::return_message($message, 'confirmation', false));
2392
}
2393
2394
/**
2395
 * This function stores a new thread. This is done through an entry in the forum_thread table AND
2396
 * in the forum_post table because. The threads are also stored in the item_property table. (forum posts are not (yet)).
2397
 *
2398
 * @param bool $showMessage
2399
 * @param int  $userId      Optional. The user ID
2400
 * @param int  $sessionId
2401
 *
2402
 * @return CForumThread
2403
 *
2404
 * @author Patrick Cool <[email protected]>, Ghent University
2405
 *
2406
 * @version february 2006, dokeos 1.8
2407
 */
2408
function store_thread(
2409
    CForumForum $forum,
2410
    array $values,
2411
    array $courseInfo = [],
2412
    $showMessage = true,
2413
    $userId = 0,
2414
    $sessionId = 0
2415
) {
2416
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
2417
    $userId = $userId ?: api_get_user_id();
2418
    $course_id = $courseInfo['real_id'];
2419
    $courseCode = $courseInfo['code'];
2420
    $sessionId = $sessionId ?: api_get_session_id();
2421
2422
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2423
2424
    $post_date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
2425
    $visible = 1;
2426
    if ('1' == $forum->getApprovalDirectPost() && !api_is_allowed_to_edit(null, true)) {
2427
        $visible = 0; // The post has not been approved yet.
2428
    }
2429
    $clean_post_title = $values['post_title'];
2430
2431
    $user = api_get_user_entity(api_get_user_id());
2432
    $course = api_get_course_entity($course_id);
2433
    $session = api_get_session_entity($sessionId);
2434
2435
    // We first store an entry in the forum_thread table because the thread_id is used in the forum_post table.
2436
    $thread = new CForumThread();
2437
    $thread
2438
        ->setCId($course_id)
2439
        ->setThreadTitle($clean_post_title)
2440
        ->setForum($forum)
2441
        ->setThreadPosterId($userId)
2442
        ->setThreadPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2443
        ->setThreadDate($post_date)
2444
        ->setThreadSticky(isset($values['thread_sticky']) ? $values['thread_sticky'] : 0)
2445
        ->setThreadTitleQualify(
2446
            isset($values['calification_notebook_title']) ? $values['calification_notebook_title'] : null
2447
        )
2448
        ->setThreadQualifyMax(isset($values['numeric_calification']) ? (int) $values['numeric_calification'] : 0)
2449
        ->setThreadWeight(isset($values['weight_calification']) ? (int) $values['weight_calification'] : 0)
2450
        ->setThreadPeerQualify(isset($values['thread_peer_qualify']) ? (bool) $values['thread_peer_qualify'] : false)
2451
        ->setSessionId($sessionId)
2452
        ->setLpItemId(isset($values['lp_item_id']) ? (int) $values['lp_item_id'] : 0)
2453
        ->setParent($forum)
2454
        ->addCourseLink(
2455
            $course,
2456
            $session
2457
        )
2458
    ;
2459
2460
    $repo = Container::getForumThreadRepository();
2461
    $em = $repo->getEntityManager();
2462
    $em->persist($thread);
2463
    $em->flush();
2464
2465
    if (!$thread->getIid()) {
2466
        return null;
2467
    }
2468
2469
    // Add option gradebook qualify.
2470
    if (isset($values['thread_qualify_gradebook']) &&
2471
        1 == $values['thread_qualify_gradebook']
2472
    ) {
2473
        // Add function gradebook.
2474
        $resourcename = stripslashes($values['calification_notebook_title']);
2475
        GradebookUtils::add_resource_to_course_gradebook(
2476
            $values['category_id'],
2477
            $courseCode,
2478
            5,
2479
            $thread->getIid(),
2480
            $resourcename,
2481
            $values['weight_calification'],
2482
            $values['numeric_calification'],
2483
            '',
2484
            0,
2485
            $sessionId
2486
        );
2487
    }
2488
2489
    /*api_item_property_update(
2490
        $courseInfo,
2491
        TOOL_FORUM_THREAD,
2492
        $thread->getIid(),
2493
        'ForumThreadAdded',
2494
        $userId,
2495
        $groupInfo,
2496
        null,
2497
        null,
2498
        null,
2499
        $sessionId
2500
    );*/
2501
2502
    // If the forum properties tell that the posts have to be approved
2503
    // we have to put the whole thread invisible,
2504
    // because otherwise the students will see the thread and not the post
2505
    // in the thread.
2506
    // We also have to change $visible because the post itself has to be
2507
    // visible in this case (otherwise the teacher would have
2508
    // to make the thread visible AND the post.
2509
    // Default behaviour
2510
    /*api_set_default_visibility(
2511
        $thread->getIid(),
2512
        TOOL_FORUM_THREAD,
2513
        $groupId,
2514
        $courseInfo,
2515
        $sessionId,
2516
        $userId
2517
    );*/
2518
2519
    if (0 == $visible) {
2520
        /*api_item_property_update(
2521
            $courseInfo,
2522
            TOOL_FORUM_THREAD,
2523
            $thread->getIid(),
2524
            'invisible',
2525
            $userId,
2526
            $groupInfo
2527
        );*/
2528
        $visible = 1;
2529
    }
2530
2531
    $logInfo = [
2532
        'tool' => TOOL_FORUM,
2533
        'tool_id' => $values['forum_id'],
2534
        'tool_id_detail' => $thread->getIid(),
2535
        'action' => 'new-thread',
2536
        'info' => $clean_post_title,
2537
    ];
2538
    Event::registerLog($logInfo);
2539
2540
    // We now store the content in the table_post table.
2541
    $post = new CForumPost();
2542
    $post
2543
        ->setCId($course_id)
2544
        ->setPostTitle($clean_post_title)
2545
        ->setPostText($values['post_text'])
2546
        ->setThread($thread)
2547
        ->setForum($forum)
2548
        ->setPosterId($userId)
2549
        ->setPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2550
        ->setPostDate($post_date)
2551
        ->setPostNotification(isset($values['post_notification']) ? (int) $values['post_notification'] : null)
2552
        ->setVisible($visible)
2553
        ->setStatus(CForumPost::STATUS_VALIDATED)
2554
        ->setParent($thread)
2555
        ->addCourseLink(
2556
            $course,
2557
            $session
2558
        )
2559
    ;
2560
2561
    if ($forum->isModerated()) {
2562
        $post->setStatus(
2563
            api_is_course_admin() ? CForumPost::STATUS_VALIDATED : CForumPost::STATUS_WAITING_MODERATION
2564
        );
2565
    }
2566
2567
    $repo = Container::getForumPostRepository();
2568
    $em = $repo->getEntityManager();
2569
    $em->persist($post);
2570
    $em->flush();
2571
2572
    $postId = $post->getIid();
2573
    $thread->setThreadLastPost($postId);
2574
    $em->persist($thread);
2575
    $em->flush();
2576
2577
    $logInfo = [
2578
        'tool' => TOOL_FORUM,
2579
        'tool_id' => $values['forum_id'],
2580
        'tool_id_detail' => $thread->getIid(),
2581
        'action' => 'new-post',
2582
        'info' => $clean_post_title,
2583
    ];
2584
    Event::registerLog($logInfo);
2585
2586
    // Now we have to update the thread table to fill the thread_last_post
2587
    // field (so that we know when the thread has been updated for the last time).
2588
    $sql = "UPDATE $table_threads
2589
            SET thread_last_post = '".$postId."'
2590
            WHERE
2591
                c_id = $course_id AND
2592
                iid = '".$thread->getIid()."'";
2593
    Database::query($sql);
2594
    $message = get_lang('The new thread has been added');
2595
2596
    // Overwrite default message.
2597
    if ($forum->isModerated() &&
2598
        !api_is_allowed_to_edit(null, true)
2599
    ) {
2600
        $message = get_lang('Your message has to be approved before people can view it.');
2601
    }
2602
2603
    add_forum_attachment_file(
2604
        null,
2605
        $post
2606
    );
2607
2608
    if ('1' == $forum->getApprovalDirectPost() &&
2609
        !api_is_allowed_to_edit(null, true)
2610
    ) {
2611
        $message .= get_lang('Your message has to be approved before people can view it.').'<br />';
2612
        $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2613
            get_lang('Forum').'</a><br />';
2614
    } else {
2615
        $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2616
            get_lang('Forum').'</a><br />';
2617
        $message .= get_lang('You can now return to the').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&thread='.$thread->getIid().'">'.
2618
            get_lang('Message').'</a>';
2619
    }
2620
    $reply_info['new_post_id'] = $postId;
2621
    $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
2622
2623
    if (1 == $my_post_notification) {
2624
        set_notification('thread', $thread->getIid(), true);
2625
    }
2626
2627
    send_notification_mails(
2628
        $forum,
2629
        $thread,
2630
        $reply_info,
2631
        $courseInfo['code']
2632
    );
2633
2634
    Session::erase('formelements');
2635
    Session::erase('origin');
2636
    Session::erase('breadcrumbs');
2637
    Session::erase('addedresource');
2638
    Session::erase('addedresourceid');
2639
2640
    if ($showMessage) {
2641
        Display::addFlash(Display::return_message($message, 'success', false));
2642
    }
2643
2644
    return $thread;
2645
}
2646
2647
/**
2648
 * This function displays the form that is used to add a post. This can be a new thread or a reply.
2649
 *
2650
 * @param string $action
2651
 *                            is the parameter that determines if we are
2652
 *                            2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete
2653
 *                            thread (if enabled)
2654
 *                            3. replymessage: Replying to a message ($action =replymessage) => I-frame with the
2655
 *                            complete thread (if enabled)
2656
 *                            (I first thought to put and I-frame with the message only)
2657
 *                            4. quote: Quoting a message ($action= quotemessage) => I-frame with the complete thread
2658
 *                            (if enabled). The message will be in the reply. (I first thought not to put an I-frame
2659
 *                            here)
2660
 * @param array  $form_values
2661
 * @param bool   $showPreview
2662
 *
2663
 * @return FormValidator
2664
 */
2665
function show_add_post_form(CForumForum $forum, CForumThread $thread, CForumPost $post = null, $action, $form_values, $showPreview = true)
2666
{
2667
    $_user = api_get_user_info();
2668
    $action = isset($action) ? Security::remove_XSS($action) : '';
2669
    $threadId = $thread->getIid();
2670
    $forumId = $forum->getIid();
2671
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
2672
    $postId = $post ? $post->getIid() : 0;
2673
2674
    $url = api_get_self().'?'.http_build_query(
2675
        [
2676
            'action' => $action,
2677
            'forum' => $forumId,
2678
            'thread' => $threadId,
2679
            'post' => $postId,
2680
        ]
2681
    ).'&'.api_get_cidreq();
2682
2683
    $form = new FormValidator(
2684
        'thread',
2685
        'post',
2686
        $url
2687
    );
2688
    $form->setConstants(['forum' => '5']);
2689
2690
    // Setting the form elements.
2691
    $form->addElement('hidden', 'forum_id', $forumId);
2692
    $form->addElement('hidden', 'thread_id', $threadId);
2693
    $form->addElement('hidden', 'action', $action);
2694
2695
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2696
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2697
        $form->addElement('text', 'poster_name', get_lang('Name'));
2698
        $form->applyFilter('poster_name', 'html_filter');
2699
    }
2700
2701
    $form->addElement('text', 'post_title', get_lang('Title'));
2702
    $form->addHtmlEditor(
2703
        'post_text',
2704
        get_lang('Text'),
2705
        true,
2706
        false,
2707
        api_is_allowed_to_edit(null, true) ? [
2708
            'ToolbarSet' => 'Forum',
2709
            'Width' => '100%',
2710
            'Height' => '300',
2711
        ] : [
2712
            'ToolbarSet' => 'ForumStudent',
2713
            'Width' => '100%',
2714
            'Height' => '300',
2715
            'UserStatus' => 'student',
2716
        ]
2717
    );
2718
    $form->addRule('post_text', get_lang('Required field'), 'required');
2719
2720
    if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2721
        $extraFields = new ExtraField('forum_post');
2722
        $extraFields->addElements(
2723
            $form,
2724
            null,
2725
            [], //exclude
2726
            false, // filter
2727
            false, // tag as select
2728
            ['ask_for_revision'], //show only fields
2729
            [], // order fields
2730
            [] // extra data);
2731
        );
2732
    }
2733
2734
    $iframe = null;
2735
    if ($showPreview) {
2736
        if ('newthread' !== $action && !empty($threadId)) {
2737
            $iframe = '<iframe style="border: 1px solid black"
2738
            src="iframe_thread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId.'#'.$postId.'" width="100%"></iframe>';
2739
        }
2740
        if (!empty($iframe)) {
2741
            $form->addElement('label', get_lang('Thread'), $iframe);
2742
        }
2743
    }
2744
2745
    if (in_array($action, ['quote', 'replymessage'])) {
2746
        $form->addFile('user_upload[]', get_lang('Attachment'));
2747
        $form->addButton(
2748
            'add_attachment',
2749
            get_lang('Add attachment'),
2750
            'paperclip',
2751
            'default',
2752
            'default',
2753
            null,
2754
            ['id' => 'reply-add-attachment']
2755
        );
2756
    } else {
2757
        $form->addFile('user_upload', get_lang('Attachment'));
2758
    }
2759
2760
    if ($giveRevision) {
2761
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
2762
        $form->addHidden('give_revision', 1);
2763
        if (false === $hide) {
2764
            $extraField = new ExtraField('forum_post');
2765
            $extraField->addElements(
2766
                $form,
2767
                null,
2768
                [], //exclude
2769
                false, // filter
2770
                false, // tag as select
2771
                ['revision_language'], //show only fields
2772
                [], // order fields
2773
                [] // extra data
2774
            );
2775
        } else {
2776
            $form->addHidden('extra_revision_language', 1);
2777
        }
2778
    }
2779
2780
    // Setting the class and text of the form title and submit button.
2781
    if ('quote' === $action) {
2782
        $form->addButtonCreate(get_lang('Quote this message'), 'SubmitPost');
2783
    } elseif ('replythread' === $action) {
2784
        $form->addButtonCreate(get_lang('Reply to this thread'), 'SubmitPost');
2785
    } elseif ('replymessage' === $action) {
2786
        $form->addButtonCreate(get_lang('Reply to this message'), 'SubmitPost');
2787
    }
2788
2789
    $defaults['thread_peer_qualify'] = 0;
2790
    if (!empty($form_values)) {
2791
        $defaults['post_title'] = prepare4display($form_values['post_title']);
2792
        $defaults['post_text'] = prepare4display($form_values['post_text']);
2793
        $defaults['post_notification'] = (int) $form_values['post_notification'];
2794
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
2795
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
2796
    }
2797
2798
    // If we are quoting a message we have to retrieve the information of the post we are quoting so that
2799
    // we can add this as default to the textarea.
2800
    // We also need to put the parent_id of the post in a hidden form when
2801
    if (('quote' === $action || 'replymessage' === $action || $giveRevision) && !empty($postId)) {
2802
        // we are quoting or replying to a message (<> reply to a thread !!!)
2803
        $form->addHidden('post_parent_id', $post->getIid());
2804
        // If we are replying or are quoting then we display a default title.
2805
        $posterInfo = api_get_user_info($post->getPosterId());
2806
        $posterName = '';
2807
        if ($posterInfo) {
2808
            $posterName = $posterInfo['complete_name'];
2809
        }
2810
        $defaults['post_title'] = get_lang('Re:').api_html_entity_decode($post->getPostTitle(), ENT_QUOTES);
2811
        // When we are quoting a message then we have to put that message into the wysiwyg editor.
2812
        // Note: The style has to be hardcoded here because using class="quote" didn't work.
2813
        if ('quote' === $action) {
2814
            $defaults['post_text'] = '<div>&nbsp;</div>
2815
                <div style="margin: 5px;">
2816
                    <div style="font-size: 90%; font-style: italic;">'.
2817
                get_lang('Quoting').' '.$posterName.':</div>
2818
                        <div style="color: #006600; font-size: 90%;  font-style: italic; background-color: #FAFAFA; border: #D1D7DC 1px solid; padding: 3px;">'.
2819
                prepare4display($post->getPostText()).'
2820
                        </div>
2821
                    </div>
2822
                <div>&nbsp;</div>
2823
                <div>&nbsp;</div>
2824
            ';
2825
        }
2826
        if ($giveRevision) {
2827
            $defaults['post_text'] = prepare4display($post->getPostText());
2828
        }
2829
    }
2830
2831
    $form->setDefaults(isset($defaults) ? $defaults : []);
2832
2833
    // The course admin can make a thread sticky (=appears with special icon and always on top).
2834
    $form->addRule('post_title', get_lang('Required field'), 'required');
2835
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2836
        $form->addRule(
2837
            'poster_name',
2838
            get_lang('Required field'),
2839
            'required'
2840
        );
2841
    }
2842
2843
    // Validation or display
2844
    if ($form->validate()) {
2845
        $check = Security::check_token('post');
2846
        if ($check) {
2847
            $values = $form->getSubmitValues();
2848
            if (isset($values['thread_qualify_gradebook']) &&
2849
                '1' == $values['thread_qualify_gradebook'] &&
2850
                empty($values['weight_calification'])
2851
            ) {
2852
                Display::addFlash(
2853
                    Display::return_message(
2854
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
2855
                        'error',
2856
                        false
2857
                    )
2858
                );
2859
2860
                return false;
2861
            }
2862
2863
            $postId = 0;
2864
            $threadId = 0;
2865
2866
            switch ($action) {
2867
                case 'quote':
2868
                case 'replythread':
2869
                case 'replymessage':
2870
                    $postId = store_reply($forum, $thread, $values);
2871
2872
                    break;
2873
            }
2874
2875
            if ($postId) {
2876
                if (isset($values['give_revision']) && 1 == $values['give_revision']) {
2877
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2878
                    $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
2879
                    $params = [
2880
                        'item_id' => $postId,
2881
                        'extra_revision_language' => $revisionLanguage,
2882
                    ];
2883
2884
                    $extraFieldValues->saveFieldValues(
2885
                        $params,
2886
                        false,
2887
                        false,
2888
                        ['revision_language']
2889
                    );
2890
                }
2891
2892
                if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2893
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2894
                    $params = [
2895
                        'item_id' => $postId,
2896
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
2897
                    ];
2898
                    $extraFieldValues->saveFieldValues(
2899
                        $params,
2900
                        false,
2901
                        false,
2902
                        ['ask_for_revision']
2903
                    );
2904
                }
2905
            }
2906
2907
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
2908
                [
2909
                    'forum' => $forumId,
2910
                    'thread' => $thread->getIid(),
2911
                ]
2912
            );
2913
2914
            Security::clear_token();
2915
            header('Location: '.$url);
2916
            exit;
2917
        }
2918
    } else {
2919
        $token = Security::get_token();
2920
        $form->addElement('hidden', 'sec_token');
2921
        $form->setConstants(['sec_token' => $token]);
2922
2923
        // Delete from $_SESSION forum attachment from other posts
2924
        // and keep only attachments for new post
2925
        clearAttachedFiles(FORUM_NEW_POST);
2926
        // Get forum attachment ajax table to add it to form
2927
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
2928
        $ajaxHtml = $attachmentAjaxTable;
2929
        $form->addElement('html', $ajaxHtml);
2930
2931
        return $form;
2932
    }
2933
}
2934
2935
function newThread(CForumForum $forum, $form_values = '', $showPreview = true)
2936
{
2937
    $_user = api_get_user_info();
2938
    $forumId = $forum->getIid();
2939
    $my_post = isset($_GET['post']) ? (int) $_GET['post'] : '';
2940
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
2941
    $action = 'new_thread';
2942
2943
    $url = api_get_self().'?'.http_build_query(
2944
            [
2945
                'action' => $action,
2946
                'forum' => $forumId,
2947
                'post' => $my_post,
2948
            ]
2949
        ).'&'.api_get_cidreq();
2950
2951
    $form = new FormValidator(
2952
        'thread',
2953
        'post',
2954
        $url
2955
    );
2956
2957
    // Setting the form elements.
2958
    $form->addElement('hidden', 'forum_id', $forumId);
2959
    $form->addElement('hidden', 'thread_id', 0);
2960
    $form->addElement('hidden', 'action', $action);
2961
2962
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2963
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2964
        $form->addElement('text', 'poster_name', get_lang('Name'));
2965
        $form->applyFilter('poster_name', 'html_filter');
2966
    }
2967
2968
    $form->addElement('text', 'post_title', get_lang('Title'));
2969
    $form->addHtmlEditor(
2970
        'post_text',
2971
        get_lang('Text'),
2972
        true,
2973
        false,
2974
        api_is_allowed_to_edit(null, true) ? [
2975
            'ToolbarSet' => 'Forum',
2976
            'Width' => '100%',
2977
            'Height' => '300',
2978
        ] : [
2979
            'ToolbarSet' => 'ForumStudent',
2980
            'Width' => '100%',
2981
            'Height' => '300',
2982
            'UserStatus' => 'student',
2983
        ]
2984
    );
2985
    $form->addRule('post_text', get_lang('Required field'), 'required');
2986
2987
    $extraFields = new ExtraField('forum_post');
2988
    $extraFields->addElements(
2989
        $form,
2990
        null,
2991
        [], //exclude
2992
        false, // filter
2993
        false, // tag as select
2994
        ['ask_for_revision'], //show only fields
2995
        [], // order fields
2996
        [] // extra data);
2997
    );
2998
2999
    if (Gradebook::is_active() &&
3000
        (api_is_course_admin() || api_is_session_general_coach() || api_is_course_tutor())
3001
    ) {
3002
        $form->addElement('advanced_settings', 'advanced_params', get_lang('Advanced settings'));
3003
        $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3004
3005
        // Thread qualify
3006
        if (Gradebook::is_active()) {
3007
            //Loading gradebook select
3008
            GradebookUtils::load_gradebook_select_in_tool($form);
3009
            $form->addElement(
3010
                'checkbox',
3011
                'thread_qualify_gradebook',
3012
                '',
3013
                get_lang('Grade this thread'),
3014
                'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"'
3015
            );
3016
        } else {
3017
            $form->addElement('hidden', 'thread_qualify_gradebook', false);
3018
        }
3019
3020
        $form->addElement('html', '<div id="options_field" style="display:none">');
3021
        $form->addElement('text', 'numeric_calification', get_lang('Maximum score'));
3022
        $form->applyFilter('numeric_calification', 'html_filter');
3023
        $form->addElement('text', 'calification_notebook_title', get_lang('Column header in Competences Report'));
3024
        $form->applyFilter('calification_notebook_title', 'html_filter');
3025
3026
        $form->addElement(
3027
            'text',
3028
            'weight_calification',
3029
            get_lang('Weight in Report'),
3030
            ['value' => '0.00', 'onfocus' => 'javascript: this.select();']
3031
        );
3032
        $form->applyFilter('weight_calification', 'html_filter');
3033
3034
        $group = [];
3035
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('Yes'), 1);
3036
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('No'), 0);
3037
        $form->addGroup(
3038
            $group,
3039
            '',
3040
            [
3041
                get_lang('Thread scored by peers'),
3042
                get_lang('Thread scored by peersComment'),
3043
            ]
3044
        );
3045
        $form->addElement('html', '</div>');
3046
        $form->addElement('html', '</div>');
3047
    }
3048
3049
    Skill::addSkillsToForm($form, ITEM_TYPE_FORUM_THREAD, 0);
3050
    $form->addElement('checkbox', 'thread_sticky', '', get_lang('This is a sticky message (appears always on top and has a special sticky icon)'));
3051
3052
    $form->addFile('user_upload', get_lang('Attachment'));
3053
3054
    if ($giveRevision) {
3055
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
3056
        $form->addHidden('give_revision', 1);
3057
        if (false === $hide) {
3058
            $extraField = new ExtraField('forum_post');
3059
            $extraField->addElements(
3060
                $form,
3061
                null,
3062
                [], //exclude
3063
                false, // filter
3064
                false, // tag as select
3065
                ['revision_language'], //show only fields
3066
                [], // order fields
3067
                [] // extra data
3068
            );
3069
        } else {
3070
            $form->addHidden('extra_revision_language', 1);
3071
        }
3072
    }
3073
    $form->addButtonCreate(get_lang('Create thread'), 'SubmitPost');
3074
3075
    $defaults['thread_peer_qualify'] = 0;
3076
    if (!empty($form_values)) {
3077
        $defaults['post_title'] = prepare4display($form_values['post_title']);
3078
        $defaults['post_text'] = prepare4display($form_values['post_text']);
3079
        $defaults['post_notification'] = (int) $form_values['post_notification'];
3080
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
3081
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
3082
    }
3083
3084
    $form->setDefaults(isset($defaults) ? $defaults : []);
3085
3086
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3087
    $form->addRule('post_title', get_lang('Required field'), 'required');
3088
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
3089
        $form->addRule(
3090
            'poster_name',
3091
            get_lang('Required field'),
3092
            'required'
3093
        );
3094
    }
3095
3096
    // Validation or display
3097
    if ($form->validate()) {
3098
        $check = Security::check_token('post');
3099
        if ($check) {
3100
            $values = $form->getSubmitValues();
3101
            if (isset($values['thread_qualify_gradebook']) &&
3102
                '1' == $values['thread_qualify_gradebook'] &&
3103
                empty($values['weight_calification'])
3104
            ) {
3105
                Display::addFlash(
3106
                    Display::return_message(
3107
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
3108
                        'error',
3109
                        false
3110
                    )
3111
                );
3112
3113
                return false;
3114
            }
3115
3116
            $newThread = store_thread($forum, $values);
3117
            if ($newThread) {
3118
                Skill::saveSkills($form, ITEM_TYPE_FORUM_THREAD, $newThread->getIid());
3119
                $postId = $newThread->getThreadLastPost();
3120
3121
                if ($postId) {
3122
                    if (isset($values['give_revision']) && 1 == $values['give_revision']) {
3123
                        $extraFieldValues = new ExtraFieldValue('forum_post');
3124
                        $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
3125
3126
                        $params = [
3127
                            'item_id' => $postId,
3128
                            'extra_revision_language' => $revisionLanguage,
3129
                        ];
3130
3131
                        $extraFieldValues->saveFieldValues(
3132
                            $params,
3133
                            false,
3134
                            false,
3135
                            ['revision_language']
3136
                        );
3137
                    }
3138
                    $extraFieldValues = new ExtraFieldValue('forum_post');
3139
                    $params = [
3140
                        'item_id' => $postId,
3141
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
3142
                    ];
3143
                    $extraFieldValues->saveFieldValues(
3144
                        $params,
3145
                        false,
3146
                        false,
3147
                        ['ask_for_revision']
3148
                    );
3149
                }
3150
            }
3151
3152
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
3153
                [
3154
                    'forum' => $forumId,
3155
                    'thread' => $newThread->getIid(),
3156
                ]
3157
            );
3158
3159
            Security::clear_token();
3160
            header('Location: '.$url);
3161
            exit;
3162
        }
3163
    } else {
3164
        $token = Security::get_token();
3165
        $form->addElement('hidden', 'sec_token');
3166
        $form->setConstants(['sec_token' => $token]);
3167
3168
        // Delete from $_SESSION forum attachment from other posts
3169
        // and keep only attachments for new post
3170
        clearAttachedFiles(FORUM_NEW_POST);
3171
        // Get forum attachment ajax table to add it to form
3172
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
3173
        $ajaxHtml = $attachmentAjaxTable;
3174
        $form->addElement('html', $ajaxHtml);
3175
3176
        return $form;
3177
    }
3178
}
3179
3180
/**
3181
 * @param CForumThread $threadInfo
3182
 * @param int          $user_id
3183
 * @param int          $thread_id
3184
 * @param int          $thread_qualify
3185
 * @param int          $qualify_time
3186
 * @param int          $session_id
3187
 *
3188
 * @return array optional
3189
 *
3190
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3191
 *
3192
 * @version October 2008, dokeos  1.8.6
3193
 */
3194
function saveThreadScore(
3195
    CForumThread $threadEntity,
3196
    $user_id,
3197
    $thread_id,
3198
    $thread_qualify = 0,
3199
    $qualify_time,
3200
    $session_id = 0
3201
) {
3202
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3203
3204
    $course_id = api_get_course_int_id();
3205
    $session_id = (int) $session_id;
3206
    $currentUserId = api_get_user_id();
3207
3208
    if ($user_id == (string) ((int) $user_id) &&
3209
        $thread_id == (string) ((int) $thread_id) &&
3210
        $thread_qualify == (string) ((float) $thread_qualify)
3211
    ) {
3212
        $max = $threadEntity->getThreadQualifyMax();
3213
        if ($thread_qualify <= $max) {
3214
            if ($threadEntity->isThreadPeerQualify()) {
3215
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3216
                        WHERE
3217
                            c_id = $course_id AND
3218
                            user_id = $user_id AND
3219
                            qualify_user_id = $currentUserId AND
3220
                            thread_id = ".$thread_id;
3221
            } else {
3222
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3223
                        WHERE
3224
                            c_id = $course_id AND
3225
                            user_id = $user_id AND
3226
                            thread_id = ".$thread_id;
3227
            }
3228
3229
            $result = Database::query($sql);
3230
            $row = Database::fetch_array($result);
3231
3232
            if (0 == $row[0]) {
3233
                $sql = "INSERT INTO $table_threads_qualify (c_id, user_id, thread_id,qualify,qualify_user_id,qualify_time,session_id)
3234
                        VALUES (".$course_id.", '".$user_id."','".$thread_id."',".(float) $thread_qualify.", '".$currentUserId."','".$qualify_time."','".$session_id."')";
3235
                Database::query($sql);
3236
3237
                return 'insert';
3238
            } else {
3239
                saveThreadScoreHistory(
3240
                    '1',
3241
                    $course_id,
3242
                    $user_id,
3243
                    $thread_id
3244
                );
3245
3246
                // Update
3247
                $sql = "UPDATE $table_threads_qualify
3248
                        SET
3249
                            qualify = '".$thread_qualify."',
3250
                            qualify_time = '".$qualify_time."'
3251
                        WHERE
3252
                            c_id = $course_id AND
3253
                            user_id=".$user_id.' AND
3254
                            thread_id='.$thread_id." AND
3255
                            qualify_user_id = $currentUserId
3256
                        ";
3257
                Database::query($sql);
3258
3259
                return 'update';
3260
            }
3261
        } else {
3262
            return null;
3263
        }
3264
    }
3265
}
3266
3267
/**
3268
 * This function shows qualify.
3269
 *
3270
 * @param string $option    contains the information of option to run
3271
 * @param int    $user_id   contains the information the current user id
3272
 * @param int    $thread_id contains the information the current thread id
3273
 *
3274
 * @return int qualify
3275
 *             <code> $option=1 obtained the qualification of the current thread</code>
3276
 *
3277
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3278
 *
3279
 * @version October 2008, dokeos  1.8.6
3280
 */
3281
function showQualify($option, $user_id, $thread_id)
3282
{
3283
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3284
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3285
3286
    $course_id = api_get_course_int_id();
3287
    $user_id = (int) $user_id;
3288
    $thread_id = (int) $thread_id;
3289
3290
    if (empty($user_id) || empty($thread_id)) {
3291
        return false;
3292
    }
3293
3294
    $sql = '';
3295
    switch ($option) {
3296
        case 1:
3297
            $sql = "SELECT qualify FROM $table_threads_qualify
3298
                    WHERE
3299
                        c_id = $course_id AND
3300
                        user_id=".$user_id.' AND
3301
                        thread_id='.$thread_id;
3302
3303
            break;
3304
        case 2:
3305
            $sql = "SELECT thread_qualify_max FROM $table_threads
3306
                    WHERE c_id = $course_id AND thread_id=".$thread_id;
3307
3308
            break;
3309
    }
3310
3311
    if (!empty($sql)) {
3312
        $rs = Database::query($sql);
3313
        $row = Database::fetch_array($rs);
3314
3315
        return $row[0];
3316
    }
3317
3318
    return [];
3319
}
3320
3321
/**
3322
 * This function gets qualify historical.
3323
 *
3324
 * @param int  $user_id   contains the information the current user id
3325
 * @param int  $thread_id contains the information the current thread id
3326
 * @param bool $opt       contains the information of option to run
3327
 *
3328
 * @return array
3329
 *
3330
 * @author Christian Fasanando <[email protected]>,
3331
 * @author Isaac Flores <[email protected]>,
3332
 *
3333
 * @version October 2008, dokeos  1.8.6
3334
 */
3335
function getThreadScoreHistory($user_id, $thread_id, $opt)
3336
{
3337
    $user_id = (int) $user_id;
3338
    $thread_id = (int) $thread_id;
3339
3340
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3341
    $course_id = api_get_course_int_id();
3342
3343
    if ('false' == $opt) {
3344
        $sql = "SELECT * FROM $table_threads_qualify_log
3345
                WHERE
3346
                    c_id = $course_id AND
3347
                    thread_id='".$thread_id."' AND
3348
                    user_id='".$user_id."'
3349
                ORDER BY qualify_time";
3350
    } else {
3351
        $sql = "SELECT * FROM $table_threads_qualify_log
3352
                WHERE
3353
                    c_id = $course_id AND
3354
                    thread_id='".$thread_id."' AND
3355
                    user_id='".$user_id."'
3356
                ORDER BY qualify_time DESC";
3357
    }
3358
    $rs = Database::query($sql);
3359
    $log = [];
3360
    while ($row = Database::fetch_array($rs, 'ASSOC')) {
3361
        $log[] = $row;
3362
    }
3363
3364
    return $log;
3365
}
3366
3367
/**
3368
 * This function stores qualify historical.
3369
 *
3370
 * @param bool contains the information of option to run
3371
 * @param string contains the information the current course id
3372
 * @param int contains the information the current forum id
3373
 * @param int contains the information the current user id
3374
 * @param int contains the information the current thread id
3375
 * @param int contains the information the current qualify
3376
 * @param string $option
3377
 * @param int    $course_id
3378
 * @param int    $user_id
3379
 * @param int    $thread_id
3380
 *
3381
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3382
 *
3383
 * @version October 2008, dokeos  1.8.6
3384
 */
3385
function saveThreadScoreHistory(
3386
    $option,
3387
    $course_id,
3388
    $user_id,
3389
    $thread_id
3390
) {
3391
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3392
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3393
3394
    $course_id = (int) $course_id;
3395
    $qualify_user_id = api_get_user_id();
3396
3397
    if ($user_id == (string) ((int) $user_id) &&
3398
        $thread_id == (string) ((int) $thread_id) && 1 == $option
3399
    ) {
3400
        // Extract information of thread_qualify.
3401
        $sql = "SELECT qualify, qualify_time
3402
                FROM $table_threads_qualify
3403
                WHERE
3404
                    c_id = $course_id AND
3405
                    user_id = ".$user_id.' AND
3406
                    thread_id = '.$thread_id." AND
3407
                    qualify_user_id = $qualify_user_id
3408
                ";
3409
        $rs = Database::query($sql);
3410
        $row = Database::fetch_array($rs);
3411
3412
        // Insert thread_historical.
3413
        $sql = "INSERT INTO $table_threads_qualify_log (c_id, user_id, thread_id, qualify, qualify_user_id,qualify_time,session_id)
3414
                VALUES(".$course_id.", '".$user_id."','".$thread_id."',".(float) $row[0].", '".$qualify_user_id."','".$row[1]."','')";
3415
        Database::query($sql);
3416
    }
3417
}
3418
3419
/**
3420
 * This function shows current thread qualify .
3421
 *
3422
 * @param int $threadId
3423
 * @param int $sessionId
3424
 * @param int $userId
3425
 *
3426
 * @return array or null if is empty
3427
 *
3428
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3429
 *
3430
 * @version December 2008, dokeos  1.8.6
3431
 */
3432
function current_qualify_of_thread($threadId, $sessionId, $userId)
3433
{
3434
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3435
3436
    $course_id = api_get_course_int_id();
3437
    $currentUserId = api_get_user_id();
3438
    $sessionId = (int) $sessionId;
3439
    $threadId = (int) $threadId;
3440
3441
    $sql = "SELECT qualify FROM $table_threads_qualify
3442
            WHERE
3443
                c_id = $course_id AND
3444
                thread_id = $threadId AND
3445
                session_id = $sessionId AND
3446
                qualify_user_id = $currentUserId AND
3447
                user_id = $userId
3448
            ";
3449
    $res = Database::query($sql);
3450
    $row = Database::fetch_array($res, 'ASSOC');
3451
3452
    return $row['qualify'];
3453
}
3454
3455
/**
3456
 * This function stores a reply in the forum_post table.
3457
 * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date).
3458
 *
3459
 * @param array $values
3460
 * @param int   $courseId Optional
3461
 * @param int   $userId   Optional
3462
 *
3463
 * @return int post id
3464
 */
3465
function store_reply(CForumForum $forum, CForumThread $thread, $values, $courseId = 0, $userId = 0)
3466
{
3467
    $courseId = !empty($courseId) ? $courseId : api_get_course_int_id();
3468
    $_course = api_get_course_info_by_id($courseId);
3469
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3470
    $post_date = api_get_utc_datetime();
3471
    $userId = $userId ?: api_get_user_id();
3472
3473
    if (1 == $forum->getAllowAnonymous()) {
3474
        if (api_is_anonymous() && empty($userId)) {
3475
            $userId = api_get_anonymous_id();
3476
        }
3477
    }
3478
3479
    if (empty($userId)) {
3480
        return false;
3481
    }
3482
3483
    $visible = 1;
3484
    if ('1' == $forum->getApprovalDirectPost() &&
3485
        !api_is_allowed_to_edit(null, true)
3486
    ) {
3487
        $visible = 0;
3488
    }
3489
3490
    $upload_ok = 1;
3491
    $new_post_id = 0;
3492
3493
    if ($upload_ok) {
3494
        $course = api_get_course_entity($courseId);
3495
        $session = api_get_session_entity();
3496
3497
        $post = new CForumPost();
3498
        $post
3499
            ->setCId($courseId)
3500
            ->setPostTitle($values['post_title'])
3501
            ->setPostText(isset($values['post_text']) ?: null)
3502
            ->setThread($thread)
3503
            ->setForum($forum)
3504
            ->setPosterId($userId)
3505
            ->setPostNotification(isset($values['post_notification']) ? $values['post_notification'] : null)
3506
            ->setPostParentId(isset($values['post_parent_id']) ? $values['post_parent_id'] : null)
3507
            ->setVisible($visible)
3508
            ->setPostDate(api_get_utc_datetime(null, false, true))
3509
            ->setParent($thread)
3510
            ->addCourseLink(
3511
                $course,
3512
                $session
3513
            );
3514
3515
        $repo = Container::getForumPostRepository();
3516
        $em = $repo->getEntityManager();
3517
        $em->persist($post);
3518
        $em->flush();
3519
3520
        $new_post_id = $post->getIid();
3521
        if ($new_post_id) {
3522
            $values['new_post_id'] = $new_post_id;
3523
            $message = get_lang('The reply has been added');
3524
3525
            if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3526
                foreach ($_POST['file_ids'] as $key => $id) {
3527
                    editAttachedFile(
3528
                        [
3529
                            'comment' => $_POST['file_comments'][$key],
3530
                            'post_id' => $new_post_id,
3531
                        ],
3532
                        $id
3533
                    );
3534
                }
3535
            }
3536
3537
            // Update the thread.
3538
            updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
3539
3540
            // Update the forum.
3541
            /*api_item_property_update(
3542
                $_course,
3543
                TOOL_FORUM,
3544
                $values['forum_id'],
3545
                'NewMessageInForum',
3546
                $userId
3547
            );
3548
3549
            // Insert post
3550
            api_item_property_update(
3551
                $_course,
3552
                TOOL_FORUM_POST,
3553
                $new_post_id,
3554
                'NewPost',
3555
                $userId
3556
            );*/
3557
3558
            if ('1' == $forum->getApprovalDirectPost() &&
3559
                !api_is_allowed_to_edit(null, true)
3560
            ) {
3561
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
3562
            }
3563
3564
            if ($forum->isModerated() &&
3565
                !api_is_allowed_to_edit(null, true)
3566
            ) {
3567
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
3568
            }
3569
3570
            // Setting the notification correctly.
3571
            $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
3572
            if (1 == $my_post_notification) {
3573
                set_notification('thread', $values['thread_id'], true);
3574
            }
3575
3576
            send_notification_mails(
3577
                $forum,
3578
                $thread,
3579
                $values
3580
            );
3581
            add_forum_attachment_file('', $post);
3582
3583
            $logInfo = [
3584
                'tool' => TOOL_FORUM,
3585
                'tool_id' => $values['forum_id'],
3586
                'tool_id_detail' => $values['thread_id'],
3587
                'action' => 'new-post',
3588
                'action_details' => $values['action'],
3589
                'info' => $values['post_title'],
3590
            ];
3591
            Event::registerLog($logInfo);
3592
        }
3593
3594
        Session::erase('formelements');
3595
        Session::erase('origin');
3596
        Session::erase('breadcrumbs');
3597
        Session::erase('addedresource');
3598
        Session::erase('addedresourceid');
3599
3600
        Display::addFlash(Display::return_message($message, 'confirmation', false));
3601
    } else {
3602
        Display::addFlash(
3603
            Display::return_message(
3604
                get_lang('No file was uploaded.').' '.get_lang('Please select a file before pressing the upload button.'),
3605
                'error'
3606
            )
3607
        );
3608
    }
3609
3610
    return $new_post_id;
3611
}
3612
3613
/**
3614
 * This function displays the form that is used to edit a post. This can be a new thread or a reply.
3615
 *
3616
 * @param CForumPost   $post        contains all the information about the current post
3617
 * @param CForumThread $thread      contains all the information about the current thread
3618
 * @param CForumForum  $forum       contains all info about the current forum (to check if attachments are allowed)
3619
 * @param array        $form_values contains the default values to fill the form
3620
 *
3621
 * @author Patrick Cool <[email protected]>, Ghent University
3622
 *
3623
 * @version february 2006, dokeos 1.8
3624
 */
3625
function show_edit_post_form(
3626
    $post,
3627
    $thread,
3628
    $forum,
3629
    $form_values,
3630
    $id_attach = 0
3631
) {
3632
    // Initialize the object.
3633
    $form = new FormValidator(
3634
        'edit_post',
3635
        'post',
3636
        api_get_self().'?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&post='.(int) ($_GET['post'])
3637
    );
3638
    $form->addElement('header', get_lang('Edit a post'));
3639
    // Setting the form elements.
3640
    $form->addElement('hidden', 'post_id', $post->getIid());
3641
    $form->addElement('hidden', 'thread_id', $thread->getIid());
3642
    $form->addElement('hidden', 'id_attach', $id_attach);
3643
3644
    if (empty($post->getPostParentId())) {
3645
        $form->addElement('hidden', 'is_first_post_of_thread', '1');
3646
    }
3647
3648
    $form->addElement('text', 'post_title', get_lang('Title'));
3649
    $form->applyFilter('post_title', 'html_filter');
3650
    $form->addElement(
3651
        'html_editor',
3652
        'post_text',
3653
        get_lang('Text'),
3654
        null,
3655
        api_is_allowed_to_edit(null, true) ? [
3656
            'ToolbarSet' => 'Forum',
3657
            'Width' => '100%',
3658
            'Height' => '400',
3659
        ] : [
3660
            'ToolbarSet' => 'ForumStudent',
3661
            'Width' => '100%',
3662
            'Height' => '400',
3663
            'UserStatus' => 'student',
3664
        ]
3665
    );
3666
    $form->addRule('post_text', get_lang('Required field'), 'required');
3667
3668
    $extraFields = new ExtraField('forum_post');
3669
    $extraFields->addElements($form, $post->getIid());
3670
3671
    $form->addButtonAdvancedSettings('advanced_params');
3672
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3673
3674
    if ($forum->isModerated() && api_is_allowed_to_edit(null, true)) {
3675
        $group = [];
3676
        $group[] = $form->createElement(
3677
            'radio',
3678
            'status',
3679
            null,
3680
            get_lang('Validated'),
3681
            1
3682
        );
3683
        $group[] = $form->createElement(
3684
            'radio',
3685
            'status',
3686
            null,
3687
            get_lang('Waiting for moderation'),
3688
            2
3689
        );
3690
        $group[] = $form->createElement(
3691
            'radio',
3692
            'status',
3693
            null,
3694
            get_lang('Rejected'),
3695
            3
3696
        );
3697
        $form->addGroup($group, 'status', get_lang('Status'));
3698
    }
3699
3700
    $defaults['status']['status'] = $post->getStatus();
3701
3702
    $form->addElement(
3703
        'checkbox',
3704
        'post_notification',
3705
        '',
3706
        get_lang('Notify me by e-mail when somebody replies')
3707
    );
3708
3709
    if (api_is_allowed_to_edit(null, true) &&
3710
        empty($post->getPostParentId())
3711
    ) {
3712
        // The sticky checkbox only appears when it is the first post of a thread.
3713
        $form->addElement(
3714
            'checkbox',
3715
            'thread_sticky',
3716
            '',
3717
            get_lang('This is a sticky message (appears always on top and has a special sticky icon)')
3718
        );
3719
        if (1 == $thread->getThreadSticky()) {
3720
            $defaults['thread_sticky'] = true;
3721
        }
3722
    }
3723
3724
    $form->addElement('html', '</div>');
3725
3726
    $form->addFile('user_upload[]', get_lang('Attachment'));
3727
    $form->addButton(
3728
        'add_attachment',
3729
        get_lang('Add attachment'),
3730
        'paperclip',
3731
        'default',
3732
        'default',
3733
        null,
3734
        ['id' => 'reply-add-attachment']
3735
    );
3736
3737
    $form->addButtonUpdate(get_lang('Edit'), 'SubmitPost');
3738
3739
    // Setting the default values for the form elements.
3740
    $defaults['post_title'] = $post->getPostTitle();
3741
    $defaults['post_text'] = $post->getPostText();
3742
3743
    if (1 == $post->getPostNotification()) {
3744
        $defaults['post_notification'] = true;
3745
    }
3746
3747
    if (!empty($form_values)) {
3748
        $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
3749
        $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
3750
    }
3751
3752
    $form->setDefaults($defaults);
3753
3754
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3755
    $form->addRule('post_title', get_lang('Required field'), 'required');
3756
3757
    // Validation or display
3758
    if ($form->validate()) {
3759
        $values = $form->exportValues();
3760
        $values['item_id'] = $post->getIid();
3761
        $extraFieldValues = new ExtraFieldValue('forum_post');
3762
        $extraFieldValues->saveFieldValues($values);
3763
3764
        store_edit_post($forum, $values);
3765
    } else {
3766
        // Delete from $_SESSION forum attachment from other posts
3767
        clearAttachedFiles($post->getIid());
3768
        // Get forum attachment ajax table to add it to form
3769
        $fileData = getAttachmentsAjaxTable($post->getIid(), $forum->getIid());
3770
        $form->addElement('html', $fileData);
3771
        $form->display();
3772
    }
3773
}
3774
3775
/**
3776
 * This function stores the edit of a post in the forum_post table.
3777
 *
3778
 * @author Patrick Cool <[email protected]>, Ghent University
3779
 *
3780
 * @version february 2006, dokeos 1.8
3781
 */
3782
function store_edit_post(CForumForum $forum, $values)
3783
{
3784
    $logInfo = [
3785
        'tool' => TOOL_FORUM,
3786
        'tool_id' => $_GET['forum'],
3787
        'tool_id_detail' => $values['thread_id'],
3788
        'action' => 'edit-post',
3789
        'action_details' => 'post',
3790
        'info' => $values['post_title'],
3791
    ];
3792
    Event::registerLog($logInfo);
3793
3794
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
3795
    $course_id = api_get_course_int_id();
3796
3797
    //check if this post is the first of the thread
3798
    // First we check if the change affects the thread and if so we commit
3799
    // the changes (sticky and post_title=thread_title are relevant).
3800
    $posts = getPosts($forum, $values['thread_id']);
3801
    $first_post = null;
3802
    if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
3803
        $first_post = $posts[0];
3804
    }
3805
3806
    if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
3807
        // Simple edit
3808
        $params = [
3809
            'thread_title' => $values['post_title'],
3810
            'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
3811
        ];
3812
        $where = ['iid = ?' => [$values['thread_id']]];
3813
        Database::update($threadTable, $params, $where);
3814
    }
3815
3816
    $status = '';
3817
    $updateStatus = false;
3818
    if ($forum->isModerated()) {
3819
        if (api_is_allowed_to_edit(null, true)) {
3820
            $status = $values['status']['status'];
3821
            $updateStatus = true;
3822
        } else {
3823
            $status = CForumPost::STATUS_WAITING_MODERATION;
3824
            $updateStatus = true;
3825
        }
3826
    }
3827
3828
    $postId = $values['post_id'];
3829
    $repo = Container::getForumPostRepository();
3830
    /** @var CForumPost $post */
3831
    $post = $repo->find($postId);
3832
    if ($post) {
3833
        $post
3834
            ->setPostTitle($values['post_title'])
3835
            ->setPostText($values['post_text'])
3836
            ->setPostNotification(isset($values['post_notification']) ? 1 : 0)
3837
        ;
3838
3839
        if ($updateStatus) {
3840
            $post->setStatus($status);
3841
        }
3842
        $repo->getEntityManager()->persist($post);
3843
        $repo->getEntityManager()->flush();
3844
    }
3845
3846
    // Update attached files
3847
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3848
        foreach ($_POST['file_ids'] as $key => $id) {
3849
            editAttachedFile(
3850
                [
3851
                    'comment' => $_POST['file_comments'][$key],
3852
                    'post_id' => $values['post_id'],
3853
                ],
3854
                $id
3855
            );
3856
        }
3857
    }
3858
3859
    if (!empty($values['remove_attach'])) {
3860
        throw new Exception('remove_attach');
3861
        //delete_attachment($post->getIid());
3862
    }
3863
3864
    if (empty($values['id_attach'])) {
3865
        add_forum_attachment_file(
3866
            isset($values['file_comment']) ? $values['file_comment'] : null,
3867
            $post
3868
        );
3869
    } else {
3870
        /*edit_forum_attachment_file(
3871
            isset($values['file_comment']) ? $values['file_comment'] : null,
3872
            $values['post_id'],
3873
            $values['id_attach']
3874
        );*/
3875
    }
3876
3877
    $message = get_lang('The post has been modified').'<br />';
3878
    $message .= get_lang('You can now return to the').
3879
        ' <a href="viewforum.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&">'.
3880
        get_lang('Forum').'</a><br />';
3881
    $message .= get_lang('You can now return to the').
3882
        ' <a
3883
            href="viewthread.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.$values['thread_id'].'&post='.Security::remove_XSS($_GET['post']).'">'.
3884
        get_lang('Message').'</a>';
3885
3886
    Session::erase('formelements');
3887
    Session::erase('origin');
3888
    Session::erase('breadcrumbs');
3889
    Session::erase('addedresource');
3890
    Session::erase('addedresourceid');
3891
3892
    echo Display::return_message($message, 'confirmation', false);
3893
}
3894
3895
/**
3896
 * This function displays the firstname and lastname of the user as a link to the user tool.
3897
 *
3898
 * @param string $user_id names
3899
 * @ in_title : title tootip
3900
 *
3901
 * @return string HTML
3902
 *
3903
 * @author Patrick Cool <[email protected]>, Ghent University
3904
 *
3905
 * @version february 2006, dokeos 1.8
3906
 */
3907
function display_user_link($user_id, $name, $origin = '', $in_title = '')
3908
{
3909
    if (0 != $user_id) {
3910
        $userInfo = api_get_user_info($user_id);
3911
3912
        return '<a href="'.$userInfo['profile_url'].'">'.Security::remove_XSS($userInfo['complete_name']).'</a>';
3913
    } else {
3914
        return $name.' ('.get_lang('Anonymous').')';
3915
    }
3916
}
3917
3918
/**
3919
 * This function displays the user image from the profile, with a link to the user's details.
3920
 *
3921
 * @param int    $user_id User's database ID
3922
 * @param string $name    User's name
3923
 * @param string $origin  the origin where the forum is called (example : learnpath)
3924
 *
3925
 * @return string An HTML with the anchor and the image of the user
3926
 *
3927
 * @author Julio Montoya <[email protected]>
3928
 */
3929
function display_user_image($user_id, $name, $origin = '')
3930
{
3931
    $userInfo = api_get_user_info($user_id);
3932
    $link = '<a href="'.(!empty($origin) ? '#' : $userInfo['profile_url']).'" '.(!empty($origin) ? 'target="_self"' : '').'>';
3933
3934
    if (0 != $user_id) {
3935
        return $link.'<img src="'.$userInfo['avatar'].'"  alt="'.$name.'"  title="'.$name.'" /></a>';
3936
    } else {
3937
        return $link.Display::return_icon('unknown.jpg', $name).'</a>';
3938
    }
3939
}
3940
3941
/**
3942
 * The thread view counter gets increased every time someone looks at the thread.
3943
 *
3944
 * @param int $thread_id
3945
 *
3946
 * @author Patrick Cool <[email protected]>, Ghent University
3947
 *
3948
 * @version february 2006, dokeos 1.8
3949
 */
3950
function increase_thread_view($thread_id)
3951
{
3952
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3953
    $course_id = api_get_course_int_id();
3954
3955
    $sql = "UPDATE $table_threads
3956
            SET thread_views = thread_views + 1
3957
            WHERE
3958
                c_id = $course_id AND
3959
                iid = '".(int) $thread_id."'";
3960
    Database::query($sql);
3961
}
3962
3963
/**
3964
 * The relies counter gets increased every time somebody replies to the thread.
3965
 *
3966
 * @author Patrick Cool <[email protected]>, Ghent University
3967
 *
3968
 * @version february 2006, dokeos 1.8
3969
 *
3970
 * @param int    $threadId
3971
 * @param string $lastPostId
3972
 * @param string $post_date
3973
 */
3974
function updateThreadInfo($threadId, $lastPostId, $post_date)
3975
{
3976
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3977
    $course_id = api_get_course_int_id();
3978
    $sql = "UPDATE $table_threads SET
3979
            thread_replies = thread_replies+1,
3980
            thread_last_post = '".Database::escape_string($lastPostId)."',
3981
            thread_date = '".Database::escape_string($post_date)."'
3982
            WHERE
3983
                c_id = $course_id AND
3984
                iid ='".Database::escape_string($threadId)."'"; // this needs to be cleaned first
3985
    Database::query($sql);
3986
}
3987
3988
/**
3989
 * This function is used to find all the information about what's new in the forum tool.
3990
 *
3991
 * @author Patrick Cool <[email protected]>, Ghent University
3992
 *
3993
 * @version february 2006, dokeos 1.8
3994
 */
3995
function get_whats_new()
3996
{
3997
    $userId = api_get_user_id();
3998
    $course_id = api_get_course_int_id();
3999
4000
    if (empty($course_id) || empty($userId)) {
4001
        return false;
4002
    }
4003
4004
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4005
    $tracking_last_tool_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4006
4007
    $tool = TOOL_FORUM;
4008
    $lastForumAccess = Session::read('last_forum_access');
4009
4010
    if (!$lastForumAccess) {
4011
        $sql = "SELECT * FROM $tracking_last_tool_access
4012
                WHERE
4013
                    access_user_id = $userId AND
4014
                    c_id = $course_id AND
4015
                    access_tool = '".Database::escape_string($tool)."'";
4016
        $result = Database::query($sql);
4017
        $row = Database::fetch_array($result);
4018
        if ($row) {
4019
            Session::write('last_forum_access', $row['access_date']);
4020
            $lastForumAccess = $row['access_date'];
4021
        }
4022
    }
4023
4024
    $whatsNew = Session::read('whatsnew_post_info');
4025
4026
    if (!$whatsNew) {
4027
        if ('' != $lastForumAccess) {
4028
            $postInfo = [];
4029
            $sql = "SELECT * FROM $table_posts
4030
                    WHERE
4031
                        c_id = $course_id AND
4032
                        visible = 1 AND
4033
                        post_date > '".Database::escape_string($lastForumAccess)."'";
4034
            $result = Database::query($sql);
4035
            while ($row = Database::fetch_array($result)) {
4036
                $postInfo[$row['forum_id']][$row['thread_id']][$row['iid']] = $row['post_date'];
4037
            }
4038
            Session::write('whatsnew_post_info', $postInfo);
4039
        }
4040
    }
4041
}
4042
4043
function approvePost(CForumPost $post, $action)
4044
{
4045
    if ('invisible' === $action) {
4046
        $visibility = 0;
4047
    }
4048
4049
    if ('visible' === $action) {
4050
        $visibility = 1;
4051
        handle_mail_cue('post', $post->getIid());
4052
    }
4053
4054
    $post->setVisible($visibility);
4055
    Database::getManager()->persist($post);
4056
    Database::getManager()->flush();
4057
4058
    Display::addFlash(Display::return_message(get_lang('The visibility has been changed')));
4059
}
4060
4061
/**
4062
 * This function retrieves all the unapproved messages for a given forum
4063
 * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see
4064
 * this).
4065
 *
4066
 * @param int $forum_id forum where we want to know the unapproved messages of
4067
 *
4068
 * @return array returns
4069
 *
4070
 * @author Patrick Cool <[email protected]>, Ghent University
4071
 *
4072
 * @version february 2006, dokeos 1.8
4073
 */
4074
function get_unaproved_messages($forum_id)
4075
{
4076
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4077
    $course_id = api_get_course_int_id();
4078
4079
    $return_array = [];
4080
    $sql = "SELECT DISTINCT thread_id FROM $table_posts
4081
            WHERE
4082
                c_id = $course_id AND
4083
                forum_id='".Database::escape_string($forum_id)."' AND
4084
                visible='0' ";
4085
    $result = Database::query($sql);
4086
    while ($row = Database::fetch_array($result)) {
4087
        $return_array[] = $row['thread_id'];
4088
    }
4089
4090
    return $return_array;
4091
}
4092
4093
/**
4094
 * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
4095
 * was added to a given thread.
4096
 */
4097
function send_notification_mails(CForumForum $forum, CForumThread $thread, $reply_info)
4098
{
4099
    $courseEntity = api_get_course_entity($forum->getCId());
4100
    $courseId = $courseEntity->getId();
4101
4102
    $sessionId = api_get_session_id();
4103
    $sessionEntity = api_get_session_entity($sessionId);
4104
4105
    $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4106
4107
    // First we need to check if
4108
    // 1. the forum category is visible
4109
    // 2. the forum is visible
4110
    // 3. the thread is visible
4111
    // 4. the reply is visible (=when there is)
4112
4113
    $current_forum_category = null;
4114
    if ($forum->getForumCategory()) {
4115
        $current_forum_category = $forum->getForumCategory();
4116
    }
4117
4118
    $send_mails = false;
4119
    if ($thread->isVisible($courseEntity, $sessionEntity) &&
4120
        $forum->isVisible($courseEntity, $sessionEntity) &&
4121
        ($current_forum_category && $forum->getForumCategory()->isVisible($courseEntity, $sessionEntity)) &&
4122
        '1' != $forum->getApprovalDirectPost()
4123
    ) {
4124
        $send_mails = true;
4125
    }
4126
4127
    // The forum category, the forum, the thread and the reply are visible to the user
4128
    if ($send_mails && !empty($forum)) {
4129
        $postId = isset($reply_info['new_post_id']) ? $reply_info['new_post_id'] : 0;
4130
        send_notifications($forum, $thread, $postId);
4131
    } else {
4132
        $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4133
        if ($forum) {
4134
            $sql = "SELECT * FROM $table_notification
4135
                    WHERE
4136
                        c_id = ".$courseId." AND
4137
                        (
4138
                            forum_id = '".$forum->getIid()."' OR
4139
                            thread_id = '".$thread->getIid()."'
4140
                        ) ";
4141
            $result = Database::query($sql);
4142
            $user_id = api_get_user_id();
4143
            while ($row = Database::fetch_array($result)) {
4144
                $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
4145
                        VALUES (".$courseId.", '".$thread->getIid()."', '".(int) ($reply_info['new_post_id'])."', '$user_id' )";
4146
                Database::query($sql);
4147
            }
4148
        }
4149
    }
4150
}
4151
4152
/**
4153
 * This function is called whenever something is made visible because there might
4154
 * be new posts and the user might have indicated that (s)he wanted to be
4155
 * informed about the new posts by mail.
4156
 *
4157
 * @param string $content Content type (post, thread, forum, forum_category)
4158
 * @param int    $id      Item DB ID of the corresponding content type
4159
 *
4160
 * @return string language variable
4161
 *
4162
 * @author Patrick Cool <[email protected]>, Ghent University
4163
 *
4164
 * @version february 2006, dokeos 1.8
4165
 */
4166
function handle_mail_cue($content, $id)
4167
{
4168
    $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4169
    $table_forums = Database::get_course_table(TABLE_FORUM);
4170
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4171
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4172
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4173
4174
    $course_id = api_get_course_int_id();
4175
    $id = (int) $id;
4176
4177
    /* If the post is made visible we only have to send mails to the people
4178
     who indicated that they wanted to be informed for that thread.*/
4179
    if ('post' === $content) {
4180
        // Getting the information about the post (need the thread_id).
4181
        /** @var CForumPost $post */
4182
        $post = Container::getForumPostRepository()->find($id);
4183
        $thread_id = $post->getThread()->getIid();
4184
4185
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4186
        $sql = "SELECT users.firstname, users.lastname, users.id as user_id, users.email
4187
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4188
                WHERE
4189
                    posts.c_id = $course_id AND
4190
                    mailcue.c_id = $course_id AND
4191
                    posts.thread_id = $thread_id AND
4192
                    posts.post_notification = '1' AND
4193
                    mailcue.thread_id = $thread_id AND
4194
                    users.id = posts.poster_id AND
4195
                    users.active = 1
4196
                GROUP BY users.email";
4197
4198
        $result = Database::query($sql);
4199
        $forum = Container::getForumRepository()->find($post->getForum()->getIid());
4200
4201
        while ($row = Database::fetch_array($result)) {
4202
            send_mail($row, $forum, $post->getThread(), $post);
4203
        }
4204
    } elseif ('thread' === $content) {
4205
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4206
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
4207
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4208
                WHERE
4209
                    posts.c_id = $course_id AND
4210
                    mailcue.c_id = $course_id AND
4211
                    posts.thread_id = $id AND
4212
                    posts.post_notification = '1' AND
4213
                    mailcue.thread_id = $id AND
4214
                    users.user_id = posts.poster_id AND
4215
                    users.active = 1
4216
                GROUP BY users.email";
4217
        $result = Database::query($sql);
4218
        while ($row = Database::fetch_array($result)) {
4219
            $forum = Container::getForumRepository()->find($row['forum_id']);
4220
            $thread = Container::getForumThreadRepository()->find($id);
4221
            send_mail($row, $forum, $thread);
4222
        }
4223
4224
        // Deleting the relevant entries from the mailcue.
4225
        $sql = "DELETE FROM $table_mailcue
4226
                WHERE c_id = $course_id AND thread_id = $id";
4227
        Database::query($sql);
4228
    } elseif ('forum' == $content) {
4229
        $sql = "SELECT thread_id FROM $table_threads
4230
                WHERE c_id = $course_id AND forum_id = $id";
4231
        $result = Database::query($sql);
4232
        while ($row = Database::fetch_array($result)) {
4233
            handle_mail_cue('thread', $row['thread_id']);
4234
        }
4235
    } elseif ('forum_category' === $content) {
4236
        $sql = "SELECT forum_id FROM $table_forums
4237
                WHERE c_id = $course_id AND forum_category = $id";
4238
        $result = Database::query($sql);
4239
        while ($row = Database::fetch_array($result)) {
4240
            handle_mail_cue('forum', $row['forum_id']);
4241
        }
4242
    } else {
4243
        return get_lang('Error');
4244
    }
4245
}
4246
4247
/**
4248
 * This function sends the mails for the mail notification.
4249
 */
4250
function send_mail($userInfo, CForumForum $forum, CForumThread $thread, CForumPost $postInfo = null)
4251
{
4252
    if (empty($userInfo) || empty($forum) || empty($thread)) {
4253
        return false;
4254
    }
4255
4256
    $_course = api_get_course_info();
4257
    $user_id = api_get_user_id();
4258
    $forumId = $forum->getIid();
4259
    $threadId = $thread->getIid();
4260
4261
    $thread_link = api_get_path(WEB_CODE_PATH).
4262
        'forum/viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId;
4263
4264
    $email_body = get_lang('Dear').' '.api_get_person_name($userInfo['firstname'], $userInfo['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
4265
    $email_body .= get_lang('New Post in the forum').': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4266
4267
    $courseId = api_get_configuration_value('global_forums_course_id');
4268
    $subject = get_lang('New Post in the forum').' - '.$_course['official_code'].': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4269
4270
    $courseInfoTitle = get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
4271
    if (!empty($courseId) && $_course['real_id'] == $courseId) {
4272
        $subject = get_lang('New Post in the forum').': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4273
        $courseInfoTitle = " <br />\n";
4274
    }
4275
    $email_body .= $courseInfoTitle;
4276
4277
    if (!empty($postInfo)) {
4278
        $text = cut(strip_tags($postInfo->getPostText()), 100);
4279
        if (!empty($text)) {
4280
            $email_body .= get_lang('Message').": <br />\n ";
4281
            $email_body .= $text;
4282
            $email_body .= "<br /><br />\n";
4283
        }
4284
    }
4285
4286
    $email_body .= get_lang('You stated that you wanted to be informed by e-mail whenever somebody replies on the thread')."<br />\n";
4287
4288
    if (!empty($thread_link)) {
4289
        $email_body .= get_lang('The thread can be found here').' : <br /><a href="'.$thread_link.'">'.$thread_link."</a>\n";
4290
    }
4291
4292
    if ($userInfo['user_id'] != $user_id) {
4293
        MessageManager::send_message(
4294
            $userInfo['user_id'],
4295
            $subject,
4296
            $email_body,
4297
            [],
4298
            [],
4299
            null,
4300
            null,
4301
            null,
4302
            null,
4303
            $user_id
4304
        );
4305
    }
4306
}
4307
4308
/**
4309
 * This function displays the form for moving a thread to a different (already existing) forum.
4310
 *
4311
 * @author Patrick Cool <[email protected]>, Ghent University
4312
 *
4313
 * @version february 2006, dokeos 1.8
4314
 */
4315
function move_thread_form()
4316
{
4317
    $form = new FormValidator(
4318
        'movepost',
4319
        'post',
4320
        api_get_self().'?forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
4321
    );
4322
    $form->addHeader(get_lang('Move Thread'));
4323
    // Invisible form: the thread_id
4324
    $form->addHidden('thread_id', (int) ($_GET['thread']));
4325
    $forum_categories = get_forum_categories();
4326
4327
    $htmlcontent = '<div class="row">
4328
        <div class="label">
4329
            <span class="form_required">*</span>'.get_lang('Move to').'
4330
        </div>
4331
        <div class="formw">';
4332
    $htmlcontent .= '<select name="forum">';
4333
    foreach ($forum_categories as $category) {
4334
        $htmlcontent .= '<optgroup label="'.$category->getCatTitle().'">';
4335
        $forums = $category->getForums();
4336
        foreach ($forums as $forum) {
4337
            $htmlcontent .= '<option value="'.$forum->getIid().'">'.$forum->getForumTitle().'</option>';
4338
        }
4339
        $htmlcontent .= '</optgroup>';
4340
    }
4341
    $htmlcontent .= '</select>';
4342
    $htmlcontent .= '   </div>
4343
                    </div>';
4344
4345
    $form->addElement('html', $htmlcontent);
4346
4347
    // The OK button
4348
    $form->addButtonSave(get_lang('Move Thread'), 'SubmitForum');
4349
4350
    // Validation or display
4351
    if ($form->validate()) {
4352
        $values = $form->exportValues();
4353
        if (isset($_POST['forum'])) {
4354
            store_move_thread($values);
4355
            Display::addFlash(Display::return_message(get_lang('Moved')));
4356
        }
4357
    } else {
4358
        return $form->returnForm();
4359
    }
4360
}
4361
4362
/**
4363
 * This function displays the form for moving a post message to a different (already existing) or a new thread.
4364
 *
4365
 * @author Patrick Cool <[email protected]>, Ghent University
4366
 *
4367
 * @version february 2006, dokeos 1.8
4368
 */
4369
function move_post_form()
4370
{
4371
    $form = new FormValidator(
4372
        'movepost',
4373
        'post',
4374
        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'])
4375
    );
4376
    // The header for the form
4377
    $form->addElement('header', '', get_lang('Move post'));
4378
4379
    // Invisible form: the post_id
4380
    $form->addElement('hidden', 'post_id', (int) ($_GET['post']));
4381
4382
    // Dropdown list: Threads of this forum
4383
    $threads = get_threads($_GET['forum']);
4384
    $threads_list[0] = get_lang('A new thread');
4385
    foreach ($threads as $thread) {
4386
        $threads_list[$thread->getIid()] = $thread->getThreadTitle();
4387
    }
4388
    $form->addElement('select', 'thread', get_lang('Move toThread'), $threads_list);
4389
    $form->applyFilter('thread', 'html_filter');
4390
4391
    // The OK button
4392
    $form->addButtonSave(get_lang('Move post'), 'submit');
4393
4394
    // Setting the rules
4395
    $form->addRule('thread', get_lang('Required field'), 'required');
4396
4397
    return $form;
4398
}
4399
4400
/**
4401
 * @param array $values
4402
 *
4403
 * @return string HTML language variable
4404
 *
4405
 * @author Patrick Cool <[email protected]>, Ghent University
4406
 *
4407
 * @version february 2006, dokeos 1.8
4408
 */
4409
function store_move_post($values)
4410
{
4411
    $_course = api_get_course_info();
4412
    $course_id = api_get_course_int_id();
4413
4414
    $table_forums = Database::get_course_table(TABLE_FORUM);
4415
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4416
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4417
4418
    $user = api_get_user_entity(api_get_user_id());
4419
    $course = api_get_course_entity($course_id);
4420
    $session = api_get_session_entity();
4421
4422
    if ('0' == $values['thread']) {
4423
        $repoPost = Container::getForumPostRepository();
4424
        $repoThread = Container::getForumThreadRepository();
4425
        $repoForum = Container::getForumRepository();
4426
4427
        $em = $repoPost->getEntityManager();
4428
4429
        /** @var CForumPost $post */
4430
        $post = $repoPost->find($values['post_id']);
4431
        $forumId = $post->getForum()->getIid();
4432
        $threadId = $post->getThread()->getIid();
4433
4434
        $thread = new CForumThread();
4435
        $thread
4436
            ->setCId($course_id)
4437
            ->setThreadTitle($post->getPostTitle())
4438
            ->setForum($post->getForum())
4439
            ->setThreadPosterId($post->getPosterId())
4440
            ->setThreadPosterName($post->getPosterName())
4441
            ->setThreadLastPost($post->getIid())
4442
            ->setThreadDate($post->getPostDate())
4443
            ->setParent($post->getForum())
4444
            ->addCourseLink(
4445
                $user,
4446
                $course,
4447
                $session
4448
            );
4449
4450
        $repo = Container::getForumThreadRepository();
4451
        $em = $repo->getEntityManager();
4452
        $em->persist($thread);
4453
        $em->flush();
4454
4455
        $new_thread_id = $thread->getIid();
4456
4457
        // Storing a new thread.
4458
        /*$params = [
4459
            'c_id' => $course_id,
4460
            'thread_title' => $current_post['post_title'],
4461
            'forum_id' => $current_post['forum_id'],
4462
            'thread_poster_id' => $current_post['poster_id'],
4463
            'thread_poster_name' => $current_post['poster_name'],
4464
            'thread_last_post' => $values['post_id'],
4465
            'thread_date' => $current_post['post_date'],
4466
        ];
4467
4468
        $new_thread_id = Database::insert($table_threads, $params);
4469
4470
        api_item_property_update(
4471
            $_course,
4472
            TOOL_FORUM_THREAD,
4473
            $new_thread_id,
4474
            'visible',
4475
            $current_post['poster_id']
4476
        );*/
4477
4478
        // Moving the post to the newly created thread.
4479
        $sql = "UPDATE $table_posts SET thread_id='".$new_thread_id."', post_parent_id = NULL
4480
                WHERE c_id = $course_id AND iid ='".(int) ($values['post_id'])."'";
4481
        Database::query($sql);
4482
4483
        // Resetting the parent_id of the thread to 0 for all those who had this moved post as parent.
4484
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4485
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
4486
        Database::query($sql);
4487
4488
        // Updating updating the number of threads in the forum.
4489
        $sql = "UPDATE $table_forums SET forum_threads=forum_threads+1
4490
                WHERE c_id = $course_id AND iid ='".$forumId."'";
4491
        Database::query($sql);
4492
4493
        // Resetting the last post of the old thread and decreasing the number of replies and the thread.
4494
        $sql = "SELECT * FROM $table_posts
4495
                WHERE c_id = $course_id AND thread_id='".$threadId."'
4496
                ORDER BY iid DESC";
4497
        $result = Database::query($sql);
4498
        $row = Database::fetch_array($result);
4499
        $sql = "UPDATE $table_threads SET
4500
                    thread_last_post='".$row['iid']."',
4501
                    thread_replies=thread_replies-1
4502
                WHERE
4503
                    c_id = $course_id AND
4504
                    iid ='".$threadId."'";
4505
        Database::query($sql);
4506
    } else {
4507
        // Moving to the chosen thread.
4508
        $sql = 'SELECT thread_id FROM '.$table_posts."
4509
                WHERE c_id = $course_id AND iid = '".$values['post_id']."' ";
4510
        $result = Database::query($sql);
4511
        $row = Database::fetch_array($result);
4512
4513
        $original_thread_id = $row['thread_id'];
4514
        $sql = 'SELECT thread_last_post FROM '.$table_threads."
4515
                WHERE c_id = $course_id AND iid = '".$original_thread_id."' ";
4516
4517
        $result = Database::query($sql);
4518
        $row = Database::fetch_array($result);
4519
        $thread_is_last_post = $row['thread_last_post'];
4520
        // If is this thread, update the thread_last_post with the last one.
4521
4522
        if ($thread_is_last_post == $values['post_id']) {
4523
            $sql = 'SELECT iid as post_id FROM '.$table_posts."
4524
                    WHERE
4525
                        c_id = $course_id AND
4526
                        thread_id = '".$original_thread_id."' AND
4527
                        iid <> '".$values['post_id']."'
4528
                    ORDER BY post_date DESC LIMIT 1";
4529
            $result = Database::query($sql);
4530
4531
            $row = Database::fetch_array($result);
4532
            $thread_new_last_post = $row['post_id'];
4533
4534
            $sql = 'UPDATE '.$table_threads."
4535
                    SET thread_last_post = '".$thread_new_last_post."'
4536
                    WHERE c_id = $course_id AND iid = '".$original_thread_id."' ";
4537
            Database::query($sql);
4538
        }
4539
4540
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies-1
4541
                WHERE c_id = $course_id AND iid ='".$original_thread_id."'";
4542
        Database::query($sql);
4543
4544
        // moving to the chosen thread
4545
        $sql = "UPDATE $table_posts SET thread_id='".(int) ($_POST['thread'])."', post_parent_id = NULL
4546
                WHERE c_id = $course_id AND iid ='".(int) ($values['post_id'])."'";
4547
        Database::query($sql);
4548
4549
        // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
4550
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4551
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
4552
        Database::query($sql);
4553
4554
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies+1
4555
                WHERE c_id = $course_id AND iid ='".(int) ($_POST['thread'])."'";
4556
        Database::query($sql);
4557
    }
4558
4559
    return get_lang('Thread moved');
4560
}
4561
4562
/**
4563
 * @param array $values
4564
 *
4565
 * @return string HTML language variable
4566
 *
4567
 * @author Patrick Cool <[email protected]>, Ghent University
4568
 *
4569
 * @version february 2006, dokeos 1.8
4570
 */
4571
function store_move_thread($values)
4572
{
4573
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4574
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4575
4576
    $courseId = api_get_course_int_id();
4577
    $sessionId = api_get_session_id();
4578
4579
    $forumId = (int) ($_POST['forum']);
4580
    $threadId = (int) ($_POST['thread_id']);
4581
    //$forumInfo = get_forums($forumId);
4582
4583
    // Change the thread table: Setting the forum_id to the new forum.
4584
    $sql = "UPDATE $table_threads SET forum_id = $forumId
4585
            WHERE c_id = $courseId AND thread_id = $threadId";
4586
    Database::query($sql);
4587
4588
    // Changing all the posts of the thread: setting the forum_id to the new forum.
4589
    $sql = "UPDATE $table_posts SET forum_id = $forumId
4590
            WHERE c_id = $courseId AND thread_id= $threadId";
4591
    Database::query($sql);
4592
4593
    // Fix group id, if forum is moved to a different group
4594
    /*if (!empty($forumInfo['to_group_id'])) {
4595
        $groupId = $forumInfo['to_group_id'];
4596
        $item = api_get_item_property_info(
4597
            $courseId,
4598
            TABLE_FORUM_THREAD,
4599
            $threadId,
4600
            $sessionId,
4601
            $groupId
4602
        );
4603
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4604
        $sessionCondition = api_get_session_condition($sessionId);
4605
4606
        if (!empty($item)) {
4607
            if ($item['to_group_id'] != $groupId) {
4608
                $sql = "UPDATE $table
4609
                    SET to_group_id = $groupId
4610
                    WHERE
4611
                      tool = '".TABLE_FORUM_THREAD."' AND
4612
                      c_id = $courseId AND
4613
                      ref = ".$item['ref']."
4614
                      $sessionCondition
4615
                ";
4616
                Database::query($sql);
4617
            }
4618
        } else {
4619
            $sql = "UPDATE $table
4620
                    SET to_group_id = $groupId
4621
                    WHERE
4622
                      tool = '".TABLE_FORUM_THREAD."' AND
4623
                      c_id = $courseId AND
4624
                      ref = ".$threadId."
4625
                      $sessionCondition
4626
            ";
4627
            Database::query($sql);
4628
        }
4629
    }*/
4630
4631
    return get_lang('Thread moved');
4632
}
4633
4634
/**
4635
 * Prepares a string for displaying by highlighting the search results inside, if any.
4636
 *
4637
 * @param string $input the input string
4638
 *
4639
 * @return string the same string with highlighted hits inside
4640
 *
4641
 * @author Patrick Cool <[email protected]>, Ghent University, February 2006 - the initial version.
4642
 * @author Ivan Tcholakov, March 2011 - adaptation for Chamilo LMS.
4643
 */
4644
function prepare4display($input)
4645
{
4646
    static $highlightcolors = ['yellow', '#33CC33', '#3399CC', '#9999FF', '#33CC33'];
4647
    static $search;
4648
4649
    if (!isset($search)) {
4650
        if (isset($_POST['search_term'])) {
4651
            $search = $_POST['search_term']; // No html at all.
4652
        } elseif (isset($_GET['search'])) {
4653
            $search = $_GET['search'];
4654
        } else {
4655
            $search = '';
4656
        }
4657
    }
4658
4659
    if (!empty($search)) {
4660
        if (strstr($search, '+')) {
4661
            $search_terms = explode('+', $search);
4662
        } else {
4663
            $search_terms[] = trim($search);
4664
        }
4665
        $counter = 0;
4666
        foreach ($search_terms as $key => $search_term) {
4667
            $input = api_preg_replace(
4668
                '/'.preg_quote(trim($search_term), '/').'/i',
4669
                '<span style="background-color: '.$highlightcolors[$counter].'">$0</span>',
4670
                $input
4671
            );
4672
            $counter++;
4673
        }
4674
    }
4675
4676
    // TODO: Security should be implemented outside this function.
4677
    // Change this to COURSEMANAGERLOWSECURITY or COURSEMANAGER to lower filtering and allow more styles
4678
    // (see comments of Security::remove_XSS() method to learn about other levels).
4679
4680
    return Security::remove_XSS($input, STUDENT, true);
4681
}
4682
4683
/**
4684
 * Display the search form for the forum and display the search results.
4685
 *
4686
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4687
 *
4688
 * @version march 2008, dokeos 1.8.5
4689
 */
4690
function forum_search()
4691
{
4692
    $form = new FormValidator(
4693
        'forumsearch',
4694
        'post',
4695
        'forumsearch.php?'.api_get_cidreq()
4696
    );
4697
4698
    // Setting the form elements.
4699
    $form->addElement('header', '', get_lang('Search in the Forum'));
4700
    $form->addElement('text', 'search_term', get_lang('Search term'), ['autofocus']);
4701
    $form->applyFilter('search_term', 'html_filter');
4702
    $form->addElement('static', 'search_information', '', get_lang('Search in the ForumInformation'));
4703
    $form->addButtonSearch(get_lang('Search'));
4704
4705
    // Setting the rules.
4706
    $form->addRule('search_term', get_lang('Required field'), 'required');
4707
    $form->addRule('search_term', get_lang('Too short'), 'minlength', 3);
4708
4709
    // Validation or display.
4710
    if ($form->validate()) {
4711
        $values = $form->exportValues();
4712
        $form->setDefaults($values);
4713
        $form->display();
4714
        // Display the search results.
4715
        display_forum_search_results(stripslashes($values['search_term']));
4716
    } else {
4717
        $form->display();
4718
    }
4719
}
4720
4721
/**
4722
 * Display the search results.
4723
 *
4724
 * @param string $search_term
4725
 *
4726
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4727
 *
4728
 * @version march 2008, dokeos 1.8.5
4729
 */
4730
function display_forum_search_results($search_term)
4731
{
4732
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4733
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4734
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
4735
    $session_id = api_get_session_id();
4736
    $course_id = api_get_course_int_id();
4737
4738
    // Defining the search strings as an array.
4739
    if (strstr($search_term, '+')) {
4740
        $search_terms = explode('+', $search_term);
4741
    } else {
4742
        $search_terms[] = $search_term;
4743
    }
4744
4745
    // Search restriction.
4746
    foreach ($search_terms as $value) {
4747
        $search_restriction[] = "
4748
        (
4749
            posts.post_title LIKE '%".Database::escape_string(trim($value))."%' OR
4750
            posts.post_text LIKE '%".Database::escape_string(trim($value))."%'
4751
        )";
4752
    }
4753
4754
    $sessionCondition = api_get_session_condition(
4755
        $session_id,
4756
        true,
4757
        false,
4758
        'item_property.session_id'
4759
    );
4760
4761
    $sql = "SELECT posts.*
4762
            FROM $table_posts posts
4763
            INNER JOIN $table_threads threads
4764
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
4765
            INNER JOIN $table_item_property item_property
4766
            ON (item_property.ref = threads.thread_id AND item_property.c_id = threads.c_id)
4767
            WHERE
4768
                posts.c_id = $course_id AND
4769
                item_property.c_id = $course_id AND
4770
                item_property.visibility = 1
4771
                $sessionCondition AND
4772
                posts.visible = 1 AND
4773
                item_property.tool = '".TOOL_FORUM_THREAD."' AND
4774
                ".implode(' AND ', $search_restriction).'
4775
            GROUP BY posts.post_id';
4776
4777
    // Getting all the information of the forum categories.
4778
    $forum_categories_list = get_forum_categories();
4779
4780
    // Getting all the information of the forums.
4781
    $forum_list = get_forums();
4782
4783
    $result = Database::query($sql);
4784
    $search_results = [];
4785
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4786
        $forumId = $row['forum_id'];
4787
        $forumData = get_forums($forumId);
4788
        $category = isset($forum_categories_list[$forumData['forum_category']]) ? $forum_categories_list[$forumData['forum_category']] : null;
4789
        $display_result = false;
4790
        /*
4791
          We only show it when
4792
          1. forum category is visible
4793
          2. forum is visible
4794
          3. thread is visible (to do)
4795
          4. post is visible
4796
         */
4797
        if (!api_is_allowed_to_edit(null, true)) {
4798
            if (!empty($category)) {
4799
                if ('1' == $category['visibility'] && '1' == $forumData['visibility']) {
4800
                    $display_result = true;
4801
                }
4802
            } else {
4803
                if ('1' == $forumData['visible']) {
4804
                    $display_result = true;
4805
                }
4806
            }
4807
        } else {
4808
            $display_result = true;
4809
        }
4810
4811
        if ($display_result) {
4812
            $categoryName = !empty($category) ? $category['cat_title'] : '';
4813
            $search_results_item = '<li><a href="viewforumcategory.php?'.api_get_cidreq().'&forumcategory='.$forumData['forum_category'].'&search='.urlencode($search_term).'">'.
4814
                prepare4display($categoryName).'</a> &gt; ';
4815
            $search_results_item .= '<a href="viewforum.php?'.api_get_cidreq().'&forum='.$forumId.'&search='.urlencode($search_term).'">'.
4816
                prepare4display($forum_list[$row['forum_id']]['forum_title']).'</a> &gt; ';
4817
            $search_results_item .= '<a href="viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$row['thread_id'].'&search='.urlencode($search_term).'">'.
4818
                prepare4display($row['post_title']).'</a>';
4819
            $search_results_item .= '<br />';
4820
            if (api_strlen($row['post_title']) > 200) {
4821
                $search_results_item .= prepare4display(api_substr(strip_tags($row['post_title']), 0, 200)).'...';
4822
            } else {
4823
                $search_results_item .= prepare4display($row['post_title']);
4824
            }
4825
            $search_results_item .= '</li>';
4826
            $search_results[] = $search_results_item;
4827
        }
4828
    }
4829
    echo '<legend>'.count($search_results).' '.get_lang('Search in the ForumResults').'</legend>';
4830
    echo '<ol>';
4831
    if ($search_results) {
4832
        echo implode($search_results);
4833
    }
4834
    echo '</ol>';
4835
}
4836
4837
/**
4838
 * Return the link to the forum search page.
4839
 *
4840
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4841
 *
4842
 * @version April 2008, dokeos 1.8.5
4843
 */
4844
function search_link()
4845
{
4846
    // @todo implement search
4847
4848
    return '';
4849
4850
    $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...
4851
    $origin = api_get_origin();
4852
    if ('learnpath' != $origin) {
4853
        $return = '<a href="forumsearch.php?'.api_get_cidreq().'&action=search"> ';
4854
        $return .= Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
4855
4856
        if (!empty($_GET['search'])) {
4857
            $return .= ': '.Security::remove_XSS($_GET['search']).' ';
4858
            $url = api_get_self().'?';
4859
            $url_parameter = [];
4860
            foreach ($_GET as $key => $value) {
4861
                if ('search' != $key) {
4862
                    $url_parameter[] = Security::remove_XSS($key).'='.Security::remove_XSS($value);
4863
                }
4864
            }
4865
            $url .= implode('&', $url_parameter);
4866
            $return .= '<a href="'.$url.'">'.Display::return_icon('delete.gif', get_lang('Clean search results')).'</a>';
4867
        }
4868
    }
4869
4870
    return $return;
4871
}
4872
4873
/**
4874
 * This function adds an attachment file into a forum.
4875
 *
4876
 * @param string     $file_comment a comment about file
4877
 * @param CForumPost $post         from forum_post table
4878
 *
4879
 * @return false|null
4880
 */
4881
function add_forum_attachment_file($file_comment, CForumPost $post)
4882
{
4883
    $request = Container::getRequest();
4884
    if (false === $request->files->has('user_upload')) {
4885
        return false;
4886
    }
4887
4888
    $file = $request->files->get('user_upload');
4889
    if (empty($file)) {
4890
        return false;
4891
    }
4892
4893
    $files = [];
4894
    if ($file instanceof UploadedFile) {
4895
        $files[] = $file;
4896
    } else {
4897
        $files = $file;
4898
    }
4899
4900
    /** @var UploadedFile $attachment */
4901
    foreach ($files as $file) {
4902
        $valid = process_uploaded_file($file);
4903
4904
        if (!$valid) {
4905
            continue;
4906
        }
4907
4908
        // Try to add an extension to the file if it hasn't one.
4909
        $new_file_name = add_ext_on_mime(
4910
            stripslashes($file->getPathname()),
4911
            $file->getType()
4912
        );
4913
4914
        // User's file name
4915
        $file_name = $file->getClientOriginalName();
4916
4917
        if (!filter_extension($new_file_name)) {
4918
            Display::addFlash(
4919
                Display::return_message(
4920
                    get_lang('File upload failed: this file extension or file type is prohibited'),
4921
                    'error'
4922
                )
4923
            );
4924
4925
            return;
4926
        }
4927
4928
        $new_file_name = uniqid('');
4929
        $safe_file_comment = Database::escape_string($file_comment);
4930
4931
        $user = api_get_user_entity(api_get_user_id());
4932
        $course = api_get_course_entity(api_get_course_int_id());
4933
        $session = api_get_session_entity(api_get_session_id());
4934
4935
        $attachment = new CForumAttachment();
4936
        $attachment
4937
            ->setCId(api_get_course_int_id())
4938
            ->setComment($safe_file_comment)
4939
            ->setFilename($file_name)
4940
            ->setPath($file_name)
4941
            ->setPost($post)
4942
            ->setSize($file->getSize())
4943
            ->setParent($post)
4944
            ->addCourseLink(
4945
                $course,
4946
                $session
4947
            );
4948
4949
        $repo = Container::getForumAttachmentRepository();
4950
        $em = $repo->getEntityManager();
4951
        $em->persist($attachment);
4952
        $em->flush();
4953
4954
        /*$last_id_file = Database::insert(
4955
            $agenda_forum_attachment,
4956
            [
4957
                'path' => $safe_new_file_name,
4958
            ]
4959
        );*/
4960
4961
        /*api_item_property_update(
4962
            $_course,
4963
            TOOL_FORUM_ATTACH,
4964
            $last_id_file,
4965
            'ForumAttachmentAdded',
4966
            api_get_user_id()
4967
        );*/
4968
    }
4969
}
4970
4971
/**
4972
 * This function edits an attachment file into a forum.
4973
 *
4974
 * @param string $file_comment a comment about file
4975
 * @param int    $post_id
4976
 * @param int    $id_attach    attachment file Id
4977
 */
4978
function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
4979
{
4980
    $_course = api_get_course_info();
4981
    $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
4982
    $course_id = api_get_course_int_id();
4983
4984
    $filesData = [];
4985
4986
    if (!is_array($_FILES['user_upload']['name'])) {
4987
        $filesData[] = $_FILES['user_upload'];
4988
    } else {
4989
        $fileCount = count($_FILES['user_upload']['name']);
4990
        $fileKeys = array_keys($_FILES['user_upload']);
4991
4992
        for ($i = 0; $i < $fileCount; $i++) {
4993
            foreach ($fileKeys as $key) {
4994
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
4995
            }
4996
        }
4997
    }
4998
4999
    foreach ($filesData as $attachment) {
5000
        if (empty($attachment['name'])) {
5001
            continue;
5002
        }
5003
5004
        $upload_ok = process_uploaded_file($attachment);
5005
5006
        if (!$upload_ok) {
5007
            continue;
5008
        }
5009
5010
        $course_dir = $_course['path'].'/upload/forum';
5011
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
5012
        $updir = $sys_course_path.$course_dir;
5013
5014
        // Try to add an extension to the file if it hasn't one.
5015
        $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
5016
        // User's file name
5017
        $file_name = $attachment['name'];
5018
5019
        if (!filter_extension($new_file_name)) {
5020
            Display::addFlash(
5021
                Display::return_message(
5022
                    get_lang('File upload failed: this file extension or file type is prohibited'),
5023
                    'error'
5024
                )
5025
            );
5026
        } else {
5027
            $new_file_name = uniqid('');
5028
            $new_path = $updir.'/'.$new_file_name;
5029
            $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5030
            $safe_file_comment = Database::escape_string($file_comment);
5031
            $safe_file_name = Database::escape_string($file_name);
5032
            $safe_new_file_name = Database::escape_string($new_file_name);
5033
            $safe_post_id = (int) $post_id;
5034
            $safe_id_attach = (int) $id_attach;
5035
            // Storing the attachments if any.
5036
            if ($result) {
5037
                $sql = "UPDATE $table_forum_attachment
5038
                        SET
5039
                            filename = '$safe_file_name',
5040
                            comment = '$safe_file_comment',
5041
                            path = '$safe_new_file_name',
5042
                            post_id = '$safe_post_id',
5043
                            size ='".$attachment['size']."'
5044
                        WHERE c_id = $course_id AND id = '$safe_id_attach'";
5045
                Database::query($sql);
5046
                api_item_property_update(
5047
                    $_course,
5048
                    TOOL_FORUM_ATTACH,
5049
                    $safe_id_attach,
5050
                    'ForumAttachmentUpdated',
5051
                    api_get_user_id()
5052
                );
5053
            }
5054
        }
5055
    }
5056
}
5057
5058
/**
5059
 * Show a list with all the attachments according to the post's id.
5060
 *
5061
 * @param int $postId
5062
 *
5063
 * @return array with the post info
5064
 *
5065
 * @author Julio Montoya
5066
 *
5067
 * @version avril 2008, dokeos 1.8.5
5068
 */
5069
function get_attachment($postId)
5070
{
5071
    $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5072
    $course_id = api_get_course_int_id();
5073
    $row = [];
5074
    $postId = (int) $postId;
5075
5076
    if (empty($postId)) {
5077
        return [];
5078
    }
5079
5080
    $sql = "SELECT iid, path, filename, comment
5081
            FROM $table
5082
            WHERE c_id = $course_id AND post_id = $postId";
5083
    $result = Database::query($sql);
5084
    if (0 != Database::num_rows($result)) {
5085
        $row = Database::fetch_array($result);
5086
    }
5087
5088
    return $row;
5089
}
5090
5091
/**
5092
 * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
5093
 *
5094
 * @param int $postId
5095
 * @param int $attachmentId
5096
 *
5097
 * @return bool
5098
 */
5099
function delete_attachment($postId, $attachmentId)
5100
{
5101
    $repo = Container::getForumPostRepository();
5102
    /** @var CForumPost $post */
5103
    $post = $repo->find($postId);
5104
    if ($post) {
5105
        $repoAttachment = Container::getForumAttachmentRepository();
5106
        $attachment = $repoAttachment->find($attachmentId);
5107
        if ($attachment) {
5108
            $post->removeAttachment($attachment);
5109
            $repo->getEntityManager()->remove($attachment);
5110
        }
5111
        $repo->getEntityManager()->persist($post);
5112
        $repo->getEntityManager()->flush();
5113
5114
        Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
5115
    }
5116
5117
    return true;
5118
5119
    $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...
5120
    $course_id = api_get_course_int_id();
5121
5122
    $cond = !empty($id_attach) ? ' iid = '.(int) $id_attach.'' : ' post_id = '.(int) $post_id.'';
5123
    $sql = "SELECT path FROM $forum_table_attachment WHERE c_id = $course_id AND $cond";
5124
    $res = Database::query($sql);
5125
    $row = Database::fetch_array($res);
5126
5127
    $course_dir = $_course['path'].'/upload/forum';
5128
    $sys_course_path = api_get_path(SYS_COURSE_PATH);
5129
    $updir = $sys_course_path.$course_dir;
5130
    $my_path = isset($row['path']) ? $row['path'] : null;
5131
    $file = $updir.'/'.$my_path;
5132
    if (Security::check_abs_path($file, $updir)) {
5133
        @unlink($file);
5134
    }
5135
5136
    // Delete from forum_attachment table.
5137
    $sql = "DELETE FROM $forum_table_attachment
5138
            WHERE c_id = $course_id AND $cond ";
5139
    $result = Database::query($sql);
5140
    if (false !== $result) {
5141
        $affectedRows = Database::affected_rows($result);
5142
    } else {
5143
        $affectedRows = 0;
5144
    }
5145
5146
    // Update item_property.
5147
    api_item_property_update(
5148
        $_course,
5149
        TOOL_FORUM_ATTACH,
5150
        $id_attach,
5151
        'ForumAttachmentDelete',
5152
        api_get_user_id()
5153
    );
5154
5155
    if (!empty($result) && !empty($id_attach)) {
5156
        Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
5157
    }
5158
5159
    return $affectedRows;
5160
}
5161
5162
/**
5163
 * This function gets all the forum information of the all the forum of the group.
5164
 *
5165
 * @param array $groupInfo the id of the group we need the fora of (see forum.forum_of_group)
5166
 *
5167
 * @return CForumForum[]
5168
 *
5169
 * @todo this is basically the same code as the get_forums function. Consider merging the two.
5170
 */
5171
function get_forums_of_group($groupInfo)
5172
{
5173
    $groupId = (int) $groupInfo['id'];
5174
5175
    $group = api_get_group_entity($groupId);
5176
    $course = api_get_course_entity();
5177
    $session = api_get_session_entity();
5178
5179
    $repo = Container::getForumRepository();
5180
5181
    $qb = $repo->getResourcesByCourse($course, $session, $group);
5182
5183
    return $qb->getQuery()->getResult();
5184
5185
    $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...
5186
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
5187
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5188
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
5189
    $course_id = api_get_course_int_id();
5190
    $groupId = (int) $groupInfo['id'];
5191
5192
    // Student
5193
    // Select all the forum information of all forums (that are visible to students).
5194
    $sql = "SELECT * FROM $table_forums forum
5195
            INNER JOIN $table_item_property item_properties
5196
            ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5197
            WHERE
5198
                forum.forum_of_group = $groupId AND
5199
                forum.c_id = $course_id AND
5200
                item_properties.c_id = $course_id AND
5201
                item_properties.visibility = 1 AND
5202
                item_properties.tool = '".TOOL_FORUM."'
5203
            ORDER BY forum.forum_order ASC";
5204
5205
    // Select the number of threads of the forums (only the threads that are visible).
5206
    $sql2 = "SELECT
5207
                count(thread_id) AS number_of_threads,
5208
                threads.forum_id
5209
            FROM $table_threads threads
5210
            INNER JOIN $table_item_property item_properties
5211
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5212
            WHERE
5213
                threads.c_id = $course_id AND
5214
                item_properties.c_id = $course_id AND
5215
                item_properties.visibility = 1 AND
5216
                item_properties.tool='".TOOL_FORUM_THREAD."'
5217
            GROUP BY threads.forum_id";
5218
5219
    // Select the number of posts of the forum (post that are visible and that are in a thread that is visible).
5220
    $sql3 = "SELECT count(post_id) AS number_of_posts, posts.forum_id
5221
            FROM $table_posts posts
5222
            INNER JOIN $table_threads threads
5223
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
5224
            INNER JOIN $table_item_property item_properties
5225
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5226
            WHERE
5227
                posts.visible=1 AND
5228
                posts.c_id = $course_id AND
5229
                item_properties.c_id = $course_id AND
5230
                threads.c_id = $course_id AND
5231
                item_properties.visibility = 1 AND
5232
                item_properties.tool='".TOOL_FORUM_THREAD."'
5233
            GROUP BY threads.forum_id";
5234
5235
    // Course Admin
5236
    if (api_is_allowed_to_edit()) {
5237
        // Select all the forum information of all forums (that are not deleted).
5238
        $sql = "SELECT *
5239
                FROM $table_forums forum
5240
                INNER JOIN $table_item_property item_properties
5241
                ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5242
                WHERE
5243
                    forum.forum_of_group = $groupId AND
5244
                    forum.c_id = $course_id AND
5245
                    item_properties.c_id = $course_id AND
5246
                    item_properties.visibility <> 2 AND
5247
                    item_properties.tool = '".TOOL_FORUM."'
5248
                ORDER BY forum_order ASC";
5249
5250
        // Select the number of threads of the forums (only the threads that are not deleted).
5251
        $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id
5252
                 FROM $table_threads threads
5253
                 INNER JOIN $table_item_property item_properties
5254
                 ON (threads.thread_id=item_properties.ref AND item_properties.c_id = threads.c_id)
5255
                 WHERE
5256
                    threads.c_id = $course_id AND
5257
                    item_properties.c_id = $course_id AND
5258
                    item_properties.visibility <> 2 AND
5259
                    item_properties.tool='".TOOL_FORUM_THREAD."'
5260
                GROUP BY threads.forum_id";
5261
        // Select the number of posts of the forum.
5262
        $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id
5263
                FROM $table_posts
5264
                WHERE c_id = $course_id
5265
                GROUP BY forum_id";
5266
    }
5267
5268
    // Handling all the forum information.
5269
    $result = Database::query($sql);
5270
    $forum_list = [];
5271
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5272
        $forum_list[$row['forum_id']] = $row;
5273
    }
5274
5275
    // Handling the thread count information.
5276
    $result2 = Database::query($sql2);
5277
    while ($row2 = Database::fetch_array($result2, 'ASSOC')) {
5278
        if (is_array($forum_list)) {
5279
            if (array_key_exists($row2['forum_id'], $forum_list)) {
5280
                $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
5281
            }
5282
        }
5283
    }
5284
5285
    // Handling the post count information.
5286
    $result3 = Database::query($sql3);
5287
    while ($row3 = Database::fetch_array($result3, 'ASSOC')) {
5288
        if (is_array($forum_list)) {
5289
            if (array_key_exists($row3['forum_id'], $forum_list)) {
5290
                // This is needed because sql3 takes also the deleted forums into account.
5291
                $forum_list[$row3['forum_id']]['number_of_posts'] = $row3['number_of_posts'];
5292
            }
5293
        }
5294
    }
5295
5296
    // Finding the last post information
5297
    // (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname).
5298
    if (!empty($forum_list)) {
5299
        foreach ($forum_list as $key => $value) {
5300
            $lastPost = get_last_post_information($key, api_is_allowed_to_edit());
5301
            if ($lastPost) {
5302
                $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
5303
                $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
5304
                $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
5305
                $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
5306
                $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
5307
                $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
5308
            }
5309
        }
5310
    }
5311
5312
    return $forum_list;
5313
}
5314
5315
/**
5316
 * This function stores which users have to be notified of which forums or threads.
5317
 *
5318
 * @param string $content    does the user want to be notified about a forum or about a thread
5319
 * @param int    $id         the id of the forum or thread
5320
 * @param bool   $addOnly
5321
 * @param array  $userInfo
5322
 * @param array  $courseInfo
5323
 *
5324
 * @return string language variable
5325
 *
5326
 * @author  Patrick Cool <[email protected]>, Ghent University, Belgium
5327
 * @author  Julio Montoya
5328
 *
5329
 * @since   May 2008 v1.8.5
5330
 */
5331
function set_notification($content, $id, $addOnly = false, $userInfo = [], $courseInfo = [])
5332
{
5333
    $userInfo = empty($userInfo) ? api_get_user_info() : $userInfo;
5334
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
5335
    $id = (int) $id;
5336
5337
    if (empty($userInfo) || empty($courseInfo) || empty($id) || empty($content)) {
5338
        return false;
5339
    }
5340
5341
    // Database table definition
5342
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5343
    $course_id = $courseInfo['real_id'];
5344
5345
    // Which database field do we have to store the id in?
5346
    $field = 'thread_id';
5347
    if ('forum' === $content) {
5348
        $field = 'forum_id';
5349
    }
5350
5351
    $userId = $userInfo['user_id'];
5352
5353
    // First we check if the notification is already set for this.
5354
    $sql = "SELECT * FROM $table_notification
5355
            WHERE
5356
                c_id = $course_id AND
5357
                $field = $id AND
5358
                user_id = $userId ";
5359
    $result = Database::query($sql);
5360
    $total = Database::num_rows($result);
5361
5362
    // If the user did not indicate that (s)he wanted to be notified already
5363
    // then we store the notification request (to prevent double notification requests).
5364
    if ($total <= 0) {
5365
        $notification = new CForumNotification();
5366
        $notification
5367
            ->setCId($course_id)
5368
            ->setUserId($userId)
5369
        ;
5370
5371
        if ('forum' === $content) {
5372
            $notification->setForumId($id);
5373
        } else {
5374
            $notification->setThreadId($id);
5375
        }
5376
5377
        $em = Database::getManager();
5378
        $em->persist($notification);
5379
        $em->flush();
5380
5381
        Session::erase('forum_notification');
5382
        getNotificationsPerUser(0, true);
5383
5384
        return get_lang('You will be notified of new posts by e-mail.');
5385
    } else {
5386
        if (!$addOnly) {
5387
            $sql = "DELETE FROM $table_notification
5388
                    WHERE
5389
                        c_id = $course_id AND
5390
                        $field = $id AND
5391
                        user_id = $userId ";
5392
            Database::query($sql);
5393
            Session::erase('forum_notification');
5394
            getNotificationsPerUser(0, true);
5395
5396
            return get_lang('You will no longer be notified of new posts by email');
5397
        }
5398
    }
5399
}
5400
5401
/**
5402
 * This function retrieves all the email adresses of the users who wanted to be notified
5403
 * about a new post in a certain forum or thread.
5404
 *
5405
 * @param string $content does the user want to be notified about a forum or about a thread
5406
 * @param int    $id      the id of the forum or thread
5407
 *
5408
 * @return array returns
5409
 *
5410
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5411
 * @author Julio Montoya
5412
 *
5413
 * @version May 2008, dokeos 1.8.5
5414
 *
5415
 * @since May 2008, dokeos 1.8.5
5416
 */
5417
function get_notifications($content, $id)
5418
{
5419
    // Database table definition
5420
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5421
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5422
    $course_id = api_get_course_int_id();
5423
5424
    // Which database field contains the notification?
5425
    $field = 'thread_id';
5426
    if ('forum' === $content) {
5427
        $field = 'forum_id';
5428
    }
5429
5430
    $id = (int) $id;
5431
5432
    $sql = "SELECT user.id as user_id, user.firstname, user.lastname, user.email, user.id user
5433
            FROM $table_users user, $table_notification notification
5434
            WHERE
5435
                notification.c_id = $course_id AND user.active = 1 AND
5436
                user.id = notification.user_id AND
5437
                notification.$field = $id ";
5438
5439
    $result = Database::query($sql);
5440
    $return = [];
5441
5442
    while ($row = Database::fetch_array($result)) {
5443
        $return['user'.$row['user_id']] = ['email' => $row['email'], 'user_id' => $row['user_id']];
5444
    }
5445
5446
    return $return;
5447
}
5448
5449
/**
5450
 * Get all the users who need to receive a notification of a new post (those subscribed to
5451
 * the forum or the thread).
5452
 *
5453
 * @param int $post_id the id of the post
5454
 *
5455
 * @return false|null
5456
 *
5457
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5458
 *
5459
 * @version May 2008, dokeos 1.8.5
5460
 *
5461
 * @since May 2008, dokeos 1.8.5
5462
 */
5463
function send_notifications(CForumForum $forum, CForumThread $thread, $post_id = 0)
5464
{
5465
    if (!$forum) {
5466
        return false;
5467
    }
5468
5469
    // Users who subscribed to the forum
5470
    $users_to_be_notified_by_forum = get_notifications('forum', $forum->getIid());
5471
5472
    // User who subscribed to the thread
5473
    $users_to_be_notified_by_thread = [];
5474
    if (!$thread) {
5475
        $users_to_be_notified_by_thread = get_notifications('thread', $thread->getIid());
5476
    }
5477
5478
    $postInfo = null;
5479
    if (!empty($post_id)) {
5480
        $postInfo = Container::getForumPostRepository()->find($post_id);
5481
    }
5482
5483
    // Merging the two
5484
    $users_to_be_notified = array_merge($users_to_be_notified_by_forum, $users_to_be_notified_by_thread);
5485
5486
    if (is_array($users_to_be_notified)) {
5487
        foreach ($users_to_be_notified as $value) {
5488
            $userInfo = api_get_user_info($value['user_id']);
5489
            send_mail($userInfo, $forum, $thread, $postInfo);
5490
        }
5491
    }
5492
}
5493
5494
/**
5495
 * Get all the notification subscriptions of the user
5496
 * = which forums and which threads does the user wants to be informed of when a new
5497
 * post is added to this thread.
5498
 *
5499
 * @param int  $user_id the user_id of a user (default = 0 => the current user)
5500
 * @param bool $force   force get the notification subscriptions (even if the information is already in the session
5501
 *
5502
 * @return array
5503
 *
5504
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5505
 *
5506
 * @version May 2008, dokeos 1.8.5
5507
 *
5508
 * @since May 2008, dokeos 1.8.5
5509
 */
5510
function getNotificationsPerUser($user_id = 0, $force = false, $course_id = 0)
5511
{
5512
    // Database table definition
5513
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5514
    $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
5515
    if (empty($course_id) || -1 == $course_id) {
5516
        return null;
5517
    }
5518
5519
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
5520
5521
    if (!isset($_SESSION['forum_notification']) ||
5522
        $_SESSION['forum_notification']['course'] != $course_id ||
5523
        true == $force
5524
    ) {
5525
        $_SESSION['forum_notification']['course'] = $course_id;
5526
        $sql = "SELECT * FROM $table_notification
5527
                WHERE c_id = $course_id AND user_id='".$user_id."'";
5528
5529
        $result = Database::query($sql);
5530
        while ($row = Database::fetch_array($result)) {
5531
            if (null !== $row['forum_id']) {
5532
                $_SESSION['forum_notification']['forum'][] = $row['forum_id'];
5533
            }
5534
            if (null !== $row['thread_id']) {
5535
                $_SESSION['forum_notification']['thread'][] = $row['thread_id'];
5536
            }
5537
        }
5538
    }
5539
}
5540
5541
/**
5542
 * This function counts the number of post inside a thread.
5543
 *
5544
 * @param int $thread_id
5545
 *
5546
 * @return int the number of post inside a thread
5547
 *
5548
 * @author Jhon Hinojosa <[email protected]>,
5549
 *
5550
 * @version octubre 2008, dokeos 1.8
5551
 */
5552
function count_number_of_post_in_thread($thread_id)
5553
{
5554
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5555
    $course_id = api_get_course_int_id();
5556
    if (empty($course_id)) {
5557
        return 0;
5558
    }
5559
    $sql = "SELECT count(*) count FROM $table_posts
5560
            WHERE
5561
                c_id = $course_id AND
5562
                thread_id='".(int) $thread_id."' ";
5563
    $result = Database::query($sql);
5564
5565
    $count = 0;
5566
    if (Database::num_rows($result) > 0) {
5567
        $row = Database::fetch_array($result);
5568
        $count = $row['count'];
5569
    }
5570
5571
    return $count;
5572
}
5573
5574
/**
5575
 * This function counts the number of post inside a thread user.
5576
 *
5577
 * @param int $thread_id
5578
 * @param int $user_id
5579
 *
5580
 * @return int the number of post inside a thread user
5581
 */
5582
function count_number_of_post_for_user_thread($thread_id, $user_id)
5583
{
5584
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5585
    $course_id = api_get_course_int_id();
5586
    $sql = "SELECT count(iid) as count
5587
            FROM $table_posts
5588
            WHERE c_id = $course_id AND
5589
                  thread_id=".(int) $thread_id.' AND
5590
                  poster_id = '.(int) $user_id.' AND visible = 1 ';
5591
    $result = Database::query($sql);
5592
    $count = 0;
5593
    if (Database::num_rows($result) > 0) {
5594
        $count = Database::fetch_array($result);
5595
        $count = $count['count'];
5596
    }
5597
5598
    return $count;
5599
}
5600
5601
/**
5602
 * This function retrieves information of statistical.
5603
 *
5604
 * @param int $thread_id
5605
 * @param int $user_id
5606
 * @param int $course_id
5607
 *
5608
 * @return array the information of statistical
5609
 *
5610
 * @author Jhon Hinojosa <[email protected]>,
5611
 *
5612
 * @version oct 2008, dokeos 1.8
5613
 */
5614
function get_statistical_information($thread_id, $user_id, $course_id)
5615
{
5616
    $result = [];
5617
    $courseInfo = api_get_course_info_by_id($course_id);
5618
    $result['user_course'] = CourseManager::get_users_count_in_course($courseInfo['code']);
5619
    $result['post'] = count_number_of_post_in_thread($thread_id);
5620
    $result['user_post'] = count_number_of_post_for_user_thread($thread_id, $user_id);
5621
5622
    return $result;
5623
}
5624
5625
/**
5626
 * This function return the posts inside a thread from a given user.
5627
 *
5628
 * @param string $course_code
5629
 * @param int    $thread_id
5630
 * @param int    $user_id
5631
 *
5632
 * @return array posts inside a thread
5633
 *
5634
 * @author Jhon Hinojosa <[email protected]>,
5635
 *
5636
 * @version oct 2008, dokeos 1.8
5637
 */
5638
function get_thread_user_post($course_code, $thread_id, $user_id)
5639
{
5640
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5641
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5642
    $thread_id = (int) $thread_id;
5643
    $user_id = (int) $user_id;
5644
    $course_info = api_get_user_info($course_code);
5645
    $course_id = $course_info['real_id'];
5646
5647
    if (empty($course_id)) {
5648
        $course_id = api_get_course_int_id();
5649
    }
5650
    $sql = "SELECT * FROM $table_posts posts
5651
            LEFT JOIN  $table_users users
5652
                ON posts.poster_id=users.user_id
5653
            WHERE
5654
                posts.c_id = $course_id AND
5655
                posts.thread_id='$thread_id'
5656
                AND posts.poster_id='$user_id'
5657
            ORDER BY posts.post_id ASC";
5658
5659
    $result = Database::query($sql);
5660
    $post_list = [];
5661
    while ($row = Database::fetch_array($result)) {
5662
        $row['status'] = '1';
5663
        $post_list[] = $row;
5664
        $sql = "SELECT * FROM $table_posts posts
5665
                LEFT JOIN $table_users users
5666
                ON (posts.poster_id=users.user_id)
5667
                WHERE
5668
                    posts.c_id = $course_id AND
5669
                    posts.thread_id='$thread_id'
5670
                    AND posts.post_parent_id='".$row['post_id']."'
5671
                ORDER BY posts.post_id ASC";
5672
        $result2 = Database::query($sql);
5673
        while ($row2 = Database::fetch_array($result2)) {
5674
            $row2['status'] = '0';
5675
            $post_list[] = $row2;
5676
        }
5677
    }
5678
5679
    return $post_list;
5680
}
5681
5682
/**
5683
 * This function get the name of an thread by id.
5684
 *
5685
 * @param int $thread_id
5686
 *
5687
 * @return string
5688
 *
5689
 * @author Christian Fasanando
5690
 * @author Julio Montoya <[email protected]> Adding security
5691
 */
5692
function get_name_thread_by_id($thread_id)
5693
{
5694
    $t_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
5695
    $course_id = api_get_course_int_id();
5696
    $sql = "SELECT thread_title
5697
            FROM $t_forum_thread
5698
            WHERE c_id = $course_id AND thread_id = '".(int) $thread_id."' ";
5699
    $result = Database::query($sql);
5700
    $row = Database::fetch_array($result);
5701
5702
    return $row[0];
5703
}
5704
5705
/**
5706
 * This function gets all the post written by an user.
5707
 *
5708
 * @param int $user_id
5709
 *
5710
 * @return string
5711
 */
5712
function get_all_post_from_user($user_id, $courseId)
5713
{
5714
    $j = 0;
5715
    $forums = get_forums($courseId);
5716
    krsort($forums);
5717
    $forum_results = '';
5718
5719
    foreach ($forums as $forum) {
5720
        $forumId = $forum->getIid();
5721
5722
        /*if (0 == $forum['visibility']) {
5723
            continue;
5724
        }*/
5725
        if ($j <= 4) {
5726
            $threads = get_threads($forumId);
5727
5728
            if ($threads) {
5729
                $i = 0;
5730
                $hand_forums = '';
5731
                $post_counter = 0;
5732
                foreach ($threads as $thread) {
5733
                    /*if (0 == $thread['visibility']) {
5734
                        continue;
5735
                    }*/
5736
                    if ($i <= 4) {
5737
                        $post_list = get_thread_user_post_limit(
5738
                            $courseId,
5739
                            $thread->getIid(),
5740
                            $user_id,
5741
                            1
5742
                        );
5743
                        $post_counter = count($post_list);
5744
                        if (is_array($post_list) && count($post_list) > 0) {
5745
                            $hand_forums .= '<div id="social-thread">';
5746
                            $hand_forums .= Display::return_icon(
5747
                                'thread.png',
5748
                                get_lang('Thread'),
5749
                                '',
5750
                                ICON_SIZE_MEDIUM
5751
                            );
5752
                            $hand_forums .= '&nbsp;'.Security::remove_XSS($thread->getThreadTitle(), STUDENT);
5753
                            $hand_forums .= '</div>';
5754
5755
                            foreach ($post_list as $posts) {
5756
                                $hand_forums .= '<div id="social-post">';
5757
                                $hand_forums .= '<strong>'.Security::remove_XSS($posts['post_title'], STUDENT).'</strong>';
5758
                                $hand_forums .= '<br / >';
5759
                                $hand_forums .= Security::remove_XSS($posts['post_text'], STUDENT);
5760
                                $hand_forums .= '</div>';
5761
                                $hand_forums .= '<br / >';
5762
                            }
5763
                        }
5764
                    }
5765
                    $i++;
5766
                }
5767
                $forum_results .= '<div id="social-forum">';
5768
                $forum_results .= '<div class="clear"></div><br />';
5769
                $forum_results .= '<div id="social-forum-title">'.
5770
                    Display::return_icon('forum.gif', get_lang('Forum')).'&nbsp;'.Security::remove_XSS($forum->getForumTitle(), STUDENT).
5771
                    '<div style="float:right;margin-top:-35px">
5772
                        <a href="../forum/viewforum.php?'.api_get_cidreq_params($courseId).'&forum='.$forum->getIid().' " >'.
5773
                    get_lang('See forum').'
5774
                        </a>
5775
                     </div></div>';
5776
                $forum_results .= '<br / >';
5777
                if ($post_counter > 0) {
5778
                    $forum_results .= $hand_forums;
5779
                }
5780
                $forum_results .= '</div>';
5781
            }
5782
            $j++;
5783
        }
5784
    }
5785
5786
    return $forum_results;
5787
}
5788
5789
/**
5790
 * @param int $thread_id
5791
 * @param int $user_id
5792
 * @param int $limit
5793
 *
5794
 * @return array
5795
 */
5796
function get_thread_user_post_limit($courseId, $thread_id, $user_id, $limit = 10)
5797
{
5798
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5799
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5800
5801
    $courseId = (int) $courseId;
5802
5803
    $sql = "SELECT * FROM $table_posts posts
5804
            LEFT JOIN $table_users users
5805
                ON posts.poster_id=users.user_id
5806
            WHERE
5807
                posts.c_id = $courseId AND
5808
                posts.thread_id='".Database::escape_string($thread_id)."' AND
5809
                posts.poster_id='".Database::escape_string($user_id)."'
5810
            ORDER BY posts.post_id DESC LIMIT $limit ";
5811
    $result = Database::query($sql);
5812
    $post_list = [];
5813
    while ($row = Database::fetch_array($result)) {
5814
        $row['status'] = '1';
5815
        $post_list[] = $row;
5816
    }
5817
5818
    return $post_list;
5819
}
5820
5821
/**
5822
 * @param string $userId
5823
 * @param array  $courseInfo
5824
 * @param int    $sessionId
5825
 *
5826
 * @return array
5827
 */
5828
function getForumCreatedByUser($userId, $courseInfo, $sessionId)
5829
{
5830
    if (empty($userId) || empty($courseInfo)) {
5831
        return [];
5832
    }
5833
5834
    $courseId = $courseInfo['real_id'];
5835
5836
    $repo = Container::getForumRepository();
5837
5838
    $courseEntity = api_get_course_entity($courseId);
5839
    $sessionEntity = api_get_session_entity($sessionId);
5840
5841
    $qb = $repo->getResourcesByCourse($courseEntity, $sessionEntity);
5842
5843
    $qb->andWhere('node.creator = :creator');
5844
    $qb->setParameter('creator', $userId);
5845
    $items = $qb->getQuery()->getResult();
5846
5847
    $forumList = [];
5848
    if (!empty($items)) {
5849
        /** @var CForumForum $forum */
5850
        foreach ($items as $forum) {
5851
            $forumList[] = [
5852
                $forum->getForumTitle(),
5853
                api_get_local_time($forum->getResourceNode()->getCreatedAt()),
5854
                api_get_local_time($forum->getResourceNode()->getUpdatedAt()),
5855
            ];
5856
        }
5857
    }
5858
5859
    return $forumList;
5860
}
5861
5862
/**
5863
 * This function builds an array of all the posts in a given thread
5864
 * where the key of the array is the post_id
5865
 * It also adds an element children to the array which itself is an array
5866
 * that contains all the id's of the first-level children.
5867
 *
5868
 * @return array containing all the information on the posts of a thread
5869
 *
5870
 * @author Patrick Cool <[email protected]>, Ghent University
5871
 */
5872
function calculate_children($rows)
5873
{
5874
    $sorted_rows = [0 => []];
5875
    if (!empty($rows)) {
5876
        foreach ($rows as $row) {
5877
            $rows_with_children[$row['post_id']] = $row;
5878
            $rows_with_children[$row['post_parent_id']]['children'][] = $row['post_id'];
5879
        }
5880
5881
        $rows = $rows_with_children;
5882
        forumRecursiveSort($rows, $sorted_rows);
5883
        unset($sorted_rows[0]);
5884
    }
5885
5886
    return $sorted_rows;
5887
}
5888
5889
/**
5890
 * @param $rows
5891
 * @param $threads
5892
 * @param int $seed
5893
 * @param int $indent
5894
 */
5895
function forumRecursiveSort($rows, &$threads, $seed = 0, $indent = 0)
5896
{
5897
    if ($seed > 0) {
5898
        $threads[$rows[$seed]['post_id']] = $rows[$seed];
5899
        $threads[$rows[$seed]['post_id']]['indent_cnt'] = $indent;
5900
        $indent++;
5901
    }
5902
5903
    if (isset($rows[$seed]['children'])) {
5904
        foreach ($rows[$seed]['children'] as $child) {
5905
            forumRecursiveSort($rows, $threads, $child, $indent);
5906
        }
5907
    }
5908
}
5909
5910
/**
5911
 * Update forum attachment data, used to update comment and post ID.
5912
 *
5913
 * @param array $array    (field => value) to update forum attachment row
5914
 * @param int   $id       ID to find row to update
5915
 * @param int   $courseId course ID to find row to update
5916
 *
5917
 * @return int number of affected rows
5918
 */
5919
function editAttachedFile($array, $id, $courseId = null)
5920
{
5921
    // Init variables
5922
    $setString = '';
5923
    $id = (int) $id;
5924
    $courseId = (int) $courseId;
5925
    if (empty($courseId)) {
5926
        // $courseId can be null, use api method
5927
        $courseId = api_get_course_int_id();
5928
    }
5929
    /*
5930
     * Check if Attachment ID and Course ID are greater than zero
5931
     * and array of field values is not empty
5932
     */
5933
    if ($id > 0 && $courseId > 0 && !empty($array) && is_array($array)) {
5934
        foreach ($array as $key => &$item) {
5935
            $item = Database::escape_string($item);
5936
            $setString .= $key.' = "'.$item.'", ';
5937
        }
5938
        // Delete last comma
5939
        $setString = substr($setString, 0, strlen($setString) - 2);
5940
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5941
        $sql = "UPDATE $forumAttachmentTable
5942
                SET $setString WHERE c_id = $courseId AND id = $id";
5943
        $result = Database::query($sql);
5944
        if (false !== $result) {
5945
            $affectedRows = Database::affected_rows($result);
5946
            if ($affectedRows > 0) {
5947
                /*
5948
                 * If exist in $_SESSION variable, then delete them from it
5949
                 * because they would be deprecated
5950
                 */
5951
                if (!empty($_SESSION['forum']['upload_file'][$courseId][$id])) {
5952
                    unset($_SESSION['forum']['upload_file'][$courseId][$id]);
5953
                }
5954
            }
5955
5956
            return $affectedRows;
5957
        }
5958
    }
5959
5960
    return 0;
5961
}
5962
5963
/**
5964
 * Return a table where the attachments will be set.
5965
 *
5966
 * @param int $postId Forum Post ID
5967
 *
5968
 * @return string The Forum Attachments Ajax Table
5969
 */
5970
function getAttachmentsAjaxTable($postId = 0)
5971
{
5972
    $postId = (int) $postId;
5973
    $courseId = api_get_course_int_id();
5974
    $attachIds = getAttachmentIdsByPostId($postId, $courseId);
5975
    $fileDataContent = '';
5976
    // Update comment to show if form did not pass validation
5977
    if (!empty($_REQUEST['file_ids']) && is_array($_REQUEST['file_ids'])) {
5978
        // 'file_ids is the name from forum attachment ajax form
5979
        foreach ($_REQUEST['file_ids'] as $key => $attachId) {
5980
            if (!empty($_SESSION['forum']['upload_file'][$courseId][$attachId]) &&
5981
                is_array($_SESSION['forum']['upload_file'][$courseId][$attachId])
5982
            ) {
5983
                // If exist forum attachment then update into $_SESSION data
5984
                $_SESSION['forum']['upload_file'][$courseId][$attachId]['comment'] = $_POST['file_comments'][$key];
5985
            }
5986
        }
5987
    }
5988
5989
    // Get data to fill into attachment files table
5990
    if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
5991
        is_array($_SESSION['forum']['upload_file'][$courseId])
5992
    ) {
5993
        $uploadedFiles = $_SESSION['forum']['upload_file'][$courseId];
5994
        foreach ($uploadedFiles as $k => $uploadedFile) {
5995
            if (!empty($uploadedFile) && in_array($uploadedFile['id'], $attachIds)) {
5996
                // Buil html table including an input with attachmentID
5997
                $fileDataContent .= '<tr id="'.$uploadedFile['id'].'" ><td>'.$uploadedFile['name'].'</td><td>'.$uploadedFile['size'].'</td><td>&nbsp;'.$uploadedFile['result'].
5998
                    ' </td><td> <input style="width:90%;" type="text" value="'.$uploadedFile['comment'].'" name="file_comments[]"> </td><td>'.
5999
                    $uploadedFile['delete'].'</td>'.
6000
                    '<input type="hidden" value="'.$uploadedFile['id'].'" name="file_ids[]">'.'</tr>';
6001
            } else {
6002
                /*
6003
                 * If attachment data is empty, then delete it from $_SESSION
6004
                 * because could generate and empty row into html table
6005
                 */
6006
                unset($_SESSION['forum']['upload_file'][$courseId][$k]);
6007
            }
6008
        }
6009
    }
6010
    $style = empty($fileDataContent) ? 'display: none;' : '';
6011
    // Forum attachment Ajax table
6012
    return '
6013
    <div class="control-group " style="'.$style.'">
6014
        <label class="control-label">'.get_lang('Attachments list').'</label>
6015
        <div class="controls">
6016
            <table id="attachmentFileList" class="files data_table span10">
6017
                <tr>
6018
                    <th>'.get_lang('Filename').'</th>
6019
                    <th>'.get_lang('Size').'</th>
6020
                    <th>'.get_lang('Status').'</th>
6021
                    <th>'.get_lang('Comment').'</th>
6022
                    <th>'.get_lang('Delete').'</th>
6023
                </tr>
6024
                '.$fileDataContent.'
6025
            </table>
6026
        </div>
6027
    </div>';
6028
}
6029
6030
/**
6031
 * Return an array of prepared attachment data to build forum attachment table
6032
 * Also, save this array into $_SESSION to do available the attachment data.
6033
 *
6034
 * @param int $forumId
6035
 * @param int $threadId
6036
 * @param int $postId
6037
 * @param int $attachId
6038
 * @param int $courseId
6039
 *
6040
 * @return array
6041
 */
6042
function getAttachedFiles(
6043
    $forumId,
6044
    $threadId,
6045
    $postId = 0,
6046
    $attachId = 0,
6047
    $courseId = 0
6048
) {
6049
    $forumId = (int) $forumId;
6050
    $courseId = (int) $courseId;
6051
    $attachId = (int) $attachId;
6052
    $postId = (int) $postId;
6053
    $threadId = !empty($threadId) ? (int) $threadId : isset($_REQUEST['thread']) ? (int) ($_REQUEST['thread']) : '';
6054
    if (empty($courseId)) {
6055
        // $courseId can be null, use api method
6056
        $courseId = api_get_course_int_id();
6057
    }
6058
    if (empty($forumId)) {
6059
        if (!empty($_REQUEST['forum'])) {
6060
            $forumId = (int) $_REQUEST['forum'];
6061
        } else {
6062
            // if forum ID is empty, cannot generate delete url
6063
6064
            return [];
6065
        }
6066
    }
6067
    // Check if exist at least one of them to filter forum attachment select query
6068
    if (empty($postId) && empty($attachId)) {
6069
        return [];
6070
    }
6071
6072
    if (empty($postId)) {
6073
        $filter = "AND iid = $attachId";
6074
    } elseif (empty($attachId)) {
6075
        $filter = "AND post_id = $postId";
6076
    } else {
6077
        $filter = "AND post_id = $postId AND iid = $attachId";
6078
    }
6079
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6080
    $sql = "SELECT iid
6081
            FROM $forumAttachmentTable
6082
            WHERE c_id = $courseId $filter";
6083
    $result = Database::query($sql);
6084
    $json = [];
6085
    if (Database::num_rows($result) > 0) {
6086
        $repo = Container::getForumAttachmentRepository();
6087
        while ($row = Database::fetch_array($result, 'ASSOC')) {
6088
            /** @var CForumAttachment $attachment */
6089
            $attachment = $repo->find($row['iid']);
6090
            $downloadUrl = $repo->getResourceFileDownloadUrl($attachment);
6091
6092
            // name contains an URL to download attachment file and its filename
6093
            $json['name'] = Display::url(
6094
                api_htmlentities($attachment->getFilename()),
6095
                $downloadUrl,
6096
                ['target' => '_blank', 'class' => 'attachFilename']
6097
            );
6098
            $json['id'] = $row['iid'];
6099
            $json['comment'] = $attachment->getComment();
6100
            // Format file size
6101
            $json['size'] = format_file_size($attachment->getSize());
6102
            // Check if $row is consistent
6103
            if ($attachment) {
6104
                // Set result as success and bring delete URL
6105
                $json['result'] = Display::return_icon('accept.png', get_lang('Uploaded.'));
6106
                $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&action=delete_attach&forum='.$forumId.'&thread='.$threadId.'&id_attach='.$row['iid'];
6107
                $json['delete'] = Display::url(
6108
                    Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL),
6109
                    $url,
6110
                    ['class' => 'deleteLink']
6111
                );
6112
            } else {
6113
                // If not, set an exclamation result
6114
                $json['result'] = Display::return_icon('exclamation.png', get_lang('Error'));
6115
            }
6116
            // Store array data into $_SESSION
6117
            $_SESSION['forum']['upload_file'][$courseId][$json['id']] = $json;
6118
        }
6119
    }
6120
6121
    return $json;
6122
}
6123
6124
/**
6125
 * Clear forum attachment data stored in $_SESSION,
6126
 * If is not defined post, it will clear all forum attachment data from course.
6127
 *
6128
 * @param int $postId   -1 : Clear all attachments from course stored in $_SESSION
6129
 *                      0 : Clear attachments from course, except from temporal post "0"
6130
 *                      but without delete them from file system and database
6131
 *                      Other values : Clear attachments from course except specified post
6132
 *                      and delete them from file system and database
6133
 * @param int $courseId : Course ID, if it is null, will use api_get_course_int_id()
6134
 *
6135
 * @return array
6136
 */
6137
function clearAttachedFiles($postId = 0, $courseId = 0)
6138
{
6139
    // Init variables
6140
    $courseId = (int) $courseId;
6141
    $postId = (int) $postId;
6142
    $array = [];
6143
    if (empty($courseId)) {
6144
        // $courseId can be null, use api method
6145
        $courseId = api_get_course_int_id();
6146
    }
6147
    if (-1 === $postId) {
6148
        // If post ID is -1 then delete course's attachment data from $_SESSION
6149
        if (!empty($_SESSION['forum']['upload_file'][$courseId])) {
6150
            $array = array_keys($_SESSION['forum']['upload_file'][$courseId]);
6151
            unset($_SESSION['forum']['upload_file'][$courseId]);
6152
        }
6153
    } else {
6154
        $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6155
        if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6156
            is_array($_SESSION['forum']['upload_file'][$courseId])) {
6157
            foreach ($_SESSION['forum']['upload_file'][$courseId] as $attachId => $attach) {
6158
                if (!in_array($attachId, $attachIds)) {
6159
                    // If attach ID is not into specified post, delete attachment
6160
                    // Save deleted attachment ID
6161
                    $array[] = $attachId;
6162
                    if (0 !== $postId) {
6163
                        // Post 0 is temporal, delete them from file system and DB
6164
                        delete_attachment(0, $attachId);
6165
                    }
6166
                    // Delete attachment data from $_SESSION
6167
                    unset($_SESSION['forum']['upload_file'][$courseId][$attachId]);
6168
                }
6169
            }
6170
        }
6171
    }
6172
6173
    return $array;
6174
}
6175
6176
/**
6177
 * Returns an array of forum attachment ids into a course and forum post.
6178
 *
6179
 * @param int $postId
6180
 * @param int $courseId
6181
 *
6182
 * @return array
6183
 */
6184
function getAttachmentIdsByPostId($postId, $courseId = 0)
6185
{
6186
    $array = [];
6187
    $courseId = (int) $courseId;
6188
    $postId = (int) $postId;
6189
    if (empty($courseId)) {
6190
        // $courseId can be null, use api method
6191
        $courseId = api_get_course_int_id();
6192
    }
6193
    if ($courseId > 0) {
6194
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6195
        $sql = "SELECT iid FROM $forumAttachmentTable
6196
                WHERE c_id = $courseId AND post_id = $postId";
6197
        $result = Database::query($sql);
6198
        if (false !== $result && Database::num_rows($result) > 0) {
6199
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6200
                $array[] = $row['iid'];
6201
            }
6202
        }
6203
    }
6204
6205
    return $array;
6206
}
6207
6208
/**
6209
 * Check if the forum category exists looking for its title.
6210
 *
6211
 * @param string $title     The forum category title
6212
 * @param int    $courseId  The course ID
6213
 * @param int    $sessionId Optional. The session ID
6214
 *
6215
 * @return bool
6216
 */
6217
function getForumCategoryByTitle($title, $courseId, $sessionId = 0)
6218
{
6219
    $sessionId = (int) $sessionId;
6220
    $courseId = (int) $courseId;
6221
    $forumCategoryTable = Database::get_course_table(TABLE_FORUM_CATEGORY);
6222
    $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6223
6224
    $fakeFrom = "$forumCategoryTable fc
6225
        INNER JOIN $itemProperty ip ";
6226
6227
    if (0 === $sessionId) {
6228
        $fakeFrom .= '
6229
            ON (
6230
                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)
6231
            )
6232
        ';
6233
    } else {
6234
        $fakeFrom .= '
6235
            ON (
6236
                fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND fc.session_id = ip.session_id
6237
            )
6238
        ';
6239
    }
6240
6241
    $resultData = Database::select(
6242
        'fc.*',
6243
        $fakeFrom,
6244
        [
6245
            'where' => [
6246
                'ip.visibility != ? AND ' => 2,
6247
                'ip.tool = ? AND ' => TOOL_FORUM_CATEGORY,
6248
                'fc.session_id = ? AND ' => $sessionId,
6249
                'fc.cat_title = ? AND ' => $title,
6250
                'fc.c_id = ?' => $courseId,
6251
            ],
6252
        ],
6253
        'first'
6254
    );
6255
6256
    if (empty($resultData)) {
6257
        return false;
6258
    }
6259
6260
    return $resultData;
6261
}
6262
6263
/**
6264
 * @param array $row
6265
 * @param bool  $addWrapper
6266
 *
6267
 * @return string
6268
 */
6269
function getPostStatus(CForumForum $forum, $row, $addWrapper = true)
6270
{
6271
    $statusIcon = '';
6272
    if ($forum->isModerated()) {
6273
        if ($addWrapper) {
6274
            $statusIcon = '<br /><br /><span id="status_post_'.$row['iid'].'">';
6275
        }
6276
        $row['status'] = empty($row['status']) ? 2 : $row['status'];
6277
6278
        $addUrl = false;
6279
        $showStatus = false;
6280
        if (api_is_allowed_to_edit(false, true)) {
6281
            $addUrl = true;
6282
        } else {
6283
            if ($row['user_id'] == api_get_user_id()) {
6284
                $showStatus = true;
6285
            }
6286
        }
6287
6288
        $label = '';
6289
        $icon = '';
6290
        $buttonType = '';
6291
        switch ($row['status']) {
6292
            case CForumPost::STATUS_VALIDATED:
6293
                $label = get_lang('Validated');
6294
                $icon = 'check-circle';
6295
                $buttonType = 'success';
6296
6297
                break;
6298
            case CForumPost::STATUS_WAITING_MODERATION:
6299
                $label = get_lang('Waiting for moderation');
6300
                $icon = 'warning';
6301
                $buttonType = 'warning';
6302
6303
                break;
6304
            case CForumPost::STATUS_REJECTED:
6305
                $label = get_lang('Rejected');
6306
                $icon = 'minus-circle';
6307
                $buttonType = 'danger';
6308
6309
                break;
6310
        }
6311
6312
        if ($addUrl) {
6313
            $statusIcon .= Display::toolbarButton(
6314
                $label.'&nbsp;',
6315
                'javascript:void(0)',
6316
                $icon,
6317
                $buttonType,
6318
                ['class' => 'change_post_status']
6319
            );
6320
        } else {
6321
            if ($showStatus) {
6322
                $statusIcon .= Display::label(
6323
                    Display::returnFontAwesomeIcon($icon).$label,
6324
                    $buttonType
6325
                );
6326
            }
6327
        }
6328
6329
        if ($addWrapper) {
6330
            $statusIcon .= '</span>';
6331
        }
6332
    }
6333
6334
    return $statusIcon;
6335
}
6336
6337
/**
6338
 * @param CForumForum $forum
6339
 * @param int         $threadId
6340
 * @param int         $status
6341
 */
6342
function getCountPostsWithStatus($status, $forum, $threadId = null)
6343
{
6344
    $em = Database::getManager();
6345
    $criteria = Criteria::create();
6346
    $criteria
6347
        ->where(Criteria::expr()->eq('status', $status))
6348
        ->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
6349
        ->andWhere(Criteria::expr()->eq('visible', 1))
6350
    ;
6351
6352
    if (!empty($threadId)) {
6353
        $criteria->andWhere(Criteria::expr()->eq('thread', $threadId));
6354
    }
6355
6356
    $qb = $em->getRepository(CForumPost::class)->createQueryBuilder('p');
6357
    $qb->select('count(p.iid)')
6358
        ->addCriteria($criteria);
6359
6360
    return $qb->getQuery()->getSingleScalarResult();
6361
}
6362
6363
/**
6364
 * @param CForumForum $forum
6365
 * @param CForumPost  $post
6366
 *
6367
 * @return bool
6368
 */
6369
function postIsEditableByStudent($forum, $post)
6370
{
6371
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
6372
        return true;
6373
    }
6374
6375
    if (1 == $forum->isModerated()) {
6376
        if (null === $post->getStatus()) {
6377
            return true;
6378
        } else {
6379
            return in_array(
6380
                $post->getStatus(),
6381
                [
6382
                    CForumPost::STATUS_WAITING_MODERATION,
6383
                    CForumPost::STATUS_REJECTED,
6384
                ]
6385
            );
6386
        }
6387
    }
6388
6389
    return true;
6390
}
6391
6392
/**
6393
 * @return bool
6394
 */
6395
function savePostRevision(CForumPost $post)
6396
{
6397
    $userId = api_get_user_id();
6398
6399
    if ($post->getPosterId() != $userId) {
6400
        return false;
6401
    }
6402
6403
    $status = (int) !postNeedsRevision($post);
6404
    $extraFieldValue = new ExtraFieldValue('forum_post');
6405
    $params = [
6406
        'item_id' => $post->getIid(),
6407
        'extra_ask_for_revision' => ['extra_ask_for_revision' => $status],
6408
    ];
6409
    if (empty($status)) {
6410
        unset($params['extra_ask_for_revision']);
6411
    }
6412
    $extraFieldValue->saveFieldValues(
6413
        $params,
6414
        true,
6415
        false,
6416
        ['ask_for_revision']
6417
    );
6418
}
6419
6420
/**
6421
 * @param int $postId
6422
 *
6423
 * @return string
6424
 */
6425
function getPostRevision($postId)
6426
{
6427
    $extraFieldValue = new ExtraFieldValue('forum_post');
6428
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6429
        $postId,
6430
        'revision_language'
6431
    );
6432
    $revision = '';
6433
    if ($value && isset($value['value'])) {
6434
        $revision = $value['value'];
6435
    }
6436
6437
    return $revision;
6438
}
6439
6440
function postNeedsRevision(CForumPost $post): bool
6441
{
6442
    $postId = $post->getIid();
6443
    $extraFieldValue = new ExtraFieldValue('forum_post');
6444
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6445
        $postId,
6446
        'ask_for_revision'
6447
    );
6448
    $hasRevision = false;
6449
    if ($value && isset($value['value'])) {
6450
        return 1 == $value['value'];
6451
    }
6452
6453
    return $hasRevision;
6454
}
6455
6456
/**
6457
 * @param array $threadInfo
6458
 *
6459
 * @return string
6460
 */
6461
function getAskRevisionButton(CForumPost $post, $threadInfo)
6462
{
6463
    if (false === api_get_configuration_value('allow_forum_post_revisions')) {
6464
        return '';
6465
    }
6466
6467
    $postId = $post->getIid();
6468
6469
    $status = 'btn-default';
6470
    if (postNeedsRevision($post)) {
6471
        $status = 'btn-success';
6472
    }
6473
6474
    return Display::url(
6475
        get_lang('Ask for a revision'),
6476
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6477
        api_get_cidreq().'&action=ask_revision&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6478
        ['class' => "btn $status", 'title' => get_lang('Ask for a revision')]
6479
    );
6480
}
6481
6482
/**
6483
 * @param int   $postId
6484
 * @param array $threadInfo
6485
 *
6486
 * @return string
6487
 */
6488
function giveRevisionButton($postId, $threadInfo)
6489
{
6490
    $postId = (int) $postId;
6491
6492
    return Display::toolbarButton(
6493
        get_lang('Give revision'),
6494
        api_get_path(WEB_CODE_PATH).'forum/reply.php?'.api_get_cidreq().'&'.http_build_query(
6495
            [
6496
                'forum' => $threadInfo['forum_id'],
6497
                'thread' => $threadInfo['thread_id'],
6498
                'post' => $postId = (int) $postId,
6499
                'action' => 'replymessage',
6500
                'give_revision' => 1,
6501
            ]
6502
        ),
6503
        'reply',
6504
        'primary',
6505
        ['id' => "reply-to-post-{$postId}"]
6506
    );
6507
}
6508
6509
/**
6510
 * @param int   $postId
6511
 * @param array $threadInfo
6512
 *
6513
 * @return string
6514
 */
6515
function getReportButton($postId, $threadInfo)
6516
{
6517
    $postId = (int) $postId;
6518
6519
    return Display::url(
6520
        Display::returnFontAwesomeIcon('flag'),
6521
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6522
        api_get_cidreq().'&action=report&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6523
        ['class' => 'btn btn-danger', 'title' => get_lang('Report')]
6524
    );
6525
}
6526
6527
/**
6528
 * @return bool
6529
 */
6530
function reportAvailable()
6531
{
6532
    $extraFieldValue = new ExtraFieldValue('course');
6533
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6534
        api_get_course_int_id(),
6535
        'allow_forum_report_button'
6536
    );
6537
    $allowReport = false;
6538
    if ($value && isset($value['value']) && 1 == $value['value']) {
6539
        $allowReport = true;
6540
    }
6541
6542
    return $allowReport;
6543
}
6544
6545
/**
6546
 * @return array
6547
 */
6548
function getReportRecipients()
6549
{
6550
    $extraFieldValue = new ExtraFieldValue('course');
6551
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6552
        api_get_course_int_id(),
6553
        'forum_report_recipients'
6554
    );
6555
    $users = [];
6556
    if ($value && isset($value['value'])) {
6557
        $usersType = explode(';', $value['value']);
6558
6559
        foreach ($usersType as $type) {
6560
            switch ($type) {
6561
                case 'teachers':
6562
                    $teachers = CourseManager::get_teacher_list_from_course_code(api_get_course_id());
6563
                    if (!empty($teachers)) {
6564
                        $users = array_merge($users, array_column($teachers, 'user_id'));
6565
                    }
6566
6567
                break;
6568
                case 'admins':
6569
                    $admins = UserManager::get_all_administrators();
6570
                    if (!empty($admins)) {
6571
                        $users = array_merge($users, array_column($admins, 'user_id'));
6572
                    }
6573
6574
                    break;
6575
                case 'community_managers':
6576
                    $managers = api_get_configuration_value('community_managers_user_list');
6577
                    if (!empty($managers) && isset($managers['users'])) {
6578
                        $users = array_merge($users, $managers['users']);
6579
                    }
6580
6581
                    break;
6582
            }
6583
        }
6584
6585
        $users = array_unique(array_filter($users));
6586
    }
6587
6588
    return $users;
6589
}
6590
6591
/**
6592
 * @param array $forumInfo
6593
 * @param array $threadInfo
6594
 *
6595
 * @return bool
6596
 */
6597
function reportPost(CForumPost $post, $forumInfo, $threadInfo)
6598
{
6599
    if (!reportAvailable()) {
6600
        return false;
6601
    }
6602
6603
    if (empty($forumInfo) || empty($threadInfo)) {
6604
        return false;
6605
    }
6606
6607
    $postId = $post->getIid();
6608
6609
    $currentUser = api_get_user_info();
6610
    $users = getReportRecipients();
6611
    if (!empty($users)) {
6612
        $url = api_get_path(WEB_CODE_PATH).
6613
            'forum/viewthread.php?forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'].'&'.api_get_cidreq().'&post_id='.$postId.'#post_id_'.$postId;
6614
        $postLink = Display::url(
6615
            $post->getPostTitle(),
6616
            $url
6617
        );
6618
        $subject = get_lang('Post reported');
6619
        $content = sprintf(
6620
            get_lang('User %s has reported the message %s in the forum %s'),
6621
            $currentUser['complete_name'],
6622
            $postLink,
6623
            $forumInfo['forum_title']
6624
        );
6625
        foreach ($users as $userId) {
6626
            MessageManager::send_message_simple($userId, $subject, $content);
6627
        }
6628
    }
6629
}
6630