Passed
Push — master ( c87549...c35fdc )
by Julito
09:10
created

get_all_post_from_user()   B

Complexity

Conditions 10
Paths 5

Size

Total Lines 75
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

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

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

    return false;
}

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

Loading history...
1797
    $sessionId = null !== $sessionId ? (int) $sessionId : api_get_session_id();
1798
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1799
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
1800
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
1801
1802
    $courseId = null !== $courseId ? (int) $courseId : api_get_course_int_id();
1803
    $groupInfo = GroupManager::get_group_properties($groupId);
1804
    $groupCondition = '';
1805
1806
    if (!empty($groupInfo)) {
1807
        $groupIid = $groupInfo['iid'];
1808
        $groupCondition = " AND item_properties.to_group_id = '$groupIid' ";
1809
    }
1810
1811
    $sessionCondition = api_get_session_condition(
1812
        $sessionId,
1813
        true,
1814
        false,
1815
        'item_properties.session_id'
1816
    );
1817
1818
    // important note:  it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
1819
    // because we also have thread.* in it. This is because thread has a field locked and post also has the same field
1820
    // since we are merging these we would have the post.locked value but in fact we want the thread.locked value
1821
    // This is why it is added to the end of the field selection
1822
    $sql = "SELECT DISTINCT
1823
                item_properties.*,
1824
                users.firstname,
1825
                users.lastname,
1826
                users.user_id,
1827
                thread.locked as locked,
1828
                thread.*
1829
            FROM $table_threads thread
1830
            INNER JOIN $table_item_property item_properties
1831
            ON
1832
                thread.thread_id = item_properties.ref AND
1833
                item_properties.c_id = thread.c_id AND
1834
                item_properties.tool = '".TABLE_FORUM_THREAD."'
1835
                $groupCondition
1836
                $sessionCondition
1837
            LEFT JOIN $table_users users
1838
                ON thread.thread_poster_id = users.user_id
1839
            WHERE
1840
                item_properties.visibility='1' AND
1841
                thread.forum_id = ".(int) $forum_id." AND
1842
                thread.c_id = $courseId
1843
            ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1844
1845
    if (api_is_allowed_to_edit()) {
1846
        $sql = "SELECT DISTINCT
1847
                    item_properties.*,
1848
                    users.firstname,
1849
                    users.lastname,
1850
                    users.user_id,
1851
                    thread.locked as locked,
1852
                    thread.*
1853
                FROM $table_threads thread
1854
                INNER JOIN $table_item_property item_properties
1855
                ON
1856
                    thread.thread_id = item_properties.ref AND
1857
                    item_properties.c_id = thread.c_id AND
1858
                    item_properties.tool = '".TABLE_FORUM_THREAD."'
1859
                    $groupCondition
1860
                    $sessionCondition
1861
                LEFT JOIN $table_users users
1862
                    ON thread.thread_poster_id=users.user_id
1863
                WHERE
1864
                    item_properties.visibility<>2 AND
1865
                    thread.forum_id = ".(int) $forum_id." AND
1866
                    thread.c_id = $courseId
1867
                ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1868
    }
1869
    $result = Database::query($sql);
1870
    $list = [];
1871
    $alreadyAdded = [];
1872
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1873
        if (in_array($row['thread_id'], $alreadyAdded)) {
1874
            continue;
1875
        }
1876
        $list[] = $row;
1877
        $alreadyAdded[] = $row['thread_id'];
1878
    }
1879
1880
    return $list;
1881
}
1882
1883
/**
1884
 * Get a thread by Id and course id.
1885
 *
1886
 * @param int $threadId the thread Id
1887
 * @param int $cId      the course id
1888
 *
1889
 * @return array containing all the information about the thread
1890
 */
1891
function getThreadInfo($threadId, $cId)
1892
{
1893
    $repo = Database::getManager()->getRepository(CForumThread::class);
1894
    /** @var CForumThread $forumThread */
1895
    $forumThread = $repo->findOneBy(['iid' => $threadId, 'cId' => $cId]);
1896
1897
    $thread = [];
1898
    if ($forumThread) {
1899
        $thread['iid'] = $forumThread->getIid();
1900
        $thread['threadId'] = $forumThread->getIid();
1901
        $thread['threadTitle'] = $forumThread->getThreadTitle();
1902
        $thread['forumId'] = $forumThread->getForum() ? $forumThread->getForum()->getIid() : 0;
1903
        $thread['sessionId'] = $forumThread->getSessionId();
1904
        $thread['threadSticky'] = $forumThread->getThreadSticky();
1905
        $thread['locked'] = $forumThread->getLocked();
1906
        $thread['threadTitleQualify'] = $forumThread->getThreadTitleQualify();
1907
        $thread['threadQualifyMax'] = $forumThread->getThreadQualifyMax();
1908
        $thread['threadCloseDate'] = $forumThread->getThreadCloseDate();
1909
        $thread['threadWeight'] = $forumThread->getThreadWeight();
1910
        $thread['threadPeerQualify'] = $forumThread->isThreadPeerQualify();
1911
    }
1912
1913
    return $thread;
1914
}
1915
1916
/**
1917
 * Retrieve all posts of a given thread.
1918
 *
1919
 * @param int    $threadId       The thread ID
1920
 * @param string $orderDirection Optional. The direction for sort the posts
1921
 * @param bool   $recursive      Optional. If the list is recursive
1922
 * @param int    $postId         Optional. The post ID for recursive list
1923
 * @param int    $depth          Optional. The depth to indicate the indent
1924
 *
1925
 * @todo move to a repository
1926
 *
1927
 * @return array containing all the information about the posts of a given thread
1928
 */
1929
function getPosts(
1930
    CForumForum $forum,
1931
    $threadId,
1932
    $orderDirection = 'ASC',
1933
    $recursive = false,
1934
    $postId = null,
1935
    $depth = -1
1936
) {
1937
    $em = Database::getManager();
1938
1939
    if (api_is_allowed_to_edit(false, true)) {
1940
        $visibleCriteria = Criteria::expr()->neq('visible', 2);
1941
    } else {
1942
        $visibleCriteria = Criteria::expr()->eq('visible', 1);
1943
    }
1944
1945
    $criteria = Criteria::create();
1946
    $criteria
1947
        ->where(Criteria::expr()->eq('thread', $threadId))
1948
        ->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
1949
        ->andWhere($visibleCriteria)
1950
    ;
1951
1952
    $groupId = api_get_group_id();
1953
    $groupInfo = GroupManager::get_group_properties($groupId);
1954
    $filterModerated = true;
1955
1956
    if (empty($groupId)) {
1957
        if (api_is_allowed_to_edit()) {
1958
            $filterModerated = false;
1959
        }
1960
    } else {
1961
        if (GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo) ||
1962
            api_is_allowed_to_edit(false, true)
1963
        ) {
1964
            $filterModerated = false;
1965
        }
1966
    }
1967
1968
    if ($recursive) {
1969
        $criteria->andWhere(Criteria::expr()->eq('postParentId', $postId));
1970
    }
1971
1972
    $qb = $em->getRepository(CForumPost::class)->createQueryBuilder('p');
1973
    $qb->select('p')
1974
        ->addCriteria($criteria)
1975
        ->addOrderBy('p.iid', $orderDirection);
1976
1977
    if ($filterModerated && 1 == $forum->isModerated()) {
1978
        if (!api_is_allowed_to_edit(false, true)) {
1979
            $userId = api_get_user_id();
1980
            $qb->andWhere(
1981
                'p.status = 1 OR
1982
                    (p.status = '.CForumPost::STATUS_WAITING_MODERATION." AND p.posterId = $userId) OR
1983
                    (p.status = ".CForumPost::STATUS_REJECTED." AND p.posterId = $userId) OR
1984
                    (p.status IS NULL AND p.posterId = $userId)
1985
                    "
1986
            );
1987
        }
1988
    }
1989
1990
    $posts = $qb->getQuery()->getResult();
1991
    $depth++;
1992
1993
    $list = [];
1994
    /** @var CForumPost $post */
1995
    foreach ($posts as $post) {
1996
        $postInfo = [
1997
            'iid' => $post->getIid(),
1998
            'c_id' => $post->getCId(),
1999
            'post_id' => $post->getIid(),
2000
            'post_title' => $post->getPostTitle(),
2001
            'post_text' => $post->getPostText(),
2002
            'thread_id' => $post->getThread() ? $post->getThread()->getIid() : 0,
2003
            'forum_id' => $post->getForum()->getIid(),
2004
            'poster_id' => $post->getPosterId(),
2005
            'poster_name' => $post->getPosterName(),
2006
            'post_date' => $post->getPostDate(),
2007
            'post_notification' => $post->getPostNotification(),
2008
            'post_parent_id' => $post->getPostParentId(),
2009
            'visible' => $post->getVisible(),
2010
            'status' => $post->getStatus(),
2011
            'indent_cnt' => $depth,
2012
            'entity' => $post,
2013
        ];
2014
2015
        $posterId = $post->getPosterId();
2016
        if (!empty($posterId)) {
2017
            $user = api_get_user_entity($posterId);
2018
            if ($user) {
2019
                $postInfo['user_id'] = $user->getId();
2020
                $postInfo['username'] = $user->getUsername();
2021
                $postInfo['username_canonical'] = $user->getUsernameCanonical();
2022
                $postInfo['lastname'] = $user->getLastname();
2023
                $postInfo['firstname'] = $user->getFirstname();
2024
                $postInfo['complete_name'] = UserManager::formatUserFullName($user);
2025
            }
2026
        }
2027
2028
        $list[] = $postInfo;
2029
2030
        if (!$recursive) {
2031
            continue;
2032
        }
2033
        $list = array_merge(
2034
            $list,
2035
            getPosts(
2036
                $forum,
2037
                $threadId,
2038
                $orderDirection,
2039
                $recursive,
2040
                $post->getIid(),
2041
                $depth
2042
            )
2043
        );
2044
    }
2045
2046
    return $list;
2047
}
2048
2049
/**
2050
 * This function retrieves forum thread users details.
2051
 *
2052
 * @param int $thread_id Thread ID
2053
 * @param   string  Course DB name (optional)
2054
 *
2055
 * @return Doctrine\DBAL\Driver\Statement|null array Array of type
2056
 *                                             ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2057
 *
2058
 * @author Christian Fasanando <[email protected]>,
2059
 *
2060
 * @todo     this function need to be improved
2061
 *
2062
 * @version octubre 2008, dokeos 1.8
2063
 */
2064
function get_thread_users_details($thread_id)
2065
{
2066
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2067
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2068
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2069
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2070
2071
    $course_id = api_get_course_int_id();
2072
2073
    $is_western_name_order = api_is_western_name_order();
2074
    if ($is_western_name_order) {
2075
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2076
    } else {
2077
        $orderby = 'ORDER BY user.lastname, user.firstname';
2078
    }
2079
2080
    if (api_get_session_id()) {
2081
        $session_info = api_get_session_info(api_get_session_id());
2082
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2083
        //not showing coaches
2084
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2085
                FROM $t_posts p, $t_users user, $t_session_rel_user session_rel_user_rel_course
2086
                WHERE
2087
                    p.poster_id = user.id AND
2088
                    user.id = session_rel_user_rel_course.user_id AND
2089
                    session_rel_user_rel_course.status<>'2' AND
2090
                    session_rel_user_rel_course.user_id NOT IN ($user_to_avoid) AND
2091
                    p.thread_id = ".(int) $thread_id.' AND
2092
                    session_id = '.api_get_session_id()." AND
2093
                    p.c_id = $course_id AND
2094
                    session_rel_user_rel_course.c_id = ".$course_id." $orderby ";
2095
    } else {
2096
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
2097
                FROM $t_posts p, $t_users user, $t_course_user course_user
2098
                WHERE
2099
                    p.poster_id = user.id
2100
                    AND user.id = course_user.user_id
2101
                    AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
2102
                    AND p.thread_id = '.(int) $thread_id."
2103
                    AND course_user.status NOT IN('1') AND
2104
                    p.c_id = $course_id AND
2105
                    course_user.c_id = ".$course_id." $orderby";
2106
    }
2107
2108
    return Database::query($sql);
2109
}
2110
2111
/**
2112
 * This function retrieves forum thread users qualify.
2113
 *
2114
 * @param int $thread_id Thread ID
2115
 * @param   string  Course DB name (optional)
2116
 *
2117
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2118
 *
2119
 * @author Jhon Hinojosa
2120
 *
2121
 * @todo     this function need to be improved
2122
 */
2123
function get_thread_users_qualify($thread_id)
2124
{
2125
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2126
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2127
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2128
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2129
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2130
2131
    $course_id = api_get_course_int_id();
2132
    $sessionId = api_get_session_id();
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
    if ($sessionId) {
2142
        $session_info = api_get_session_info($sessionId);
2143
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2144
        //not showing coaches
2145
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2146
                FROM $t_posts post , $t_users user, $t_session_rel_user scu, $t_qualify qualify
2147
                WHERE poster_id = user.id
2148
                    AND post.poster_id = qualify.user_id
2149
                    AND user.id = scu.user_id
2150
                    AND scu.status<>'2'
2151
                    AND scu.user_id NOT IN ($user_to_avoid)
2152
                    AND qualify.thread_id = ".(int) $thread_id.'
2153
                    AND post.thread_id = '.(int) $thread_id."
2154
                    AND scu.session_id = $sessionId
2155
                    AND scu.c_id = ".$course_id." AND
2156
                    qualify.c_id = $course_id AND
2157
                    post.c_id = $course_id
2158
                $orderby ";
2159
    } else {
2160
        $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
2161
                FROM $t_posts post,
2162
                     $t_qualify qualify,
2163
                     $t_users user,
2164
                     $t_course_user course_user
2165
                WHERE
2166
                     post.poster_id = user.id
2167
                     AND post.poster_id = qualify.user_id
2168
                     AND user.id = course_user.user_id
2169
                     AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH.'
2170
                     AND qualify.thread_id = '.(int) $thread_id.'
2171
                     AND post.thread_id = '.(int) $thread_id."
2172
                     AND course_user.status not in('1')
2173
                     AND course_user.c_id = $course_id
2174
                     AND qualify.c_id = $course_id
2175
                     AND post.c_id = $course_id
2176
                 $orderby ";
2177
    }
2178
2179
    return Database::query($sql);
2180
}
2181
2182
/**
2183
 * This function retrieves forum thread users not qualify.
2184
 *
2185
 * @param int $thread_id Thread ID
2186
 * @param   string  Course DB name (optional)
2187
 *
2188
 * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
2189
 *
2190
 * @author   Jhon Hinojosa<[email protected]>,
2191
 *
2192
 * @version oct 2008, dokeos 1.8
2193
 */
