Passed
Push — master ( b95980...a81919 )
by Julito
08:46
created

saveThreadScore()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 70
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 44
nc 5
nop 6
dl 0
loc 70
rs 9.216
c 0
b 0
f 0

How to fix   Long Method   

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