Passed
Push — master ( 4728a8...8dc8d6 )
by Julito
10:29
created

getAttachedFiles()   B

Complexity

Conditions 11
Paths 30

Size

Total Lines 81
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

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