2194
function get_thread_users_not_qualify($thread_id)
2195
{
2196
    $t_posts = Database::get_course_table(TABLE_FORUM_POST);
2197
    $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
2198
    $t_users = Database::get_main_table(TABLE_MAIN_USER);
2199
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2200
    $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2201
2202
    $is_western_name_order = api_is_western_name_order();
2203
    if ($is_western_name_order) {
2204
        $orderby = 'ORDER BY user.firstname, user.lastname ';
2205
    } else {
2206
        $orderby = 'ORDER BY user.lastname, user.firstname';
2207
    }
2208
2209
    $course_id = api_get_course_int_id();
2210
2211
    $sql1 = "SELECT user_id FROM  $t_qualify
2212
             WHERE c_id = $course_id AND thread_id = '".$thread_id."'";
2213
    $result1 = Database::query($sql1);
2214
    $cad = '';
2215
    while ($row = Database::fetch_array($result1)) {
2216
        $cad .= $row['user_id'].',';
2217
    }
2218
    if ('' == $cad) {
2219
        $cad = '0';
2220
    } else {
2221
        $cad = substr($cad, 0, strlen($cad) - 1);
2222
    }
2223
2224
    if (api_get_session_id()) {
2225
        $session_info = api_get_session_info(api_get_session_id());
2226
        $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
2227
        //not showing coaches
2228
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2229
                FROM $t_posts post , $t_users user, $t_session_rel_user session_rel_user_rel_course
2230
                WHERE poster_id = user.id
2231
                    AND user.id NOT IN (".$cad.")
2232
                    AND user.id = session_rel_user_rel_course.user_id
2233
                    AND session_rel_user_rel_course.status<>'2'
2234
                    AND session_rel_user_rel_course.user_id NOT IN ($user_to_avoid)
2235
                    AND post.thread_id = ".(int) $thread_id.'
2236
                    AND session_id = '.api_get_session_id()."
2237
                    AND session_rel_user_rel_course.c_id = $course_id AND post.c_id = $course_id $orderby ";
2238
    } else {
2239
        $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
2240
                FROM $t_posts post, $t_users user,$t_course_user course_user
2241
                WHERE post.poster_id = user.id
2242
                AND user.id NOT IN (".$cad.')
2243
                AND user.id = course_user.user_id
2244
                AND course_user.relation_type<>'.COURSE_RELATION_TYPE_RRHH.'
2245
                AND post.thread_id = '.(int) $thread_id."
2246
                AND course_user.status not in('1')
2247
                AND course_user.c_id = $course_id AND post.c_id = $course_id  $orderby";
2248
    }
2249
2250
    return Database::query($sql);
2251
}
2252
2253
/**
2254
 * This function retrieves all the information of a given forumcategory id.
2255
 *
2256
 * @param int $cat_id that indicates the forum
2257
 *
2258
 * @return array returns if there are category or bool returns if there aren't category
2259
 *
2260
 * @author Patrick Cool <[email protected]>, Ghent University
2261
 *
2262
 * @version february 2006, dokeos 1.8
2263
 */
2264
function get_forumcategory_information($cat_id)
2265
{
2266
    $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
2267
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2268
2269
    $course_id = api_get_course_int_id();
2270
    $sql = "SELECT *
2271
            FROM $table_categories forumcategories
2272
            INNER JOIN $table_item_property item_properties
2273
            ON (forumcategories.c_id = item_properties.c_id)
2274
            WHERE
2275
                forumcategories.c_id = $course_id AND
2276
                item_properties.c_id = $course_id AND
2277
                item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
2278
                item_properties.ref='".Database::escape_string($cat_id)."' AND
2279
                forumcategories.cat_id='".Database::escape_string($cat_id)."'";
2280
    $result = Database::query($sql);
2281
2282
    return Database::fetch_array($result);
2283
}
2284
2285
/**
2286
 * This function counts the number of forums inside a given category.
2287
 *
2288
 * @param int $cat_id the id of the forum category
2289
 *
2290
 * @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return
2291
 *       the number of visible forums, $countinvisible=1 would return the number of visible and invisible forums
2292
 *
2293
 * @return int the number of forums inside the given category
2294
 *
2295
 * @author Patrick Cool <[email protected]>, Ghent University
2296
 *
2297
 * @version february 2006, dokeos 1.8
2298
 */
2299
function count_number_of_forums_in_category($cat_id)
2300
{
2301
    $table_forums = Database::get_course_table(TABLE_FORUM);
2302
    $course_id = api_get_course_int_id();
2303
    $cat_id = (int) $cat_id;
2304
    $sql = "SELECT count(*) AS number_of_forums
2305
            FROM $table_forums
2306
            WHERE c_id = $course_id AND forum_category = $cat_id";
2307
    $result = Database::query($sql);
2308
    $row = Database::fetch_array($result);
2309
2310
    return $row['number_of_forums'];
2311
}
2312
2313
/**
2314
 * This function update a thread.
2315
 *
2316
 * @param array $values - The form Values
2317
 */
2318
function updateThread($values)
2319
{
2320
    if (!api_is_allowed_to_edit()) {
2321
        return '';
2322
    }
2323
2324
    $logInfo = [
2325
        'tool' => TOOL_FORUM,
2326
        'tool_id' => $values['forum_id'],
2327
        'tool_id_detail' => $values['thread_id'],
2328
        'action' => 'edit-thread',
2329
        'action_details' => 'thread',
2330
        'info' => $values['thread_title'],
2331
    ];
2332
    Event::registerLog($logInfo);
2333
2334
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
2335
    $courseId = api_get_course_int_id();
2336
    $courseCode = api_get_course_id();
2337
    $sessionId = api_get_session_id();
2338
2339
    // Simple update + set gradebook values to null
2340
    $params = [
2341
        'thread_title' => $values['thread_title'],
2342
        'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
2343
    ];
2344
    $where = ['c_id = ? AND iid = ?' => [$courseId, $values['thread_id']]];
2345
    Database::update($threadTable, $params, $where);
2346
2347
    $id = $values['thread_id'];
2348
    $linkInfo = GradebookUtils::isResourceInCourseGradebook(
2349
        $courseCode,
2350
        LINK_FORUM_THREAD,
2351
        $id,
2352
        $sessionId
2353
    );
2354
2355
    $gradebookLink = null;
2356
    $em = Database::getManager();
2357
    if (!empty($linkInfo) && isset($linkInfo['id'])) {
2358
        $gradebookLink = $em->getRepository(GradebookLink::class)->find($linkInfo['id']);
2359
    }
2360
2361
    // values 1 or 0
2362
    $check = isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : false;
2363
    if ($check) {
2364
        $title = Security::remove_XSS(stripslashes($values['calification_notebook_title']));
2365
        $value = isset($values['numeric_calification']) ? (int) ($values['numeric_calification']) : 0;
2366
        $weight = isset($values['weight_calification']) ? (float) ($values['weight_calification']) : 0;
2367
        $description = '';
2368
        // Update title
2369
        $params = [
2370
            'thread_title_qualify' => $values['calification_notebook_title'],
2371
            'thread_qualify_max' => api_float_val($values['numeric_calification']),
2372
            'thread_weight' => api_float_val($values['weight_calification']),
2373
            'thread_peer_qualify' => $values['thread_peer_qualify'],
2374
        ];
2375
        $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
2376
        Database::update($threadTable, $params, $where);
2377
2378
        if (!$linkInfo) {
2379
            GradebookUtils::add_resource_to_course_gradebook(
2380
                $values['category_id'],
2381
                $courseCode,
2382
                LINK_FORUM_THREAD,
2383
                $id,
2384
                $title,
2385
                $weight,
2386
                $value,
2387
                $description,
2388
                1,
2389
                $sessionId
2390
            );
2391
        } else {
2392
            if ($gradebookLink) {
2393
                $gradebookLink->setWeight($weight);
2394
                $em->persist($gradebookLink);
2395
                $em->flush();
2396
            }
2397
        }
2398
    } else {
2399
        $params = [
2400
            'thread_title_qualify' => '',
2401
            'thread_qualify_max' => 0,
2402
            'thread_weight' => 0,
2403
            'thread_peer_qualify' => 0,
2404
        ];
2405
        $where = ['c_id = ? AND iid = ?' => [$courseId, $values['thread_id']]];
2406
        Database::update($threadTable, $params, $where);
2407
2408
        if (!empty($linkInfo)) {
2409
            if ($gradebookLink) {
2410
                $em->remove($gradebookLink);
2411
                $em->flush();
2412
            }
2413
        }
2414
    }
2415
2416
    $message = get_lang('The post has been modified').'<br />';
2417
    Display::addFlash(Display::return_message($message, 'confirmation', false));
2418
}
2419
2420
/**
2421
 * This function stores a new thread. This is done through an entry in the forum_thread table AND
2422
 * in the forum_post table because. The threads are also stored in the item_property table. (forum posts are not (yet)).
2423
 *
2424
 * @param bool $showMessage
2425
 * @param int  $userId      Optional. The user ID
2426
 * @param int  $sessionId
2427
 *
2428
 * @return CForumThread
2429
 *
2430
 * @author Patrick Cool <[email protected]>, Ghent University
2431
 *
2432
 * @version february 2006, dokeos 1.8
2433
 */
2434
function store_thread(
2435
    CForumForum $forum,
2436
    array $values,
2437
    array $courseInfo = [],
2438
    $showMessage = true,
2439
    $userId = 0,
2440
    $sessionId = 0
2441
) {
2442
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
2443
    $userId = $userId ?: api_get_user_id();
2444
    $course_id = $courseInfo['real_id'];
2445
    $courseCode = $courseInfo['code'];
2446
    $sessionId = $sessionId ?: api_get_session_id();
2447
2448
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
2449
2450
    $post_date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
2451
    $visible = 1;
2452
    if ('1' == $forum->getApprovalDirectPost() && !api_is_allowed_to_edit(null, true)) {
2453
        $visible = 0; // The post has not been approved yet.
2454
    }
2455
    $clean_post_title = $values['post_title'];
2456
2457
    $user = api_get_user_entity(api_get_user_id());
2458
    $course = api_get_course_entity($course_id);
2459
    $session = api_get_session_entity($sessionId);
2460
2461
    // We first store an entry in the forum_thread table because the thread_id is used in the forum_post table.
2462
    $thread = new CForumThread();
2463
    $thread
2464
        ->setCId($course_id)
2465
        ->setThreadTitle($clean_post_title)
2466
        ->setForum($forum)
2467
        ->setThreadPosterId($userId)
2468
        ->setThreadPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2469
        ->setThreadDate($post_date)
2470
        ->setThreadSticky(isset($values['thread_sticky']) ? $values['thread_sticky'] : 0)
2471
        ->setThreadTitleQualify(
2472
            isset($values['calification_notebook_title']) ? $values['calification_notebook_title'] : null
2473
        )
2474
        ->setThreadQualifyMax(isset($values['numeric_calification']) ? (int) $values['numeric_calification'] : 0)
2475
        ->setThreadWeight(isset($values['weight_calification']) ? (int) $values['weight_calification'] : 0)
2476
        ->setThreadPeerQualify(isset($values['thread_peer_qualify']) ? (bool) $values['thread_peer_qualify'] : false)
2477
        ->setSessionId($sessionId)
2478
        ->setLpItemId(isset($values['lp_item_id']) ? (int) $values['lp_item_id'] : 0)
2479
        ->setParent($forum)
2480
        ->addCourseLink(
2481
            $course,
2482
            $session
2483
        )
2484
    ;
2485
2486
    $repo = Container::getForumThreadRepository();
2487
    $em = $repo->getEntityManager();
2488
    $em->persist($thread);
2489
    $em->flush();
2490
2491
    if (!$thread->getIid()) {
2492
        return null;
2493
    }
2494
2495
    // Add option gradebook qualify.
2496
    if (isset($values['thread_qualify_gradebook']) &&
2497
        1 == $values['thread_qualify_gradebook']
2498
    ) {
2499
        // Add function gradebook.
2500
        $resourcename = stripslashes($values['calification_notebook_title']);
2501
        GradebookUtils::add_resource_to_course_gradebook(
2502
            $values['category_id'],
2503
            $courseCode,
2504
            5,
2505
            $thread->getIid(),
2506
            $resourcename,
2507
            $values['weight_calification'],
2508
            $values['numeric_calification'],
2509
            '',
2510
            0,
2511
            $sessionId
2512
        );
2513
    }
2514
2515
    /*api_item_property_update(
2516
        $courseInfo,
2517
        TOOL_FORUM_THREAD,
2518
        $thread->getIid(),
2519
        'ForumThreadAdded',
2520
        $userId,
2521
        $groupInfo,
2522
        null,
2523
        null,
2524
        null,
2525
        $sessionId
2526
    );*/
2527
2528
    // If the forum properties tell that the posts have to be approved
2529
    // we have to put the whole thread invisible,
2530
    // because otherwise the students will see the thread and not the post
2531
    // in the thread.
2532
    // We also have to change $visible because the post itself has to be
2533
    // visible in this case (otherwise the teacher would have
2534
    // to make the thread visible AND the post.
2535
    // Default behaviour
2536
    /*api_set_default_visibility(
2537
        $thread->getIid(),
2538
        TOOL_FORUM_THREAD,
2539
        $groupId,
2540
        $courseInfo,
2541
        $sessionId,
2542
        $userId
2543
    );*/
2544
2545
    if (0 == $visible) {
2546
        /*api_item_property_update(
2547
            $courseInfo,
2548
            TOOL_FORUM_THREAD,
2549
            $thread->getIid(),
2550
            'invisible',
2551
            $userId,
2552
            $groupInfo
2553
        );*/
2554
        $visible = 1;
2555
    }
2556
2557
    $logInfo = [
2558
        'tool' => TOOL_FORUM,
2559
        'tool_id' => $values['forum_id'],
2560
        'tool_id_detail' => $thread->getIid(),
2561
        'action' => 'new-thread',
2562
        'info' => $clean_post_title,
2563
    ];
2564
    Event::registerLog($logInfo);
2565
2566
    // We now store the content in the table_post table.
2567
    $post = new CForumPost();
2568
    $post
2569
        ->setCId($course_id)
2570
        ->setPostTitle($clean_post_title)
2571
        ->setPostText($values['post_text'])
2572
        ->setThread($thread)
2573
        ->setForum($forum)
2574
        ->setPosterId($userId)
2575
        ->setPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
2576
        ->setPostDate($post_date)
2577
        ->setPostNotification(isset($values['post_notification']) ? (int) $values['post_notification'] : null)
2578
        ->setVisible($visible)
2579
        ->setStatus(CForumPost::STATUS_VALIDATED)
2580
        ->setParent($thread)
2581
        ->addCourseLink(
2582
            $course,
2583
            $session
2584
        )
2585
    ;
2586
2587
    if ($forum->isModerated()) {
2588
        $post->setStatus(
2589
            api_is_course_admin() ? CForumPost::STATUS_VALIDATED : CForumPost::STATUS_WAITING_MODERATION
2590
        );
2591
    }
2592
2593
    $repo = Container::getForumPostRepository();
2594
    $em = $repo->getEntityManager();
2595
    $em->persist($post);
2596
    $em->flush();
2597
2598
    $postId = $post->getIid();
2599
    $thread->setThreadLastPost($postId);
2600
    $em->persist($thread);
2601
    $em->flush();
2602
2603
    $logInfo = [
2604
        'tool' => TOOL_FORUM,
2605
        'tool_id' => $values['forum_id'],
2606
        'tool_id_detail' => $thread->getIid(),
2607
        'action' => 'new-post',
2608
        'info' => $clean_post_title,
2609
    ];
2610
    Event::registerLog($logInfo);
2611
2612
    // Now we have to update the thread table to fill the thread_last_post
2613
    // field (so that we know when the thread has been updated for the last time).
2614
    $sql = "UPDATE $table_threads
2615
            SET thread_last_post = '".$postId."'
2616
            WHERE
2617
                c_id = $course_id AND
2618
                iid = '".$thread->getIid()."'";
2619
    Database::query($sql);
2620
    $message = get_lang('The new thread has been added');
2621
2622
    // Overwrite default message.
2623
    if ($forum->isModerated() &&
2624
        !api_is_allowed_to_edit(null, true)
2625
    ) {
2626
        $message = get_lang('Your message has to be approved before people can view it.');
2627
    }
2628
2629
    add_forum_attachment_file(
2630
        null,
2631
        $post
2632
    );
2633
2634
    if ('1' == $forum->getApprovalDirectPost() &&
2635
        !api_is_allowed_to_edit(null, true)
2636
    ) {
2637
        $message .= get_lang('Your message has to be approved before people can view it.').'<br />';
2638
        $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2639
            get_lang('Forum').'</a><br />';
2640
    } else {
2641
        $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
2642
            get_lang('Forum').'</a><br />';
2643
        $message .= get_lang('You can now return to the').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&thread='.$thread->getIid().'">'.
2644
            get_lang('Message').'</a>';
2645
    }
2646
    $reply_info['new_post_id'] = $postId;
2647
    $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
2648
2649
    if (1 == $my_post_notification) {
2650
        set_notification('thread', $thread->getIid(), true);
2651
    }
2652
2653
    send_notification_mails(
2654
        $forum,
2655
        $thread,
2656
        $reply_info,
2657
        $courseInfo['code']
2658
    );
2659
2660
    Session::erase('formelements');
2661
    Session::erase('origin');
2662
    Session::erase('breadcrumbs');
2663
    Session::erase('addedresource');
2664
    Session::erase('addedresourceid');
2665
2666
    if ($showMessage) {
2667
        Display::addFlash(Display::return_message($message, 'success', false));
2668
    }
2669
2670
    return $thread;
2671
}
2672
2673
/**
2674
 * This function displays the form that is used to add a post. This can be a new thread or a reply.
2675
 *
2676
 * @param string $action
2677
 *                            is the parameter that determines if we are
2678
 *                            2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete thread (if enabled)
2679
 *                            3. replymessage: Replying to a message ($action =replymessage) => I-frame with the complete thread (if enabled)
2680
 *                            (I first thought to put and I-frame with the message only)
2681
 *                            4. quote: Quoting a message ($action= quotemessage) => I-frame with the complete thread (if enabled).
2682
 *                            The message will be in the reply. (I first thought not to put an I-frame here)
2683
 * @param array  $form_values
2684
 * @param bool   $showPreview
2685
 *
2686
 * @return FormValidator
2687
 */
2688
function show_add_post_form(CForumForum $forum, CForumThread $thread, CForumPost $post = null, $action, $form_values, $showPreview = true)
2689
{
2690
    $_user = api_get_user_info();
2691
    $action = isset($action) ? Security::remove_XSS($action) : '';
2692
    $threadId = $thread->getIid();
2693
    $forumId = $forum->getIid();
2694
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
2695
    $postId = $post ? $post->getIid() : 0;
2696
2697
    $url = api_get_self().'?'.http_build_query(
2698
        [
2699
            'action' => $action,
2700
            'forum' => $forumId,
2701
            'thread' => $threadId,
2702
            'post' => $postId,
2703
        ]
2704
    ).'&'.api_get_cidreq();
2705
2706
    $form = new FormValidator(
2707
        'thread',
2708
        'post',
2709
        $url
2710
    );
2711
    $form->setConstants(['forum' => '5']);
2712
2713
    // Setting the form elements.
2714
    $form->addElement('hidden', 'forum_id', $forumId);
2715
    $form->addElement('hidden', 'thread_id', $threadId);
2716
    $form->addElement('hidden', 'action', $action);
2717
2718
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2719
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2720
        $form->addElement('text', 'poster_name', get_lang('Name'));
2721
        $form->applyFilter('poster_name', 'html_filter');
2722
    }
2723
2724
    $form->addElement('text', 'post_title', get_lang('Title'));
2725
    $form->addHtmlEditor(
2726
        'post_text',
2727
        get_lang('Text'),
2728
        true,
2729
        false,
2730
        api_is_allowed_to_edit(null, true) ? [
2731
            'ToolbarSet' => 'Forum',
2732
            'Width' => '100%',
2733
            'Height' => '300',
2734
        ] : [
2735
            'ToolbarSet' => 'ForumStudent',
2736
            'Width' => '100%',
2737
            'Height' => '300',
2738
            'UserStatus' => 'student',
2739
        ]
2740
    );
2741
    $form->addRule('post_text', get_lang('Required field'), 'required');
2742
2743
    if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2744
        $extraFields = new ExtraField('forum_post');
2745
        $extraFields->addElements(
2746
            $form,
2747
            null,
2748
            [], //exclude
2749
            false, // filter
2750
            false, // tag as select
2751
            ['ask_for_revision'], //show only fields
2752
            [], // order fields
2753
            [] // extra data);
2754
        );
2755
    }
2756
2757
    $iframe = null;
2758
    if ($showPreview) {
2759
        if ('newthread' !== $action && !empty($threadId)) {
2760
            $iframe = '<iframe style="border: 1px solid black"
2761
            src="iframe_thread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId.'#'.$postId.'" width="100%"></iframe>';
2762
        }
2763
        if (!empty($iframe)) {
2764
            $form->addElement('label', get_lang('Thread'), $iframe);
2765
        }
2766
    }
2767
2768
    if (in_array($action, ['quote', 'replymessage'])) {
2769
        $form->addFile('user_upload[]', get_lang('Attachment'));
2770
        $form->addButton(
2771
            'add_attachment',
2772
            get_lang('Add attachment'),
2773
            'paperclip',
2774
            'default',
2775
            'default',
2776
            null,
2777
            ['id' => 'reply-add-attachment']
2778
        );
2779
    } else {
2780
        $form->addFile('user_upload', get_lang('Attachment'));
2781
    }
2782
2783
    if ($giveRevision) {
2784
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
2785
        $form->addHidden('give_revision', 1);
2786
        if (false === $hide) {
2787
            $extraField = new ExtraField('forum_post');
2788
            $extraField->addElements(
2789
                $form,
2790
                null,
2791
                [], //exclude
2792
                false, // filter
2793
                false, // tag as select
2794
                ['revision_language'], //show only fields
2795
                [], // order fields
2796
                [] // extra data
2797
            );
2798
        } else {
2799
            $form->addHidden('extra_revision_language', 1);
2800
        }
2801
    }
2802
2803
    // Setting the class and text of the form title and submit button.
2804
    if ('quote' === $action) {
2805
        $form->addButtonCreate(get_lang('Quote this message'), 'SubmitPost');
2806
    } elseif ('replythread' === $action) {
2807
        $form->addButtonCreate(get_lang('Reply to this thread'), 'SubmitPost');
2808
    } elseif ('replymessage' === $action) {
2809
        $form->addButtonCreate(get_lang('Reply to this message'), 'SubmitPost');
2810
    }
2811
2812
    $defaults['thread_peer_qualify'] = 0;
2813
    if (!empty($form_values)) {
2814
        $defaults['post_title'] = prepare4display($form_values['post_title']);
2815
        $defaults['post_text'] = prepare4display($form_values['post_text']);
2816
        $defaults['post_notification'] = (int) $form_values['post_notification'];
2817
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
2818
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
2819
    }
2820
2821
    // If we are quoting a message we have to retrieve the information of the post we are quoting so that
2822
    // we can add this as default to the textarea.
2823
    // We also need to put the parent_id of the post in a hidden form when
2824
    if (('quote' === $action || 'replymessage' === $action || $giveRevision) && !empty($postId)) {
2825
        // we are quoting or replying to a message (<> reply to a thread !!!)
2826
        $form->addHidden('post_parent_id', $post->getIid());
2827
        // If we are replying or are quoting then we display a default title.
2828
        $posterInfo = api_get_user_info($post->getPosterId());
2829
        $posterName = '';
2830
        if ($posterInfo) {
2831
            $posterName = $posterInfo['complete_name'];
2832
        }
2833
        $defaults['post_title'] = get_lang('Re:').api_html_entity_decode($post->getPostTitle(), ENT_QUOTES);
2834
        // When we are quoting a message then we have to put that message into the wysiwyg editor.
2835
        // Note: The style has to be hardcoded here because using class="quote" didn't work.
2836
        if ('quote' === $action) {
2837
            $defaults['post_text'] = '<div>&nbsp;</div>
2838
                <div style="margin: 5px;">
2839
                    <div style="font-size: 90%; font-style: italic;">'.
2840
                get_lang('Quoting').' '.$posterName.':</div>
2841
                        <div style="color: #006600; font-size: 90%;  font-style: italic; background-color: #FAFAFA; border: #D1D7DC 1px solid; padding: 3px;">'.
2842
                prepare4display($post->getPostText()).'
2843
                        </div>
2844
                    </div>
2845
                <div>&nbsp;</div>
2846
                <div>&nbsp;</div>
2847
            ';
2848
        }
2849
        if ($giveRevision) {
2850
            $defaults['post_text'] = prepare4display($post->getPostText());
2851
        }
2852
    }
2853
2854
    $form->setDefaults(isset($defaults) ? $defaults : []);
2855
2856
    // The course admin can make a thread sticky (=appears with special icon and always on top).
2857
    $form->addRule('post_title', get_lang('Required field'), 'required');
2858
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2859
        $form->addRule(
2860
            'poster_name',
2861
            get_lang('Required field'),
2862
            'required'
2863
        );
2864
    }
2865
2866
    // Validation or display
2867
    if ($form->validate()) {
2868
        $check = Security::check_token('post');
2869
        if ($check) {
2870
            $values = $form->getSubmitValues();
2871
            if (isset($values['thread_qualify_gradebook']) &&
2872
                '1' == $values['thread_qualify_gradebook'] &&
2873
                empty($values['weight_calification'])
2874
            ) {
2875
                Display::addFlash(
2876
                    Display::return_message(
2877
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
2878
                        'error',
2879
                        false
2880
                    )
2881
                );
2882
2883
                return false;
2884
            }
2885
2886
            $postId = 0;
2887
            $threadId = 0;
2888
2889
            switch ($action) {
2890
                case 'quote':
2891
                case 'replythread':
2892
                case 'replymessage':
2893
                    $postId = store_reply($forum, $thread, $values);
2894
2895
                    break;
2896
            }
2897
2898
            if ($postId) {
2899
                if (isset($values['give_revision']) && 1 == $values['give_revision']) {
2900
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2901
                    $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
2902
                    $params = [
2903
                        'item_id' => $postId,
2904
                        'extra_revision_language' => $revisionLanguage,
2905
                    ];
2906
2907
                    $extraFieldValues->saveFieldValues(
2908
                        $params,
2909
                        false,
2910
                        false,
2911
                        ['revision_language']
2912
                    );
2913
                }
2914
2915
                if (in_array($action, ['replythread', 'replymessage', 'quote'])) {
2916
                    $extraFieldValues = new ExtraFieldValue('forum_post');
2917
                    $params = [
2918
                        'item_id' => $postId,
2919
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
2920
                    ];
2921
                    $extraFieldValues->saveFieldValues(
2922
                        $params,
2923
                        false,
2924
                        false,
2925
                        ['ask_for_revision']
2926
                    );
2927
                }
2928
            }
2929
2930
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
2931
                [
2932
                    'forum' => $forumId,
2933
                    'thread' => $thread->getIid(),
2934
                ]
2935
            );
2936
2937
            Security::clear_token();
2938
            header('Location: '.$url);
2939
            exit;
2940
        }
2941
    } else {
2942
        $token = Security::get_token();
2943
        $form->addElement('hidden', 'sec_token');
2944
        $form->setConstants(['sec_token' => $token]);
2945
2946
        // Delete from $_SESSION forum attachment from other posts
2947
        // and keep only attachments for new post
2948
        clearAttachedFiles(FORUM_NEW_POST);
2949
        // Get forum attachment ajax table to add it to form
2950
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
2951
        $ajaxHtml = $attachmentAjaxTable;
2952
        $form->addElement('html', $ajaxHtml);
2953
2954
        return $form;
2955
    }
2956
}
2957
2958
function newThread(CForumForum $forum, $form_values = '', $showPreview = true)
2959
{
2960
    $_user = api_get_user_info();
2961
    $forumId = $forum->getIid();
2962
    $my_post = isset($_GET['post']) ? (int) $_GET['post'] : '';
2963
    $giveRevision = isset($_GET['give_revision']) && 1 == $_GET['give_revision'];
2964
    $action = 'new_thread';
2965
2966
    $url = api_get_self().'?'.http_build_query(
2967
            [
2968
                'action' => $action,
2969
                'forum' => $forumId,
2970
                'post' => $my_post,
2971
            ]
2972
        ).'&'.api_get_cidreq();
2973
2974
    $form = new FormValidator(
2975
        'thread',
2976
        'post',
2977
        $url
2978
    );
2979
2980
    // Setting the form elements.
2981
    $form->addElement('hidden', 'forum_id', $forumId);
2982
    $form->addElement('hidden', 'thread_id', 0);
2983
    $form->addElement('hidden', 'action', $action);
2984
2985
    // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
2986
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
2987
        $form->addElement('text', 'poster_name', get_lang('Name'));
2988
        $form->applyFilter('poster_name', 'html_filter');
2989
    }
