Completed
Push — master ( 23e37a...6a2455 )
by Julito
13:06 queued 16s
created

move_up_down()   F

Complexity

Conditions 14
Paths 323

Size

Total Lines 93
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

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