Completed
Push — master ( 4fc9f8...d0e06e )
by Julito
12:04
created

send_mail()   B

Complexity

Conditions 10
Paths 25

Size

Total Lines 54
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

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

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

    return false;
}

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

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

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

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

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

    return false;
}

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

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