2990
2991
    $form->addElement('text', 'post_title', get_lang('Title'));
2992
    $form->addHtmlEditor(
2993
        'post_text',
2994
        get_lang('Text'),
2995
        true,
2996
        false,
2997
        api_is_allowed_to_edit(null, true) ? [
2998
            'ToolbarSet' => 'Forum',
2999
            'Width' => '100%',
3000
            'Height' => '300',
3001
        ] : [
3002
            'ToolbarSet' => 'ForumStudent',
3003
            'Width' => '100%',
3004
            'Height' => '300',
3005
            'UserStatus' => 'student',
3006
        ]
3007
    );
3008
    $form->addRule('post_text', get_lang('Required field'), 'required');
3009
3010
    $extraFields = new ExtraField('forum_post');
3011
    $extraFields->addElements(
3012
        $form,
3013
        null,
3014
        [], //exclude
3015
        false, // filter
3016
        false, // tag as select
3017
        ['ask_for_revision'], //show only fields
3018
        [], // order fields
3019
        [] // extra data);
3020
    );
3021
3022
    if (Gradebook::is_active() &&
3023
        (api_is_course_admin() || api_is_session_general_coach() || api_is_course_tutor())
3024
    ) {
3025
        $form->addElement('advanced_settings', 'advanced_params', get_lang('Advanced settings'));
3026
        $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3027
3028
        // Thread qualify
3029
        if (Gradebook::is_active()) {
3030
            //Loading gradebook select
3031
            GradebookUtils::load_gradebook_select_in_tool($form);
3032
            $form->addElement(
3033
                'checkbox',
3034
                'thread_qualify_gradebook',
3035
                '',
3036
                get_lang('Grade this thread'),
3037
                'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"'
3038
            );
3039
        } else {
3040
            $form->addElement('hidden', 'thread_qualify_gradebook', false);
3041
        }
3042
3043
        $form->addElement('html', '<div id="options_field" style="display:none">');
3044
        $form->addElement('text', 'numeric_calification', get_lang('Maximum score'));
3045
        $form->applyFilter('numeric_calification', 'html_filter');
3046
        $form->addElement('text', 'calification_notebook_title', get_lang('Column header in Competences Report'));
3047
        $form->applyFilter('calification_notebook_title', 'html_filter');
3048
3049
        $form->addElement(
3050
            'text',
3051
            'weight_calification',
3052
            get_lang('Weight in Report'),
3053
            ['value' => '0.00', 'onfocus' => 'javascript: this.select();']
3054
        );
3055
        $form->applyFilter('weight_calification', 'html_filter');
3056
3057
        $group = [];
3058
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('Yes'), 1);
3059
        $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('No'), 0);
3060
        $form->addGroup(
3061
            $group,
3062
            '',
3063
            [
3064
                get_lang('Thread scored by peers'),
3065
                get_lang('Thread scored by peersComment'),
3066
            ]
3067
        );
3068
        $form->addElement('html', '</div>');
3069
        $form->addElement('html', '</div>');
3070
    }
3071
3072
    Skill::addSkillsToForm($form, ITEM_TYPE_FORUM_THREAD, 0);
3073
    $form->addElement('checkbox', 'thread_sticky', '', get_lang('This is a sticky message (appears always on top and has a special sticky icon)'));
3074
3075
    $form->addFile('user_upload', get_lang('Attachment'));
3076
3077
    if ($giveRevision) {
3078
        $hide = api_get_configuration_value('hide_forum_post_revision_language');
3079
        $form->addHidden('give_revision', 1);
3080
        if (false === $hide) {
3081
            $extraField = new ExtraField('forum_post');
3082
            $extraField->addElements(
3083
                $form,
3084
                null,
3085
                [], //exclude
3086
                false, // filter
3087
                false, // tag as select
3088
                ['revision_language'], //show only fields
3089
                [], // order fields
3090
                [] // extra data
3091
            );
3092
        } else {
3093
            $form->addHidden('extra_revision_language', 1);
3094
        }
3095
    }
3096
    $form->addButtonCreate(get_lang('Create thread'), 'SubmitPost');
3097
3098
    $defaults['thread_peer_qualify'] = 0;
3099
    if (!empty($form_values)) {
3100
        $defaults['post_title'] = prepare4display($form_values['post_title']);
3101
        $defaults['post_text'] = prepare4display($form_values['post_text']);
3102
        $defaults['post_notification'] = (int) $form_values['post_notification'];
3103
        $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
3104
        $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
3105
    }
3106
3107
    $form->setDefaults(isset($defaults) ? $defaults : []);
3108
3109
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3110
    $form->addRule('post_title', get_lang('Required field'), 'required');
3111
    if (1 == $forum->getAllowAnonymous() && !isset($_user['user_id'])) {
3112
        $form->addRule(
3113
            'poster_name',
3114
            get_lang('Required field'),
3115
            'required'
3116
        );
3117
    }
3118
3119
    // Validation or display
3120
    if ($form->validate()) {
3121
        $check = Security::check_token('post');
3122
        if ($check) {
3123
            $values = $form->getSubmitValues();
3124
            if (isset($values['thread_qualify_gradebook']) &&
3125
                '1' == $values['thread_qualify_gradebook'] &&
3126
                empty($values['weight_calification'])
3127
            ) {
3128
                Display::addFlash(
3129
                    Display::return_message(
3130
                        get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
3131
                        'error',
3132
                        false
3133
                    )
3134
                );
3135
3136
                return false;
3137
            }
3138
3139
            $newThread = store_thread($forum, $values);
3140
            if ($newThread) {
3141
                Skill::saveSkills($form, ITEM_TYPE_FORUM_THREAD, $newThread->getIid());
3142
                $postId = $newThread->getThreadLastPost();
3143
3144
                if ($postId) {
3145
                    if (isset($values['give_revision']) && 1 == $values['give_revision']) {
3146
                        $extraFieldValues = new ExtraFieldValue('forum_post');
3147
                        $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
3148
3149
                        $params = [
3150
                            'item_id' => $postId,
3151
                            'extra_revision_language' => $revisionLanguage,
3152
                        ];
3153
3154
                        $extraFieldValues->saveFieldValues(
3155
                            $params,
3156
                            false,
3157
                            false,
3158
                            ['revision_language']
3159
                        );
3160
                    }
3161
                    $extraFieldValues = new ExtraFieldValue('forum_post');
3162
                    $params = [
3163
                        'item_id' => $postId,
3164
                        'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
3165
                    ];
3166
                    $extraFieldValues->saveFieldValues(
3167
                        $params,
3168
                        false,
3169
                        false,
3170
                        ['ask_for_revision']
3171
                    );
3172
                }
3173
            }
3174
3175
            $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
3176
                [
3177
                    'forum' => $forumId,
3178
                    'thread' => $newThread->getIid(),
3179
                ]
3180
            );
3181
3182
            Security::clear_token();
3183
            header('Location: '.$url);
3184
            exit;
3185
        }
3186
    } else {
3187
        $token = Security::get_token();
3188
        $form->addElement('hidden', 'sec_token');
3189
        $form->setConstants(['sec_token' => $token]);
3190
3191
        // Delete from $_SESSION forum attachment from other posts
3192
        // and keep only attachments for new post
3193
        clearAttachedFiles(FORUM_NEW_POST);
3194
        // Get forum attachment ajax table to add it to form
3195
        $attachmentAjaxTable = getAttachmentsAjaxTable(0, $forum->getIid());
3196
        $ajaxHtml = $attachmentAjaxTable;
3197
        $form->addElement('html', $ajaxHtml);
3198
3199
        return $form;
3200
    }
3201
}
3202
3203
/**
3204
 * @param array $threadInfo
3205
 * @param int   $user_id
3206
 * @param int   $thread_id
3207
 * @param int   $thread_qualify
3208
 * @param int   $qualify_time
3209
 * @param int   $session_id
3210
 *
3211
 * @return array optional
3212
 *
3213
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3214
 *
3215
 * @version October 2008, dokeos  1.8.6
3216
 */
3217
function saveThreadScore(
3218
    $threadInfo,
3219
    $user_id,
3220
    $thread_id,
3221
    $thread_qualify = 0,
3222
    $qualify_time,
3223
    $session_id = 0
3224
) {
3225
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3226
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3227
3228
    $course_id = api_get_course_int_id();
3229
    $session_id = (int) $session_id;
3230
    $currentUserId = api_get_user_id();
3231
3232
    if ($user_id == (string) ((int) $user_id) &&
3233
        $thread_id == (string) ((int) $thread_id) &&
3234
        $thread_qualify == (string) ((float) $thread_qualify)
3235
    ) {
3236
        // Testing
3237
        $sql = "SELECT thread_qualify_max FROM $table_threads
3238
                WHERE c_id = $course_id AND thread_id=".$thread_id;
3239
        $res_string = Database::query($sql);
3240
        $row_string = Database::fetch_array($res_string);
3241
        if ($thread_qualify <= $row_string[0]) {
3242
            if (0 == $threadInfo['thread_peer_qualify']) {
3243
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3244
                        WHERE
3245
                            c_id = $course_id AND
3246
                            user_id = $user_id AND
3247
                            thread_id = ".$thread_id;
3248
            } else {
3249
                $sql = "SELECT COUNT(*) FROM $table_threads_qualify
3250
                        WHERE
3251
                            c_id = $course_id AND
3252
                            user_id = $user_id AND
3253
                            qualify_user_id = $currentUserId AND
3254
                            thread_id = ".$thread_id;
3255
            }
3256
3257
            $result = Database::query($sql);
3258
            $row = Database::fetch_array($result);
3259
3260
            if (0 == $row[0]) {
3261
                $sql = "INSERT INTO $table_threads_qualify (c_id, user_id, thread_id,qualify,qualify_user_id,qualify_time,session_id)
3262
                        VALUES (".$course_id.", '".$user_id."','".$thread_id."',".(float) $thread_qualify.", '".$currentUserId."','".$qualify_time."','".$session_id."')";
3263
                Database::query($sql);
3264
                $insertId = Database::insert_id();
3265
3266
                return 'insert';
3267
            } else {
3268
                saveThreadScoreHistory(
3269
                    '1',
3270
                    $course_id,
3271
                    $user_id,
3272
                    $thread_id
3273
                );
3274
3275
                // Update
3276
                $sql = "UPDATE $table_threads_qualify
3277
                        SET
3278
                            qualify = '".$thread_qualify."',
3279
                            qualify_time = '".$qualify_time."'
3280
                        WHERE
3281
                            c_id = $course_id AND
3282
                            user_id=".$user_id.' AND
3283
                            thread_id='.$thread_id." AND
3284
                            qualify_user_id = $currentUserId
3285
                        ";
3286
                Database::query($sql);
3287
3288
                return 'update';
3289
            }
3290
        } else {
3291
            return null;
3292
        }
3293
    }
3294
}
3295
3296
/**
3297
 * This function shows qualify.
3298
 *
3299
 * @param string $option    contains the information of option to run
3300
 * @param int    $user_id   contains the information the current user id
3301
 * @param int    $thread_id contains the information the current thread id
3302
 *
3303
 * @return int qualify
3304
 *             <code> $option=1 obtained the qualification of the current thread</code>
3305
 *
3306
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3307
 *
3308
 * @version October 2008, dokeos  1.8.6
3309
 */
3310
function showQualify($option, $user_id, $thread_id)
3311
{
3312
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3313
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3314
3315
    $course_id = api_get_course_int_id();
3316
    $user_id = (int) $user_id;
3317
    $thread_id = (int) $thread_id;
3318
3319
    if (empty($user_id) || empty($thread_id)) {
3320
        return false;
3321
    }
3322
3323
    $sql = '';
3324
    switch ($option) {
3325
        case 1:
3326
            $sql = "SELECT qualify FROM $table_threads_qualify
3327
                    WHERE
3328
                        c_id = $course_id AND
3329
                        user_id=".$user_id.' AND
3330
                        thread_id='.$thread_id;
3331
3332
            break;
3333
        case 2:
3334
            $sql = "SELECT thread_qualify_max FROM $table_threads
3335
                    WHERE c_id = $course_id AND thread_id=".$thread_id;
3336
3337
            break;
3338
    }
3339
3340
    if (!empty($sql)) {
3341
        $rs = Database::query($sql);
3342
        $row = Database::fetch_array($rs);
3343
3344
        return $row[0];
3345
    }
3346
3347
    return [];
3348
}
3349
3350
/**
3351
 * This function gets qualify historical.
3352
 *
3353
 * @param int  $user_id   contains the information the current user id
3354
 * @param int  $thread_id contains the information the current thread id
3355
 * @param bool $opt       contains the information of option to run
3356
 *
3357
 * @return array
3358
 *
3359
 * @author Christian Fasanando <[email protected]>,
3360
 * @author Isaac Flores <[email protected]>,
3361
 *
3362
 * @version October 2008, dokeos  1.8.6
3363
 */
3364
function getThreadScoreHistory($user_id, $thread_id, $opt)
3365
{
3366
    $user_id = (int) $user_id;
3367
    $thread_id = (int) $thread_id;
3368
3369
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3370
    $course_id = api_get_course_int_id();
3371
3372
    if ('false' == $opt) {
3373
        $sql = "SELECT * FROM $table_threads_qualify_log
3374
                WHERE
3375
                    c_id = $course_id AND
3376
                    thread_id='".$thread_id."' AND
3377
                    user_id='".$user_id."'
3378
                ORDER BY qualify_time";
3379
    } else {
3380
        $sql = "SELECT * FROM $table_threads_qualify_log
3381
                WHERE
3382
                    c_id = $course_id AND
3383
                    thread_id='".$thread_id."' AND
3384
                    user_id='".$user_id."'
3385
                ORDER BY qualify_time DESC";
3386
    }
3387
    $rs = Database::query($sql);
3388
    $log = [];
3389
    while ($row = Database::fetch_array($rs, 'ASSOC')) {
3390
        $log[] = $row;
3391
    }
3392
3393
    return $log;
3394
}
3395
3396
/**
3397
 * This function stores qualify historical.
3398
 *
3399
 * @param bool contains the information of option to run
3400
 * @param string contains the information the current course id
3401
 * @param int contains the information the current forum id
3402
 * @param int contains the information the current user id
3403
 * @param int contains the information the current thread id
3404
 * @param int contains the information the current qualify
3405
 * @param string $option
3406
 * @param int    $course_id
3407
 * @param int    $user_id
3408
 * @param int    $thread_id
3409
 *
3410
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3411
 *
3412
 * @version October 2008, dokeos  1.8.6
3413
 */
3414
function saveThreadScoreHistory(
3415
    $option,
3416
    $course_id,
3417
    $user_id,
3418
    $thread_id
3419
) {
3420
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3421
    $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
3422
3423
    $course_id = (int) $course_id;
3424
    $qualify_user_id = api_get_user_id();
3425
3426
    if ($user_id == (string) ((int) $user_id) &&
3427
        $thread_id == (string) ((int) $thread_id) && 1 == $option
3428
    ) {
3429
        // Extract information of thread_qualify.
3430
        $sql = "SELECT qualify, qualify_time
3431
                FROM $table_threads_qualify
3432
                WHERE
3433
                    c_id = $course_id AND
3434
                    user_id = ".$user_id.' AND
3435
                    thread_id = '.$thread_id." AND
3436
                    qualify_user_id = $qualify_user_id
3437
                ";
3438
        $rs = Database::query($sql);
3439
        $row = Database::fetch_array($rs);
3440
3441
        // Insert thread_historical.
3442
        $sql = "INSERT INTO $table_threads_qualify_log (c_id, user_id, thread_id, qualify, qualify_user_id,qualify_time,session_id)
3443
                VALUES(".$course_id.", '".$user_id."','".$thread_id."',".(float) $row[0].", '".$qualify_user_id."','".$row[1]."','')";
3444
        Database::query($sql);
3445
    }
3446
}
3447
3448
/**
3449
 * This function shows current thread qualify .
3450
 *
3451
 * @param int $threadId
3452
 * @param int $sessionId
3453
 * @param int $userId
3454
 *
3455
 * @return array or null if is empty
3456
 *
3457
 * @author Isaac Flores <[email protected]>, U.N.A.S University
3458
 *
3459
 * @version December 2008, dokeos  1.8.6
3460
 */
3461
function current_qualify_of_thread($threadId, $sessionId, $userId)
3462
{
3463
    $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
3464
3465
    $course_id = api_get_course_int_id();
3466
    $currentUserId = api_get_user_id();
3467
    $sessionId = (int) $sessionId;
3468
    $threadId = (int) $threadId;
3469
3470
    $sql = "SELECT qualify FROM $table_threads_qualify
3471
            WHERE
3472
                c_id = $course_id AND
3473
                thread_id = $threadId AND
3474
                session_id = $sessionId AND
3475
                qualify_user_id = $currentUserId AND
3476
                user_id = $userId
3477
            ";
3478
    $res = Database::query($sql);
3479
    $row = Database::fetch_array($res, 'ASSOC');
3480
3481
    return $row['qualify'];
3482
}
3483
3484
/**
3485
 * This function stores a reply in the forum_post table.
3486
 * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date).
3487
 *
3488
 * @param array $values
3489
 * @param int   $courseId Optional
3490
 * @param int   $userId   Optional
3491
 *
3492
 * @return int post id
3493
 */
3494
function store_reply(CForumForum $forum, CForumThread $thread, $values, $courseId = 0, $userId = 0)
3495
{
3496
    $courseId = !empty($courseId) ? $courseId : api_get_course_int_id();
3497
    $_course = api_get_course_info_by_id($courseId);
3498
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
3499
    $post_date = api_get_utc_datetime();
3500
    $userId = $userId ?: api_get_user_id();
3501
3502
    if (1 == $forum->getAllowAnonymous()) {
3503
        if (api_is_anonymous() && empty($userId)) {
3504
            $userId = api_get_anonymous_id();
3505
        }
3506
    }
3507
3508
    if (empty($userId)) {
3509
        return false;
3510
    }
3511
3512
    $visible = 1;
3513
    if ('1' == $forum->getApprovalDirectPost() &&
3514
        !api_is_allowed_to_edit(null, true)
3515
    ) {
3516
        $visible = 0;
3517
    }
3518
3519
    $upload_ok = 1;
3520
    $new_post_id = 0;
3521
3522
    if ($upload_ok) {
3523
        $course = api_get_course_entity($courseId);
3524
        $session = api_get_session_entity();
3525
3526
        $post = new CForumPost();
3527
        $post
3528
            ->setCId($courseId)
3529
            ->setPostTitle($values['post_title'])
3530
            ->setPostText(isset($values['post_text']) ?: null)
3531
            ->setThread($thread)
3532
            ->setForum($forum)
3533
            ->setPosterId($userId)
3534
            ->setPostNotification(isset($values['post_notification']) ? $values['post_notification'] : null)
3535
            ->setPostParentId(isset($values['post_parent_id']) ? $values['post_parent_id'] : null)
3536
            ->setVisible($visible)
3537
            ->setPostDate(api_get_utc_datetime(null, false, true))
3538
            ->setParent($thread)
3539
            ->addCourseLink(
3540
                $course,
3541
                $session
3542
            );
3543
3544
        $repo = Container::getForumPostRepository();
3545
        $em = $repo->getEntityManager();
3546
        $em->persist($post);
3547
        $em->flush();
3548
3549
        $new_post_id = $post->getIid();
3550
        if ($new_post_id) {
3551
            $values['new_post_id'] = $new_post_id;
3552
            $message = get_lang('The reply has been added');
3553
3554
            if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3555
                foreach ($_POST['file_ids'] as $key => $id) {
3556
                    editAttachedFile(
3557
                        [
3558
                            'comment' => $_POST['file_comments'][$key],
3559
                            'post_id' => $new_post_id,
3560
                        ],
3561
                        $id
3562
                    );
3563
                }
3564
            }
3565
3566
            // Update the thread.
3567
            updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
3568
3569
            // Update the forum.
3570
            /*api_item_property_update(
3571
                $_course,
3572
                TOOL_FORUM,
3573
                $values['forum_id'],
3574
                'NewMessageInForum',
3575
                $userId
3576
            );
3577
3578
            // Insert post
3579
            api_item_property_update(
3580
                $_course,
3581
                TOOL_FORUM_POST,
3582
                $new_post_id,
3583
                'NewPost',
3584
                $userId
3585
            );*/
3586
3587
            if ('1' == $forum->getApprovalDirectPost() &&
3588
                !api_is_allowed_to_edit(null, true)
3589
            ) {
3590
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
3591
            }
3592
3593
            if ($forum->isModerated() &&
3594
                !api_is_allowed_to_edit(null, true)
3595
            ) {
3596
                $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
3597
            }
3598
3599
            // Setting the notification correctly.
3600
            $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
3601
            if (1 == $my_post_notification) {
3602
                set_notification('thread', $values['thread_id'], true);
3603
            }
3604
3605
            send_notification_mails(
3606
                $forum,
3607
                $thread,
3608
                $values
3609
            );
3610
            add_forum_attachment_file('', $post);
3611
3612
            $logInfo = [
3613
                'tool' => TOOL_FORUM,
3614
                'tool_id' => $values['forum_id'],
3615
                'tool_id_detail' => $values['thread_id'],
3616
                'action' => 'new-post',
3617
                'action_details' => $values['action'],
3618
                'info' => $values['post_title'],
3619
            ];
3620
            Event::registerLog($logInfo);
3621
        }
3622
3623
        Session::erase('formelements');
3624
        Session::erase('origin');
3625
        Session::erase('breadcrumbs');
3626
        Session::erase('addedresource');
3627
        Session::erase('addedresourceid');
3628
3629
        Display::addFlash(Display::return_message($message, 'confirmation', false));
3630
    } else {
3631
        Display::addFlash(
3632
            Display::return_message(
3633
                get_lang('No file was uploaded.').' '.get_lang('Please select a file before pressing the upload button.'),
3634
                'error'
3635
            )
3636
        );
3637
    }
