Passed
Push — master ( 4357b6...fb3111 )
by Julito
08:58
created

saveThread()   F

Complexity

Conditions 23
Paths 1028

Size

Total Lines 227
Code Lines 128

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
eloc 128
nc 1028
nop 6
dl 0
loc 227
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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