3638
3639
    return $new_post_id;
3640
}
3641
3642
/**
3643
 * This function displays the form that is used to edit a post. This can be a new thread or a reply.
3644
 *
3645
 * @param CForumPost   $post        contains all the information about the current post
3646
 * @param CForumThread $thread      contains all the information about the current thread
3647
 * @param CForumForum  $forum       contains all info about the current forum (to check if attachments are allowed)
3648
 * @param array        $form_values contains the default values to fill the form
3649
 *
3650
 * @author Patrick Cool <[email protected]>, Ghent University
3651
 *
3652
 * @version february 2006, dokeos 1.8
3653
 */
3654
function show_edit_post_form(
3655
    $post,
3656
    $thread,
3657
    $forum,
3658
    $form_values,
3659
    $id_attach = 0
3660
) {
3661
    // Initialize the object.
3662
    $form = new FormValidator(
3663
        'edit_post',
3664
        'post',
3665
        api_get_self().'?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&post='.(int) ($_GET['post'])
3666
    );
3667
    $form->addElement('header', get_lang('Edit a post'));
3668
    // Setting the form elements.
3669
    $form->addElement('hidden', 'post_id', $post->getIid());
3670
    $form->addElement('hidden', 'thread_id', $thread->getIid());
3671
    $form->addElement('hidden', 'id_attach', $id_attach);
3672
3673
    if (empty($post->getPostParentId())) {
3674
        $form->addElement('hidden', 'is_first_post_of_thread', '1');
3675
    }
3676
3677
    $form->addElement('text', 'post_title', get_lang('Title'));
3678
    $form->applyFilter('post_title', 'html_filter');
3679
    $form->addElement(
3680
        'html_editor',
3681
        'post_text',
3682
        get_lang('Text'),
3683
        null,
3684
        api_is_allowed_to_edit(null, true) ? [
3685
            'ToolbarSet' => 'Forum',
3686
            'Width' => '100%',
3687
            'Height' => '400',
3688
        ] : [
3689
            'ToolbarSet' => 'ForumStudent',
3690
            'Width' => '100%',
3691
            'Height' => '400',
3692
            'UserStatus' => 'student',
3693
        ]
3694
    );
3695
    $form->addRule('post_text', get_lang('Required field'), 'required');
3696
3697
    $extraFields = new ExtraField('forum_post');
3698
    $extraFields->addElements($form, $post->getIid());
3699
3700
    $form->addButtonAdvancedSettings('advanced_params');
3701
    $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
3702
3703
    if ($forum->isModerated() && api_is_allowed_to_edit(null, true)) {
3704
        $group = [];
3705
        $group[] = $form->createElement(
3706
            'radio',
3707
            'status',
3708
            null,
3709
            get_lang('Validated'),
3710
            1
3711
        );
3712
        $group[] = $form->createElement(
3713
            'radio',
3714
            'status',
3715
            null,
3716
            get_lang('Waiting for moderation'),
3717
            2
3718
        );
3719
        $group[] = $form->createElement(
3720
            'radio',
3721
            'status',
3722
            null,
3723
            get_lang('Rejected'),
3724
            3
3725
        );
3726
        $form->addGroup($group, 'status', get_lang('Status'));
3727
    }
3728
3729
    $defaults['status']['status'] = $post->getStatus();
3730
3731
    $form->addElement(
3732
        'checkbox',
3733
        'post_notification',
3734
        '',
3735
        get_lang('Notify me by e-mail when somebody replies')
3736
    );
3737
3738
    if (api_is_allowed_to_edit(null, true) &&
3739
        empty($post->getPostParentId())
3740
    ) {
3741
        // The sticky checkbox only appears when it is the first post of a thread.
3742
        $form->addElement(
3743
            'checkbox',
3744
            'thread_sticky',
3745
            '',
3746
            get_lang('This is a sticky message (appears always on top and has a special sticky icon)')
3747
        );
3748
        if (1 == $thread->getThreadSticky()) {
3749
            $defaults['thread_sticky'] = true;
3750
        }
3751
    }
3752
3753
    $form->addElement('html', '</div>');
3754
3755
    $form->addFile('user_upload[]', get_lang('Attachment'));
3756
    $form->addButton(
3757
        'add_attachment',
3758
        get_lang('Add attachment'),
3759
        'paperclip',
3760
        'default',
3761
        'default',
3762
        null,
3763
        ['id' => 'reply-add-attachment']
3764
    );
3765
3766
    $form->addButtonUpdate(get_lang('Edit'), 'SubmitPost');
3767
3768
    // Setting the default values for the form elements.
3769
    $defaults['post_title'] = $post->getPostTitle();
3770
    $defaults['post_text'] = $post->getPostText();
3771
3772
    if (1 == $post->getPostNotification()) {
3773
        $defaults['post_notification'] = true;
3774
    }
3775
3776
    if (!empty($form_values)) {
3777
        $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
3778
        $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
3779
    }
3780
3781
    $form->setDefaults($defaults);
3782
3783
    // The course admin can make a thread sticky (=appears with special icon and always on top).
3784
    $form->addRule('post_title', get_lang('Required field'), 'required');
3785
3786
    // Validation or display
3787
    if ($form->validate()) {
3788
        $values = $form->exportValues();
3789
        $values['item_id'] = $post->getIid();
3790
        $extraFieldValues = new ExtraFieldValue('forum_post');
3791
        $extraFieldValues->saveFieldValues($values);
3792
3793
        store_edit_post($forum, $values);
3794
    } else {
3795
        // Delete from $_SESSION forum attachment from other posts
3796
        clearAttachedFiles($post->getIid());
3797
        // Get forum attachment ajax table to add it to form
3798
        $fileData = getAttachmentsAjaxTable($post->getIid(), $forum->getIid());
3799
        $form->addElement('html', $fileData);
3800
        $form->display();
3801
    }
3802
}
3803
3804
/**
3805
 * This function stores the edit of a post in the forum_post table.
3806
 *
3807
 * @author Patrick Cool <[email protected]>, Ghent University
3808
 *
3809
 * @version february 2006, dokeos 1.8
3810
 */
3811
function store_edit_post(CForumForum $forum, $values)
3812
{
3813
    $logInfo = [
3814
        'tool' => TOOL_FORUM,
3815
        'tool_id' => $_GET['forum'],
3816
        'tool_id_detail' => $values['thread_id'],
3817
        'action' => 'edit-post',
3818
        'action_details' => 'post',
3819
        'info' => $values['post_title'],
3820
    ];
3821
    Event::registerLog($logInfo);
3822
3823
    $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
3824
    $course_id = api_get_course_int_id();
3825
3826
    //check if this post is the first of the thread
3827
    // First we check if the change affects the thread and if so we commit
3828
    // the changes (sticky and post_title=thread_title are relevant).
3829
    $posts = getPosts($forum, $values['thread_id']);
3830
    $first_post = null;
3831
    if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
3832
        $first_post = $posts[0];
3833
    }
3834
3835
    if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
3836
        // Simple edit
3837
        $params = [
3838
            'thread_title' => $values['post_title'],
3839
            'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
3840
        ];
3841
        $where = ['iid = ?' => [$values['thread_id']]];
3842
        Database::update($threadTable, $params, $where);
3843
    }
3844
3845
    $status = '';
3846
    $updateStatus = false;
3847
    if ($forum->isModerated()) {
3848
        if (api_is_allowed_to_edit(null, true)) {
3849
            $status = $values['status']['status'];
3850
            $updateStatus = true;
3851
        } else {
3852
            $status = CForumPost::STATUS_WAITING_MODERATION;
3853
            $updateStatus = true;
3854
        }
3855
    }
3856
3857
    $postId = $values['post_id'];
3858
    $repo = Container::getForumPostRepository();
3859
    /** @var CForumPost $post */
3860
    $post = $repo->find($postId);
3861
    if ($post) {
3862
        $post
3863
            ->setPostTitle($values['post_title'])
3864
            ->setPostText($values['post_text'])
3865
            ->setPostNotification(isset($values['post_notification']) ? 1 : 0)
3866
        ;
3867
3868
        if ($updateStatus) {
3869
            $post->setStatus($status);
3870
        }
3871
        $repo->getEntityManager()->persist($post);
3872
        $repo->getEntityManager()->flush();
3873
    }
3874
3875
    // Update attached files
3876
    if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
3877
        foreach ($_POST['file_ids'] as $key => $id) {
3878
            editAttachedFile(
3879
                [
3880
                    'comment' => $_POST['file_comments'][$key],
3881
                    'post_id' => $values['post_id'],
3882
                ],
3883
                $id
3884
            );
3885
        }
3886
    }
3887
3888
    if (!empty($values['remove_attach'])) {
3889
        throw new Exception('remove_attach');
3890
        //delete_attachment($post->getIid());
3891
    }
3892
3893
    if (empty($values['id_attach'])) {
3894
        add_forum_attachment_file(
3895
            isset($values['file_comment']) ? $values['file_comment'] : null,
3896
            $post
3897
        );
3898
    } else {
3899
        /*edit_forum_attachment_file(
3900
            isset($values['file_comment']) ? $values['file_comment'] : null,
3901
            $values['post_id'],
3902
            $values['id_attach']
3903
        );*/
3904
    }
3905
3906
    $message = get_lang('The post has been modified').'<br />';
3907
    $message .= get_lang('You can now return to the').
3908
        ' <a href="viewforum.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&">'.
3909
        get_lang('Forum').'</a><br />';
3910
    $message .= get_lang('You can now return to the').
3911
        ' <a
3912
            href="viewthread.php?'.api_get_cidreq().'&forum='.(int) ($_GET['forum']).'&thread='.$values['thread_id'].'&post='.Security::remove_XSS($_GET['post']).'">'.
3913
        get_lang('Message').'</a>';
3914
3915
    Session::erase('formelements');
3916
    Session::erase('origin');
3917
    Session::erase('breadcrumbs');
3918
    Session::erase('addedresource');
3919
    Session::erase('addedresourceid');
3920
3921
    echo Display::return_message($message, 'confirmation', false);
3922
}
3923
3924
/**
3925
 * This function displays the firstname and lastname of the user as a link to the user tool.
3926
 *
3927
 * @param string $user_id names
3928
 * @ in_title : title tootip
3929
 *
3930
 * @return string HTML
3931
 *
3932
 * @author Patrick Cool <[email protected]>, Ghent University
3933
 *
3934
 * @version february 2006, dokeos 1.8
3935
 */
3936
function display_user_link($user_id, $name, $origin = '', $in_title = '')
3937
{
3938
    if (0 != $user_id) {
3939
        $userInfo = api_get_user_info($user_id);
3940
3941
        return '<a href="'.$userInfo['profile_url'].'">'.Security::remove_XSS($userInfo['complete_name']).'</a>';
3942
    } else {
3943
        return $name.' ('.get_lang('Anonymous').')';
3944
    }
3945
}
3946
3947
/**
3948
 * This function displays the user image from the profile, with a link to the user's details.
3949
 *
3950
 * @param int    $user_id User's database ID
3951
 * @param string $name    User's name
3952
 * @param string $origin  the origin where the forum is called (example : learnpath)
3953
 *
3954
 * @return string An HTML with the anchor and the image of the user
3955
 *
3956
 * @author Julio Montoya <[email protected]>
3957
 */
3958
function display_user_image($user_id, $name, $origin = '')
3959
{
3960
    $userInfo = api_get_user_info($user_id);
3961
    $link = '<a href="'.(!empty($origin) ? '#' : $userInfo['profile_url']).'" '.(!empty($origin) ? 'target="_self"' : '').'>';
3962
3963
    if (0 != $user_id) {
3964
        return $link.'<img src="'.$userInfo['avatar'].'"  alt="'.$name.'"  title="'.$name.'" /></a>';
3965
    } else {
3966
        return $link.Display::return_icon('unknown.jpg', $name).'</a>';
3967
    }
3968
}
3969
3970
/**
3971
 * The thread view counter gets increased every time someone looks at the thread.
3972
 *
3973
 * @param int $thread_id
3974
 *
3975
 * @author Patrick Cool <[email protected]>, Ghent University
3976
 *
3977
 * @version february 2006, dokeos 1.8
3978
 */
3979
function increase_thread_view($thread_id)
3980
{
3981
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3982
    $course_id = api_get_course_int_id();
3983
3984
    $sql = "UPDATE $table_threads
3985
            SET thread_views = thread_views + 1
3986
            WHERE
3987
                c_id = $course_id AND
3988
                iid = '".(int) $thread_id."'";
3989
    Database::query($sql);
3990
}
3991
3992
/**
3993
 * The relies counter gets increased every time somebody replies to the thread.
3994
 *
3995
 * @author Patrick Cool <[email protected]>, Ghent University
3996
 *
3997
 * @version february 2006, dokeos 1.8
3998
 *
3999
 * @param int    $threadId
4000
 * @param string $lastPostId
4001
 * @param string $post_date
4002
 */
4003
function updateThreadInfo($threadId, $lastPostId, $post_date)
4004
{
4005
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4006
    $course_id = api_get_course_int_id();
4007
    $sql = "UPDATE $table_threads SET
4008
            thread_replies = thread_replies+1,
4009
            thread_last_post = '".Database::escape_string($lastPostId)."',
4010
            thread_date = '".Database::escape_string($post_date)."'
4011
            WHERE
4012
                c_id = $course_id AND
4013
                iid ='".Database::escape_string($threadId)."'"; // this needs to be cleaned first
4014
    Database::query($sql);
4015
}
4016
4017
/**
4018
 * This function is used to find all the information about what's new in the forum tool.
4019
 *
4020
 * @author Patrick Cool <[email protected]>, Ghent University
4021
 *
4022
 * @version february 2006, dokeos 1.8
4023
 */
4024
function get_whats_new()
4025
{
4026
    $userId = api_get_user_id();
4027
    $course_id = api_get_course_int_id();
4028
4029
    if (empty($course_id) || empty($userId)) {
4030
        return false;
4031
    }
4032
4033
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4034
    $tracking_last_tool_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4035
4036
    $tool = TOOL_FORUM;
4037
    $lastForumAccess = Session::read('last_forum_access');
4038
4039
    if (!$lastForumAccess) {
4040
        $sql = "SELECT * FROM $tracking_last_tool_access
4041
                WHERE
4042
                    access_user_id = $userId AND
4043
                    c_id = $course_id AND
4044
                    access_tool = '".Database::escape_string($tool)."'";
4045
        $result = Database::query($sql);
4046
        $row = Database::fetch_array($result);
4047
        if ($row) {
4048
            Session::write('last_forum_access', $row['access_date']);
4049
            $lastForumAccess = $row['access_date'];
4050
        }
4051
    }
4052
4053
    $whatsNew = Session::read('whatsnew_post_info');
4054
4055
    if (!$whatsNew) {
4056
        if ('' != $lastForumAccess) {
4057
            $postInfo = [];
4058
            $sql = "SELECT * FROM $table_posts
4059
                    WHERE
4060
                        c_id = $course_id AND
4061
                        visible = 1 AND
4062
                        post_date > '".Database::escape_string($lastForumAccess)."'";
4063
            $result = Database::query($sql);
4064
            while ($row = Database::fetch_array($result)) {
4065
                $postInfo[$row['forum_id']][$row['thread_id']][$row['iid']] = $row['post_date'];
4066
            }
4067
            Session::write('whatsnew_post_info', $postInfo);
4068
        }
4069
    }
4070
}
4071
4072
/**
4073
 * This function approves a post = change.
4074
 *
4075
 * @param int    $post_id the id of the post that will be deleted
4076
 * @param string $action  make the post visible or invisible
4077
 *
4078
 * @return string language variable
4079
 *
4080
 * @author Patrick Cool <[email protected]>, Ghent University
4081
 *
4082
 * @version february 2006, dokeos 1.8
4083
 */
4084
function approve_post($post_id, $action)
4085
{
4086
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4087
    $course_id = api_get_course_int_id();
4088
4089
    if ('invisible' == $action) {
4090
        $visibility_value = 0;
4091
    }
4092
4093
    if ('visible' == $action) {
4094
        $visibility_value = 1;
4095
        handle_mail_cue('post', $post_id);
4096
    }
4097
4098
    $sql = "UPDATE $table_posts SET
4099
            visible='".Database::escape_string($visibility_value)."'
4100
            WHERE c_id = $course_id AND post_id='".Database::escape_string($post_id)."'";
4101
    $return = Database::query($sql);
4102
4103
    if ($return) {
4104
        return 'PostThe visibility has been changed.';
4105
    }
4106
}
4107
4108
/**
4109
 * This function retrieves all the unapproved messages for a given forum
4110
 * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see
4111
 * this).
4112
 *
4113
 * @param int $forum_id forum where we want to know the unapproved messages of
4114
 *
4115
 * @return array returns
4116
 *
4117
 * @author Patrick Cool <[email protected]>, Ghent University
4118
 *
4119
 * @version february 2006, dokeos 1.8
4120
 */
4121
function get_unaproved_messages($forum_id)
4122
{
4123
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4124
    $course_id = api_get_course_int_id();
4125
4126
    $return_array = [];
4127
    $sql = "SELECT DISTINCT thread_id FROM $table_posts
4128
            WHERE
4129
                c_id = $course_id AND
4130
                forum_id='".Database::escape_string($forum_id)."' AND
4131
                visible='0' ";
4132
    $result = Database::query($sql);
4133
    while ($row = Database::fetch_array($result)) {
4134
        $return_array[] = $row['thread_id'];
4135
    }
4136
4137
    return $return_array;
4138
}
4139
4140
/**
4141
 * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
4142
 * was added to a given thread.
4143
 */
4144
function send_notification_mails(CForumForum $forum, CForumThread $thread, $reply_info)
4145
{
4146
    $courseEntity = api_get_course_entity($forum->getCId());
4147
    $courseId = $courseEntity->getId();
4148
4149
    $sessionId = api_get_session_id();
4150
    $sessionEntity = api_get_session_entity($sessionId);
4151
4152
    $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4153
4154
    // First we need to check if
4155
    // 1. the forum category is visible
4156
    // 2. the forum is visible
4157
    // 3. the thread is visible
4158
    // 4. the reply is visible (=when there is)
4159
4160
    $current_forum_category = null;
4161
    if ($forum->getForumCategory()) {
4162
        $current_forum_category = $forum->getForumCategory();
4163
    }
4164
4165
    $send_mails = false;
4166
    if ($thread->isVisible($courseEntity, $sessionEntity) &&
4167
        $forum->isVisible($courseEntity, $sessionEntity) &&
4168
        ($current_forum_category && $forum->getForumCategory()->isVisible($courseEntity, $sessionEntity)) &&
4169
        '1' != $forum->getApprovalDirectPost()
4170
    ) {
4171
        $send_mails = true;
4172
    }
4173
4174
    // The forum category, the forum, the thread and the reply are visible to the user
4175
    if ($send_mails && !empty($forum)) {
4176
        $postId = isset($reply_info['new_post_id']) ? $reply_info['new_post_id'] : 0;
4177
        send_notifications($forum, $thread, $postId);
4178
    } else {
4179
        $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
4180
        if ($forum) {
4181
            $sql = "SELECT * FROM $table_notification
4182
                    WHERE
4183
                        c_id = ".$courseId." AND
4184
                        (
4185
                            forum_id = '".$forum->getIid()."' OR
4186
                            thread_id = '".$thread->getIid()."'
4187
                        ) ";
4188
            $result = Database::query($sql);
4189
            $user_id = api_get_user_id();
4190
            while ($row = Database::fetch_array($result)) {
4191
                $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
4192
                        VALUES (".$courseId.", '".$thread->getIid()."', '".(int) ($reply_info['new_post_id'])."', '$user_id' )";
4193
                Database::query($sql);
4194
            }
4195
        }
4196
    }
4197
}
4198
4199
/**
4200
 * This function is called whenever something is made visible because there might
4201
 * be new posts and the user might have indicated that (s)he wanted to be
4202
 * informed about the new posts by mail.
4203
 *
4204
 * @param string $content Content type (post, thread, forum, forum_category)
4205
 * @param int    $id      Item DB ID of the corresponding content type
4206
 *
4207
 * @return string language variable
4208
 *
4209
 * @author Patrick Cool <[email protected]>, Ghent University
4210
 *
4211
 * @version february 2006, dokeos 1.8
4212
 */
4213
function handle_mail_cue($content, $id)
4214
{
4215
    $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
4216
    $table_forums = Database::get_course_table(TABLE_FORUM);
4217
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4218
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4219
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
4220
4221
    $course_id = api_get_course_int_id();
4222
    $id = (int) $id;
4223
4224
    /* If the post is made visible we only have to send mails to the people
4225
     who indicated that they wanted to be informed for that thread.*/
4226
    if ('post' === $content) {
4227
        // Getting the information about the post (need the thread_id).
4228
        /** @var CForumPost $post */
4229
        $post = Container::getForumPostRepository()->find($id);
4230
        $thread_id = $post->getThread()->getIid();
4231
4232
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4233
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email
4234
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4235
                WHERE
4236
                    posts.c_id = $course_id AND
4237
                    mailcue.c_id = $course_id AND
4238
                    posts.thread_id = $thread_id AND
4239
                    posts.post_notification = '1' AND
4240
                    mailcue.thread_id = $thread_id AND
4241
                    users.user_id = posts.poster_id AND
4242
                    users.active = 1
4243
                GROUP BY users.email";
4244
4245
        $result = Database::query($sql);
4246
        $forum = Container::getForumRepository()->find($post->getForum()->getIid());
4247
4248
        while ($row = Database::fetch_array($result)) {
4249
            send_mail($row, $forum, $post->getThread(), $post);
4250
        }
4251
    } elseif ('thread' === $content) {
4252
        // Sending the mail to all the users that wanted to be informed for replies on this thread.
4253
        $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
4254
                FROM $table_mailcue mailcue, $table_posts posts, $table_users users
4255
                WHERE
4256
                    posts.c_id = $course_id AND
4257
                    mailcue.c_id = $course_id AND
4258
                    posts.thread_id = $id AND
4259
                    posts.post_notification = '1' AND
4260
                    mailcue.thread_id = $id AND
4261
                    users.user_id = posts.poster_id AND
4262
                    users.active = 1
4263
                GROUP BY users.email";
4264
        $result = Database::query($sql);
4265
        while ($row = Database::fetch_array($result)) {
4266
            $forum = Container::getForumRepository()->find($row['forum_id']);
4267
            $thread = Container::getForumThreadRepository()->find($id);
4268
            send_mail($row, $forum, $thread);
4269
        }
4270
4271
        // Deleting the relevant entries from the mailcue.
4272
        $sql = "DELETE FROM $table_mailcue
4273
                WHERE c_id = $course_id AND thread_id = $id";
4274
        Database::query($sql);
4275
    } elseif ('forum' == $content) {
4276
        $sql = "SELECT thread_id FROM $table_threads
4277
                WHERE c_id = $course_id AND forum_id = $id";
4278
        $result = Database::query($sql);
4279
        while ($row = Database::fetch_array($result)) {
4280
            handle_mail_cue('thread', $row['thread_id']);
4281
        }
4282
    } elseif ('forum_category' === $content) {
4283
        $sql = "SELECT forum_id FROM $table_forums
4284
                WHERE c_id = $course_id AND forum_category = $id";
4285
        $result = Database::query($sql);
4286
        while ($row = Database::fetch_array($result)) {
4287
            handle_mail_cue('forum', $row['forum_id']);
4288
        }
4289
    } else {
4290
        return get_lang('Error');
4291
    }
4292
}
4293
4294
/**
4295
 * This function sends the mails for the mail notification.
4296
 */
4297
function send_mail($userInfo, CForumForum $forum, CForumThread $thread, CForumPost $postInfo = null)
4298
{
4299
    if (empty($userInfo) || empty($forum) || empty($thread)) {
4300
        return false;
4301
    }
4302
4303
    $_course = api_get_course_info();
4304
    $user_id = api_get_user_id();
4305
    $forumId = $forum->getIid();
4306
    $threadId = $thread->getIid();
4307
4308
    $thread_link = api_get_path(WEB_CODE_PATH).
4309
        'forum/viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$threadId;
4310
4311
    $email_body = get_lang('Dear').' '.api_get_person_name($userInfo['firstname'], $userInfo['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
4312
    $email_body .= get_lang('New Post in the forum').': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4313
4314
    $courseId = api_get_configuration_value('global_forums_course_id');
4315
    $subject = get_lang('New Post in the forum').' - '.$_course['official_code'].': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4316
4317
    $courseInfoTitle = get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
4318
    if (!empty($courseId) && $_course['real_id'] == $courseId) {
4319
        $subject = get_lang('New Post in the forum').': '.$forum->getForumTitle().' - '.$thread->getThreadTitle()." <br />\n";
4320
        $courseInfoTitle = " <br />\n";
4321
    }
4322
    $email_body .= $courseInfoTitle;
4323
4324
    if (!empty($postInfo)) {
4325
        $text = cut(strip_tags($postInfo->getPostText()), 100);
4326
        if (!empty($text)) {
4327
            $email_body .= get_lang('Message').": <br />\n ";
4328
            $email_body .= $text;
4329
            $email_body .= "<br /><br />\n";
4330
        }
4331
    }
4332
4333
    $email_body .= get_lang('You stated that you wanted to be informed by e-mail whenever somebody replies on the thread')."<br />\n";
4334
4335
    if (!empty($thread_link)) {
4336
        $email_body .= get_lang('The thread can be found here').' : <br /><a href="'.$thread_link.'">'.$thread_link."</a>\n";
4337
    }
4338
4339
    if ($userInfo['user_id'] != $user_id) {
4340
        MessageManager::send_message(
4341
            $userInfo['user_id'],
4342
            $subject,
4343
            $email_body,
4344
            [],
4345
            [],
4346
            null,
4347
            null,
4348
            null,
4349
            null,
4350
            $user_id
4351
        );
4352
    }
4353
}
4354
4355
/**
4356
 * This function displays the form for moving a thread to a different (already existing) forum.
4357
 *
4358
 * @author Patrick Cool <[email protected]>, Ghent University
4359
 *
4360
 * @version february 2006, dokeos 1.8
4361
 */
4362
function move_thread_form()
4363
{
4364
    $form = new FormValidator(
4365
        'movepost',
4366
        'post',
4367
        api_get_self().'?forum='.(int) ($_GET['forum']).'&thread='.(int) ($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
4368
    );
4369
    $form->addHeader(get_lang('Move Thread'));
4370
    // Invisible form: the thread_id
4371
    $form->addHidden('thread_id', (int) ($_GET['thread']));
4372
    $forum_categories = get_forum_categories();
4373
4374
    $htmlcontent = '<div class="row">
4375
        <div class="label">
4376
            <span class="form_required">*</span>'.get_lang('Move to').'
4377
        </div>
4378
        <div class="formw">';
4379
    $htmlcontent .= '<select name="forum">';
4380
    foreach ($forum_categories as $category) {
4381
        $htmlcontent .= '<optgroup label="'.$category->getCatTitle().'">';
4382
        $forums = $category->getForums();
4383
        foreach ($forums as $forum) {
4384
            $htmlcontent .= '<option value="'.$forum->getIid().'">'.$forum->getForumTitle().'</option>';
4385
        }
4386
        $htmlcontent .= '</optgroup>';
4387
    }
4388
    $htmlcontent .= '</select>';
4389
    $htmlcontent .= '   </div>
4390
                    </div>';
4391
4392
    $form->addElement('html', $htmlcontent);
4393
4394
    // The OK button
4395
    $form->addButtonSave(get_lang('Move Thread'), 'SubmitForum');
4396
4397
    // Validation or display
4398
    if ($form->validate()) {
4399
        $values = $form->exportValues();
4400
        if (isset($_POST['forum'])) {
4401
            store_move_thread($values);
4402
            Display::addFlash(Display::return_message(get_lang('Moved')));
4403
        }
4404
    } else {
4405
        return $form->returnForm();
4406
    }
4407
}
4408
4409
/**
4410
 * This function displays the form for moving a post message to a different (already existing) or a new thread.
4411
 *
4412
 * @author Patrick Cool <[email protected]>, Ghent University
4413
 *
4414
 * @version february 2006, dokeos 1.8
4415
 */
4416
function move_post_form()
4417
{
4418
    $form = new FormValidator(
4419
        'movepost',
4420
        'post',
4421
        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'])
4422
    );
4423
    // The header for the form
4424
    $form->addElement('header', '', get_lang('Move post'));
4425
4426
    // Invisible form: the post_id
4427
    $form->addElement('hidden', 'post_id', (int) ($_GET['post']));
4428
4429
    // Dropdown list: Threads of this forum
4430
    $threads = get_threads($_GET['forum']);
4431
    $threads_list[0] = get_lang('A new thread');
4432
    foreach ($threads as $thread) {
4433
        $threads_list[$thread->getIid()] = $thread->getThreadTitle();
4434
    }
4435
    $form->addElement('select', 'thread', get_lang('Move toThread'), $threads_list);
4436
    $form->applyFilter('thread', 'html_filter');
4437
4438
    // The OK button
4439
    $form->addButtonSave(get_lang('Move post'), 'submit');
4440
4441
    // Setting the rules
4442
    $form->addRule('thread', get_lang('Required field'), 'required');
4443
4444
    return $form;
4445
}
4446
4447
/**
4448
 * @param array $values
4449
 *
4450
 * @return string HTML language variable
4451
 *
4452
 * @author Patrick Cool <[email protected]>, Ghent University
4453
 *
4454
 * @version february 2006, dokeos 1.8
4455
 */
4456
function store_move_post($values)
4457
{
4458
    $_course = api_get_course_info();
4459
    $course_id = api_get_course_int_id();
4460
4461
    $table_forums = Database::get_course_table(TABLE_FORUM);
4462
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4463
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4464
4465
    $user = api_get_user_entity(api_get_user_id());
4466
    $course = api_get_course_entity($course_id);
4467
    $session = api_get_session_entity();
4468
4469
    if ('0' == $values['thread']) {
4470
        $repoPost = Container::getForumPostRepository();
4471
        $repoThread = Container::getForumThreadRepository();
4472
        $repoForum = Container::getForumRepository();
4473
4474
        $em = $repoPost->getEntityManager();
4475
4476
        /** @var CForumPost $post */
4477
        $post = $repoPost->find($values['post_id']);
4478
        $forumId = $post->getForum()->getIid();
4479
        $threadId = $post->getThread()->getIid();
4480
4481
        $thread = new CForumThread();
4482
        $thread
4483
            ->setCId($course_id)
4484
            ->setThreadTitle($post->getPostTitle())
4485
            ->setForum($post->getForum())
4486
            ->setThreadPosterId($post->getPosterId())
4487
            ->setThreadPosterName($post->getPosterName())
4488
            ->setThreadLastPost($post->getIid())
4489
            ->setThreadDate($post->getPostDate())
4490
            ->setParent($post->getForum())
4491
            ->addCourseLink(
4492
                $user,
4493
                $course,
4494
                $session
4495
            );
4496
4497
        $repo = Container::getForumThreadRepository();
4498
        $em = $repo->getEntityManager();
4499
        $em->persist($thread);
4500
        $em->flush();
4501
4502
        $new_thread_id = $thread->getIid();
4503
4504
        // Storing a new thread.
4505
        /*$params = [
4506
            'c_id' => $course_id,
4507
            'thread_title' => $current_post['post_title'],
4508
            'forum_id' => $current_post['forum_id'],
4509
            'thread_poster_id' => $current_post['poster_id'],
4510
            'thread_poster_name' => $current_post['poster_name'],
4511
            'thread_last_post' => $values['post_id'],
4512
            'thread_date' => $current_post['post_date'],
4513
        ];
4514
4515
        $new_thread_id = Database::insert($table_threads, $params);
4516
4517
        api_item_property_update(
4518
            $_course,
4519
            TOOL_FORUM_THREAD,
4520
            $new_thread_id,
4521
            'visible',
4522
            $current_post['poster_id']
4523
        );*/
4524
4525
        // Moving the post to the newly created thread.
4526
        $sql = "UPDATE $table_posts SET thread_id='".$new_thread_id."', post_parent_id = NULL
4527
                WHERE c_id = $course_id AND iid ='".(int) ($values['post_id'])."'";
4528
        Database::query($sql);
4529
4530
        // Resetting the parent_id of the thread to 0 for all those who had this moved post as parent.
4531
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4532
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
4533
        Database::query($sql);
4534
4535
        // Updating updating the number of threads in the forum.
4536
        $sql = "UPDATE $table_forums SET forum_threads=forum_threads+1
4537
                WHERE c_id = $course_id AND iid ='".$forumId."'";
4538
        Database::query($sql);
4539
4540
        // Resetting the last post of the old thread and decreasing the number of replies and the thread.
4541
        $sql = "SELECT * FROM $table_posts
4542
                WHERE c_id = $course_id AND thread_id='".$threadId."'
4543
                ORDER BY iid DESC";
4544
        $result = Database::query($sql);
4545
        $row = Database::fetch_array($result);
4546
        $sql = "UPDATE $table_threads SET
4547
                    thread_last_post='".$row['iid']."',
4548
                    thread_replies=thread_replies-1
4549
                WHERE
4550
                    c_id = $course_id AND
4551
                    iid ='".$threadId."'";
4552
        Database::query($sql);
4553
    } else {
4554
        // Moving to the chosen thread.
4555
        $sql = 'SELECT thread_id FROM '.$table_posts."
4556
                WHERE c_id = $course_id AND iid = '".$values['post_id']."' ";
4557
        $result = Database::query($sql);
4558
        $row = Database::fetch_array($result);
4559
4560
        $original_thread_id = $row['thread_id'];
4561
        $sql = 'SELECT thread_last_post FROM '.$table_threads."
4562
                WHERE c_id = $course_id AND iid = '".$original_thread_id."' ";
4563
4564
        $result = Database::query($sql);
4565
        $row = Database::fetch_array($result);
4566
        $thread_is_last_post = $row['thread_last_post'];
4567
        // If is this thread, update the thread_last_post with the last one.
4568
4569
        if ($thread_is_last_post == $values['post_id']) {
4570
            $sql = 'SELECT iid as post_id FROM '.$table_posts."
4571
                    WHERE
4572
                        c_id = $course_id AND
4573
                        thread_id = '".$original_thread_id."' AND
4574
                        iid <> '".$values['post_id']."'
4575
                    ORDER BY post_date DESC LIMIT 1";
4576
            $result = Database::query($sql);
4577
4578
            $row = Database::fetch_array($result);
4579
            $thread_new_last_post = $row['post_id'];
4580
4581
            $sql = 'UPDATE '.$table_threads."
4582
                    SET thread_last_post = '".$thread_new_last_post."'
4583
                    WHERE c_id = $course_id AND iid = '".$original_thread_id."' ";
4584
            Database::query($sql);
4585
        }
4586
4587
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies-1
4588
                WHERE c_id = $course_id AND iid ='".$original_thread_id."'";
4589
        Database::query($sql);
4590
4591
        // moving to the chosen thread
4592
        $sql = "UPDATE $table_posts SET thread_id='".(int) ($_POST['thread'])."', post_parent_id = NULL
4593
                WHERE c_id = $course_id AND iid ='".(int) ($values['post_id'])."'";
4594
        Database::query($sql);
4595
4596
        // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
4597
        $sql = "UPDATE $table_posts SET post_parent_id = NULL
4598
                WHERE c_id = $course_id AND post_parent_id='".(int) ($values['post_id'])."'";
4599
        Database::query($sql);
4600
4601
        $sql = "UPDATE $table_threads SET thread_replies=thread_replies+1
4602
                WHERE c_id = $course_id AND iid ='".(int) ($_POST['thread'])."'";
4603
        Database::query($sql);
4604
    }
4605
4606
    return get_lang('Thread moved');
4607
}
4608
4609
/**
4610
 * @param array $values
4611
 *
4612
 * @return string HTML language variable
4613
 *
4614
 * @author Patrick Cool <[email protected]>, Ghent University
4615
 *
4616
 * @version february 2006, dokeos 1.8
4617
 */
4618
function store_move_thread($values)
4619
{
4620
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4621
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4622
4623
    $courseId = api_get_course_int_id();
4624
    $sessionId = api_get_session_id();
4625
4626
    $forumId = (int) ($_POST['forum']);
4627
    $threadId = (int) ($_POST['thread_id']);
4628
    //$forumInfo = get_forums($forumId);
4629
4630
    // Change the thread table: Setting the forum_id to the new forum.
4631
    $sql = "UPDATE $table_threads SET forum_id = $forumId
4632
            WHERE c_id = $courseId AND thread_id = $threadId";
4633
    Database::query($sql);
4634
4635
    // Changing all the posts of the thread: setting the forum_id to the new forum.
4636
    $sql = "UPDATE $table_posts SET forum_id = $forumId
4637
            WHERE c_id = $courseId AND thread_id= $threadId";
4638
    Database::query($sql);
4639
4640
    // Fix group id, if forum is moved to a different group
4641
    if (!empty($forumInfo['to_group_id'])) {
4642
        /*$groupId = $forumInfo['to_group_id'];
4643
        $item = api_get_item_property_info(
4644
            $courseId,
4645
            TABLE_FORUM_THREAD,
4646
            $threadId,
4647
            $sessionId,
4648
            $groupId
4649
        );
4650
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4651
        $sessionCondition = api_get_session_condition($sessionId);
4652
4653
        if (!empty($item)) {
4654
            if ($item['to_group_id'] != $groupId) {
4655
                $sql = "UPDATE $table
4656
                    SET to_group_id = $groupId
4657
                    WHERE
4658
                      tool = '".TABLE_FORUM_THREAD."' AND
4659
                      c_id = $courseId AND
4660
                      ref = ".$item['ref']."
4661
                      $sessionCondition
4662
                ";
4663
                Database::query($sql);
4664
            }
4665
        } else {
4666
            $sql = "UPDATE $table
4667
                    SET to_group_id = $groupId
4668
                    WHERE
4669
                      tool = '".TABLE_FORUM_THREAD."' AND
4670
                      c_id = $courseId AND
4671
                      ref = ".$threadId."
4672
                      $sessionCondition
4673
            ";
4674
            Database::query($sql);
4675
        }*/
4676
    }
4677
4678
    return get_lang('Thread moved');
4679
}
4680
4681
/**
4682
 * Prepares a string for displaying by highlighting the search results inside, if any.
4683
 *
4684
 * @param string $input the input string
4685
 *
4686
 * @return string the same string with highlighted hits inside
4687
 *
4688
 * @author Patrick Cool <[email protected]>, Ghent University, February 2006 - the initial version.
4689
 * @author Ivan Tcholakov, March 2011 - adaptation for Chamilo LMS.
4690
 */
4691
function prepare4display($input)
4692
{
4693
    static $highlightcolors = ['yellow', '#33CC33', '#3399CC', '#9999FF', '#33CC33'];
4694
    static $search;
4695
4696
    if (!isset($search)) {
4697
        if (isset($_POST['search_term'])) {
4698
            $search = $_POST['search_term']; // No html at all.
4699
        } elseif (isset($_GET['search'])) {
4700
            $search = $_GET['search'];
4701
        } else {
4702
            $search = '';
4703
        }
4704
    }
4705
4706
    if (!empty($search)) {
4707
        if (strstr($search, '+')) {
4708
            $search_terms = explode('+', $search);
4709
        } else {
4710
            $search_terms[] = trim($search);
4711
        }
4712
        $counter = 0;
4713
        foreach ($search_terms as $key => $search_term) {
4714
            $input = api_preg_replace(
4715
                '/'.preg_quote(trim($search_term), '/').'/i',
4716
                '<span style="background-color: '.$highlightcolors[$counter].'">$0</span>',
4717
                $input
4718
            );
4719
            $counter++;
4720
        }
4721
    }
4722
4723
    // TODO: Security should be implemented outside this function.
4724
    // Change this to COURSEMANAGERLOWSECURITY or COURSEMANAGER to lower filtering and allow more styles
4725
    // (see comments of Security::remove_XSS() method to learn about other levels).
4726
4727
    return Security::remove_XSS($input, STUDENT, true);
4728
}
4729
4730
/**
4731
 * Display the search form for the forum and display the search results.
4732
 *
4733
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4734
 *
4735
 * @version march 2008, dokeos 1.8.5
4736
 */
4737
function forum_search()
4738
{
4739
    $form = new FormValidator(
4740
        'forumsearch',
4741
        'post',
4742
        'forumsearch.php?'.api_get_cidreq()
4743
    );
4744
4745
    // Setting the form elements.
4746
    $form->addElement('header', '', get_lang('Search in the Forum'));
4747
    $form->addElement('text', 'search_term', get_lang('Search term'), ['autofocus']);
4748
    $form->applyFilter('search_term', 'html_filter');
4749
    $form->addElement('static', 'search_information', '', get_lang('Search in the ForumInformation'));
4750
    $form->addButtonSearch(get_lang('Search'));
4751
4752
    // Setting the rules.
4753
    $form->addRule('search_term', get_lang('Required field'), 'required');
4754
    $form->addRule('search_term', get_lang('Too short'), 'minlength', 3);
4755
4756
    // Validation or display.
4757
    if ($form->validate()) {
4758
        $values = $form->exportValues();
4759
        $form->setDefaults($values);
4760
        $form->display();
4761
        // Display the search results.
4762
        display_forum_search_results(stripslashes($values['search_term']));
4763
    } else {
4764
        $form->display();
4765
    }
4766
}
4767
4768
/**
4769
 * Display the search results.
4770
 *
4771
 * @param string $search_term
4772
 *
4773
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4774
 *
4775
 * @version march 2008, dokeos 1.8.5
4776
 */
4777
function display_forum_search_results($search_term)
4778
{
4779
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4780
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
4781
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
4782
    $session_id = api_get_session_id();
4783
    $course_id = api_get_course_int_id();
4784
4785
    // Defining the search strings as an array.
4786
    if (strstr($search_term, '+')) {
4787
        $search_terms = explode('+', $search_term);
4788
    } else {
4789
        $search_terms[] = $search_term;
4790
    }
4791
4792
    // Search restriction.
4793
    foreach ($search_terms as $value) {
4794
        $search_restriction[] = "
4795
        (
4796
            posts.post_title LIKE '%".Database::escape_string(trim($value))."%' OR
4797
            posts.post_text LIKE '%".Database::escape_string(trim($value))."%'
4798
        )";
4799
    }
4800
4801
    $sessionCondition = api_get_session_condition(
4802
        $session_id,
4803
        true,
4804
        false,
4805
        'item_property.session_id'
4806
    );
4807
4808
    $sql = "SELECT posts.*
4809
            FROM $table_posts posts
4810
            INNER JOIN $table_threads threads
4811
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
4812
            INNER JOIN $table_item_property item_property
4813
            ON (item_property.ref = threads.thread_id AND item_property.c_id = threads.c_id)
4814
            WHERE
4815
                posts.c_id = $course_id AND
4816
                item_property.c_id = $course_id AND
4817
                item_property.visibility = 1
4818
                $sessionCondition AND
4819
                posts.visible = 1 AND
4820
                item_property.tool = '".TOOL_FORUM_THREAD."' AND
4821
                ".implode(' AND ', $search_restriction).'
4822
            GROUP BY posts.post_id';
4823
4824
    // Getting all the information of the forum categories.
4825
    $forum_categories_list = get_forum_categories();
4826
4827
    // Getting all the information of the forums.
4828
    $forum_list = get_forums();
4829
4830
    $result = Database::query($sql);
4831
    $search_results = [];
4832
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4833
        $forumId = $row['forum_id'];
4834
        $forumData = get_forums($forumId);
4835
        $category = isset($forum_categories_list[$forumData['forum_category']]) ? $forum_categories_list[$forumData['forum_category']] : null;
4836
        $display_result = false;
4837
        /*
4838
          We only show it when
4839
          1. forum category is visible
4840
          2. forum is visible
4841
          3. thread is visible (to do)
4842
          4. post is visible
4843
         */
4844
        if (!api_is_allowed_to_edit(null, true)) {
4845
            if (!empty($category)) {
4846
                if ('1' == $category['visibility'] && '1' == $forumData['visibility']) {
4847
                    $display_result = true;
4848
                }
4849
            } else {
4850
                if ('1' == $forumData['visible']) {
4851
                    $display_result = true;
4852
                }
4853
            }
4854
        } else {
4855
            $display_result = true;
4856
        }
4857
4858
        if ($display_result) {
4859
            $categoryName = !empty($category) ? $category['cat_title'] : '';
4860
            $search_results_item = '<li><a href="viewforumcategory.php?'.api_get_cidreq().'&forumcategory='.$forumData['forum_category'].'&search='.urlencode($search_term).'">'.
4861
                prepare4display($categoryName).'</a> &gt; ';
4862
            $search_results_item .= '<a href="viewforum.php?'.api_get_cidreq().'&forum='.$forumId.'&search='.urlencode($search_term).'">'.
4863
                prepare4display($forum_list[$row['forum_id']]['forum_title']).'</a> &gt; ';
4864
            $search_results_item .= '<a href="viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$row['thread_id'].'&search='.urlencode($search_term).'">'.
4865
                prepare4display($row['post_title']).'</a>';
4866
            $search_results_item .= '<br />';
4867
            if (api_strlen($row['post_title']) > 200) {
4868
                $search_results_item .= prepare4display(api_substr(strip_tags($row['post_title']), 0, 200)).'...';
4869
            } else {
4870
                $search_results_item .= prepare4display($row['post_title']);
4871
            }
4872
            $search_results_item .= '</li>';
4873
            $search_results[] = $search_results_item;
4874
        }
4875
    }
4876
    echo '<legend>'.count($search_results).' '.get_lang('Search in the ForumResults').'</legend>';
4877
    echo '<ol>';
4878
    if ($search_results) {
4879
        echo implode($search_results);
4880
    }
4881
    echo '</ol>';
4882
}
4883
4884
/**
4885
 * Return the link to the forum search page.
4886
 *
4887
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
4888
 *
4889
 * @version April 2008, dokeos 1.8.5
4890
 */
4891
function search_link()
4892
{
4893
    // @todo implement search
4894
4895
    return '';
4896
4897
    $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...
4898
    $origin = api_get_origin();
4899
    if ('learnpath' != $origin) {
4900
        $return = '<a href="forumsearch.php?'.api_get_cidreq().'&action=search"> ';
4901
        $return .= Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
4902
4903
        if (!empty($_GET['search'])) {
4904
            $return .= ': '.Security::remove_XSS($_GET['search']).' ';
4905
            $url = api_get_self().'?';
4906
            $url_parameter = [];
4907
            foreach ($_GET as $key => $value) {
4908
                if ('search' != $key) {
4909
                    $url_parameter[] = Security::remove_XSS($key).'='.Security::remove_XSS($value);
4910
                }
4911
            }
4912
            $url .= implode('&', $url_parameter);
4913
            $return .= '<a href="'.$url.'">'.Display::return_icon('delete.gif', get_lang('Clean search results')).'</a>';
4914
        }
4915
    }
4916
4917
    return $return;
4918
}
4919
4920
/**
4921
 * This function adds an attachment file into a forum.
4922
 *
4923
 * @param string     $file_comment a comment about file
4924
 * @param CForumPost $post         from forum_post table
4925
 *
4926
 * @return false|null
4927
 */
4928
function add_forum_attachment_file($file_comment, CForumPost $post)
4929
{
4930
    $request = Container::getRequest();
4931
    if (false === $request->files->has('user_upload')) {
4932
        return false;
4933
    }
4934
4935
    $file = $request->files->get('user_upload');
4936
    if (empty($file)) {
4937
        return false;
4938
    }
4939
4940
    $files = [];
4941
    if ($file instanceof UploadedFile) {
4942
        $files[] = $file;
4943
    } else {
4944
        $files = $file;
4945
    }
4946
4947
    /** @var UploadedFile $attachment */
4948
    foreach ($files as $file) {
4949
        $valid = process_uploaded_file($file);
4950
4951
        if (!$valid) {
4952
            continue;
4953
        }
4954
4955
        // Try to add an extension to the file if it hasn't one.
4956
        $new_file_name = add_ext_on_mime(
4957
            stripslashes($file->getPathname()),
4958
            $file->getType()
4959
        );
4960
4961
        // User's file name
4962
        $file_name = $file->getClientOriginalName();
4963
4964
        if (!filter_extension($new_file_name)) {
4965
            Display::addFlash(
4966
                Display::return_message(
4967
                    get_lang('File upload failed: this file extension or file type is prohibited'),
4968
                    'error'
4969
                )
4970
            );
4971
4972
            return;
4973
        }
4974
4975
        $new_file_name = uniqid('');
4976
        $safe_file_comment = Database::escape_string($file_comment);
4977
4978
        $user = api_get_user_entity(api_get_user_id());
4979
        $course = api_get_course_entity(api_get_course_int_id());
4980
        $session = api_get_session_entity(api_get_session_id());
4981
4982
        $attachment = new CForumAttachment();
4983
        $attachment
4984
            ->setCId(api_get_course_int_id())
4985
            ->setComment($safe_file_comment)
4986
            ->setFilename($file_name)
4987
            ->setPath($file_name)
4988
            ->setPost($post)
4989
            ->setSize($file->getSize())
4990
            ->setParent($post)
4991
            ->addCourseLink(
4992
                $course,
4993
                $session
4994
            );
4995
4996
        $repo = Container::getForumAttachmentRepository();
4997
        $em = $repo->getEntityManager();
4998
        $em->persist($attachment);
4999
        $em->flush();
5000
5001
        /*$last_id_file = Database::insert(
5002
            $agenda_forum_attachment,
5003
            [
5004
                'path' => $safe_new_file_name,
5005
            ]
5006
        );*/
5007
5008
        /*api_item_property_update(
5009
            $_course,
5010
            TOOL_FORUM_ATTACH,
5011
            $last_id_file,
5012
            'ForumAttachmentAdded',
5013
            api_get_user_id()
5014
        );*/
5015
    }
5016
}
5017
5018
/**
5019
 * This function edits an attachment file into a forum.
5020
 *
5021
 * @param string $file_comment a comment about file
5022
 * @param int    $post_id
5023
 * @param int    $id_attach    attachment file Id
5024
 */
5025
function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
5026
{
5027
    $_course = api_get_course_info();
5028
    $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5029
    $course_id = api_get_course_int_id();
5030
5031
    $filesData = [];
5032
5033
    if (!is_array($_FILES['user_upload']['name'])) {
5034
        $filesData[] = $_FILES['user_upload'];
5035
    } else {
5036
        $fileCount = count($_FILES['user_upload']['name']);
5037
        $fileKeys = array_keys($_FILES['user_upload']);
5038
5039
        for ($i = 0; $i < $fileCount; $i++) {
5040
            foreach ($fileKeys as $key) {
5041
                $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
5042
            }
5043
        }
5044
    }
5045
5046
    foreach ($filesData as $attachment) {
5047
        if (empty($attachment['name'])) {
5048
            continue;
5049
        }
5050
5051
        $upload_ok = process_uploaded_file($attachment);
5052
5053
        if (!$upload_ok) {
5054
            continue;
5055
        }
5056
5057
        $course_dir = $_course['path'].'/upload/forum';
5058
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
5059
        $updir = $sys_course_path.$course_dir;
5060
5061
        // Try to add an extension to the file if it hasn't one.
5062
        $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
5063
        // User's file name
5064
        $file_name = $attachment['name'];
5065
5066
        if (!filter_extension($new_file_name)) {
5067
            Display::addFlash(
5068
                Display::return_message(
5069
                    get_lang('File upload failed: this file extension or file type is prohibited'),
5070
                    'error'
5071
                )
5072
            );
5073
        } else {
5074
            $new_file_name = uniqid('');
5075
            $new_path = $updir.'/'.$new_file_name;
5076
            $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
5077
            $safe_file_comment = Database::escape_string($file_comment);
5078
            $safe_file_name = Database::escape_string($file_name);
5079
            $safe_new_file_name = Database::escape_string($new_file_name);
5080
            $safe_post_id = (int) $post_id;
5081
            $safe_id_attach = (int) $id_attach;
5082
            // Storing the attachments if any.
5083
            if ($result) {
5084
                $sql = "UPDATE $table_forum_attachment
5085
                        SET
5086
                            filename = '$safe_file_name',
5087
                            comment = '$safe_file_comment',
5088
                            path = '$safe_new_file_name',
5089
                            post_id = '$safe_post_id',
5090
                            size ='".$attachment['size']."'
5091
                        WHERE c_id = $course_id AND id = '$safe_id_attach'";
5092
                Database::query($sql);
5093
                api_item_property_update(
5094
                    $_course,
5095
                    TOOL_FORUM_ATTACH,
5096
                    $safe_id_attach,
5097
                    'ForumAttachmentUpdated',
5098
                    api_get_user_id()
5099
                );
5100
            }
5101
        }
5102
    }
5103
}
5104
5105
/**
5106
 * Show a list with all the attachments according to the post's id.
5107
 *
5108
 * @param int $postId
5109
 *
5110
 * @return array with the post info
5111
 *
5112
 * @author Julio Montoya
5113
 *
5114
 * @version avril 2008, dokeos 1.8.5
5115
 */
5116
function get_attachment($postId)
5117
{
5118
    $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5119
    $course_id = api_get_course_int_id();
5120
    $row = [];
5121
    $postId = (int) $postId;
5122
5123
    if (empty($postId)) {
5124
        return [];
5125
    }
5126
5127
    $sql = "SELECT iid, path, filename, comment
5128
            FROM $table
5129
            WHERE c_id = $course_id AND post_id = $postId";
5130
    $result = Database::query($sql);
5131
    if (0 != Database::num_rows($result)) {
5132
        $row = Database::fetch_array($result);
5133
    }
5134
5135
    return $row;
5136
}
5137
5138
/**
5139
 * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
5140
 *
5141
 * @param int $postId
5142
 * @param int $attachmentId
5143
 *
5144
 * @return bool
5145
 */
5146
function delete_attachment($postId, $attachmentId)
5147
{
5148
    $repo = Container::getForumPostRepository();
5149
    /** @var CForumPost $post */
5150
    $post = $repo->find($postId);
5151
    if ($post) {
5152
        $repoAttachment = Container::getForumAttachmentRepository();
5153
        $attachment = $repoAttachment->find($attachmentId);
5154
        if ($attachment) {
5155
            $post->removeAttachment($attachment);
5156
            $repo->getEntityManager()->remove($attachment);
5157
        }
5158
        $repo->getEntityManager()->persist($post);
5159
        $repo->getEntityManager()->flush();
5160
5161
        Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
5162
    }
5163
5164
    return true;
5165
5166
    $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...
5167
    $course_id = api_get_course_int_id();
5168
5169
    $cond = !empty($id_attach) ? ' iid = '.(int) $id_attach.'' : ' post_id = '.(int) $post_id.'';
5170
    $sql = "SELECT path FROM $forum_table_attachment WHERE c_id = $course_id AND $cond";
5171
    $res = Database::query($sql);
5172
    $row = Database::fetch_array($res);
5173
5174
    $course_dir = $_course['path'].'/upload/forum';
5175
    $sys_course_path = api_get_path(SYS_COURSE_PATH);
5176
    $updir = $sys_course_path.$course_dir;
5177
    $my_path = isset($row['path']) ? $row['path'] : null;
5178
    $file = $updir.'/'.$my_path;
5179
    if (Security::check_abs_path($file, $updir)) {
5180
        @unlink($file);
5181
    }
5182
5183
    // Delete from forum_attachment table.
5184
    $sql = "DELETE FROM $forum_table_attachment
5185
            WHERE c_id = $course_id AND $cond ";
5186
    $result = Database::query($sql);
5187
    if (false !== $result) {
5188
        $affectedRows = Database::affected_rows($result);
5189
    } else {
5190
        $affectedRows = 0;
5191
    }
5192
5193
    // Update item_property.
5194
    api_item_property_update(
5195
        $_course,
5196
        TOOL_FORUM_ATTACH,
5197
        $id_attach,
5198
        'ForumAttachmentDelete',
5199
        api_get_user_id()
5200
    );
5201
5202
    if (!empty($result) && !empty($id_attach)) {
5203
        Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
5204
    }
5205
5206
    return $affectedRows;
5207
}
5208
5209
/**
5210
 * This function gets all the forum information of the all the forum of the group.
5211
 *
5212
 * @param array $groupInfo the id of the group we need the fora of (see forum.forum_of_group)
5213
 *
5214
 * @return CForumForum[]
5215
 *
5216
 * @todo this is basically the same code as the get_forums function. Consider merging the two.
5217
 */
5218
function get_forums_of_group($groupInfo)
5219
{
5220
    $groupId = (int) $groupInfo['id'];
5221
5222
    $group = api_get_group_entity($groupId);
5223
    $course = api_get_course_entity();
5224
    $session = api_get_session_entity();
5225
5226
    $repo = Container::getForumRepository();
5227
5228
    $qb = $repo->getResourcesByCourse($course, $session, $group);
5229
5230
    return $qb->getQuery()->getResult();
5231
5232
    $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...
5233
    $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
5234
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5235
    $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
5236
    $course_id = api_get_course_int_id();
5237
    $groupId = (int) $groupInfo['id'];
5238
5239
    // Student
5240
    // Select all the forum information of all forums (that are visible to students).
5241
    $sql = "SELECT * FROM $table_forums forum
5242
            INNER JOIN $table_item_property item_properties
5243
            ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5244
            WHERE
5245
                forum.forum_of_group = $groupId AND
5246
                forum.c_id = $course_id AND
5247
                item_properties.c_id = $course_id AND
5248
                item_properties.visibility = 1 AND
5249
                item_properties.tool = '".TOOL_FORUM."'
5250
            ORDER BY forum.forum_order ASC";
5251
5252
    // Select the number of threads of the forums (only the threads that are visible).
5253
    $sql2 = "SELECT
5254
                count(thread_id) AS number_of_threads,
5255
                threads.forum_id
5256
            FROM $table_threads threads
5257
            INNER JOIN $table_item_property item_properties
5258
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5259
            WHERE
5260
                threads.c_id = $course_id AND
5261
                item_properties.c_id = $course_id AND
5262
                item_properties.visibility = 1 AND
5263
                item_properties.tool='".TOOL_FORUM_THREAD."'
5264
            GROUP BY threads.forum_id";
5265
5266
    // Select the number of posts of the forum (post that are visible and that are in a thread that is visible).
5267
    $sql3 = "SELECT count(post_id) AS number_of_posts, posts.forum_id
5268
            FROM $table_posts posts
5269
            INNER JOIN $table_threads threads
5270
            ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
5271
            INNER JOIN $table_item_property item_properties
5272
            ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
5273
            WHERE
5274
                posts.visible=1 AND
5275
                posts.c_id = $course_id AND
5276
                item_properties.c_id = $course_id AND
5277
                threads.c_id = $course_id AND
5278
                item_properties.visibility = 1 AND
5279
                item_properties.tool='".TOOL_FORUM_THREAD."'
5280
            GROUP BY threads.forum_id";
5281
5282
    // Course Admin
5283
    if (api_is_allowed_to_edit()) {
5284
        // Select all the forum information of all forums (that are not deleted).
5285
        $sql = "SELECT *
5286
                FROM $table_forums forum
5287
                INNER JOIN $table_item_property item_properties
5288
                ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
5289
                WHERE
5290
                    forum.forum_of_group = $groupId AND
5291
                    forum.c_id = $course_id AND
5292
                    item_properties.c_id = $course_id AND
5293
                    item_properties.visibility <> 2 AND
5294
                    item_properties.tool = '".TOOL_FORUM."'
5295
                ORDER BY forum_order ASC";
5296
5297
        // Select the number of threads of the forums (only the threads that are not deleted).
5298
        $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id
5299
                 FROM $table_threads threads
5300
                 INNER JOIN $table_item_property item_properties
5301
                 ON (threads.thread_id=item_properties.ref AND item_properties.c_id = threads.c_id)
5302
                 WHERE
5303
                    threads.c_id = $course_id AND
5304
                    item_properties.c_id = $course_id AND
5305
                    item_properties.visibility <> 2 AND
5306
                    item_properties.tool='".TOOL_FORUM_THREAD."'
5307
                GROUP BY threads.forum_id";
5308
        // Select the number of posts of the forum.
5309
        $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id
5310
                FROM $table_posts
5311
                WHERE c_id = $course_id
5312
                GROUP BY forum_id";
5313
    }
5314
5315
    // Handling all the forum information.
5316
    $result = Database::query($sql);
5317
    $forum_list = [];
5318
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5319
        $forum_list[$row['forum_id']] = $row;
5320
    }
5321
5322
    // Handling the thread count information.
5323
    $result2 = Database::query($sql2);
5324
    while ($row2 = Database::fetch_array($result2, 'ASSOC')) {
5325
        if (is_array($forum_list)) {
5326
            if (array_key_exists($row2['forum_id'], $forum_list)) {
5327
                $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
5328
            }
5329
        }
5330
    }
5331
5332
    // Handling the post count information.
5333
    $result3 = Database::query($sql3);
5334
    while ($row3 = Database::fetch_array($result3, 'ASSOC')) {
5335
        if (is_array($forum_list)) {
5336
            if (array_key_exists($row3['forum_id'], $forum_list)) {
5337
                // This is needed because sql3 takes also the deleted forums into account.
5338
                $forum_list[$row3['forum_id']]['number_of_posts'] = $row3['number_of_posts'];
5339
            }
5340
        }
5341
    }
5342
5343
    // Finding the last post information
5344
    // (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname).
5345
    if (!empty($forum_list)) {
5346
        foreach ($forum_list as $key => $value) {
5347
            $lastPost = get_last_post_information($key, api_is_allowed_to_edit());
5348
            if ($lastPost) {
5349
                $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
5350
                $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
5351
                $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
5352
                $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
5353
                $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
5354
                $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
5355
            }
5356
        }
5357
    }
5358
5359
    return $forum_list;
5360
}
5361
5362
/**
5363
 * This function stores which users have to be notified of which forums or threads.
5364
 *
5365
 * @param string $content    does the user want to be notified about a forum or about a thread
5366
 * @param int    $id         the id of the forum or thread
5367
 * @param bool   $addOnly
5368
 * @param array  $userInfo
5369
 * @param array  $courseInfo
5370
 *
5371
 * @return string language variable
5372
 *
5373
 * @author  Patrick Cool <[email protected]>, Ghent University, Belgium
5374
 * @author  Julio Montoya
5375
 *
5376
 * @since   May 2008 v1.8.5
5377
 */
5378
function set_notification($content, $id, $addOnly = false, $userInfo = [], $courseInfo = [])
5379
{
5380
    $userInfo = empty($userInfo) ? api_get_user_info() : $userInfo;
5381
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
5382
    $id = (int) $id;
5383
5384
    if (empty($userInfo) || empty($courseInfo) || empty($id) || empty($content)) {
5385
        return false;
5386
    }
5387
5388
    // Database table definition
5389
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5390
    $course_id = $courseInfo['real_id'];
5391
5392
    // Which database field do we have to store the id in?
5393
    $field = 'thread_id';
5394
    if ('forum' === $content) {
5395
        $field = 'forum_id';
5396
    }
5397
5398
    $userId = $userInfo['user_id'];
5399
5400
    // First we check if the notification is already set for this.
5401
    $sql = "SELECT * FROM $table_notification
5402
            WHERE
5403
                c_id = $course_id AND
5404
                $field = $id AND
5405
                user_id = $userId ";
5406
    $result = Database::query($sql);
5407
    $total = Database::num_rows($result);
5408
5409
    // If the user did not indicate that (s)he wanted to be notified already
5410
    // then we store the notification request (to prevent double notification requests).
5411
    if ($total <= 0) {
5412
        $notification = new CForumNotification();
5413
        $notification
5414
            ->setCId($course_id)
5415
            ->setUserId($userId)
5416
        ;
5417
5418
        if ('forum' === $content) {
5419
            $notification->setForumId($id);
5420
        } else {
5421
            $notification->setThreadId($id);
5422
        }
5423
5424
        $em = Database::getManager();
5425
        $em->persist($notification);
5426
        $em->flush();
5427
5428
        Session::erase('forum_notification');
5429
        getNotificationsPerUser(0, true);
5430
5431
        return get_lang('You will be notified of new posts by e-mail.');
5432
    } else {
5433
        if (!$addOnly) {
5434
            $sql = "DELETE FROM $table_notification
5435
                    WHERE
5436
                        c_id = $course_id AND
5437
                        $field = $id AND
5438
                        user_id = $userId ";
5439
            Database::query($sql);
5440
            Session::erase('forum_notification');
5441
            getNotificationsPerUser(0, true);
5442
5443
            return get_lang('You will no longer be notified of new posts by email');
5444
        }
5445
    }
5446
}
5447
5448
/**
5449
 * This function retrieves all the email adresses of the users who wanted to be notified
5450
 * about a new post in a certain forum or thread.
5451
 *
5452
 * @param string $content does the user want to be notified about a forum or about a thread
5453
 * @param int    $id      the id of the forum or thread
5454
 *
5455
 * @return array returns
5456
 *
5457
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5458
 * @author Julio Montoya
5459
 *
5460
 * @version May 2008, dokeos 1.8.5
5461
 *
5462
 * @since May 2008, dokeos 1.8.5
5463
 */
5464
function get_notifications($content, $id)
5465
{
5466
    // Database table definition
5467
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5468
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5469
    $course_id = api_get_course_int_id();
5470
5471
    // Which database field contains the notification?
5472
    $field = 'thread_id';
5473
    if ('forum' === $content) {
5474
        $field = 'forum_id';
5475
    }
5476
5477
    $id = (int) $id;
5478
5479
    $sql = "SELECT user.id as user_id, user.firstname, user.lastname, user.email, user.id user
5480
            FROM $table_users user, $table_notification notification
5481
            WHERE
5482
                notification.c_id = $course_id AND user.active = 1 AND
5483
                user.id = notification.user_id AND
5484
                notification.$field = $id ";
5485
5486
    $result = Database::query($sql);
5487
    $return = [];
5488
5489
    while ($row = Database::fetch_array($result)) {
5490
        $return['user'.$row['user_id']] = ['email' => $row['email'], 'user_id' => $row['user_id']];
5491
    }
5492
5493
    return $return;
5494
}
5495
5496
/**
5497
 * Get all the users who need to receive a notification of a new post (those subscribed to
5498
 * the forum or the thread).
5499
 *
5500
 * @param int $post_id the id of the post
5501
 *
5502
 * @return false|null
5503
 *
5504
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5505
 *
5506
 * @version May 2008, dokeos 1.8.5
5507
 *
5508
 * @since May 2008, dokeos 1.8.5
5509
 */
5510
function send_notifications(CForumForum $forum, CForumThread $thread, $post_id = 0)
5511
{
5512
    if (!$forum) {
5513
        return false;
5514
    }
5515
5516
    // Users who subscribed to the forum
5517
    $users_to_be_notified_by_forum = get_notifications('forum', $forum->getIid());
5518
5519
    // User who subscribed to the thread
5520
    $users_to_be_notified_by_thread = [];
5521
    if (!$thread) {
5522
        $users_to_be_notified_by_thread = get_notifications('thread', $thread->getIid());
5523
    }
5524
5525
    $postInfo = null;
5526
    if (!empty($post_id)) {
5527
        $postInfo = Container::getForumPostRepository()->find($post_id);
5528
    }
5529
5530
    // Merging the two
5531
    $users_to_be_notified = array_merge($users_to_be_notified_by_forum, $users_to_be_notified_by_thread);
5532
5533
    if (is_array($users_to_be_notified)) {
5534
        foreach ($users_to_be_notified as $value) {
5535
            $userInfo = api_get_user_info($value['user_id']);
5536
            send_mail($userInfo, $forum, $thread, $postInfo);
5537
        }
5538
    }
5539
}
5540
5541
/**
5542
 * Get all the notification subscriptions of the user
5543
 * = which forums and which threads does the user wants to be informed of when a new
5544
 * post is added to this thread.
5545
 *
5546
 * @param int  $user_id the user_id of a user (default = 0 => the current user)
5547
 * @param bool $force   force get the notification subscriptions (even if the information is already in the session
5548
 *
5549
 * @return array
5550
 *
5551
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
5552
 *
5553
 * @version May 2008, dokeos 1.8.5
5554
 *
5555
 * @since May 2008, dokeos 1.8.5
5556
 */
5557
function getNotificationsPerUser($user_id = 0, $force = false, $course_id = 0)
5558
{
5559
    // Database table definition
5560
    $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
5561
    $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
5562
    if (empty($course_id) || -1 == $course_id) {
5563
        return null;
5564
    }
5565
5566
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
5567
5568
    if (!isset($_SESSION['forum_notification']) ||
5569
        $_SESSION['forum_notification']['course'] != $course_id ||
5570
        true == $force
5571
    ) {
5572
        $_SESSION['forum_notification']['course'] = $course_id;
5573
        $sql = "SELECT * FROM $table_notification
5574
                WHERE c_id = $course_id AND user_id='".$user_id."'";
5575
5576
        $result = Database::query($sql);
5577
        while ($row = Database::fetch_array($result)) {
5578
            if (null !== $row['forum_id']) {
5579
                $_SESSION['forum_notification']['forum'][] = $row['forum_id'];
5580
            }
5581
            if (null !== $row['thread_id']) {
5582
                $_SESSION['forum_notification']['thread'][] = $row['thread_id'];
5583
            }
5584
        }
5585
    }
5586
}
5587
5588
/**
5589
 * This function counts the number of post inside a thread.
5590
 *
5591
 * @param int $thread_id
5592
 *
5593
 * @return int the number of post inside a thread
5594
 *
5595
 * @author Jhon Hinojosa <[email protected]>,
5596
 *
5597
 * @version octubre 2008, dokeos 1.8
5598
 */
5599
function count_number_of_post_in_thread($thread_id)
5600
{
5601
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5602
    $course_id = api_get_course_int_id();
5603
    if (empty($course_id)) {
5604
        return 0;
5605
    }
5606
    $sql = "SELECT count(*) count FROM $table_posts
5607
            WHERE
5608
                c_id = $course_id AND
5609
                thread_id='".(int) $thread_id."' ";
5610
    $result = Database::query($sql);
5611
5612
    $count = 0;
5613
    if (Database::num_rows($result) > 0) {
5614
        $row = Database::fetch_array($result);
5615
        $count = $row['count'];
5616
    }
5617
5618
    return $count;
5619
}
5620
5621
/**
5622
 * This function counts the number of post inside a thread user.
5623
 *
5624
 * @param int $thread_id
5625
 * @param int $user_id
5626
 *
5627
 * @return int the number of post inside a thread user
5628
 */
5629
function count_number_of_post_for_user_thread($thread_id, $user_id)
5630
{
5631
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5632
    $course_id = api_get_course_int_id();
5633
    $sql = "SELECT count(iid) as count
5634
            FROM $table_posts
5635
            WHERE c_id = $course_id AND
5636
                  thread_id=".(int) $thread_id.' AND
5637
                  poster_id = '.(int) $user_id.' AND visible = 1 ';
5638
    $result = Database::query($sql);
5639
    $count = 0;
5640
    if (Database::num_rows($result) > 0) {
5641
        $count = Database::fetch_array($result);
5642
        $count = $count['count'];
5643
    }
5644
5645
    return $count;
5646
}
5647
5648
/**
5649
 * This function retrieves information of statistical.
5650
 *
5651
 * @param int $thread_id
5652
 * @param int $user_id
5653
 * @param int $course_id
5654
 *
5655
 * @return array the information of statistical
5656
 *
5657
 * @author Jhon Hinojosa <[email protected]>,
5658
 *
5659
 * @version oct 2008, dokeos 1.8
5660
 */
5661
function get_statistical_information($thread_id, $user_id, $course_id)
5662
{
5663
    $result = [];
5664
    $courseInfo = api_get_course_info_by_id($course_id);
5665
    $result['user_course'] = CourseManager::get_users_count_in_course($courseInfo['code']);
5666
    $result['post'] = count_number_of_post_in_thread($thread_id);
5667
    $result['user_post'] = count_number_of_post_for_user_thread($thread_id, $user_id);
5668
5669
    return $result;
5670
}
5671
5672
/**
5673
 * This function return the posts inside a thread from a given user.
5674
 *
5675
 * @param string $course_code
5676
 * @param int    $thread_id
5677
 * @param int    $user_id
5678
 *
5679
 * @return array posts inside a thread
5680
 *
5681
 * @author Jhon Hinojosa <[email protected]>,
5682
 *
5683
 * @version oct 2008, dokeos 1.8
5684
 */
5685
function get_thread_user_post($course_code, $thread_id, $user_id)
5686
{
5687
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5688
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5689
    $thread_id = (int) $thread_id;
5690
    $user_id = (int) $user_id;
5691
    $course_info = api_get_user_info($course_code);
5692
    $course_id = $course_info['real_id'];
5693
5694
    if (empty($course_id)) {
5695
        $course_id = api_get_course_int_id();
5696
    }
5697
    $sql = "SELECT * FROM $table_posts posts
5698
            LEFT JOIN  $table_users users
5699
                ON posts.poster_id=users.user_id
5700
            WHERE
5701
                posts.c_id = $course_id AND
5702
                posts.thread_id='$thread_id'
5703
                AND posts.poster_id='$user_id'
5704
            ORDER BY posts.post_id ASC";
5705
5706
    $result = Database::query($sql);
5707
    $post_list = [];
5708
    while ($row = Database::fetch_array($result)) {
5709
        $row['status'] = '1';
5710
        $post_list[] = $row;
5711
        $sql = "SELECT * FROM $table_posts posts
5712
                LEFT JOIN $table_users users
5713
                ON (posts.poster_id=users.user_id)
5714
                WHERE
5715
                    posts.c_id = $course_id AND
5716
                    posts.thread_id='$thread_id'
5717
                    AND posts.post_parent_id='".$row['post_id']."'
5718
                ORDER BY posts.post_id ASC";
5719
        $result2 = Database::query($sql);
5720
        while ($row2 = Database::fetch_array($result2)) {
5721
            $row2['status'] = '0';
5722
            $post_list[] = $row2;
5723
        }
5724
    }
5725
5726
    return $post_list;
5727
}
5728
5729
/**
5730
 * This function get the name of an thread by id.
5731
 *
5732
 * @param int $thread_id
5733
 *
5734
 * @return string
5735
 *
5736
 * @author Christian Fasanando
5737
 * @author Julio Montoya <[email protected]> Adding security
5738
 */
5739
function get_name_thread_by_id($thread_id)
5740
{
5741
    $t_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
5742
    $course_id = api_get_course_int_id();
5743
    $sql = "SELECT thread_title
5744
            FROM $t_forum_thread
5745
            WHERE c_id = $course_id AND thread_id = '".(int) $thread_id."' ";
5746
    $result = Database::query($sql);
5747
    $row = Database::fetch_array($result);
5748
5749
    return $row[0];
5750
}
5751
5752
/**
5753
 * This function gets all the post written by an user.
5754
 *
5755
 * @param int $user_id
5756
 *
5757
 * @return string
5758
 */
5759
function get_all_post_from_user($user_id, $courseId)
5760
{
5761
    $j = 0;
5762
    $forums = get_forums($courseId);
5763
    krsort($forums);
5764
    $forum_results = '';
5765
5766
    foreach ($forums as $forum) {
5767
        $forumId = $forum->getIid();
5768
5769
        /*if (0 == $forum['visibility']) {
5770
            continue;
5771
        }*/
5772
        if ($j <= 4) {
5773
            $threads = get_threads($forumId);
5774
5775
            if ($threads) {
5776
                $i = 0;
5777
                $hand_forums = '';
5778
                $post_counter = 0;
5779
                foreach ($threads as $thread) {
5780
                    /*if (0 == $thread['visibility']) {
5781
                        continue;
5782
                    }*/
5783
                    if ($i <= 4) {
5784
                        $post_list = get_thread_user_post_limit(
5785
                            $courseId,
5786
                            $thread->getIid(),
5787
                            $user_id,
5788
                            1
5789
                        );
5790
                        $post_counter = count($post_list);
5791
                        if (is_array($post_list) && count($post_list) > 0) {
5792
                            $hand_forums .= '<div id="social-thread">';
5793
                            $hand_forums .= Display::return_icon(
5794
                                'thread.png',
5795
                                get_lang('Thread'),
5796
                                '',
5797
                                ICON_SIZE_MEDIUM
5798
                            );
5799
                            $hand_forums .= '&nbsp;'.Security::remove_XSS($thread->getThreadTitle(), STUDENT);
5800
                            $hand_forums .= '</div>';
5801
5802
                            foreach ($post_list as $posts) {
5803
                                $hand_forums .= '<div id="social-post">';
5804
                                $hand_forums .= '<strong>'.Security::remove_XSS($posts['post_title'], STUDENT).'</strong>';
5805
                                $hand_forums .= '<br / >';
5806
                                $hand_forums .= Security::remove_XSS($posts['post_text'], STUDENT);
5807
                                $hand_forums .= '</div>';
5808
                                $hand_forums .= '<br / >';
5809
                            }
5810
                        }
5811
                    }
5812
                    $i++;
5813
                }
5814
                $forum_results .= '<div id="social-forum">';
5815
                $forum_results .= '<div class="clear"></div><br />';
5816
                $forum_results .= '<div id="social-forum-title">'.
5817
                    Display::return_icon('forum.gif', get_lang('Forum')).'&nbsp;'.Security::remove_XSS($forum['forum_title'], STUDENT).
5818
                    '<div style="float:right;margin-top:-35px">
5819
                        <a href="../forum/viewforum.php?'.api_get_cidreq_params($courseId).'&forum='.$forum['forum_id'].' " >'.
5820
                    get_lang('See forum').'
5821
                        </a>
5822
                     </div></div>';
5823
                $forum_results .= '<br / >';
5824
                if ($post_counter > 0) {
5825
                    $forum_results .= $hand_forums;
5826
                }
5827
                $forum_results .= '</div>';
5828
            }
5829
            $j++;
5830
        }
5831
    }
5832
5833
    return $forum_results;
5834
}
5835
5836
/**
5837
 * @param int $thread_id
5838
 * @param int $user_id
5839
 * @param int $limit
5840
 *
5841
 * @return array
5842
 */
5843
function get_thread_user_post_limit($courseId, $thread_id, $user_id, $limit = 10)
5844
{
5845
    $table_posts = Database::get_course_table(TABLE_FORUM_POST);
5846
    $table_users = Database::get_main_table(TABLE_MAIN_USER);
5847
5848
    $courseId = (int) $courseId;
5849
5850
    $sql = "SELECT * FROM $table_posts posts
5851
            LEFT JOIN $table_users users
5852
                ON posts.poster_id=users.user_id
5853
            WHERE
5854
                posts.c_id = $courseId AND
5855
                posts.thread_id='".Database::escape_string($thread_id)."' AND
5856
                posts.poster_id='".Database::escape_string($user_id)."'
5857
            ORDER BY posts.post_id DESC LIMIT $limit ";
5858
    $result = Database::query($sql);
5859
    $post_list = [];
5860
    while ($row = Database::fetch_array($result)) {
5861
        $row['status'] = '1';
5862
        $post_list[] = $row;
5863
    }
5864
5865
    return $post_list;
5866
}
5867
5868
/**
5869
 * @param string $userId
5870
 * @param array  $courseInfo
5871
 * @param int    $sessionId
5872
 *
5873
 * @return array
5874
 */
5875
function getForumCreatedByUser($userId, $courseInfo, $sessionId)
5876
{
5877
    if (empty($userId) || empty($courseInfo)) {
5878
        return [];
5879
    }
5880
5881
    $courseId = $courseInfo['real_id'];
5882
    $items = api_get_item_property_list_by_tool_by_user(
5883
        $userId,
5884
        'forum',
5885
        $courseId,
5886
        $sessionId
5887
    );
5888
5889
    $forumList = [];
5890
    if (!empty($items)) {
5891
        foreach ($items as $forum) {
5892
            $forumInfo = get_forums(
5893
                $forum['ref'],
5894
                $courseInfo['code'],
5895
                true,
5896
                $sessionId
5897
            );
5898
            if (!empty($forumInfo) && isset($forumInfo['forum_title'])) {
5899
                $forumList[] = [
5900
                    $forumInfo['forum_title'],
5901
                    api_get_local_time($forum['insert_date']),
5902
                    api_get_local_time($forum['lastedit_date']),
5903
                ];
5904
            }
5905
        }
5906
    }
5907
5908
    return $forumList;
5909
}
5910
5911
/**
5912
 * This function builds an array of all the posts in a given thread
5913
 * where the key of the array is the post_id
5914
 * It also adds an element children to the array which itself is an array
5915
 * that contains all the id's of the first-level children.
5916
 *
5917
 * @return array containing all the information on the posts of a thread
5918
 *
5919
 * @author Patrick Cool <[email protected]>, Ghent University
5920
 */
5921
function calculate_children($rows)
5922
{
5923
    $sorted_rows = [0 => []];
5924
    if (!empty($rows)) {
5925
        foreach ($rows as $row) {
5926
            $rows_with_children[$row['post_id']] = $row;
5927
            $rows_with_children[$row['post_parent_id']]['children'][] = $row['post_id'];
5928
        }
5929
5930
        $rows = $rows_with_children;
5931
        forumRecursiveSort($rows, $sorted_rows);
5932
        unset($sorted_rows[0]);
5933
    }
5934
5935
    return $sorted_rows;
5936
}
5937
5938
/**
5939
 * @param $rows
5940
 * @param $threads
5941
 * @param int $seed
5942
 * @param int $indent
5943
 */
5944
function forumRecursiveSort($rows, &$threads, $seed = 0, $indent = 0)
5945
{
5946
    if ($seed > 0) {
5947
        $threads[$rows[$seed]['post_id']] = $rows[$seed];
5948
        $threads[$rows[$seed]['post_id']]['indent_cnt'] = $indent;
5949
        $indent++;
5950
    }
5951
5952
    if (isset($rows[$seed]['children'])) {
5953
        foreach ($rows[$seed]['children'] as $child) {
5954
            forumRecursiveSort($rows, $threads, $child, $indent);
5955
        }
5956
    }
5957
}
5958
5959
/**
5960
 * Update forum attachment data, used to update comment and post ID.
5961
 *
5962
 * @param array  $array    (field => value) to update forum attachment row
5963
 * @param attach $id       ID to find row to update
5964
 * @param null   $courseId course ID to find row to update
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $courseId is correct as it would always require null to be passed?
Loading history...
5965
 *
5966
 * @return int number of affected rows
5967
 */
5968
function editAttachedFile($array, $id, $courseId = null)
5969
{
5970
    // Init variables
5971
    $setString = '';
5972
    $id = (int) $id;
5973
    $courseId = (int) $courseId;
5974
    if (empty($courseId)) {
5975
        // $courseId can be null, use api method
5976
        $courseId = api_get_course_int_id();
5977
    }
5978
    /*
5979
     * Check if Attachment ID and Course ID are greater than zero
5980
     * and array of field values is not empty
5981
     */
5982
    if ($id > 0 && $courseId > 0 && !empty($array) && is_array($array)) {
5983
        foreach ($array as $key => &$item) {
5984
            $item = Database::escape_string($item);
5985
            $setString .= $key.' = "'.$item.'", ';
5986
        }
5987
        // Delete last comma
5988
        $setString = substr($setString, 0, strlen($setString) - 2);
5989
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
5990
        $sql = "UPDATE $forumAttachmentTable
5991
                SET $setString WHERE c_id = $courseId AND id = $id";
5992
        $result = Database::query($sql);
5993
        if (false !== $result) {
5994
            $affectedRows = Database::affected_rows($result);
5995
            if ($affectedRows > 0) {
5996
                /*
5997
                 * If exist in $_SESSION variable, then delete them from it
5998
                 * because they would be deprecated
5999
                 */
6000
                if (!empty($_SESSION['forum']['upload_file'][$courseId][$id])) {
6001
                    unset($_SESSION['forum']['upload_file'][$courseId][$id]);
6002
                }
6003
            }
6004
6005
            return $affectedRows;
6006
        }
6007
    }
6008
6009
    return 0;
6010
}
6011
6012
/**
6013
 * Return a table where the attachments will be set.
6014
 *
6015
 * @param int $postId Forum Post ID
6016
 *
6017
 * @return string The Forum Attachments Ajax Table
6018
 */
6019
function getAttachmentsAjaxTable($postId = 0)
6020
{
6021
    $postId = (int) $postId;
6022
    $courseId = api_get_course_int_id();
6023
    $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6024
    $fileDataContent = '';
6025
    // Update comment to show if form did not pass validation
6026
    if (!empty($_REQUEST['file_ids']) && is_array($_REQUEST['file_ids'])) {
6027
        // 'file_ids is the name from forum attachment ajax form
6028
        foreach ($_REQUEST['file_ids'] as $key => $attachId) {
6029
            if (!empty($_SESSION['forum']['upload_file'][$courseId][$attachId]) &&
6030
                is_array($_SESSION['forum']['upload_file'][$courseId][$attachId])
6031
            ) {
6032
                // If exist forum attachment then update into $_SESSION data
6033
                $_SESSION['forum']['upload_file'][$courseId][$attachId]['comment'] = $_POST['file_comments'][$key];
6034
            }
6035
        }
6036
    }
6037
6038
    // Get data to fill into attachment files table
6039
    if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6040
        is_array($_SESSION['forum']['upload_file'][$courseId])
6041
    ) {
6042
        $uploadedFiles = $_SESSION['forum']['upload_file'][$courseId];
6043
        foreach ($uploadedFiles as $k => $uploadedFile) {
6044
            if (!empty($uploadedFile) && in_array($uploadedFile['id'], $attachIds)) {
6045
                // Buil html table including an input with attachmentID
6046
                $fileDataContent .= '<tr id="'.$uploadedFile['id'].'" ><td>'.$uploadedFile['name'].'</td><td>'.$uploadedFile['size'].'</td><td>&nbsp;'.$uploadedFile['result'].
6047
                    ' </td><td> <input style="width:90%;" type="text" value="'.$uploadedFile['comment'].'" name="file_comments[]"> </td><td>'.
6048
                    $uploadedFile['delete'].'</td>'.
6049
                    '<input type="hidden" value="'.$uploadedFile['id'].'" name="file_ids[]">'.'</tr>';
6050
            } else {
6051
                /*
6052
                 * If attachment data is empty, then delete it from $_SESSION
6053
                 * because could generate and empty row into html table
6054
                 */
6055
                unset($_SESSION['forum']['upload_file'][$courseId][$k]);
6056
            }
6057
        }
6058
    }
6059
    $style = empty($fileDataContent) ? 'display: none;' : '';
6060
    // Forum attachment Ajax table
6061
    return '
6062
    <div class="control-group " style="'.$style.'">
6063
        <label class="control-label">'.get_lang('Attachments list').'</label>
6064
        <div class="controls">
6065
            <table id="attachmentFileList" class="files data_table span10">
6066
                <tr>
6067
                    <th>'.get_lang('Filename').'</th>
6068
                    <th>'.get_lang('Size').'</th>
6069
                    <th>'.get_lang('Status').'</th>
6070
                    <th>'.get_lang('Comment').'</th>
6071
                    <th>'.get_lang('Delete').'</th>
6072
                </tr>
6073
                '.$fileDataContent.'
6074
            </table>
6075
        </div>
6076
    </div>';
6077
}
6078
6079
/**
6080
 * Return an array of prepared attachment data to build forum attachment table
6081
 * Also, save this array into $_SESSION to do available the attachment data.
6082
 *
6083
 * @param int $forumId
6084
 * @param int $threadId
6085
 * @param int $postId
6086
 * @param int $attachId
6087
 * @param int $courseId
6088
 *
6089
 * @return array
6090
 */
6091
function getAttachedFiles(
6092
    $forumId,
6093
    $threadId,
6094
    $postId = 0,
6095
    $attachId = 0,
6096
    $courseId = 0
6097
) {
6098
    $forumId = (int) $forumId;
6099
    $courseId = (int) $courseId;
6100
    $attachId = (int) $attachId;
6101
    $postId = (int) $postId;
6102
    $threadId = !empty($threadId) ? (int) $threadId : isset($_REQUEST['thread']) ? (int) ($_REQUEST['thread']) : '';
6103
    if (empty($courseId)) {
6104
        // $courseId can be null, use api method
6105
        $courseId = api_get_course_int_id();
6106
    }
6107
    if (empty($forumId)) {
6108
        if (!empty($_REQUEST['forum'])) {
6109
            $forumId = (int) $_REQUEST['forum'];
6110
        } else {
6111
            // if forum ID is empty, cannot generate delete url
6112
6113
            return [];
6114
        }
6115
    }
6116
    // Check if exist at least one of them to filter forum attachment select query
6117
    if (empty($postId) && empty($attachId)) {
6118
        return [];
6119
    }
6120
6121
    if (empty($postId)) {
6122
        $filter = "AND iid = $attachId";
6123
    } elseif (empty($attachId)) {
6124
        $filter = "AND post_id = $postId";
6125
    } else {
6126
        $filter = "AND post_id = $postId AND iid = $attachId";
6127
    }
6128
    $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6129
    $sql = "SELECT iid
6130
            FROM $forumAttachmentTable
6131
            WHERE c_id = $courseId $filter";
6132
    $result = Database::query($sql);
6133
    $json = [];
6134
    if (Database::num_rows($result) > 0) {
6135
        $repo = Container::getForumAttachmentRepository();
6136
        while ($row = Database::fetch_array($result, 'ASSOC')) {
6137
            /** @var CForumAttachment $attachment */
6138
            $attachment = $repo->find($row['iid']);
6139
            $downloadUrl = $repo->getResourceFileDownloadUrl($attachment);
6140
6141
            // name contains an URL to download attachment file and its filename
6142
            $json['name'] = Display::url(
6143
                api_htmlentities($attachment->getFilename()),
6144
                $downloadUrl,
6145
                ['target' => '_blank', 'class' => 'attachFilename']
6146
            );
6147
            $json['id'] = $row['iid'];
6148
            $json['comment'] = $attachment->getComment();
6149
            // Format file size
6150
            $json['size'] = format_file_size($attachment->getSize());
6151
            // Check if $row is consistent
6152
            if ($attachment) {
6153
                // Set result as success and bring delete URL
6154
                $json['result'] = Display::return_icon('accept.png', get_lang('Uploaded.'));
6155
                $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&action=delete_attach&forum='.$forumId.'&thread='.$threadId.'&id_attach='.$row['iid'];
6156
                $json['delete'] = Display::url(
6157
                    Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL),
6158
                    $url,
6159
                    ['class' => 'deleteLink']
6160
                );
6161
            } else {
6162
                // If not, set an exclamation result
6163
                $json['result'] = Display::return_icon('exclamation.png', get_lang('Error'));
6164
            }
6165
            // Store array data into $_SESSION
6166
            $_SESSION['forum']['upload_file'][$courseId][$json['id']] = $json;
6167
        }
6168
    }
6169
6170
    return $json;
6171
}
6172
6173
/**
6174
 * Clear forum attachment data stored in $_SESSION,
6175
 * If is not defined post, it will clear all forum attachment data from course.
6176
 *
6177
 * @param int $postId   -1 : Clear all attachments from course stored in $_SESSION
6178
 *                      0 : Clear attachments from course, except from temporal post "0"
6179
 *                      but without delete them from file system and database
6180
 *                      Other values : Clear attachments from course except specified post
6181
 *                      and delete them from file system and database
6182
 * @param int $courseId : Course ID, if it is null, will use api_get_course_int_id()
6183
 *
6184
 * @return array
6185
 */
6186
function clearAttachedFiles($postId = 0, $courseId = 0)
6187
{
6188
    // Init variables
6189
    $courseId = (int) $courseId;
6190
    $postId = (int) $postId;
6191
    $array = [];
6192
    if (empty($courseId)) {
6193
        // $courseId can be null, use api method
6194
        $courseId = api_get_course_int_id();
6195
    }
6196
    if (-1 === $postId) {
6197
        // If post ID is -1 then delete course's attachment data from $_SESSION
6198
        if (!empty($_SESSION['forum']['upload_file'][$courseId])) {
6199
            $array = array_keys($_SESSION['forum']['upload_file'][$courseId]);
6200
            unset($_SESSION['forum']['upload_file'][$courseId]);
6201
        }
6202
    } else {
6203
        $attachIds = getAttachmentIdsByPostId($postId, $courseId);
6204
        if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
6205
            is_array($_SESSION['forum']['upload_file'][$courseId])) {
6206
            foreach ($_SESSION['forum']['upload_file'][$courseId] as $attachId => $attach) {
6207
                if (!in_array($attachId, $attachIds)) {
6208
                    // If attach ID is not into specified post, delete attachment
6209
                    // Save deleted attachment ID
6210
                    $array[] = $attachId;
6211
                    if (0 !== $postId) {
6212
                        // Post 0 is temporal, delete them from file system and DB
6213
                        delete_attachment(0, $attachId);
6214
                    }
6215
                    // Delete attachment data from $_SESSION
6216
                    unset($_SESSION['forum']['upload_file'][$courseId][$attachId]);
6217
                }
6218
            }
6219
        }
6220
    }
6221
6222
    return $array;
6223
}
6224
6225
/**
6226
 * Returns an array of forum attachment ids into a course and forum post.
6227
 *
6228
 * @param int $postId
6229
 * @param int $courseId
6230
 *
6231
 * @return array
6232
 */
6233
function getAttachmentIdsByPostId($postId, $courseId = 0)
6234
{
6235
    $array = [];
6236
    $courseId = (int) $courseId;
6237
    $postId = (int) $postId;
6238
    if (empty($courseId)) {
6239
        // $courseId can be null, use api method
6240
        $courseId = api_get_course_int_id();
6241
    }
6242
    if ($courseId > 0) {
6243
        $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
6244
        $sql = "SELECT iid FROM $forumAttachmentTable
6245
                WHERE c_id = $courseId AND post_id = $postId";
6246
        $result = Database::query($sql);
6247
        if (false !== $result && Database::num_rows($result) > 0) {
6248
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6249
                $array[] = $row['iid'];
6250
            }
6251
        }
6252
    }
6253
6254
    return $array;
6255
}
6256
6257
/**
6258
 * Check if the forum category exists looking for its title.
6259
 *
6260
 * @param string $title     The forum category title
6261
 * @param int    $courseId  The course ID
6262
 * @param int    $sessionId Optional. The session ID
6263
 *
6264
 * @return bool
6265
 */
6266
function getForumCategoryByTitle($title, $courseId, $sessionId = 0)
6267
{
6268
    $sessionId = (int) $sessionId;
6269
    $courseId = (int) $courseId;
6270
    $forumCategoryTable = Database::get_course_table(TABLE_FORUM_CATEGORY);
6271
    $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6272
6273
    $fakeFrom = "$forumCategoryTable fc
6274
        INNER JOIN $itemProperty ip ";
6275
6276
    if (0 === $sessionId) {
6277
        $fakeFrom .= '
6278
            ON (
6279
                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)
6280
            )
6281
        ';
6282
    } else {
6283
        $fakeFrom .= '
6284
            ON (
6285
                fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND fc.session_id = ip.session_id
6286
            )
6287
        ';
6288
    }
6289
6290
    $resultData = Database::select(
6291
        'fc.*',
6292
        $fakeFrom,
6293
        [
6294
            'where' => [
6295
                'ip.visibility != ? AND ' => 2,
6296
                'ip.tool = ? AND ' => TOOL_FORUM_CATEGORY,
6297
                'fc.session_id = ? AND ' => $sessionId,
6298
                'fc.cat_title = ? AND ' => $title,
6299
                'fc.c_id = ?' => $courseId,
6300
            ],
6301
        ],
6302
        'first'
6303
    );
6304
6305
    if (empty($resultData)) {
6306
        return false;
6307
    }
6308
6309
    return $resultData;
6310
}
6311
6312
/**
6313
 * @param array $row
6314
 * @param bool  $addWrapper
6315
 *
6316
 * @return string
6317
 */
6318
function getPostStatus(CForumForum $forum, $row, $addWrapper = true)
6319
{
6320
    $statusIcon = '';
6321
    if ($forum->isModerated()) {
6322
        if ($addWrapper) {
6323
            $statusIcon = '<br /><br /><span id="status_post_'.$row['iid'].'">';
6324
        }
6325
        $row['status'] = empty($row['status']) ? 2 : $row['status'];
6326
6327
        $addUrl = false;
6328
        $showStatus = false;
6329
        if (api_is_allowed_to_edit(false, true)) {
6330
            $addUrl = true;
6331
        } else {
6332
            if ($row['user_id'] == api_get_user_id()) {
6333
                $showStatus = true;
6334
            }
6335
        }
6336
6337
        $label = '';
6338
        $icon = '';
6339
        $buttonType = '';
6340
        switch ($row['status']) {
6341
            case CForumPost::STATUS_VALIDATED:
6342
                $label = get_lang('Validated');
6343
                $icon = 'check-circle';
6344
                $buttonType = 'success';
6345
6346
                break;
6347
            case CForumPost::STATUS_WAITING_MODERATION:
6348
                $label = get_lang('Waiting for moderation');
6349
                $icon = 'warning';
6350
                $buttonType = 'warning';
6351
6352
                break;
6353
            case CForumPost::STATUS_REJECTED:
6354
                $label = get_lang('Rejected');
6355
                $icon = 'minus-circle';
6356
                $buttonType = 'danger';
6357
6358
                break;
6359
        }
6360
6361
        if ($addUrl) {
6362
            $statusIcon .= Display::toolbarButton(
6363
                $label.'&nbsp;',
6364
                'javascript:void(0)',
6365
                $icon,
6366
                $buttonType,
6367
                ['class' => 'change_post_status']
6368
            );
6369
        } else {
6370
            if ($showStatus) {
6371
                $statusIcon .= Display::label(
6372
                    Display::returnFontAwesomeIcon($icon).$label,
6373
                    $buttonType
6374
                );
6375
            }
6376
        }
6377
6378
        if ($addWrapper) {
6379
            $statusIcon .= '</span>';
6380
        }
6381
    }
6382
6383
    return $statusIcon;
6384
}
6385
6386
/**
6387
 * @param CForumForum $forum
6388
 * @param int         $threadId
6389
 * @param int         $status
6390
 */
6391
function getCountPostsWithStatus($status, $forum, $threadId = null)
6392
{
6393
    $em = Database::getManager();
6394
    $criteria = Criteria::create();
6395
    $criteria
6396
        ->where(Criteria::expr()->eq('status', $status))
6397
        ->andWhere(Criteria::expr()->eq('cId', $forum->getCId()))
6398
        ->andWhere(Criteria::expr()->eq('visible', 1))
6399
    ;
6400
6401
    if (!empty($threadId)) {
6402
        $criteria->andWhere(Criteria::expr()->eq('thread', $threadId));
6403
    }
6404
6405
    $qb = $em->getRepository(CForumPost::class)->createQueryBuilder('p');
6406
    $qb->select('count(p.iid)')
6407
        ->addCriteria($criteria);
6408
6409
    return $qb->getQuery()->getSingleScalarResult();
6410
}
6411
6412
/**
6413
 * @param CForumForum $forum
6414
 * @param CForumPost  $post
6415
 *
6416
 * @return bool
6417
 */
6418
function postIsEditableByStudent($forum, $post)
6419
{
6420
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
6421
        return true;
6422
    }
6423
6424
    if (1 == $forum->isModerated()) {
6425
        if (null === $post->getStatus()) {
6426
            return true;
6427
        } else {
6428
            return in_array(
6429
                $post->getStatus(),
6430
                [
6431
                    CForumPost::STATUS_WAITING_MODERATION,
6432
                    CForumPost::STATUS_REJECTED,
6433
                ]
6434
            );
6435
        }
6436
    }
6437
6438
    return true;
6439
}
6440
6441
/**
6442
 * @param int $postId
6443
 *
6444
 * @return bool
6445
 */
6446
function savePostRevision($postId)
6447
{
6448
    $postData = get_post_information($postId);
6449
6450
    if (empty($postData)) {
6451
        return false;
6452
    }
6453
6454
    $userId = api_get_user_id();
6455
6456
    if ($postData['poster_id'] != $userId) {
6457
        return false;
6458
    }
6459
6460
    $status = (int) !postNeedsRevision($postId);
6461
    $extraFieldValue = new ExtraFieldValue('forum_post');
6462
    $params = [
6463
        'item_id' => $postId,
6464
        'extra_ask_for_revision' => ['extra_ask_for_revision' => $status],
6465
    ];
6466
    if (empty($status)) {
6467
        unset($params['extra_ask_for_revision']);
6468
    }
6469
    $extraFieldValue->saveFieldValues(
6470
        $params,
6471
        true,
6472
        false,
6473
        ['ask_for_revision']
6474
    );
6475
}
6476
6477
/**
6478
 * @param int $postId
6479
 *
6480
 * @return string
6481
 */
6482
function getPostRevision($postId)
6483
{
6484
    $extraFieldValue = new ExtraFieldValue('forum_post');
6485
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6486
        $postId,
6487
        'revision_language'
6488
    );
6489
    $revision = '';
6490
    if ($value && isset($value['value'])) {
6491
        $revision = $value['value'];
6492
    }
6493
6494
    return $revision;
6495
}
6496
6497
/**
6498
 * @param int $postId
6499
 *
6500
 * @return bool
6501
 */
6502
function postNeedsRevision($postId)
6503
{
6504
    $extraFieldValue = new ExtraFieldValue('forum_post');
6505
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6506
        $postId,
6507
        'ask_for_revision'
6508
    );
6509
    $hasRevision = false;
6510
    if ($value && isset($value['value'])) {
6511
        return 1 == $value['value'];
6512
    }
6513
6514
    return $hasRevision;
6515
}
6516
6517
/**
6518
 * @param int   $postId
6519
 * @param array $threadInfo
6520
 *
6521
 * @return string
6522
 */
6523
function getAskRevisionButton($postId, $threadInfo)
6524
{
6525
    if (false === api_get_configuration_value('allow_forum_post_revisions')) {
6526
        return '';
6527
    }
6528
6529
    $postId = (int) $postId;
6530
6531
    $status = 'btn-default';
6532
    if (postNeedsRevision($postId)) {
6533
        $status = 'btn-success';
6534
    }
6535
6536
    return Display::url(
6537
        get_lang('Ask for a revision'),
6538
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6539
        api_get_cidreq().'&action=ask_revision&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6540
        ['class' => "btn $status", 'title' => get_lang('Ask for a revision')]
6541
    );
6542
}
6543
6544
/**
6545
 * @param int   $postId
6546
 * @param array $threadInfo
6547
 *
6548
 * @return string
6549
 */
6550
function giveRevisionButton($postId, $threadInfo)
6551
{
6552
    $postId = (int) $postId;
6553
6554
    return Display::toolbarButton(
6555
        get_lang('Give revision'),
6556
        api_get_path(WEB_CODE_PATH).'forum/reply.php?'.api_get_cidreq().'&'.http_build_query(
6557
            [
6558
                'forum' => $threadInfo['forum_id'],
6559
                'thread' => $threadInfo['thread_id'],
6560
                'post' => $postId = (int) $postId,
6561
                'action' => 'replymessage',
6562
                'give_revision' => 1,
6563
            ]
6564
        ),
6565
        'reply',
6566
        'primary',
6567
        ['id' => "reply-to-post-{$postId}"]
6568
    );
6569
}
6570
6571
/**
6572
 * @param int   $postId
6573
 * @param array $threadInfo
6574
 *
6575
 * @return string
6576
 */
6577
function getReportButton($postId, $threadInfo)
6578
{
6579
    $postId = (int) $postId;
6580
6581
    return Display::url(
6582
        Display::returnFontAwesomeIcon('flag'),
6583
        api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
6584
        api_get_cidreq().'&action=report&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
6585
        ['class' => 'btn btn-danger', 'title' => get_lang('Report')]
6586
    );
6587
}
6588
6589
/**
6590
 * @return bool
6591
 */
6592
function reportAvailable()
6593
{
6594
    $extraFieldValue = new ExtraFieldValue('course');
6595
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6596
        api_get_course_int_id(),
6597
        'allow_forum_report_button'
6598
    );
6599
    $allowReport = false;
6600
    if ($value && isset($value['value']) && 1 == $value['value']) {
6601
        $allowReport = true;
6602
    }
6603
6604
    return $allowReport;
6605
}
6606
6607
/**
6608
 * @return array
6609
 */
6610
function getReportRecipients()
6611
{
6612
    $extraFieldValue = new ExtraFieldValue('course');
6613
    $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6614
        api_get_course_int_id(),
6615
        'forum_report_recipients'
6616
    );
6617
    $users = [];
6618
    if ($value && isset($value['value'])) {
6619
        $usersType = explode(';', $value['value']);
6620
6621
        foreach ($usersType as $type) {
6622
            switch ($type) {
6623
                case 'teachers':
6624
                    $teachers = CourseManager::get_teacher_list_from_course_code(api_get_course_id());
6625
                    if (!empty($teachers)) {
6626
                        $users = array_merge($users, array_column($teachers, 'user_id'));
6627
                    }
6628
6629
                break;
6630
                case 'admins':
6631
                    $admins = UserManager::get_all_administrators();
6632
                    if (!empty($admins)) {
6633
                        $users = array_merge($users, array_column($admins, 'user_id'));
6634
                    }
6635
6636
                    break;
6637
                case 'community_managers':
6638
                    $managers = api_get_configuration_value('community_managers_user_list');
6639
                    if (!empty($managers) && isset($managers['users'])) {
6640
                        $users = array_merge($users, $managers['users']);
6641
                    }
6642
6643
                    break;
6644
            }
6645
        }
6646
6647
        $users = array_unique(array_filter($users));
6648
    }
6649
6650
    return $users;
6651
}
6652
6653
/**
6654
 * @param int   $postId
6655
 * @param array $forumInfo
6656
 * @param array $threadInfo
6657
 *
6658
 * @return bool
6659
 */
6660
function reportPost($postId, $forumInfo, $threadInfo)
6661
{
6662
    if (!reportAvailable()) {
6663
        return false;
6664
    }
6665
6666
    if (empty($forumInfo) || empty($threadInfo)) {
6667
        return false;
6668
    }
6669
6670
    $postId = (int) $postId;
6671
6672
    $postData = get_post_information($postId);
6673
    $currentUser = api_get_user_info();
6674
6675
    if (!empty($postData)) {
6676
        $users = getReportRecipients();
6677
        if (!empty($users)) {
6678
            $url = api_get_path(WEB_CODE_PATH).
6679
                'forum/viewthread.php?forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'].'&'.api_get_cidreq().'&post_id='.$postId.'#post_id_'.$postId;
6680
            $postLink = Display::url(
6681
                $postData['post_title'],
6682
                $url
6683
            );
6684
            $subject = get_lang('Post reported');
6685
            $content = sprintf(
6686
                get_lang('User %s has reported the message %s in the forum %s'),
6687
                $currentUser['complete_name'],
6688
                $postLink,
6689
                $forumInfo['forum_title']
6690
            );
6691
            foreach ($users as $userId) {
6692
                MessageManager::send_message_simple($userId, $subject, $content);
6693
            }
6694
        }
6695
    }
6696
}
6697